sábado, 14 de junho de 2014

“The Beauty of Data Visualization” de David McCandless

"Dados são o novo petróleo." E os dados são uma espécie de recursos ubíquos que podemos moldar para fornecer inovações e novas percepções e está por todo o lado, e pode ser extraída muito facilmente. "

Informações nunca tiveram tanto valor. Principalmente informações sobre temas variados. Hoje, se você não está atualizado sobre tudo, você não é uma pessoa suficientemente "inteligente". Hoje se faz necessário ter compreensão, uma "opinião formada sobre tudo", e isso é no que a tecnologia vem apostando nos últimos anos. 

Meios de comunicação que utilizam de recursos visuais nunca foram tão procurados. Notebooks de ponta são as novas ferramentas para nos mantermos informados por ser um recurso mais visual; as televisões foram (quase) esquecidas, o que dirá dos rádios e jornais de papel.

Hoje, se uma informação não chega com atrativos, é descartada, é tratada como desinteressante, então nada mais compreensível que as novas tecnologias hoje se adequem a o que é bonito de se ver, que atraiam o olhar, e David McCandless nos mostra uma ferramenta muito importante para que essa ideia seja válida, os gráficos e infográficos.

Para entender um infográfico você não precisa ler um texto enorme sobre o assunto, você só precisa olhar para ele e entender o que significam os poucos dados que nos informam, como, por exemplo o gráfico do fim do vídeo, onde David pergunta ao público sobre o que tratava o gráfico que ele mostrou e recebeu diversas interpretações das pessoas. É isso o que a tecnologia hoje deseja: maior compreensão dada da melhor forma possível.

domingo, 8 de junho de 2014

Jogo da Vida com Zoom


O exercício proposto foi achar um modo de dar um zoom no jogo da vida para melhor visualização dos comportamentos. Descobri que já existia uma função no processing que fazia isso automaticamente. A scale() onde pode-se passar por parametro a quantidade de vezes que pretende dar um zoom.

//A tela terá dimensão tam x tam
int tam = 100;
//Como o tipo PImage é armazenado em vetor, então...
int vtam = tam*tam;
//Imagem a ser exibida
PImage mundo = createImage(tam, tam, RGB);
//Imagem auxiliar para criar uma geração
PImage mundoTemp = createImage(tam, tam, RGB);

int geracao = 0;
int maiorPopulacao = 0;
int menorPopulacao = 0;

void setup() {
  size(800, 800);
  background(0);
  frameRate(5);
  criaMundo();
}

void draw() {
 
 
  scale(8);
  //Criando gerações
  evoluiMundo();
  //Exibindo
  image(mundo, 0, 0);
  geracao++;
  maiorPopulacao = maiorPopulacao(maiorPopulacao);
  menorPopulacao = menorPopulacao(menorPopulacao);
  println("Numero de células vivas " + contaCelulas() + " na geração " + geracao);
  println("Maior população: " + maiorPopulacao);
  println("Menor população: " + menorPopulacao);
}

//cria uma geração
void evoluiMundo() {
  /*A nova geração será guardada em mundoTemp, então
   é necessário copiar a geração atual para mundoTemp */
  for (int i=0; i<vtam; i++)
    mundoTemp.pixels[i] =  mundo.pixels[i];

  //Contador de vizinhos 
  int vizinhos;
  //Para cada célula aplicar as regras do jogo da vida
  for (int i=1; i<tam-1; i++)
    for (int j=1; j<tam-1; j++) {
      vizinhos = contaVizinhos(i, j); //Qtde de vizinhos de uma célula i,j     
      //Se a célula viva, ...
      if (mundo.pixels[pos(i, j)] == color (0, 255, 0)) {
        //Menor que 2 vizinhos ou maior que 3, morra
        if ((vizinhos < 2) ||(vizinhos > 3))
          mundoTemp.pixels[pos(i, j)] = color (0, 0, 0);
      }
      //Se morta, mas com 3 vizinhos, viva
      else if (vizinhos == 3)
        mundoTemp.pixels[pos(i, j)] = color (0, 255, 0);
    }

  //Depois de geração criada, atualizar o mundo, copiando de mundoTemp
  mundo.loadPixels();
  for (int i=0; i<vtam; i++)
    mundo.pixels[i] = mundoTemp.pixels[i];
  mundo.updatePixels();
}

//Conta quantos vizinhos a célula possui
int contaVizinhos(int i, int j) {
  int vizinhos=0;
  vizinhos = celula(i-1, j-1) + celula(i-1, j) + celula(i-1, j+1)
    +celula(i, j-1) + celula(i, j+1) + celula(i+1, j-1)
      +celula(i+1, j) + celula(i+1, j+1);
  return vizinhos;
}

//Se a célula for viva (cor 0,255,0 - verde), retorna 1, senão 0
int celula(int i, int j) {
  if (mundo.pixels[pos(i, j)] == color(0, 255, 0))
    return 1;
  return 0;
}

//Mapeia a posição da matriz em um vetor
int pos(int i, int j) {
  return j * tam + i;
}

//Conta células vivas
int contaCelulas()
{
  int c = 0;

  for (int i = 0; i < vtam; i++)
  {
    if (mundo.pixels[i] == color(0, 255, 0))
    {
      c++;
    }
  }
  return c;
}

//Verifica a maior populacao existente
int maiorPopulacao(int maior)
{
  if (contaCelulas() > maior)
  {
    maior = contaCelulas();
  }
  return maior;
}

//Verifica a menor populacao existente
int menorPopulacao(int menor)
{
  if (menor == 0)
  {
    menor = contaCelulas();
  }
  else if (contaCelulas() < menor)
  {
    menor = contaCelulas();
  }
  return menor;
}


//Cria um mundo aleatório em um quadrado central que vai de 1/3 a 2/3 da tela
void criaMundo() {

  for (int i=0; i<vtam; i++)
  {
    int x = int(random(tam/3, 2*tam/3));
    int y = int(random(tam/3, 2*tam/3));
    mundo.pixels[pos(x, y)] = color(0, 255, 0);
  }
}

terça-feira, 27 de maio de 2014

Análise de interface

Neste post irei fazer uma análise da usabilidade de uma aplicação feita no Processing, os autores que serão utilizados como referência são o Jakob Nielsen e o Steve Krug.

Podemos definir Usabilidade como:

"Usabilidade significa fazer algo que funciona bem, e que uma pessoa não muito experiente consiga usá-lo para a sua devida finalidade, sem nenhuma frustração durante esse processo."(Krug)



Nielsen é um cientista da computação com PHD em Interação Humano-Computador e criou 10 heurísticas para avaliar a usabilidade. Podemos definir uma heurística, segundo a wikipédia, como: Um método ou processo criado com o objetivo de encontrar soluções para um problema.

Steve Krug é um pesquisador na área de usabilidade e escreveu um livro chamado "Don't make me think" que trata do tema usabilidade e interação humano-computador.




Link da aplicação: http://vimeo.com/6875954 

Olhar para as barras de seleção de cor e de tamanho.

Olhar para as barras de seleção de cor e de tamanho.

Neste printscreen temos 5 elementos de interação (3 checkboxes, 2 barras de seleção e 4 textos informativos), as barras de seleção são bastante interessantes para a interação com o sistema, já que elas indicam o estado do "pincel". A barra de seleção de cor se modifica de acordo com a cor escolhida e o tamanho da barra "Pen Size" engrossa e afina facilitando a compreensão da aplicação por parte do usuário. Tal característica representa uma das heurísticas de Nielsen que diz:

"Feedback:
  • O sistema deve informar continuamente ao usuário sobre o que ele está fazendo.
  • 10 segundos é o limite para manter a atenção do usuário focalizada no diálogo."

Apesar de ter utilizado respostas visuais bastante eficientes a interface erra na aplicação das checkboxes e do texto informativo na parte inferior da tela.

A aplicação falha ao deixar o usuário pintar sobre a informação de limpar a tela.

"Os usuários não gostam de quebra-cabeças na hora de fazer as coisas. Isso é fato. Se as pessoas que projetam interfaces não se importarem suficientemente em criar coisas óbvias, podem abalar diretamente a confiança dos usuários sobre o seu site."(Krug)

As checkboxes são extremamente não intuitivas o que contradiz o que Krug aponta como ideal, podendo fazer que o usuário perca tempo e acabe por ter dificuldades em dizer o que o designer quis passar ao usuário. Outra falha é o fato da aplicação permitir que o usuário desenhe sobre a informação de limpar a tela.

A aplicação possui um misto em erros e acertos segundo a heurística de Nielsen que fala sobre atalhos.

"Atalho
  • Para usuários experientes executarem as operações mais rapidamente.
  • Para usuários leigos o sistema precisa ser fácil de usar.
  • Abreviações, teclas de função, duplo clique no mouse, função de volta em sistemas hipertexto.
  • Atalhos também servem para recuperar informações que estão numa profundidade na árvore navegacional a partir da interface principal."  

 Não há um botão que possa limpar a tela, utilizasse apenas um atalho por teclado, além disso o texto informando o teclado ainda pode ser encoberto pelo usuário. Acredito que o melhor seria possuir um botão e ter o atalho, assim um usuário mais experiente poderia aprimorar sua utilização do programa e o usuário mais leigo poderia recorrer à algo mais intuitivo como um botão.

 Uma sugestão seria a criação de botões e atalhos para desfazer ou refazer uma operação(Undo e Redo) segundo o Livro "Don't make me think" do Krug: "Usuários ainda são apegados ao botão de “voltar”", ou seja : Mesmo com uma boa usabilidade, não é difícil ver usuários errando o caminho de vez em quando durante a navegação. Para isso, basta um clique equivocado em um momento de pressa. Apesar dos estudos de Krug serem focados para a parte de web, podemos adaptar esse conceito aos botões de undo e redo propostos acima.

Resumo:

Pontos negativos
  • Não intuitividade sobre o funcionamento das checkboxes.
  • A possibilidade de desenhar sobre um texto que passa uma informação importante sobre o uso da aplicação.
  • Falta de botões para usuários leigos. (Ausência de botões)

Pontos positivos
  •  O bom feedback do sistema em relação ao estado do pincel (Cor, tamanho do traço).
  •  A pintura é feita de forma intuitiva.

Melhorias propostas
  • Separação do menu de configuração do pincel do quadro onde será executado a pintura.
  • Criação de botões (limpar a tela, desfazer uma ação, refazer uma ação).
  • Criação de atalhos para modificar o pincel (mudar cor ou tamanho)
  • Criar labels para os checkboxes de randomico.
Sugestão de interface



Referências:
  •  http://www.tidbits.com.br/as-10-heuristicas-de-usabilidade-do-nielsen
  • http://www.uxdesign.blog.br/usabilidade/10-licoes-de-usabilidade-de-steve-krug/
  • http://pt.slideshare.net/huxleydias/as-10-heursticas-de-nielsen
  • http://corais.org/node/99
  • http://en.wikipedia.org/wiki/Jakob_Nielsen_%28usability_consultant%29
  • http://en.wikipedia.org/wiki/Steve_Krug
  • http://pt.slideshare.net/barao/conceitos-de-usabilidade

 

terça-feira, 13 de maio de 2014

Criação de Cross-Fade.


Segue o código:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
PImage imgOriginal;
PImage img2;
float r, g, b;

void setup()
{
  size(320, 240);
  imgOriginal = loadImage("original.jpg");
  img2 = loadImage("personagem.jpg");
}

void draw()
{
  crossFadeCroma(imgOriginal, img2, 30);
}

void crossFadeCroma(PImage img1, PImage img2, float alfa)
{
  {

    loadPixels();
    alfa = alfa/100;
    
    for (int x = 0; x < 320; x++)
    {
      for (int y = 0; y < 240; y++)
      {
        pos = y * 320 +x;
        r = alfa*red(img1.pixels[pos]) + (1-alfa)*red(img2.pixels[pos]);
        g = alfa*green(img1.pixels[pos])  + (1-alfa)*green(img2.pixels[pos]);
        b = alfa*blue(img1.pixels[pos])  + (1-alfa)*blue(img2.pixels[pos]);
        pixels[pos] = color(r, g, b);
      }
    }
    updatePixels();
  }

}




Tratamento de Imagem


O exercício dessa vez é trabalhar com tratamento de imagem. O trabalho consiste em pegar uma mesma imagem e editar seus canais de cor para alterar sua forma. Na imagem abaixo podemos ver a seguinte ordem. (Foto original, foto adicionada com brilho, foto em negativo, foto em preto e branco, foto com preto e branco com média ponderada, Canal vermelho do RGB, canal verde do RGB, canal azul do rgb e as 3 ultimas é uma imagem com cada canal do padrão CMY.





quarta-feira, 7 de maio de 2014

Questão 3 - Prova

Código da questão 3, para descobrir o ângulo foi utilizado o método atan2() que recebe por parametro os 2 catetos do triangulo para calcular esse angulo, retornando um valor entre -180 e 180. Por isso na hora de realizar o text foi acrescido o valor 180 para fazer o número ficar entre 0 e 360.

float posAng = 0; int larguraTela = 600; void setup() { background(200); size(larguraTela, larguraTela); } void draw() { background(200); fill(0); rect(0, 10, larguraTela, 60); fill(255); rect(((larguraTela-30)*posAng)/360, 10, 30, 60); float ang = calculaAngulo(mouseY-larguraTela/2, mouseX-larguraTela/2) ; stroke(0); ellipse(larguraTela/2, larguraTela/2, larguraTela/2, larguraTela/2); polar(larguraTela/4, -ang); posAng = ang+180; textSize(20); text("Angulo " + posAng, larguraTela/2-50, larguraTela - 50); } void polar(float r, float a) { float x = r*cos(radians(a)); float y = r*sin(radians(a)); //stroke(255, 0, 0); strokeWeight(2); line(x+larguraTela/2, larguraTela/2-y, larguraTela/2, larguraTela/2); } float calculaAngulo(float y, float x) { float ang = atan2(y, x); ang = degrees(ang); return ang; }

segunda-feira, 28 de abril de 2014

Lançamento balistico utilizando ângulos

Exercício proposto para criação de uma função que receba como parâmetro um ângulo e a velocidade do disparo.

Print de um instante de execução do código


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
int relogio = millis();
int intervalo = 1000;
float dx;
float dy = 600;

float t;

ArrayList pontos = new ArrayList();

void setup()
{
   size(600,600);
  background(100); 
}

void draw()
{
  t = millis()/100; //contador de tempo
  disparoBalistico(70,100);
  desenhaTrajeto(pontos);
  
}


void disparoBalistico(int ang, int velLancamento)
{
  /*
  Essa função funciona a partir da decomposição dos vetores de movimento
  o Vo da formula é o valor velLancamento, passado por parametro.
  O V utilizado no dx é o resultado da decomposição do eixo X do vetor de movimentação
           |  /
V do MRUV  | /  a linha de / = resultante do vetor, ou hipotenusa, responsável pela direção do projétil
           |/___
            Velocidade do MRU
     eixo y = hipotenusa * seno(angulo)
     eixo x = hipotenusa * cos(angulo)     
  */
  background(100);
  float a = -9.8; //declaro a aceleração, uma CONSTANTE.
  float hipo = velLancamento/sin(radians(ang)); // descubro o valor da hipotenusa, necessária para descobrir o eixo X do vetor
  float velFixo = hipo * cos(radians(ang)); //Descubro o eixo X do vetor.
  //A partir daqui é apenas aplicação de formula.
 pontos.add(dx);    //pontos utilizados para a função desenhaTrajeto.
 pontos.add(dy+600);
 dx = velFixo*t;
 dy = (velLancamento*t + (a*t*t/2))*-1;
 pontos.add(dx);
 pontos.add(dy+600);
 ellipse(dx,600 + dy, 30,30);
 
}

void desenhaTrajeto(ArrayList pontos)
{
 for(int i = 3; i < pontos.size(); i+=2)
{
   line((Float)pontos.get(i-3),(Float)pontos.get(i-2),(Float)pontos.get(i-1),(Float)pontos.get(i));
   
} 
}