11.6 ggplot2
O ggplot2 é uma implementação para o da Gramática de Gráficos (Wilkinson et al. 2005) (GG). A GG estabelece princípios fundamentais para a construção de gráficos. Um gráfico consiste no mapeamento dos dados a partir de atributos estéticos (posição, cor, forma, tamanho) de objetos geométricos (pontos, linhas, barras, caixas). Os principais aspectos de um gráfico são os dados, o sistema de coordenadas, os rótulos e as anotações, os quais podem ser combinados em camadas para elaboração do gráfico. Esse é a ideia central do {ggplot2}
.
A documentação do ggplot2 está disponível aqui.
Para conhecer mais extensões do {ggplot2}
consulte a galeria https://exts.ggplot2.tidyverse.org/gallery/.
11.6.1 Exemplo de aplicação
11.6.2 Dados
Como exemplo de aplicação usaremos os dados históricos do INMET da estação meteorológica convencional (EMC) de Santa Maria-RS. Os dados utilizados podem ser acessados carregando o pacote {ADARdata}
.
#devtools::install_github("lhmet/ADARdata")
library(ADARdata)
O pacote disponibiliza os seguinte conjunto de dados formado por 3 quadro de dados que serão usados a seguir:
clima_sm
contém estatísticas e as observações históricas de temperatura do ar (tar
) e precipitação diária (prec
) para cada dia do ano em Santa Maria-RStempo_sm
contém os dados meteorológicos do último anorecordes_atual_sm
contém os recordes de temperatura e precipitação do último ano
Você pode obter mais informações sobre cada um dos quadro de dados consultado o help.
?dados_sm
Para construção do gráfico precisaremos das posições dos dia 15 e do último dia de cada mês. Esta informação será útil para especificar onde colocar os nomes dos meses no eixo x. Por isso vamos criar abaixo um tibble
com o dia do ano correspondente aquelas datas.
ultimo_ano <- unique(year(tempo_sm$date))
datas_atual <- seq(
from = as.Date(paste0(ultimo_ano, '-01-01')),
to = as.Date(paste0(ultimo_ano, '-12-31')),
by = "day"
)
library(scales)
# dda do meio do mês
meio_mes <- yday(datas_atual)[day(datas_atual) == 15]
# dda do final do mês
fim_mes <- tibble(datas_atual,
mes = month(datas_atual),
day = day(datas_atual),
yday = yday(datas_atual)) %>%
group_by(mes) %>%
summarise(ult_dia = yday[which.max(day)], .groups = "drop") %>%
pull(ult_dia)
# junção em tibble
marcas_x <- tibble(
metade = meio_mes,
final = fim_mes,
labels = c(
"Janeiro", "Fevereiro", "Março", "Abril",
"Maio", "Junho", "Julho", "Agosto", "Setembro",
"Outubro", "Novembro", "Dezembro"
)
)
marcas_x
#> # A tibble: 12 x 3
#> metade final labels
#> <dbl> <dbl> <chr>
#> 1 15 31 Janeiro
#> 2 46 60 Fevereiro
#> 3 75 91 Março
#> 4 106 121 Abril
#> 5 136 152 Maio
#> 6 167 182 Junho
#> 7 197 213 Julho
#> 8 228 244 Agosto
#> 9 259 274 Setembro
#> 10 289 305 Outubro
#> 11 320 335 Novembro
#> 12 350 366 Dezembro
PAREI AQUI
11.6.3 Gráfico do tempo de Santa Maria-RS em 2020
Para ilustrar a abordagem de construção de gráficos por camadas do {ggplot2}
vamos visualizar a variação temperatura diária do ar para o ano corrente e compará-la com a climatologia e estatísticas baseadas em 58 anos de dados. Nós vamos explorar diferentes geometrias (linhas, pontos, intervalos)
Nós criamos um gráfico a partir da função ggplot()
, especificando os dados de entrada.
ggplot(data = clima_sm)
O resultado é um painel em branco. A construção de um gráfico com o {ggplot2}
envolve a especificação de atributos estéticos (eixos x e y), adição de elementos geométricos aos nossos dados, operações estatísticas, escalas, coordenadas e várias utras componentes.
Podemos adicionar geometrias usando o operador +
, conforme mostrado abaixo. Para criar o gráfico da temperatura do ar (tar
) de Santa Maria-RS, precisamos mapear as variáveis de interesse dos dados de entrada para o eixo y e x.
O mapeamento das variáveis nos eixos é feito pela função aes()
(de aesthetics, estética em inglês). Ela indica a relação entre os dados, a variável que será representada no eixo x, a que será representada no eixo y, a cor, o tamanho dos componentes geométricos etc.
Os aspectos que podem ou devem ser mapeados dependem do tipo de gráfico que você está construindo.
Nossa 1ª camada de geometria será uma linha vertical que se estende dos valores mínimo até o máximo absoluto de tar
(variáveis tar_min
e tar_max
) registrado no dia do ano (dda
).
O dda
é especificado no eixo x. Para inserir uma linha vertical a geom_linerange()
requer os argumentos x
, ymin
e ymax
.
ggplot(data = clima_sm) +
geom_linerange(
mapping = aes(x = dda, ymin = tar_min, ymax = tar_max),
color = "wheat2"
# alpha = .1
)
Além de identificar as variáveis de cada eixo nós adicionamos o argumento color
para distinguir os intervalos variação entre os máximos e mínimos absolutos registrados.
Uma versatilidade do {ggplot2}
é de podermos armazenar os gráficos em objetos. Então o gráfico básico acima pode ser armazenado numa váriavel. A estrutura do gráfico é uma lista com todas componentes necessárias para construção do gráfico.
graf_base <-
ggplot( data = clima_sm) +
#geom_point(size = 0.01, colour = "green") +
geom_linerange(
mapping = aes(x = dda, ymin = tar_min, ymax = tar_max),
color = "wheat2"
# alpha = .1
) +
theme_void()
#glimpse(graf_base, max.level = 1)
graf_base
# ggplot( data = clima_sm) +
# #geom_point(size = 0.01, colour = "green") +
# geom_linerange(
# mapping = aes(x = dda, ymin = tar_min, ymax = tar_max),
# color = "wheat2"
# # alpha = .1
# ) +
# #theme_void()
# theme(#plot.background = element_blank(),
# panel.grid.minor.x = element_blank(),
# panel.grid.major.y = element_blank(),
# panel.border = element_blank(),
# panel.background = element_blank(),
# axis.ticks = element_blank(),
# #axis.text = element_blank(),
# axis.title = element_blank()
# )
Na sequência vamos adicionar uma segunda camada com os dados que representam o intervalo de confiança de 95% da temperatura média diária para o período de 1952-2019.
ggp_sm <- graf_base +
geom_linerange(
mapping = aes(x = dda, ymin = tar_med_min, ymax = tar_med_max),
color = "wheat4"
)
ggp_sm
Agora vamos incorporar ao gráfico os dados de temperatura do ano atual e uma linha vertical (geom_vline
) na borda esquerda do eixo y.
ggp_sm <- ggp_sm +
geom_line(
data = tempo_sm,
mapping = aes(x = dda, y = tar),
# size = 1
) +
geom_vline(
xintercept = 0,
color = "wheat4",
linetype = 1,
size = 1
)
ggp_sm
Agora vamos ajustar a escala do eixo y ao intervalo de variação da dos extremos e definir 8 marcas para os labels.
int_var <- range(c(clima_sm$tar_max, clima_sm$tar_min))
int_var <- c(floor(int_var[1]), ceiling(int_var[2]))
int_var
#> [1] 3 35
ggp_sm <- ggp_sm +
scale_y_continuous(
limits = int_var,
breaks = scales::pretty_breaks(n = 8),
labels = scales::label_number(suffix = " °C", accuracy = 5)
) +
scale_x_continuous(expand = c(0, 0),
breaks = marcas_x$metade,
labels = marcas_x$labels,
)
ggp_sm
Podemos adicionar linhas de grade horizontais e verticais como referência. As linhas verticais serão adicionadas no último dia de cada mês. As horizontais serão espaçadas de 5°C.
ggp_sm <- ggp_sm +
geom_hline(
yintercept = seq(int_var[1], int_var[2], by = 5),
color = "white",
linetype = 1
) +
geom_vline(
xintercept = marcas_x$final,
color = "wheat4",
linetype = 3,
size = 0.5
)
ggp_sm
Neste ponto, vamos identificar os dias que em 2020 ultrapassaram os recordes históricos de temperatura.
ggp_sm <- ggp_sm +
geom_point(
data = filter(recordes_atual_sm, record_min == "S"),
aes(x = dda, y = tar), color = "blue3") +
geom_point(
data = filter(recordes_atual_sm, record_max == "S"),
aes(x = dda, y = tar), color = "firebrick3")
ggp_sm
Com todos dados plotados agora podemos incrementá-lo com texto apropriado. Primeiramente vamos adicionar um título e subtítulo.
ggp_sm <- ggp_sm +
ggtitle("Tempo em Santa Maria, 2020") +
theme(
plot.title = element_text(
face = "bold",
hjust = .012,
vjust = .8,
colour = "#3C3C3C",
size = 20
)
) +
annotate("text",
x = 138,
y = 36,
label = "Temperatura",
size = 4,
fontface = "bold"
)
ggp_sm
#> Warning: Removed 1 rows containing missing values (geom_text).
Nós podemos adicionar um parágrafo abaixo do subtítulo para dar uma pequena explanação dobre os dados. O texto será separado em 4 anotações.
texto <- "Os dados representam as médias diárias de temperatura. Os dados iniciam efetivamente em 1951. Dados para 2020 são disponíveis somente até Julho. A Temperatura média anual até este mês foi de 22°C, caracterizando 2020 como o 8° ano mais quente."
ggp_sm <- ggp_sm +
annotate("text",
x = 120,
y = 32.5,
label = str_wrap(texto, width = 70),
size = 3,
colour = "gray30",
hjust = 0
)
ggp_sm
#> Warning: Removed 1 rows containing missing values (geom_text).
Anotações que explicam os pontos representando os dias nos quais ocorreram recordes de temperatura máxima e mínima.
x_rec_tmin <- filter(recordes_atual_sm, record_min == "S") %>%
pull(dda)
y_rec_tmin <- filter(recordes_atual_sm, record_min == "S") %>%
pull(tar_min)
x_rec_tmax <- filter(recordes_atual_sm, record_max == "S") %>%
pull(dda) %>%
nth(3)
y_rec_tmax <- filter(recordes_atual_sm, record_max == "S") %>%
pull(tar_max) %>%
nth(3)
ggp_sm <- ggp_sm +
annotate("segment",
x = x_rec_tmin - 2, xend = x_rec_tmin - 12,
y = y_rec_tmin - 1, yend = y_rec_tmin - 3,
color = "blue3"
) +
annotate("text",
x = x_rec_tmin - 12,
y = y_rec_tmin - 3 -0.5,
label = "Recorde de Tmin",
size=2.9,
colour="blue3"
) +
annotate("segment",
x = x_rec_tmax + 2, xend = x_rec_tmax + 12,
y = y_rec_tmax + 1, yend = y_rec_tmax + 2,
color = "firebrick3"
) +
annotate("text",
x = x_rec_tmax + 13,
y = y_rec_tmax + 3,
label = "Recordes de Tmax",
size = 2.9,
colour="firebrick3"
)
ggp_sm
#> Warning: Removed 1 rows containing missing values (geom_text).
leg_dados <- data.frame(x = seq(53, 61), y = rnorm(9, mean = 12, 1))
ggp_sm +
# limites extremos
annotate("segment",
x = marcas_x$final[2],
xend = marcas_x$final[2],
y = 9,
yend = 15,
colour = "wheat2",
size = 3
) +
# intervalo intermediário
annotate("segment",
x = marcas_x$final[2],
xend = marcas_x$final[2],
y = 10.5,
yend = 13.5,
colour = "wheat4",
size = 3
) +
geom_line(data = leg_dados, aes(x = x, y = y)) +
# labels intermediários
annotate("text",
x = 36,
y = 12,
label = "TEMPERATURA 2020",
size = 2,
colour = "gray30"
) +
annotate("text",
x = 84,
y = 12,
label = "INTERVALO NORMAL",
size = 2,
colour = "gray30"
) +
# labels extremos
annotate("text",
x = 70,
y = 15,
label = "MÁXIMO",
size = 2,
colour = "gray30"
) +
annotate("text",
x = 70,
y = 9.5,
label = "MÌNIMO",
size = 2,
colour = "gray30"
) +
# segmentos do intervalo normal
annotate("segment",
x = 63,
xend = 65,
y = 10.5,
yend = 10.5,
colour = "wheat4",
size=.5
) +
annotate("segment",
x = 63,
xend = 65,
y = 13.5,
yend = 13.5,
colour = "wheat4",
size=.5
) +
annotate("segment",
x = 65,
xend = 65,
y = 10.5,
yend = 13.5,
colour = "wheat4",
size=.5
)
#> Warning: Removed 1 rows containing missing values (geom_text).