Boxplots estão por toda parte, e muitas vezes são úteis quando queremos ver sumários de várias distribuições nos dados. Aqui vão algumas dicas para melhorar seu uso de boxplots no ggplot2.
Usaremos dados sobre Star Wars incluÃdos no pacote dplyr, que é parte do tidyverse. Os dados vem da Star Wars API e já estão no namespace se carregamos o tidyverse:
library(tidyverse)
theme_set(theme_bw())
glimpse(starwars)
## Observations: 87
## Variables: 13
## $ name <chr> "Luke Skywalker", "C-3PO", "R2-D2", "Darth Vader", "L…
## $ height <int> 172, 167, 96, 202, 150, 178, 165, 97, 183, 182, 188, …
## $ mass <dbl> 77.0, 75.0, 32.0, 136.0, 49.0, 120.0, 75.0, 32.0, 84.…
## $ hair_color <chr> "blond", NA, NA, "none", "brown", "brown, grey", "bro…
## $ skin_color <chr> "fair", "gold", "white, blue", "white", "light", "lig…
## $ eye_color <chr> "blue", "yellow", "red", "yellow", "brown", "blue", "…
## $ birth_year <dbl> 19.0, 112.0, 33.0, 41.9, 19.0, 52.0, 47.0, NA, 24.0, …
## $ gender <chr> "male", NA, NA, "male", "female", "male", "female", N…
## $ homeworld <chr> "Tatooine", "Tatooine", "Naboo", "Tatooine", "Alderaa…
## $ species <chr> "Human", "Droid", "Droid", "Human", "Human", "Human",…
## $ films <list> [<"Revenge of the Sith", "Return of the Jedi", "The …
## $ vehicles <list> [<"Snowspeeder", "Imperial Speeder Bike">, <>, <>, <…
## $ starships <list> [<"X-wing", "Imperial shuttle">, <>, <>, "TIE Advanc…
Para conhecer mais sobre essas colunas, você pode fazer help("starwars")
Para facilitar alguns exemplos, vou criar uma coluna que tem a raça dos personagens, mas apenas dizendo se é humano, androide ou outro, e uma que diz em quantos filmes o personagem apareceu.
starwars = starwars %>%
mutate(species_short = if_else(species %in% c("Human", "Droid"),
species,
"Other"),
n_films = map_dbl(films, length))
Passando nenhum parâmetro, temos o seguinte:
starwars %>%
filter(!is.na(height)) %>%
ggplot(aes(x = "", y = height)) +
geom_boxplot()
Aliás, o x = "" nesse caso significa que todas as observações estarão no mesmo ponto do eixo x, porque todos terão o valor "" definindo a posição no eixo x. É um truque se você quer ver o boxplot de tudo.
Mas os problemas:
E na estética também. Caso você não esteja acostumado, .1 = 0.1
starwars %>%
filter(!is.na(height)) %>%
ggplot(aes(x = "star wars", y = height)) +
geom_boxplot(width = .1)
Sobrepor todos os pontos no boxplot com geom_jitter ou ggbeeswarm::geom_quasirandom dá os detalhes junto com sumário que é o boxplot. Nesse caso, é importante omitir os pontos plotados pelo boxplot, para não repetÃ-los. Também ajuda mudar a cor e transparência dos pontos.
starwars %>%
filter(!is.na(height)) %>%
ggplot(aes(x = "", y = height)) +
geom_boxplot(width = .2, outlier.colour = NA) +
geom_jitter(
width = .05,
alpha = .4,
size = 1,
color = "brown"
)
Já sobre os bigodes to boxplot, temos duas opções além de usar o default: removê-los ou fazê-los indicar algo mais claro (e indicar isso junto com o gráfico!).
starwars %>%
filter(!is.na(height)) %>%
ggplot(aes(x = "", y = height)) +
geom_boxplot(width = .2, outlier.colour = NA, coef = 0) +
geom_jitter(
width = .05,
alpha = .4,
size = 1,
color = "brown"
) +
labs(
x = "Personagens",
y = "Altura (cm)",
title = "Sem as linhas"
)
starwars %>%
filter(!is.na(height)) %>%
ggplot(aes(x = "", y = height)) +
geom_boxplot(width = .2, outlier.colour = NA, coef = 1000) +
geom_jitter(
width = .05,
alpha = .4,
size = 1,
color = "brown"
) +
labs(
x = "Personagens",
y = "Altura (cm)",
title = "As linhas indo ao máximo e mÃnimo"
)
Nessa segunda opção, coef é o coeficiente que determina a quantas vezes o IQR no máximo a linha vai. Colocando um valor muito alto, ela irá até valores (ex: 1000*IQR) muito altos e baixos, e incluirá o máx e min.
As mesmas dicas valem para comparar vários boxplots:
starwars %>%
filter(!is.na(height)) %>%
ggplot(aes(x = species_short, y = height)) +
geom_boxplot(width = .2)
starwars %>%
filter(!is.na(height)) %>%
ggplot(aes(x = species_short, y = height)) +
geom_boxplot(width = .2, outlier.colour = NA, coef = 1000) +
geom_jitter(width = 0.05, alpha = 0.4, color = "orange")
Quando o eixo x é um número, precisamos indicar ao boxplot que dados vão em cada caixa:
starwars %>%
filter(!is.na(height)) %>%
ggplot(aes(x = n_films, y = height, group = n_films)) +
geom_boxplot(width = .2,
outlier.colour = NA,
coef = 1000) +
geom_jitter(width = 0.05,
alpha = 0.4,
color = "orange")
Caso queiramos criar nossos grupos, a função cut ajuda:
starwars %>%
filter(!is.na(height)) %>%
mutate(n_filmes_g = cut(n_films, breaks = c(0, 3, 5, 10))) %>%
ggplot(aes(x = n_filmes_g, y = height, group = n_filmes_g)) +
geom_boxplot(width = .2,
outlier.colour = NA,
coef = 1000) +
geom_jitter(width = 0.05,
alpha = 0.4,
color = "orange")
Outra opção legal é colocar o boxplot ao lado dos pontos:
starwars %>%
filter(!is.na(height)) %>%
ggplot(aes(x = species_short, y = height)) +
geom_boxplot(
width = .2,
outlier.colour = NA,
coef = 1000,
position = position_nudge(.2),
color = "grey"
) +
geom_jitter(width = .05,
height = 0,
alpha = 0.4)