Capítulo 5 Plotando

5.1 plot (base)

Exemplo: Dados de qualidade do ar

df <- readRDS("dados/df.rds")
summary(df)
##       TipodeRede   TipodeMonitoramento              Tipo     
##  Automático:8581   CETESB:8581         Dados Primários:8581  
##                                                              
##                                                              
##                                                              
##                                                              
##                                                              
##                                                              
##          Data           Hora      CodigoEstação
##  01/01/2014:  24   16:00  : 363   Min.   :95   
##  01/01/2015:  24   12:00  : 361   1st Qu.:95   
##  01/02/2014:  24   14:00  : 361   Median :95   
##  01/04/2014:  24   18:00  : 361   Mean   :95   
##  01/05/2014:  24   13:00  : 360   3rd Qu.:95   
##  01/06/2014:  24   17:00  : 360   Max.   :95   
##  (Other)   :8437   (Other):6415                
##                      NomeEstação                      NomeParâmetro 
##  Cid.Universitária-USP-Ipen:8581   NOx (Óxidos de Nitrogênio):8581  
##                                                                     
##                                                                     
##                                                                     
##                                                                     
##                                                                     
##                                                                     
##  UnidadedeMedida  MediaHoraria    MediaMovel Valido      tempo_char       
##  ppb:8581        Min.   :  0.00   -:8581     Não: 907   Length:8581       
##                  1st Qu.:  9.00              Sim:7674   Class :character  
##                  Median : 18.00                         Mode  :character  
##                  Mean   : 29.87                                           
##                  3rd Qu.: 34.00                                           
##                  Max.   :306.00                                           
##                  NA's   :260                                              
##      tempo                       weekdays             mes           
##  Min.   :2014-01-01 01:00:00   Length:8581        Length:8581       
##  1st Qu.:2014-04-05 14:00:00   Class :character   Class :character  
##  Median :2014-07-05 23:00:00   Mode  :character   Mode  :character  
##  Mean   :2014-07-04 20:03:16                                        
##  3rd Qu.:2014-10-03 10:00:00                                        
##  Max.   :2015-01-02 00:00:00                                        
##                                                                     
##   diajuliano           ano           
##  Length:8581       Length:8581       
##  Class :difftime   Class :character  
##  Mode  :numeric    Mode  :character  
##                                      
##                                      
##                                      
## 

A função plot precisa dos seguintes argumentos:

args(plot)
## function (x, y, ...) 
## NULL

Então, a forma mais fácil de plotar uma variável em função do tempo é:

plot(x = df$tempo, y = df$MediaHoraria)

Feio, né?
Tentando deixar mais bonito…

plot(x = df$tempo[1:100], y = df$MediaHoraria[1:100], #-- Selecionando uma parte do df!
     pch = 16, #-- Forma do ponto (círculo preenchido)
     type = "b", #-- Tipo de gráfico ("b" = both, ponto e linha)
     col = "blue", #-- Cor do elemento (definido pelo type)
     xlab = "Data", ylab = "NOx [ppb]", #-- Nome dos eixos x e y
     main = "Gráfico mais Bonito") #-- Título do gráfico

Colocando DOIS elementos no mesmo gráfico:

df_parcial <- df[1:180,] #-- Selecionando uma parte do df!
plot(x = df_parcial$tempo[df_parcial$Valido == "Sim"], 
     y = df_parcial$MediaHoraria[df_parcial$Valido == "Sim"],
     pch = 16, type = "b", col = "blue",
     xlab = "Data", ylab = "NOx [ppb]",
     main = "Dados Válidos e Inválidos")
lines(x = df_parcial$tempo[df$Valido == "Não"], 
      y = df_parcial$MediaHoraria[df$Valido == "Não"], 
      pch = 15, type = "b", col = "red")


Desafio: Coloque uma legenda na figura especificando que os dados válidos estão em azul e os inválidos em vermelho


A função plot cumpre bem o papel de gerar um gráfico simples, e até permite algumas customizações, mas ela exige cada vez mais linhas de código e argumentos dentro das funções para deixar o gráfico “mais bonito” - ao cumprir o desafio, você irá perceber como uma coisa “simples” como colocar uma legenda pode exigir muito mais do que parece!

5.2 image

A função image permite pĺotear matrieces diretamente. Vamos testar esta função com a librería cptcity. Argumentos similares de plot podem ser usados em image.

library(cptcity)
image(matrix(1:100), col = lucky())
## Colour gradient: km_cool_warm_d14, number: 4588

image(matrix(1:100), col = lucky())
## Colour gradient: bhw_bhw4_bhw4_055, number: 254

image(matrix(1:100), col = lucky())
## Colour gradient: es_rosa_es_rosa_75, number: 1797

5.3 ggplot (ggplot2)

A função ggplot funciona de um jeito um pouco diferente. Veja a figura abaixo:

Em vez de uma única função, o gráfico é formado por camadas, sendo que cada camada é um elemento (geom_... ou stat_...) ou configuração (scale_..._..., coord_..., theme ou theme_..., guides, labs, etc). Consulte a maioria das opções disponíveis em Data Visualization Cheatsheet.

Que tal refazermos os gráficos da seção anterior?

#-- Não esqueça de carregar o pacote!
library(ggplot2)
ggplot(df, aes(x = tempo, y = MediaHoraria)) +
  geom_point(pch = 1)
## Warning: Removed 260 rows containing missing values (geom_point).

ggplot(df[1:100,], aes(x = tempo, y = MediaHoraria)) + 
  geom_line(color = "blue") + #-- Linhas...
  geom_point(color = "blue", pch = 16) + #-- ... com pontos
  labs(title = "Gráfico mais Bonito", x = "Data", y = "NOx [ppb]") + #-- Títulos
  theme(plot.title = element_text(hjust = 0.5)) #-- Centralizando o título

Agora o mais interessante:

ggplot(df[1:180,], aes(x = tempo, y = MediaHoraria)) + 
  geom_line(aes(color = Valido)) +
  geom_point(aes(color = Valido, shape = Valido)) +
  labs(title = "Dados Válidos e Inválidos", x = "Data", y = "NOx [ppb]") +
  scale_color_manual(values = c("red", "blue")) + #-- Definindo as cores manualmente
  scale_shape_manual(values = c(15, 16)) + #-- Definindo as formas manualmente
  theme(plot.title = element_text(hjust = 0.5))

Pergunta: Qual a principal diferença entre o código acima e o código usando plot?

A função ggplot plota apenas data frames, pois ela mapeia as variáveis por nomes de colunas. Assim, é preciso converter matrizes ou arrays em data frames.
Uma vantagem de trabalharmos com data frames, como já vimos antes, é poder manipular esses dados de muitas formas possíveis antes de plotá-los.

Continuação do Exemplo: Extraindo algumas informações sobre os dados

Vamos analisar o ano de 2014:

  • Em média, como o NOx varia ao longo do dia?
    • E para cada dia da semana?
    • E para cada mês?

Usando algumas outras funções dentro do Tidyverse:

library(tidyverse)

df_2014 <- filter(df, ano == "2014")
df_2014_hour <- df_2014 %>% #-- A partir do data frame df_2014
  group_by(Hora) %>% #-- Agrupe os dados pela coluna hora
  summarise(Media = mean(MediaHoraria, na.rm = T)) %>% #-- E calcule as médias, 
                                                       #-- salvando em uma coluna nova
  mutate(Hora = as.POSIXct(strptime(Hora, "%H:%M"))) %>% #-- Transformando em data
  ungroup() #-- Desagrupando

ggplot(df_2014_hour) +
  scale_x_datetime(date_labels = "%H:%M") + #-- Formato de data que aparecerá no eixo x
  geom_line(aes(x = Hora, y = Media, group = 1), color = "purple") +
  labs(title = "Média Horária Anual", y = "NOx [ppb]")

df_2014_weekly <- df_2014 %>%
  group_by(Hora, weekdays) %>% #-- Agrupando os dados pelas colunas Hora e weekdays
  summarise(Media = mean(MediaHoraria, na.rm = T)) %>% 
  ungroup() %>% 
  mutate(Hora = as.POSIXct(strptime(Hora, "%H:%M"))) %>%
  mutate(weekdays = factor(weekdays, levels = c("segunda", "terça", "quarta",
                                                "quinta", "sexta", "sábado", 
                                                "domingo"))) #-- Ordenando os dias da semana

ggplot(df_2014_weekly) +
  scale_x_datetime(date_labels = "%H:%M") +
  geom_col(aes(x = Hora, y = Media), fill = "purple") +
  labs(title = "Média Horária Anual por Dia da Semana", y = "NOx [ppb]") +
  facet_wrap(~ weekdays) #-- Criando paineis em função do dia da semana

df_2014_monthly <- df_2014 %>%
  group_by(Hora, mes) %>% #-- Agrupando os dados pelas colunas Hora e mes
  summarise(Media = mean(MediaHoraria, na.rm = T)) %>%
  ungroup() %>%
  mutate(Hora = as.POSIXct(strptime(Hora, "%H:%M"))) %>%
  mutate(mes = factor(mes, levels = c("janeiro", "fevereiro", "março", 
                                      "abril", "maio", "junho", "julho",
                                      "agosto", "setembro", "outubro",
                                      "novembro", "dezembro"))) #-- Ordenando os meses

ggplot(df_2014_monthly) +
  scale_x_datetime(date_labels = "%H:%M") +
  geom_col(aes(x = Hora, y = Media), fill = "purple") +
  labs(title = "Média Horária Anual por Mes", y = "NOx [ppb]") +
  facet_wrap(~ mes) #-- Criando paineis em função do mês


Exercício: Em média, como os dados válidos de NOx variam mensalmente ao longo do ano de 2014? Faça um gráfico.

Desafio: Ainda é possível melhorar os gráficos acima! Pesquise como:

* Diminuir a quantidade de horários no eixo x
* Separar por dias da semana e meses a partir da coluna “tempo”, não precisando usar as colunas de caracteres e consequentemente ordená-las manualmente


5.3.1 Explorando outras escalas de cores e temas

Pacotes veinreport e cptcity

devtools::install_github("atmoschem/veinreport")
library(veinreport)
library(cptcity)

Refazendo alguns gráficos:

ggplot(df, aes(x = tempo, y = MediaHoraria)) + 
  geom_line(aes(color = MediaHoraria)) +
  labs(x = "Data", y = "NOx [ppb]") +
  scale_color_gradientn(colours = cpt()) + #-- Definindo as cores com uma escala gradiente
  theme_black()
## Warning: Removed 1 rows containing missing values (geom_path).

Experimentando escalas de cores com a função lucky:

ggplot(df_2014_monthly) +
  scale_x_datetime(date_labels = "%H:%M") +
  geom_col(aes(x = Hora, y = Media, fill = Media)) +
  labs(title = "Média Horária Anual por Mes", y = "NOx [ppb]") +
  scale_fill_gradientn(colors = lucky()) + #-- Definindo as cores com uma escala gradiente aleatória
  theme_black() +
  theme(legend.position = "bottom", legend.direction = "horizontal") + #-- Colocando a legenda na parte de baixo da figura
  facet_wrap(~ mes) #-- Criando paineis em função do mês
## Colour gradient: nd_turanj_Analogous_04, number: 5879

Este é só o começo! Veja aqui um pouco mais das muitas aplicações do ggplot.