Visualização de Dados

ggplot2, scales, patchwork, e mais

Jose Storopoli https://scholar.google.com/citations?user=xGU7H1QAAAAJ&hl=en (UNINOVE)https://www.uninove.br
April 12, 2021

Crie sua Obra-Prima!

Figure 1: Crie sua Obra-Prima!

{ggplot2} é um sistema para a criação declarativa de gráficos, baseado na Gramática dos Gráficos–um esquema geral para visualização de dados que divide os gráficos em componentes semânticos, como escalas e camadas. Você fornece os dados, diz ao {ggplot2} como mapear as variáveis para as estéticas, quais primitivos gráficos usar e ele cuida dos detalhes.

Um livro muito bom sobre visualização de dados é o “Fundamentals of Data Visualizations” de Claus Wilke (Figura 2). Um segredinho, ele foi todo feito em Rmarkdown e ggplot2 #ficaadica.

Fundamentals of Data Visualization

Figure 2: Fundamentals of Data Visualization

Como usar?

Cada gráfico {ggplot2} tem três componentes principais:

  1. dados (data),
  2. Um conjunto de mapeamentos estéticos (aesthetics) aes() entre variáveis nos dados e propriedades visuais, e
  3. Pelo menos uma camada (layer) que descreve como renderizar cada observação. As camadas geralmente são criadas com uma função geom_*.
library(ggplot2) # `require(ggplot2)` também serve 99.99% usam `library()`
library(dplyr)
mpg %>% # igual a isso `ggplot(data = mpg)`
  ggplot()

mpg %>% 
  ggplot(aes(hwy, cty))

mpg %>% 
  ggplot(aes(hwy, cty)) + 
  geom_point() +
  geom_smooth(method = "lm")

OBS: Porque + e não o pipe %>%? Lembra que eu falei que {ggplot2} veio antes do {tidyverse} e antes do Hadley trabalhar totalmente com opensource na RStudio? Então os geom_*() vieram antes do pipe %>%. Por isso a API adiciona camadas. Então usamos o +.

Pergunta: Quero interatividade?! E agora? Resposta: Não tema! Use o {plotly} e seja feliz!

library(plotly)
p <- mpg %>% 
  ggplot(aes(hwy, cty)) + 
  geom_point() +
  geom_smooth(method = "lm")
ggplotly(p)

Geom

Temos vários! VÁRIOS! Vou mostrar alguns mais comuns:

mpg %>% 
  ggplot(aes(cyl)) +
  geom_point(aes(y = hwy), shape = 3, color = "steelblue") +
  geom_point(aes(y = cty), shape = 1, color = "red")

ggplot(mpg, aes(displ, hwy, colour = class)) + 
  geom_point() +
  geom_smooth(method = "lm")

mpg %>% 
  ggplot(aes(class, hwy, colour = class)) +
  geom_boxplot()

mpg %>% 
  ggplot(aes(hwy)) +
  geom_histogram(bins = 30)

mpg %>% 
  ggplot(aes(hwy)) +
  geom_density(fill = "steelblue")

mpg %>% 
  ggplot(aes(class)) +
  geom_bar()

library(forcats)
mpg %>% 
  count(class) %>% 
  mutate(class = as.factor(class),
         class = fct_reorder(class, n, .desc = TRUE)) %>% 
  ggplot(aes(class, n)) +
  geom_col()

economics %>% 
  ggplot(aes(date, unemploy)) +
  geom_line()

Estéticas com aes()

Além de x e y temos outros atributos como:

mpg %>% 
  ggplot(aes(cyl, hwy, colour = class)) +
  geom_point()

mpg %>% 
  ggplot(aes(class, fill = manufacturer)) +
  geom_bar()

mpg %>% 
  ggplot(aes(cyl, cty, shape = class)) +
  geom_point()

mpg %>% 
  ggplot(aes(displ, hwy, colour = class, size = cyl)) + 
  geom_point()

Atributos dentro e fora do aes()

Vejam abaixo o que vai acontecer!

mpg %>% 
  ggplot() +
  geom_point(aes(displ, hwy, colour =  "steelblue"))

mpg %>% 
  ggplot() +
  geom_point(aes(hwy, displ), color = "steelblue", size = 5)

Rótulos com labs()

Teoricamente você precisa somente de ggplot(aes(... )) + geom_*(). Mas à vezes é legal customizar o gráfico com mais informações ou alterar alguma coisa.

{ggplot2} fornece a função auxiliar labs() para definir o nome para uma ou mais escalas, usando pares nome-valor como x = "eixo X" ou fill = "legenda do preenchimento". Além disso, você pode adicionar NULL para remover o rótulo:

mpg %>% 
  ggplot(aes(displ, hwy, colour = class, size = cyl)) + 
  geom_point() +
  labs(
    title = "Um gráfico bonito",
    subtitle = "... é aquele que tem subtítulos",
    caption = " ... juntamente com \"rubricas\"",
    x = "Deslocamento Volumétrico",
    y = "Autonomia em Milhas por Galão",
    colour = "Tipo de Carro",
    size = "QTD Cilindros"
  )

mpg %>% 
  ggplot(aes(displ, hwy, colour = class, size = cyl)) + 
  geom_point() +
  labs(
    title = NULL,
    subtitle = NULL,
    caption = NULL,
    x = NULL,
    y = NULL,
    colour = NULL,
    size = NULL
  )

Facetação com facet_wrap()

Outra técnica para exibir variáveis categóricas adicionais em um gráfico é a facetação. A facetação cria tabelas de gráficos dividindo os dados em subconjuntos e exibindo o mesmo gráfico para cada subconjunto.

Para facetar um gráfico, você simplesmente adiciona uma especificação de facetamento com facet_wrap(), que leva o nome de uma variável precedida por ~.

mpg %>% 
  ggplot(aes(displ, hwy, colour = class, size = cyl)) + 
  geom_point() +
  facet_wrap(~class)

facet_wrap() tem alguns argumentos interessentes:

mpg %>% 
  ggplot(aes(displ, hwy, colour = class, size = cyl)) + 
  geom_point() +
  facet_wrap(~class,
             ncol = 2,               # mutuamente exclusivo de `nrow`
             scales = "free",        # cada faceta tem seu eixo x e y
             labeller = "label_both" # traz o label da "facet" junto com o valor das classes da faceta
             )

Você pode colocar mais facets. Quando você tem mais variáveis o labeller = "label_value" funciona muito bem.

mpg %>% 
  ggplot(aes(displ, hwy, colour = class, size = cyl)) + 
  geom_point() +
  facet_wrap(~class + cyl,
             labeller = "label_both")

Customização de Temas com theme()

O sistema de temas é composto por quatro componentes principais:

mpg %>% 
  ggplot(aes(displ, hwy, colour = class, size = cyl)) + 
  geom_point() +
  labs(title = "Algum título que eu vou querer em Comic Sans") +
  facet_wrap(~class + cyl,
             labeller = "label_both") +
  theme(text = element_text(size = 8),
        plot.title = element_text(family = "Comic Sans MS"),
        axis.ticks.x = element_line(colour = "purple",
                                    arrow = arrow(
                                      length = unit(
                                        1, "mm"))))

mpg %>% 
  ggplot(aes(displ, hwy, colour = class, size = cyl)) + 
  geom_point() +
  theme_classic() # gosto bastante

Escalas com o scale_*_*()

As escalas controlam os detalhes de como os valores dos dados são convertidos em propriedades visuais. Temos várias, veja a documentação. Mas vou destacar algumas que uso bastante:

economics %>% 
  ggplot(aes(date, unemploy)) +
  geom_line() +
  scale_y_log10()

mpg %>% 
ggplot(aes(displ, hwy, colour = class)) + 
  geom_point(alpha = 0.5) +
  scale_color_brewer(palette = "Set1")

mpg %>% 
ggplot(aes(displ, hwy, colour = as.factor(cyl))) + 
  geom_point() +
  scale_colour_viridis_d(option = "E") # cividis que é inclusivo de quem tem "dificuldades" de cores

Vamos arrumar o gráfico anterior:

mpg %>% 
ggplot(aes(displ, hwy, colour = class, size = cyl)) + 
  geom_point(alpha = 0.5) +
  scale_size(range = c(1, 3))

Mais escalas com o {scales}

O pacote {scales} fornece a infraestrutura de escala interna usada pelo {ggplot2} e fornece ferramentas para substituir os valores padrões de breaks, labels, transformations etc.

economics %>%
  ggplot(aes(date, unemploy / pop)) +
  geom_line() +
  scale_y_continuous(labels = scales::label_percent(accuracy = 0.01, decimal.mark = ",")) +
  labs(y = "% de Desempregados da Pop Total")

economics %>% 
  ggplot(aes(date, pce)) +
  geom_line() +
  scale_y_continuous(
    labels = scales::label_dollar(prefix = "R$ ",
                                  suffix = " bi",
                                  decimal.mark = ".")
  )

“Como é que salva?” ggsave()

Só usar o ggsave(dpi = 300)

Compor múltiplos gráficos com {patchwork}

O pacote {patchwork} tem como objetivo tornar ridiculamente simples combinar gráficos {ggplot2} em um mesmo gráfico.

É apenas usando operadores aritméticos e relacionais já conhecidos como se fosse uma álgebra de gráficos: (), +, /, | etc.

library(patchwork)
p1 <- ggplot(mtcars) + geom_point(aes(mpg, disp))
p2 <- ggplot(mtcars) + geom_boxplot(aes(gear, disp, group = gear))
p3 <- ggplot(mtcars) + geom_smooth(aes(disp, qsec))
p4 <- ggplot(mtcars) + geom_bar(aes(carb))

(p1 | p2 | p4) / p3 +
  plot_annotation(title = "Quatro gráficos legais",
                  tag_levels = "I", tag_prefix = "Fig. ") +
  plot_layout(nrow = 2, widths = c(1, 3),
              heights = c(2, 1))

Free Samples

Vocês já sabem tudo o que é necessário para fazerem visualizações perfeitas no {ggplot2}. Mas tem alguns outros pacotes que valhe a pena aprender.

library(ggrepel)
ggplot(mtcars, aes(wt, mpg, label = rownames(mtcars))) +
  geom_label_repel() +
  geom_point(color = 'red') +
  theme_classic(base_size = 12)

Dá para fazer uma gambiarra

library(stringr)
ggplot(mtcars, aes(wt, mpg, label = if_else(str_detect(rownames(mtcars), "Merc"), rownames(mtcars), NA_character_))) +
  geom_text_repel() +
  geom_point(color = 'red') +
  theme_classic(base_size = 12)

set.seed(2)
d <- purrr::map_dfr(
  letters,
  ~ tibble::tibble(
      idx = 1:400,
      value = cumsum(runif(400, -1, 1)),
      type = .,
      flag = sample(c(TRUE, FALSE), size = 400, replace = TRUE)
    )
)
d %>%
  ggplot(aes(idx, value, colour = type)) +
  geom_line()

Eu posso filtrar?

d %>%
  filter(type %in% c("g", "s")) %>% 
  ggplot(aes(idx, value, colour = type)) +
  geom_line()

A solução é usar o {gghighlight}:

library(gghighlight)
d %>%
  ggplot(aes(idx, value, colour = type)) +
  geom_line() +
  gghighlight(max(abs(value)) >= 20)

library(ggExtra)
plot <- mpg %>% 
  ggplot(aes(hwy, cty)) +
  geom_point(colour = "steelblue") 
ggMarginal(plot)

library(ggridges)
diamonds %>% 
  ggplot(aes(price, cut, fill = as.factor(cut))) +
  geom_density_ridges() +
  scale_x_continuous(labels = scales::label_dollar()) +
  scale_fill_brewer(palette = "Set1")

Ambiente

R version 4.1.0 (2021-05-18)
Platform: aarch64-apple-darwin20 (64-bit)
Running under: macOS Big Sur 11.4

Matrix products: default
BLAS:   /Library/Frameworks/R.framework/Versions/4.1-arm64/Resources/lib/libRblas.dylib
LAPACK: /Library/Frameworks/R.framework/Versions/4.1-arm64/Resources/lib/libRlapack.dylib

locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods  
[7] base     

other attached packages:
 [1] ggridges_0.5.3    ggExtra_0.9       gghighlight_0.3.2
 [4] ggrepel_0.9.1     patchwork_1.1.1   forcats_0.5.1    
 [7] plotly_4.9.4.1    repurrrsive_1.0.0 ggplot2_3.3.5    
[10] stringr_1.4.0     tidyr_1.1.3       janitor_2.1.0    
[13] dplyr_1.0.7       readr_1.4.0       magrittr_2.0.1   
[16] tibble_3.1.2     

loaded via a namespace (and not attached):
 [1] nlme_3.1-152       lubridate_1.7.10   bit64_4.0.5       
 [4] RColorBrewer_1.1-2 httr_1.4.2         rprojroot_2.0.2   
 [7] tools_4.1.0        bslib_0.2.5.1      utf8_1.2.1        
[10] R6_2.5.0           DBI_1.1.1          lazyeval_0.2.2    
[13] mgcv_1.8-35        colorspace_2.0-2   withr_2.4.2       
[16] tidyselect_1.1.1   downlit_0.2.1      bit_4.0.4         
[19] compiler_4.1.0     textshaping_0.3.5  cli_3.0.0         
[22] labeling_0.4.2     bookdown_0.22      sass_0.4.0        
[25] scales_1.1.1       systemfonts_1.0.2  digest_0.6.27     
[28] rmarkdown_2.9      jpeg_0.1-8.1       pkgconfig_2.0.3   
[31] htmltools_0.5.1.1  dbplyr_2.1.1       fastmap_1.1.0     
[34] highr_0.9          htmlwidgets_1.5.3  rlang_0.4.11      
[37] rstudioapi_0.13    RSQLite_2.2.7      shiny_1.6.0       
[40] jquerylib_0.1.4    farver_2.1.0       generics_0.1.0    
[43] jsonlite_1.7.2     crosstalk_1.1.1    distill_1.2       
[46] Matrix_1.3-4       Rcpp_1.0.6         munsell_0.5.0     
[49] fansi_0.5.0        lifecycle_1.0.0    stringi_1.6.2     
[52] yaml_2.2.1         snakecase_0.11.0   plyr_1.8.6        
[55] grid_4.1.0         blob_1.2.1         promises_1.2.0.1  
[58] crayon_1.4.1       miniUI_0.1.1.1     lattice_0.20-44   
[61] splines_4.1.0      hms_1.1.0          knitr_1.33        
[64] pillar_1.6.1       glue_1.4.2         evaluate_0.14     
[67] data.table_1.14.0  httpuv_1.6.1       png_0.1-7         
[70] vctrs_0.3.8        gtable_0.3.0       purrr_0.3.4       
[73] assertthat_0.2.1   cachem_1.0.5       xfun_0.24         
[76] mime_0.11          xtable_1.8-4       later_1.2.0       
[79] ragg_1.1.3         viridisLite_0.4.0  memoise_2.0.0     
[82] ellipsis_0.3.2    

Corrections

If you see mistakes or want to suggest changes, please create an issue on the source repository.

Reuse

Text and figures are licensed under Creative Commons Attribution CC BY-SA 4.0. Source code is available at https://github.com/storopoli/Linguagem-R, unless otherwise noted. The figures that have been reused from other sources don't fall under this license and can be recognized by a note in their caption: "Figure from ...".

Citation

For attribution, please cite this work as

Storopoli (2021, April 12). Linguagem R: Visualização de Dados. Retrieved from https://storopoli.io/Linguagem-R/3-Visualizacao_Dados.html

BibTeX citation

@misc{storopoli2021visualizacaodadosR,
  author = {Storopoli, Jose},
  title = {Linguagem R: Visualização de Dados},
  url = {https://storopoli.io/Linguagem-R/3-Visualizacao_Dados.html},
  year = {2021}
}