Matheus B. Guerrero | 18/11/2016
A gramática dos gráficos
O basicão
Criado por Winston Chang, Hadley Wickham, entre outros.
O objetivo do ggvis
é tornar simples a construção de gráficos iterativos para a análise exploratória de dados. É parecido com o ggplot2
, com pequenas diferenças, em que o foco é a construção de gráficos iterativos para web. Incorpora a parte iterativa do shiny
e as tranformações de dados do dplyr
.
Como dito, os gráficos produzidos pelo ggvis
são basicamente gráficos web e trabalham de forma muito diferente dos gráficos tradicionais do R. Por exemplo, todo gráfico iterativo do ggvis
necessita estar conectado a uma sessão iniciada do R; gráficos estatísticos não precisam de uma sessão iniciada do R para serem visualizados. Logo, o ggvis
é ótimo para visualização e iteratividade (na web), mas não é muito útil para publicações (não web), no que se prefere o ggplot2
.
Um Exemplo:
mtcars %>% ggvis(~disp, ~mpg) %>% layer_points()
A sintaxe do ggvis
é muito intuitiva. Por exemplo, na primeira linha de código abaixo, pode-se alterar o argumento fill
a fim de mudar a cor dos pontos. Ou, pode-se trocar a opção layer_points()
para alterar o tipo de gráfico. Ou ainda, pode-se plotar os dados mais de uma vez para tornar o gráfico mais informativo.
mtcars %>% ggvis(~wt, ~mpg, fill := "red") %>% layer_points()
mtcars %>% ggvis(~wt, ~mpg) %>% layer_smooths()
mtcars %>% ggvis(~wt, ~mpg) %>% layer_points() %>% layer_smooths()
Gramática
ggvis
é baseado na “gramática dos gráficos”. Você pode combinar um conjunto de dados com propiedades e marcadores da seguinte forma:
<data> %>%
ggvis(~<x property>,~<y property>,
fill = ~<fill property>, ...) %>%
layer_<marks>()
Observe que todo gráfico ggvis
tem 4 componentes essenciais:
- dados (data);
- um sistema de coordenadas (coordinate system);
- marcadores (marks), e
- propriedades correspondentes (properties).
De forma mais intuitiva:
Ao alterar cada um desses componentes, pode-se criar uma variedade de gráficos distintos.
Mais alguns exemplos:
pressure %>% ggvis(~temperature, ~pressure) %>% layer_bars()
pressure %>% ggvis(~temperature, ~pressure) %>% layer_lines()
pressure %>% ggvis(~temperature, ~pressure, fill = ~temperature) %>% layer_points()
pressure %>% ggvis(~temperature, ~pressure, size = ~pressure) %>% layer_points()
Sintaxe
Os 3 operadores
O ggvis
trabalha com 3 operadores. Entender cada um é fundamental para criar os gráficos.
O Condutor (
%>%
): passa o resultado do seu lado esquerdo para o primeiro argumento da função que fica ao seu lado direito.f(x) %>% g(y)
é um atalho deg(f(x), y)
.O Mapeador (
=
): mapeia uma propriedade à valores de uma variável, ou conjunto de variáveis. É assim que se visualiza variação em um conjunto de dados. oggvis
dimensiona os valores apropriadamente (escala) e adiciona uma legenda que explica como os valores são mapeados para instâncias específicas da propriedade.O Definidor (
:=
): Atribui uma cor específica (ou tamanho, largura, etc.) a uma propriedade (não em termos de escala). É assim que se personaliza a aparência dos gráficos. Os números serão tipicamente interpretados como pixels. As especificações de cor são passadas àvega
, uma biblioteca de javascript, para que se possa usar qualquer nome de cor reconhecido por HTML/CSS.
Exemplificando: Com o operador %>%
pode-se reescrever a linha de código:
layer_points(ggvis(faithful, x = ~waiting, y = ~eruptions))
Como:
faithful %>% ggvis(~waiting, ~eruptions) %>% layer_points()
Mais exemplos:
pressure %>% ggvis(~temperature, ~pressure, size = ~pressure) %>% layer_points()
pressure %>% ggvis(~temperature, ~pressure, size:= 100) %>% layer_points()
pressure %>% ggvis(~temperature, ~pressure, fill:= "red") %>% layer_points()
Referindo-se a diferentes objetos
Podemos nos referir a 3 tipos distintos de objetos com o ggvis
, a saber:
objetos: ao se digitar uma string, o
ggvis
o tratará como um objeto doR
com esse nome;variáveis: ao se colocar um til,
~
, antes de uma string, oggvis
a tratará como o nome de uma variável. Oggvis
buscará no banco de dados uma coluna com esse nome; evalores brutos: ao se colocar aspas em torno de uma “string”, o
ggvis
a tratará como um valor bruto, i.e., como um pedaço de texto.
Exemplificando: Considere o seguinte objeto e a seguinte variáveil:
red <- "green"
pressure$red <- pressure$temperature
Agora veja os diferentes gráficos produzidos ao se usar:
fill = ~red
:
pressure %>% ggvis(~temperature, ~pressure, fill = ~red) %>% layer_points()
fill := "red"
:
pressure %>% ggvis(~temperature, ~pressure, fill = "red") %>% layer_points()
fill := red
:
pressure %>% ggvis(~temperature, ~pressure, fill := red) %>% layer_points()
Points: propriedades
É possível manipular diferentes propriedades ao se usar a função layer_points()
, incluindo x
, y
, fill
, fillOpacity
, opacity
, shape
, size
, stroke
, strokeOpacity
e strokeWidth
.
A propriedade shape
, por exemplo, reconhece diversos valores: circle
(default), square
, cross
, diamond
, triangle-up
e triangle-down
.
Para uma revisão complenta das propriedades do ggvis
consulte o vignette: properties and scales.
Exemplos nunca são d+!!!:
faithful %>% ggvis(~waiting, ~eruptions, size = ~eruptions, opacity := .5,
fill := "blue", stroke := "black") %>% layer_points()
faithful %>% ggvis(~waiting, ~eruptions, fillOpacity = ~eruptions, size := 100,
fill := "red", stroke := "red", shape := "cross") %>% layer_points()
Lines: propriedades
De forma análoga à points
, lines
tem propriedades específicas, se relacionando a: x
, y
, fill
, fillOpacity
, opacity
, stroke
, strokeDash
, strokeOpacity
e strokeWidth
. Alguns são comuns às propriedades de points
, alguns não existem, como size
; outras são novas, como strokeDash
.
Para visualizar:
pressure %>% ggvis(~temperature, ~pressure, stroke := "red",
strokeWidth := 2, strokeDash := 6) %>% layer_lines()
Path e polygons
A função layer_lines()
sempre conectará os pontos no gráfico a partir dos pontos mais a esquerda aos pontos mais a direita. O que não é desejável se o interesse é plotar uma forma específica.
Por exemplo, se em um banco de dados, tem-se as coordenadas em ordem sequencial, em termos de longitude e latitude, do estado do Texas, EUA, e o objetivo é plotar o mapa deste estado, então é preciso lançar mão da função layer_paths()
. Esta função conecta os pontos na ordem em que aparecem no banco de dados.
Visualizando:
texas <- read.csv("2016-11-18-gg_files/figure-html/texas.csv", header=TRUE, sep=";", dec=",")
texas %>% ggvis(~long, ~lat, fill:= "darkorange") %>% layer_paths()
Mostrando modelos ajustados
A função compute_model_prediction()
é uma função útil para se usar com gráficos. Essa função usa um banco de dados como entrada e retorna um novo banco de dados como saída. O novo banco de dados conterá os valores de x
e y
de uma linha ajustada ao banco de dados original.
O código abaixo calcula a linha que mostra a relação entre as variáveis eruptions
e waiting
do banco de dados faithful
faithful %>% compute_model_prediction(eruptions ~ waiting, model = "lm")
A função compute_model_prediction()
assume uma série de argumentos:
faithful
, o banco de dados,um objeto “fórmula” do R,
eruptions ~ waiting
, que especifica a relação para o modelo,um
modelo
do R a ser ajustado. Por exemplo, “lm” ajusta uma regressão linear, usando o método “loess”.
Já compute_smooth()
é uma função que “embrulha” compute_model_prediction()
e calcula uma linha de regressão “loess” por padrão.
faithful %>% compute_smooth(eruptions ~ waiting)
compute_smooth()
sempre retorna uma banco de dados com duas colunas, uma de nome pred_
e outra de nome resp_
. Pode-se passar esses dados para o ggvis
plotar uma linha aos dados, confome o exemplo:
faithful %>%
compute_smooth(eruptions ~ waiting) %>%
ggvis(~pred_, ~resp_) %>%
layer_lines()
O mesmo gráfico com a função layer_smooths()
do ggvis
:
faithful %>% ggvis(~eruptions, ~ waiting) %>% layer_points() %>% layer_smooths(stroke := "red")
Assim como layer_smooths()
é um atalho para o uso combinado das funções compute_smooth()
e layer_lines()
, existem outras funções no ggvis
que fazem transformações análogas aos dados a fim de tornar a criação de gráficos uma tarefa mais simples. Por exemplo:
layer_bars()
ao invés decompute_count()
elayer_rects()
,layer_histograms()
no lugar decompute_bin()
elayer_rects()
,layer_densities()
como alternativa àcompute_density()
elayer_lines()
.
Veja os exemplos abaixo:
Gráficos de Barras:
mtcars %>% ggvis(~factor(cyl)) %>% layer_bars()
Histogramas:
faithful %>% ggvis(~waiting) %>% layer_histograms(width=5)
Densidades:
faithful %>% ggvis(~waiting, fill:= "green") %>% layer_densities()
ggvis
e dplyr
group_by()
É possível combinar o ferramental gráfico do ggvis
com as manipulações de base de dados do pacote dplyr
. Por exemplo, a função group_by()
agrupa variáveis em grupos que possuem uma característica em comum (de acordo com uma “variável de grupo”). Assim, quando o ggvis
econtra uma variável agrupada, ele plota um “mark” separado para cada grupo distinto dessa variável.
Abaixo a praticidade de se usar a função group_by()
na construção de gráficos.
mtcars %>% group_by(cyl) %>% ggvis(~mpg, ~wt, stroke = ~factor(cyl)) %>% layer_smooths()
mtcars %>% group_by(cyl) %>% ggvis(~mpg, fill = ~factor(cyl)) %>% layer_densities()
interaction()
group_by()
pode agrupar dados baseado na interação de duas ou mais variáveis. Basta passar multiplos argumentos para a função:
my_data %>% group_by(<var1>, <var2>)
Assim, group_by()
criará um grupo separado para cada combinação distinta das variáveis passadas como argumento. Contudo, para que o ggvis
mapeie as propriedades de forma adequada para cada combinação, é necessário utilizar a função interaction()
. Por exemplo:
stroke = ~interaction(<var1>, <var2>)
mapeará stroke
para cada combinação única das variáveis <var1>
e <var2>
.
Exemplificando:
mtcars %>% group_by(cyl, am) %>% ggvis(~mpg, fill = ~interaction(cyl,am)) %>% layer_densities()
+1 exemplo:
mtcars %>%
group_by(am) %>%
ggvis(~mpg, ~hp) %>%
layer_smooths(stroke = ~factor(am)) %>%
layer_points(fill = ~factor(am))
Gráficos iterativos
O gráfico abaixo é um gráfico iterativo simples. Ele inclui uma caixa de seleção que altera a forma dos pontos do gráfico.
faithful %>%
ggvis(~waiting, ~eruptions, fillOpacity := 0.5,
shape := input_select(label = "Choose shape:",
choices = c("circle", "square", "cross",
"diamond", "triangle-up", "triangle-down")),
fill := input_select(label = "Choose color:", choices = c("black", "red", "blue", "green"))) %>%
layer_points()
Para habilitar gráficos iterativos em um relatório escrito no RMarkdown, utilize a seguinte opção do preâmbulo: runtime: shiny
.
É possível criar os gráficos iterativos atribuindo a uma propriedade de saída uma widget de entrada. O ggvis
tem 7 widgets de entrada.
- input_checkbox(),
- input_checkboxgroup(),
- input_numeric(),
- input_radiobuttons(),
- input_select(),
- input_slider(), e
- input_text().
Por defeito, cada uma retorna seu valor atual como um número ou como uma string.
Botões para selecionar as cores:
mtcars %>%
ggvis(~mpg, ~wt,
fill := input_radiobuttons(label = "Choose color:",
choices = c("black", "red", "blue", "green"))) %>%
layer_points()
Um exemplo mais elaborado:
mtcars %>% ggvis(x = ~wt) %>%
layer_densities(
adjust = input_slider(.1, 2, value = 1, step = .1, label = "Bandwidth adjustment"),
kernel = input_select(
c("Gaussian" = "gaussian",
"Epanechnikov" = "epanechnikov",
"Rectangular" = "rectangular",
"Triangular" = "triangular",
"Biweight" = "biweight",
"Cosine" = "cosine",
"Optcosine" = "optcosine"),
label = "Kernel")
)
Para mais detalhes sobre controle de iteratividade, consulte o vignette: ggvis interactivity.
Gráficos multi-camadas
É possível criar gráficos mult-camadas adicionando camadas adicioais a um gráfico com o uso do operador %>%
.
Propriedades definidas dentro da função ggvis()
são definidas globalmente, sendo aplicadas a todas as camadas. Já prorpiedades atribuidas e mapeadas dentro de uma função layer_<mark>()
são aplicadas localmente: apenas a camada criada por esta função fará uso da propriedade. Onde forem aplicadas, propriedades locais se sobrepõe sobre propriedades globais.
Exemplo:
pressure %>%
ggvis(~temperature, ~pressure) %>%
layer_lines(opacity := 0.5) %>%
layer_points() %>%
layer_model_predictions(model = "lm", stroke := "navy") %>%
layer_smooths(stroke := "skyblue")
O mesmo, alterando propriedades e o ajuste:
pressure %>%
ggvis(~temperature, ~pressure, stroke := "darkred") %>%
layer_lines(stroke := "orange", strokeDash := 5, strokeWidth := 5) %>%
layer_points( shape := "circle", size := 100, fill := "lightgreen") %>%
layer_smooths()
Eixos e legendas
Eixos
A função add_axis()
permite que se altere os títulos, o esquema dos “ticks” e a posição dos eixos. A função é bem intuitiva, como pode se observar no código abaixo:
add_axis("x",
title = "axis title",
values = c(1, 2, 3),
subdivide = 5,
orient = "top")
Exemplo:
faithful %>%
ggvis(~waiting, ~eruptions) %>%
layer_points() %>%
add_axis("x", title = "Time since previous eruption (m)",
values = c(50, 60, 70, 80, 90),
subdivide = 9,
orient = "top") %>%
add_axis("y", title = "Duration of eruption (m)",
values = c(2, 3, 4, 5),
subdivide = 9,
orient = "right")
Legendas
A função add_legend()
trabalha de forma similar à função add_axis()
.
Veja:
faithful %>%
ggvis(~waiting, ~eruptions, opacity := 0.6,
fill = ~factor(round(eruptions))) %>%
layer_points() %>%
add_legend("fill", title = "~ duration (m)", orient = "left")
Quando add_legend()
não é especificado, o ggvis
automaticamente cria uma legenda separada para cada propriedade mapeada em uma variável, o que pode resultar em legendas confusas. O código abaixo cria 3 legendas separadas para cada propriedade - fill
, shade
e size
- as sobrepondo!
What a mess!
faithful %>%
ggvis(~waiting, ~eruptions, opacity := 0.6,
fill = ~factor(round(eruptions)), shape = ~factor(round(eruptions)),
size = ~round(eruptions)) %>%
layer_points()
Para corrigir este problema, especifique um vetor com os nomes das propriedades como primeiro argumento da função add_legend()
.
Much better!:
faithful %>%
ggvis(~waiting, ~eruptions, opacity := 0.6,
fill = ~factor(round(eruptions)), shape = ~factor(round(eruptions)),
size = ~round(eruptions)) %>%
layer_points() %>%
add_legend(c("fill", "shape", "size"), title = "~ duration (m)")