O objetivo deste repositório é acompanhar alguns truques do GGPLOT2 que aprendi. Isso pressupõe que você se familiarizou com o básico do GGPlot2 e pode construir algumas parcelas legais. Caso contrário, leia o livro em seu Leasure.
Não estou incrivelmente me adaptando em parcelas gloriosamente digitadas e com temas e paletas de cores, então você teria que me perdoar. O conjunto de dados mpg
é muito versátil para plotagem, então você verá muito disso enquanto lê. Os pacotes de extensão são ótimos, e eu me envolvi, mas vou tentar me limitar a truques de baunilha ggplot2 aqui.
Por enquanto, isso será principalmente um saco de truques somente para leitura, mas posso decidir posteriormente colocá-los em grupos separados em outros arquivos.
Carregando a biblioteca e definindo um tema de plotagem. O primeiro truque aqui é usar theme_set()
para definir um tema para todas as suas parcelas em um documento. Se você estiver definindo um tema muito detalhado para cada gráfico, aqui está o local onde você define todas as suas configurações comuns. Então nunca escreva um romance de elementos temáticos novamente 1 !
library( ggplot2 )
library( scales )
theme_set(
# Pick a starting theme
theme_gray() +
# Add your favourite elements
theme(
axis.line = element_line(),
panel.background = element_rect( fill = " white " ),
panel.grid.major = element_line( " grey95 " , linewidth = 0.25 ),
legend.key = element_rect( fill = NA )
)
)
A documentação ?aes
não lhe diz isso, mas você pode unir o argumento mapping
no GGPlot2. O que isso significa? Bem, isso significa que você pode compor o argumento mapping
em movimento !!!
. Isso é especialmente bacana se você precisar reciclar a estética de vez em quando.
my_mapping <- aes( x = foo , y = bar )
aes( colour = qux , !!! my_mapping )
# > Aesthetic mapping:
# > * `x` -> `foo`
# > * `y` -> `bar`
# > * `colour` -> `qux`
Meu uso favorito disso é fazer com que a cor fill
corresponda à cor colour
, mas um pouco mais leve 2 . Usaremos o sistema de avaliação atrasado para isso, after_scale()
neste caso, que você verá mais na seção após este. Vou repetir esse truque algumas vezes ao longo deste documento.
my_fill <- aes( fill = after_scale(alpha( colour , 0.3 )))
ggplot( mpg , aes( displ , hwy )) +
geom_point(aes( colour = factor ( cyl ), !!! my_fill ), shape = 21 )
Você pode se encontrar em uma situação em que é solicitado a fazer um mapa de calor de um pequeno número de variáveis. Normalmente, as escalas seqüenciais funcionam de claro para escuro ou vice -versa, o que torna o texto em uma única cor difícil de ler. Poderíamos criar um método para escrever automaticamente o texto em branco em um fundo escuro e preto em um fundo leve. A função abaixo considera um valor de leveza para uma cor e retorna preto ou branco, dependendo dessa leveza.
contrast <- function ( colour ) {
out <- rep( " black " , length( colour ))
light <- farver :: get_channel( colour , " l " , space = " hcl " )
out [ light < 50 ] <- " white "
out
}
Agora, podemos fazer uma estética para ser emendada no argumento mapping
de uma camada sob demanda.
autocontrast <- aes( colour = after_scale(contrast( fill )))
Por fim, podemos testar nossa engenhoca automática de contraste. Você pode notar que ele se adapta à escala, para não precisar fazer um monte de formatação condicional para isso.
cors <- cor( mtcars )
# Melt matrix
df <- data.frame (
col = colnames( cors )[as.vector(col( cors ))],
row = rownames( cors )[as.vector(row( cors ))],
value = as.vector( cors )
)
# Basic plot
p <- ggplot( df , aes( row , col , fill = value )) +
geom_raster() +
geom_text(aes( label = round( value , 2 ), !!! autocontrast )) +
coord_equal()
p + scale_fill_viridis_c( direction = 1 )
p + scale_fill_viridis_c( direction = - 1 )
Existem algumas extensões que oferecem versões de meia geom. Dos que eu conheço, Gghalves e o pacote See oferecem meias-geoms.
Aqui está como abusar do sistema de avaliação atrasado para criar o seu. Isso pode ser útil se você não estiver disposto a assumir uma dependência extra apenas para esse recurso.
O estojo fácil é o boxplot. Você pode definir xmin
ou xmax
como after_scale(x)
para manter as partes direita e esquerda de uma caixa de caixa, respectivamente. Isso ainda funciona bem com position = "dodge"
.
# A basic plot to reuse for examples
p <- ggplot( mpg , aes( class , displ , colour = class , !!! my_fill )) +
guides( colour = " none " , fill = " none " ) +
labs( y = " Engine Displacement [L] " , x = " Type of car " )
p + geom_boxplot(aes( xmin = after_scale( x )))
A mesma coisa que funciona para boxplots, também funciona para ErrorBars.
p + geom_errorbar(
stat = " summary " ,
fun.data = mean_se ,
aes( xmin = after_scale( x ))
)
Mais uma vez, podemos fazer a mesma coisa para parcelas de violino, mas a camada reclama de não saber da estética xmin
. Ele usa essa estética, mas somente após a configuração dos dados, não se destina a ser uma estética acessível ao usuário. Podemos silenciar o aviso atualizando o padrão xmin
para NULL
, o que significa que ele não reclamará, mas também não o usa se estiver ausente.
update_geom_defaults( " violin " , list ( xmin = NULL ))
p + geom_violin(aes( xmin = after_scale( x )))
Desta vez, não foi deixado como exercício para o leitor, mas eu só queria mostrar como funcionaria se você combinasse duas metades e os quisesse um pouco compensado um do outro. Abusaremos as barras de erro para servir como grampos para os boxplots.
# A small nudge offset
offset <- 0.025
# We can pre-specify the mappings if we plan on recycling some
right_nudge <- aes(
xmin = after_scale( x ),
x = stage( class , after_stat = x + offset )
)
left_nudge <- aes(
xmax = after_scale( x ),
x = stage( class , after_stat = x - offset )
)
# Combining
p +
geom_violin( right_nudge ) +
geom_boxplot( left_nudge ) +
geom_errorbar( left_nudge , stat = " boxplot " , width = 0.3 )
Digamos que você tenha uma melhor intuição de cores do que eu, e três cores não são suficientes para as suas necessidades de paleta de cores divergentes. Um ponto de dor é que é complicado acertar o ponto médio se seus limites não estiverem perfeitamente centrados em torno dele. Digite o argumento rescaler
na liga com scales::rescale_mid()
.
my_palette <- c( " dodgerblue " , " deepskyblue " , " white " , " hotpink " , " deeppink " )
p <- ggplot( mpg , aes( displ , hwy , colour = cty - mean( cty ))) +
geom_point() +
labs(
x = " Engine displacement [L] " ,
y = " Highway miles per gallon " ,
colour = " Centered n value "
)
p +
scale_colour_gradientn(
colours = my_palette ,
rescaler = ~ rescale_mid( .x , mid = 0 )
)
Uma alternativa é simplesmente centralizar os limites em x. Podemos fazer isso fornecendo uma função aos limites da escala.
p +
scale_colour_gradientn(
colours = my_palette ,
limits = ~ c( - 1 , 1 ) * max(abs( .x ))
)
Você pode rotular pontos com geom_text()
, mas um problema em potencial é que o texto e os pontos se sobrepõem.
set.seed( 0 )
df <- USArrests [sample(nrow( USArrests ), 5 ), ]
df $ state <- rownames( df )
q <- ggplot( df , aes( Murder , Rape , label = state )) +
geom_point()
q + geom_text()
Existem várias soluções típicas para esse problema, e todas elas vêm com desvantagens:
nudge_x
e nudge_y
. A questão aqui é que estes são definidos nas unidades de dados, portanto o espaçamento é imprevisível e não há como fazê -las depender dos locais originais.hjust
e vjust
. Ele permite que você dependa dos locais originais, mas estes não têm compensações naturais.Aqui estão as opções 2 e 3 em ação:
q + geom_text( nudge_x = 1 , nudge_y = 1 )
q + geom_text(aes(
hjust = Murder > mean( Murder ),
vjust = Rape > mean( Rape )
))
Você pode pensar: 'Eu posso multiplicar as justificativas para obter um deslocamento mais amplo', e você estaria certo. No entanto, como a justificativa depende do tamanho do texto, você pode obter compensações desiguais. Aviso no enredo abaixo de que 'Dakota do Norte' está compensado demais na direção Y e 'Rhode Island' na direção x.
q + geom_text(aes(
label = gsub( " North Dakota " , " North n Dakota " , state ),
hjust = (( Murder > mean( Murder )) - 0.5 ) * 1.5 + 0.5 ,
vjust = (( Rape > mean( Rape )) - 0.5 ) * 3 + 0.5
))
A coisa agradável de geom_label()
é que você pode desligar a caixa da etiqueta e manter o texto. Dessa forma, você pode continuar usando outras coisas úteis, como a configuração label.padding
.
q + geom_label(
aes(
label = gsub( " " , " n " , state ),
hjust = Murder > mean( Murder ),
vjust = Rape > mean( Rape )
),
label.padding = unit( 5 , " pt " ),
label.size = NA , fill = NA
)
Isso costumava ser uma dica sobre a colocação de tags de faceta em painéis, que costumavam ser complicados. Com o GGPLOT2 3.5.0, você não precisa mais mexer com a definição de posições infinitas e ajustando os parâmetros hjust
ou vjust
. Agora você pode apenas usar x = I(0.95), y = I(0.95)
para colocar o texto no canto superior direito. Abra os detalhes para ver a dica antiga.
Colocar as anotações de texto em parcelas facetadas é uma dor, porque os limites podem variar de forma por panela, por isso é muito difícil encontrar a posição correta. Uma extensão que explora aliviando essa dor é a extensão do tagger, mas podemos fazer uma coisa semelhante no baunilha ggplot2.
Felizmente, existe um mecânico nos eixos de posição do GGPLOT2 que vamos -Inf
e Inf
interpretados como o limite mínimo e máximo da escala, respectivamente, 3 . Você pode explorar isso escolhendo x = Inf, y = Inf
para colocar os rótulos em um canto. Você também pode usar -Inf
em vez de Inf
para colocar na parte inferior em vez de superior ou esquerda em vez da direita.
Precisamos corresponder aos argumentos hjust
/ vjust
ao lado da trama. Para x/y = Inf
, eles precisariam ser hjust/vjust = 1
e, para x/y = -Inf
precisam ser hjust/vjust = 0
.
p + facet_wrap( ~ class , scales = " free " ) +
geom_text(
# We only need 1 row per facet, so we deduplicate the facetting variable
data = ~ subset( .x , ! duplicated( class )),
aes( x = Inf , y = Inf , label = LETTERS [seq_along( class )]),
hjust = 1 , vjust = 1 ,
colour = " black "
)
Infelizmente, isso coloca o texto diretamente na fronteira do painel, que pode ofender nosso senso de beleza. Podemos ficar um pouco mais sofisticados usando geom_label()
, o que nos permite controlar com mais precisão o espaçamento entre o texto e as fronteiras do painel, definindo o argumento label.padding
.
Além disso, podemos usar label.size = NA, fill = NA
para ocultar a parte da caixa de texto do geom. Para fins de ilustração, agora colocamos a etiqueta no canto superior esquerdo em vez do direito direito.
p + facet_wrap( ~ class , scales = " free " ) +
geom_label(
data = ~ subset( .x , ! duplicated( class )),
aes( x = - Inf , y = Inf , label = LETTERS [seq_along( class )]),
hjust = 0 , vjust = 1 , label.size = NA , fill = NA ,
label.padding = unit( 5 , " pt " ),
colour = " black "
)
Digamos que estamos encarregados de fazer um monte de gráficos semelhantes, com diferentes conjuntos de dados e colunas. Por exemplo, podemos querer fazer uma série de gráficos 4 com alguns precedentes específicos: gostaríamos que as barras tocassem o eixo x e não desenhem linhas de grade vertical.
Uma maneira bem conhecida de fazer um monte de parcelas semelhantes é envolver a construção da plotagem em uma função. Dessa forma, você pode usar o Encode todas as predefinições que deseja em sua função.
Caso você pode não saber, existem vários métodos para programar com a função aes()
e o uso de {{ }}
(curly-curly) é uma das maneiras mais flexíveis 5 .
barplot_fun <- function ( data , x ) {
ggplot( data , aes( x = {{ x }})) +
geom_bar( width = 0.618 ) +
scale_y_continuous( expand = c( 0 , 0 , 0.05 , 0 )) +
theme( panel.grid.major.x = element_blank())
}
barplot_fun( mpg , class )
Uma desvantagem dessa abordagem é que você bloqueia qualquer estética nos argumentos da função. Para contornar isso, uma maneira ainda mais simples é simplesmente passar ...
diretamente para aes()
.
barplot_fun <- function ( data , ... ) {
ggplot( data , aes( ... )) +
geom_bar( width = 0.618 ) +
scale_y_continuous( expand = c( 0 , 0 , 0.1 , 0 )) +
theme( panel.grid.major.x = element_blank())
}
barplot_fun( mpg , class , colour = factor ( cyl ), !!! my_fill )
Outro método de fazer uma coisa muito semelhante é usar 'esqueletos' da plotagem. A idéia por trás de um esqueleto é que você pode criar um gráfico, com ou sem qualquer argumento data
e adicionar os detalhes posteriormente. Então, quando você realmente deseja fazer um gráfico, pode usar o %+%
para preencher ou substituir o conjunto de dados e + aes(...)
para definir a estética relevante.
barplot_skelly <- ggplot() +
geom_bar( width = 0.618 ) +
scale_y_continuous( expand = c( 0 , 0 , 0.1 , 0 )) +
theme( panel.grid.major.x = element_blank())
my_plot <- barplot_skelly % + % mpg +
aes( class , colour = factor ( cyl ), !!! my_fill )
my_plot
Uma coisa interessante sobre esses esqueletos é que, mesmo quando você já preencheu os data
e os argumentos mapping
, você pode apenas substituí -los repetidamente.
my_plot % + % mtcars +
aes( factor ( carb ), colour = factor ( cyl ), !!! my_fill )
A idéia aqui é não esqueletar todo o enredo, mas apenas um conjunto de peças com frequência. Por exemplo, podemos querer rotular o nosso Barplot e reunir todas as coisas que compõem um Barplot de marcado. O truque para isso é não adicionar esses componentes com +
, mas simplesmente colocá -los em uma list()
. Você pode então +
sua lista juntamente com a principal chamada.
labelled_bars <- list (
geom_bar( my_fill , width = 0.618 ),
geom_text(
stat = " count " ,
aes( y = after_stat( count ),
label = after_stat( count ),
fill = NULL , colour = NULL ),
vjust = - 1 , show.legend = FALSE
),
scale_y_continuous( expand = c( 0 , 0 , 0.1 , 0 )),
theme( panel.grid.major.x = element_blank())
)
ggplot( mpg , aes( class , colour = factor ( cyl ))) +
labelled_bars +
ggtitle( " The `mpg` dataset " )
ggplot( mtcars , aes( factor ( carb ), colour = factor ( cyl ))) +
labelled_bars +
ggtitle( " The `mtcars` dataset " )
#> ─ Session info ───────────────────────────────────────────────────────────────
#> setting value
#> version R version 4.3.2 (2023-10-31 ucrt)
#> os Windows 11 x64 (build 22631)
#> system x86_64, mingw32
#> ui RTerm
#> language (EN)
#> collate English_Netherlands.utf8
#> ctype English_Netherlands.utf8
#> tz Europe/Amsterdam
#> date 2024-02-27
#> pandoc 3.1.1
#>
#> ─ Packages ───────────────────────────────────────────────────────────────────
#> package * version date (UTC) lib source
#> cli 3.6.2 2023-12-11 [] CRAN (R 4.3.2)
#> colorspace 2.1-0 2023-01-23 [] CRAN (R 4.3.2)
#> digest 0.6.34 2024-01-11 [] CRAN (R 4.3.2)
#> dplyr 1.1.4 2023-11-17 [] CRAN (R 4.3.2)
#> evaluate 0.23 2023-11-01 [] CRAN (R 4.3.2)
#> fansi 1.0.6 2023-12-08 [] CRAN (R 4.3.2)
#> farver 2.1.1 2022-07-06 [] CRAN (R 4.3.2)
#> fastmap 1.1.1 2023-02-24 [] CRAN (R 4.3.2)
#> generics 0.1.3 2022-07-05 [] CRAN (R 4.3.2)
#> ggplot2 * 3.5.0.9000 2024-02-27 [] local
#> glue 1.7.0 2024-01-09 [] CRAN (R 4.3.2)
#> gtable 0.3.4 2023-08-21 [] CRAN (R 4.3.2)
#> highr 0.10 2022-12-22 [] CRAN (R 4.3.2)
#> htmltools 0.5.7 2023-11-03 [] CRAN (R 4.3.2)
#> knitr 1.45 2023-10-30 [] CRAN (R 4.3.2)
#> labeling 0.4.3 2023-08-29 [] CRAN (R 4.3.1)
#> lifecycle 1.0.4 2023-11-07 [] CRAN (R 4.3.2)
#> magrittr 2.0.3 2022-03-30 [] CRAN (R 4.3.2)
#> munsell 0.5.0 2018-06-12 [] CRAN (R 4.3.2)
#> pillar 1.9.0 2023-03-22 [] CRAN (R 4.3.2)
#> pkgconfig 2.0.3 2019-09-22 [] CRAN (R 4.3.2)
#> R6 2.5.1 2021-08-19 [] CRAN (R 4.3.2)
#> ragg 1.2.7 2023-12-11 [] CRAN (R 4.3.2)
#> rlang 1.1.3 2024-01-10 [] CRAN (R 4.3.2)
#> rmarkdown 2.25 2023-09-18 [] CRAN (R 4.3.2)
#> rstudioapi 0.15.0 2023-07-07 [] CRAN (R 4.3.2)
#> scales * 1.3.0 2023-11-28 [] CRAN (R 4.3.2)
#> sessioninfo 1.2.2 2021-12-06 [] CRAN (R 4.3.2)
#> systemfonts 1.0.5 2023-10-09 [] CRAN (R 4.3.2)
#> textshaping 0.3.7 2023-10-09 [] CRAN (R 4.3.2)
#> tibble 3.2.1 2023-03-20 [] CRAN (R 4.3.2)
#> tidyselect 1.2.0 2022-10-10 [] CRAN (R 4.3.2)
#> utf8 1.2.4 2023-10-22 [] CRAN (R 4.3.2)
#> vctrs 0.6.5 2023-12-01 [] CRAN (R 4.3.2)
#> viridisLite 0.4.2 2023-05-02 [] CRAN (R 4.3.2)
#> withr 3.0.0 2024-01-16 [] CRAN (R 4.3.2)
#> xfun 0.41 2023-11-01 [] CRAN (R 4.3.2)
#> yaml 2.3.8 2023-12-11 [] CRAN (R 4.3.2)
#>
#>
#> ──────────────────────────────────────────────────────────────────────────────
Bem, você precisa fazer isso uma vez no início do seu documento. Mas então nunca mais! Exceto no seu próximo documento. Basta escrever um script plot_defaults.R
e source()
do seu documento. Copie cola esse script para cada projeto. Então, verdadeiramente, nunca mais: coração:. ↩
Isso é uma mentira. Na realidade, eu uso aes(colour = after_scale(colorspace::darken(fill, 0.3)))
em vez de iluminar o preenchimento. Eu não queria que este ReadMe dependesse de {Colorspace}. ↩
A menos que você se auto-sabote suas parcelas definindo oob = scales::oob_censor_any
na escala, por exemplo. ↩
Na sua alma das almas, você realmente quer fazer um monte de gráficos de barra? ↩
A alternativa é usar o pronome .data
, que pode ser .data$var
se você deseja bloquear essa coluna com antecedência, ou .data[[var]]
quando var
é passado como um caractere. ↩
Esse bit foi originalmente chamado de 'esqueleto parcial', mas como uma caixa torácica faz parte de um esqueleto, esse título parecia mais evocativo. ↩