Tujuan dari repositori ini adalah untuk melacak beberapa trik GGPLOT2 yang rapi yang telah saya pelajari. Ini mengasumsikan Anda telah membiasakan diri dengan dasar -dasar GGPlot2 dan dapat membangun beberapa plot yang bagus sendiri. Jika tidak, silakan teliti buku ini di leasure Anda.
Saya tidak sangat beradaptasi dalam hal -hal yang memukau dan tema -tema finetuning dan palet warna yang ahli, jadi Anda harus memaafkan saya. Dataset mpg
sangat fleksibel untuk merencanakan, jadi Anda akan melihat banyak hal saat Anda membaca. Paket ekstensi sangat bagus, dan saya telah mencoba -coba sendiri, tetapi saya akan mencoba membatasi diri pada trik vanilla ggplot2 di sini.
Untuk saat ini, ini sebagian besar akan menjadi tas trik hanya readme, tetapi saya dapat memutuskan nanti untuk memasukkannya ke dalam grup terpisah di file lain.
Dengan memuat perpustakaan dan mengatur tema plot. Trik pertama di sini adalah menggunakan theme_set()
untuk mengatur tema untuk semua plot Anda di seluruh dokumen. Jika Anda menemukan diri Anda menetapkan tema yang sangat bertele -tele untuk setiap plot, berikut adalah tempat di mana Anda mengatur semua pengaturan umum Anda. Kemudian jangan pernah menulis novel elemen tema lagi 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 )
)
)
Dokumentasi ?aes
tidak memberi tahu Anda ini, tetapi Anda dapat menyambungkan argumen mapping
di GGPlot2. Maksudnya itu apa? Nah itu berarti Anda dapat menyusun argumen mapping
saat bepergian !!!
. Ini sangat bagus jika Anda perlu mendaur ulang estetika sesekali.
my_mapping <- aes( x = foo , y = bar )
aes( colour = qux , !!! my_mapping )
# > Aesthetic mapping:
# > * `x` -> `foo`
# > * `y` -> `bar`
# > * `colour` -> `qux`
Penggunaan favorit pribadi saya dari ini adalah membuat warna fill
cocok dengan warna colour
, tetapi sedikit lebih terang 2 . Kami akan menggunakan sistem evaluasi yang tertunda untuk ini, after_scale()
dalam hal ini, yang akan Anda lihat lebih banyak di bagian yang mengikuti ini. Saya akan mengulangi trik ini beberapa kali di seluruh dokumen ini.
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 )
Anda mungkin menemukan diri Anda dalam situasi di mana Anda diminta untuk membuat peta panas dari sejumlah kecil variabel. Biasanya, skala berurutan berjalan dari terang ke gelap atau sebaliknya, yang membuat teks dalam satu warna sulit dibaca. Kami dapat menyusun metode untuk secara otomatis menulis teks dalam warna putih dengan latar belakang gelap, dan hitam dengan latar belakang terang. Fungsi di bawah ini mempertimbangkan nilai cahaya untuk suatu warna, dan mengembalikan hitam atau putih tergantung pada cahaya itu.
contrast <- function ( colour ) {
out <- rep( " black " , length( colour ))
light <- farver :: get_channel( colour , " l " , space = " hcl " )
out [ light < 50 ] <- " white "
out
}
Sekarang, kita dapat membuat estetika untuk disambungkan ke dalam argumen mapping
lapisan atas permintaan.
autocontrast <- aes( colour = after_scale(contrast( fill )))
Terakhir, kita dapat menguji alat kontras otomatis kita. Anda mungkin memperhatikan bahwa itu beradaptasi dengan skala, jadi Anda tidak perlu melakukan banyak pemformatan bersyarat untuk ini.
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 )
Ada beberapa ekstensi yang menawarkan versi setengah geom. Dari orang-orang yang saya tahu, gghalves dan paket See menawarkan beberapa setengah geom.
Berikut adalah cara menyalahgunakan sistem evaluasi yang tertunda untuk membuatnya sendiri. Ini bisa berguna jika Anda tidak mau mengambil ketergantungan tambahan hanya untuk fitur ini.
Kasing mudahnya adalah plot kotak. Anda dapat mengatur xmin
atau xmax
ke after_scale(x)
untuk menjaga bagian kanan dan kiri boxplot masing -masing. Ini masih berfungsi dengan baik dengan 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 )))
Hal yang sama yang berfungsi untuk boxplot, juga berfungsi untuk ERRORBARS.
p + geom_errorbar(
stat = " summary " ,
fun.data = mean_se ,
aes( xmin = after_scale( x ))
)
Kami sekali lagi dapat melakukan hal yang sama untuk plot biola, tetapi lapisan itu mengeluh tentang tidak mengetahui tentang estetika xmin
. Itu memang menggunakan estetika itu, tetapi hanya setelah data telah diatur, sehingga tidak dimaksudkan untuk menjadi estetika yang dapat diakses pengguna. Kita dapat membungkam peringatan dengan memperbarui default xmin
ke NULL
, yang berarti tidak akan mengeluh, tetapi juga tidak menggunakannya jika tidak ada.
update_geom_defaults( " violin " , list ( xmin = NULL ))
p + geom_violin(aes( xmin = after_scale( x )))
Tidak ditinggalkan sebagai latihan untuk pembaca kali ini, tetapi saya hanya ingin menunjukkan bagaimana itu akan bekerja jika Anda menggabungkan dua bagian dan menginginkannya sedikit diimbangi satu sama lain. Kami akan menyalahgunakan ERRORBARS untuk berfungsi sebagai bahan pokok untuk plot kotak.
# 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 )
Katakanlah Anda memiliki intuisi warna yang lebih baik daripada yang saya miliki, dan tiga warna tidak cukup untuk kebutuhan palet warna yang berbeda. Titik pertama adalah sulit untuk mendapatkan titik tengah yang tepat jika batas Anda tidak berpusat dengan sempurna di sekitarnya. Masukkan argumen rescaler
di liga dengan 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 )
)
Alternatifnya adalah dengan memusatkan batas pada x. Kita dapat melakukannya dengan memberikan fungsi pada batas skala.
p +
scale_colour_gradientn(
colours = my_palette ,
limits = ~ c( - 1 , 1 ) * max(abs( .x ))
)
Anda dapat memberi label poin dengan geom_text()
, tetapi masalah potensial adalah bahwa teks dan poin tumpang tindih.
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()
Ada beberapa solusi khas untuk masalah ini, dan semuanya datang dengan kekurangan:
nudge_x
dan nudge_y
. Masalahnya di sini adalah bahwa ini didefinisikan dalam unit data, sehingga jarak tidak dapat diprediksi, dan tidak ada cara untuk memiliki ini bergantung pada lokasi asli.hjust
dan vjust
. Ini memungkinkan Anda untuk bergantung pada lokasi asli, tetapi ini tidak memiliki offset alami.Berikut adalah opsi 2 dan 3 dalam tindakan:
q + geom_text( nudge_x = 1 , nudge_y = 1 )
q + geom_text(aes(
hjust = Murder > mean( Murder ),
vjust = Rape > mean( Rape )
))
Anda mungkin berpikir: 'Saya bisa melipatgandakan pembenaran untuk mendapatkan offset yang lebih luas', dan Anda akan benar. Namun, karena pembenaran tergantung pada ukuran teks yang mungkin Anda dapatkan dari offset yang tidak setara. Perhatikan di plot di bawah ini bahwa 'Dakota Utara' diimbangi terlalu mengunyah di arah Y dan 'Rhode Island' di arah 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
))
Yang bagus dari geom_label()
adalah Anda dapat mematikan kotak label dan menyimpan teks. Dengan begitu, Anda dapat terus menggunakan hal-hal bermanfaat lainnya, seperti pengaturan label.padding
, untuk memberikan offset absolut (independen data) dari teks ke label.
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
)
Ini dulunya adalah tip tentang meletakkan tag segi di panel, yang dulunya rumit. Dengan GGPlot2 3.5.0, Anda tidak perlu lagi mengutak -atik posisi yang tak terbatas dan mengubah parameter hjust
atau vjust
. Anda sekarang hanya dapat menggunakan x = I(0.95), y = I(0.95)
untuk menempatkan teks di sudut kanan atas. Buka detailnya untuk melihat tip lama.
Menempatkan anotasi teks pada plot facetted adalah rasa sakit, karena batas dapat bervariasi berdasarkan per-panel, sehingga sangat sulit untuk menemukan posisi yang benar. Ekstensi yang mengeksplorasi mengurangi rasa sakit ini adalah ekstensi tagger, tetapi kita dapat melakukan hal serupa di vanilla ggplot2.
Untungnya, ada mekanik dalam sumbu posisi GGPLOT2 yang memungkinkan -Inf
dan Inf
ditafsirkan sebagai batas minimum dan maksimum skala masing -masing 3 . Anda dapat mengeksploitasi ini dengan memilih x = Inf, y = Inf
untuk menempatkan label di sudut. Anda juga dapat menggunakan -Inf
alih -alih Inf
untuk menempatkan di bagian bawah, bukan atas, atau kiri, bukan kanan.
Kita perlu mencocokkan argumen hjust
/ vjust
dengan sisi plot. Untuk x/y = Inf
, mereka harus hjust/vjust = 1
, dan untuk x/y = -Inf
mereka harus 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 "
)
Sayangnya, ini menempatkan teks lurus di perbatasan panel, yang mungkin menyinggung perasaan kecantikan kita. Kita bisa mendapatkan sedikit lebih baik dengan menggunakan geom_label()
, yang memungkinkan kita lebih tepat mengontrol jarak antara teks dan perbatasan panel dengan mengatur label.padding
argumen.
Selain itu, kita dapat menggunakan label.size = NA, fill = NA
untuk menyembunyikan bagian kotak teks geom. Untuk tujuan ilustrasi, kami sekarang menempatkan tag di kiri atas alih-alih kanan atas.
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 "
)
Katakanlah kami ditugaskan untuk membuat banyak plot serupa, dengan dataset dan kolom yang berbeda. Misalnya, kami mungkin ingin membuat serangkaian barplot 4 dengan beberapa pre-set spesifik: kami ingin batang menyentuh sumbu x dan tidak menggambar garis kisi vertikal.
Salah satu cara terkenal untuk membuat banyak plot serupa adalah dengan membungkus konstruksi plot menjadi suatu fungsi. Dengan begitu, Anda dapat menggunakan Encode semua preset yang Anda inginkan dalam fungsi Anda.
Saya mungkin tidak tahu, ada berbagai metode untuk diprogram dengan fungsi aes()
, dan menggunakan {{ }}
(Curly-Curly) adalah salah satu cara yang lebih fleksibel 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 )
Salah satu kelemahan dari pendekatan ini adalah Anda mengunci estetika apa pun dalam argumen fungsi. Berkeliling di sekitar ini, cara yang lebih sederhana adalah dengan hanya lulus ...
langsung ke 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 )
Metode lain untuk melakukan hal yang sangat mirip, adalah menggunakan plot 'kerangka'. Gagasan di balik kerangka adalah Anda dapat membangun plot, dengan atau tanpa argumen data
, dan menambahkan spesifik nanti. Kemudian, ketika Anda benar -benar ingin membuat plot, Anda dapat menggunakan %+%
untuk mengisi atau mengganti dataset, dan + aes(...)
untuk mengatur estetika yang relevan.
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
Satu hal yang rapi tentang kerangka ini adalah bahwa bahkan ketika Anda sudah mengisi data
dan mapping
argumen, Anda bisa menggantinya lagi dan lagi.
my_plot % + % mtcars +
aes( factor ( carb ), colour = factor ( cyl ), !!! my_fill )
Idenya di sini adalah untuk tidak kerangka seluruh plot, tetapi hanya serangkaian bagian yang sering digunakan kembali. Misalnya, kami mungkin ingin memberi label barplot kami, dan mengemas semua hal yang membentuk barplot berlabel. Trik untuk ini adalah untuk tidak menambahkan komponen -komponen ini bersama -sama dengan +
, tetapi cukup masukkan ke dalam list()
. Anda kemudian dapat +
daftar Anda bersama dengan panggilan plot utama.
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)
#>
#>
#> ──────────────────────────────────────────────────────────────────────────────
Nah, Anda perlu melakukannya sekali di awal dokumen Anda. Tapi kemudian tidak pernah lagi! Kecuali dalam dokumen Anda berikutnya. Cukup tulis skrip dan sumber plot_defaults.R
source()
yang dari dokumen Anda. Salin-paste skrip itu untuk setiap proyek. Kemudian, sungguh, tidak pernah lagi: hati:. ↩
Ini bohong. Pada kenyataannya, saya menggunakan aes(colour = after_scale(colorspace::darken(fill, 0.3)))
alih -alih meringankan isi. Saya tidak ingin readme ini memiliki ketergantungan pada {ColorsPace}. ↩
Kecuali jika Anda menaburkan plot Anda dengan mengatur oob = scales::oob_censor_any
dalam skala misalnya. ↩
Dalam jiwa Anda, apakah Anda benar -benar ingin membuat banyak barplot? ↩
Alternatifnya adalah menggunakan kata ganti .data
, yang dapat .data$var
jika Anda ingin mengunci kolom itu terlebih dahulu, atau .data[[var]]
ketika var
dilewatkan sebagai karakter. ↩
Bit ini awalnya disebut 'kerangka parsial', tetapi karena tulang rusuk adalah bagian dari kerangka, judul ini terdengar lebih menggugah. ↩