I will show you some options to make side-by-side ggplots in R. While there are many options t=out there, I will cover only three:
patchwork
, which allows combination of two or more ggplots using a natural syntax of +
(similar output as gridExtra::grid.arrange
)ggiraph
, which leverages patchwork
’s syntax to make interactive ggplots!plotly
, which converts ggplots into interactive plotly-plots before combining everything into subplots.A more advanced example using clustering is here!
I wish to demonstrate a rather annoying behaviour of ggplotly
in the plotly
package.
One of the most powerful function in plotly
is the ggplotly
function. For a ggplot2
-addict like myself it takes a static ggplot and makes it interative.
However, this function has an undesirable legend when trying to produce a side-by-side plot. I found that the work around of this to be a bit harder than I would like. One way around this is to use the patchwork
+ ggiraph
framework.
Just so you know that I know:
mtcars
data is overused, but hey! It is only a quick coding demo!library(tidyverse)
library(ggiraph)
library(patchwork)
library(plotly)
mtcars
dataThe code below will make variables with less than 6 unique values to be factor variables. This is because variables like cyl
should be visualised as factors.
## We will make the mtcars data into a tibble and convert the rownames into a column of id
dat = mtcars %>%
tibble::rownames_to_column("id") %>%
as_tibble()
## Computing the number of unique values in each column
## We will make columns with less or equal to 6 unique values to be factors
num_unique = function(x){x %>% unique %>% length}
(vars_unique = dat %>% apply(2, num_unique))
## id mpg cyl disp hp drat wt qsec vs am gear carb
## 32 25 3 27 22 22 29 30 2 2 3 6
(fct_cols = names(vars_unique)[vars_unique <= 6])
## [1] "cyl" "vs" "am" "gear" "carb"
## Mutating the columns based on the previous calculation
dat = dat %>%
as_tibble() %>%
mutate_at(.vars = fct_cols,
.funs = as.factor)
dat
## # A tibble: 32 x 12
## id mpg cyl disp hp drat wt qsec vs am gear carb
## <chr> <dbl> <fct> <dbl> <dbl> <dbl> <dbl> <dbl> <fct> <fct> <fct> <fct>
## 1 Mazda RX4 21 6 160 110 3.9 2.62 16.5 0 1 4 4
## 2 Mazda RX4 … 21 6 160 110 3.9 2.88 17.0 0 1 4 4
## 3 Datsun 710 22.8 4 108 93 3.85 2.32 18.6 1 1 4 1
## 4 Hornet 4 D… 21.4 6 258 110 3.08 3.22 19.4 1 0 3 1
## 5 Hornet Spo… 18.7 8 360 175 3.15 3.44 17.0 0 0 3 2
## 6 Valiant 18.1 6 225 105 2.76 3.46 20.2 1 0 3 1
## 7 Duster 360 14.3 8 360 245 3.21 3.57 15.8 0 0 3 4
## 8 Merc 240D 24.4 4 147. 62 3.69 3.19 20 1 0 4 2
## 9 Merc 230 22.8 4 141. 95 3.92 3.15 22.9 1 0 4 2
## 10 Merc 280 19.2 6 168. 123 3.92 3.44 18.3 1 0 4 4
## # … with 22 more rows
These are standard ggplots.
g1 = dat %>%
ggplot(aes(x = mpg, y = disp,
colour = cyl,
shape = vs,
data_id = id,
tooltip = id)) +
geom_point_interactive(size = 4) +
labs(x = "Miles per gallon",
y = "Displacement")
g1
g2 = dat %>%
ggplot(aes(x = mpg, y = drat,
colour = cyl,
shape = vs,
data_id = id,
tooltip = id)) +
geom_point_interactive(size = 4) +
labs(x = "Miles per gallon",
y = "Rear axle ratio")
g2
patchwork
After some wait, patchwork
is finally on CRAN! It’s great advantage is putting together p1
and p2
using the familiar ggplot2
syntax of +
.
So so excited 🎉🎉🎉 patchwork is now on CRAN https://t.co/3kieCQxoJb
— Thomas Lin Pedersen (@thomasp85) December 1, 2019
g1 + g2
Note: even though we designed these two plots as interactive plots, they will not become interactive until we put a small wrapper around it, which we will see later.
ggiraph
The main function we will use is geom_point_interactive
from the ggiraph
package. It behaves just like geom_point
, but with two additional aesthetics. The data_id
aesthetic is critical to link observations between plots and the tooltip
aesthetic is optional but nice to have when mouse over a point. After making these plots, the girafe
function using the same syntax in patchwork
will allow us to make a pretty interactive plot!
Since I am writing in a RMarkdown file, I will also specify the height and width of my output using optional parameters.
girafe(code = print(g1 + g2), width_svg = 12, height_svg = 4)
plotly
In the code below, g3
and g4
are identical to g1
and g2
respectively, except that geom_point
was used. The ggplotly
function will convert the two plots into plotly interactive plots and the subplot
will combine the two plots into one singular plot.
g3 = dat %>%
ggplot(aes(x = mpg, y = disp,
colour = cyl,
shape = vs,
data_id = id,
tooltip = id)) +
geom_point(size = 4) +
labs(x = "Miles per gallon",
y = "Displacement")
g4 = dat %>%
ggplot(aes(x = mpg, y = drat,
colour = cyl,
shape = vs,
data_id = id,
tooltip = id)) +
geom_point(size = 4) +
labs(x = "Miles per gallon",
y = "Rear axle ratio")
subplot(ggplotly(g3),
ggplotly(g4))
Look at the colour and shape legend being repeated. This is the main reason that I don’t prefer ggplotly
for this type of task. But don’t get me wrong! I still use ggplotly
in my everyday work, but just not this task.
sessionInfo()
## R version 3.6.1 (2019-07-05)
## Platform: x86_64-apple-darwin15.6.0 (64-bit)
## Running under: macOS Mojave 10.14.6
##
## Matrix products: default
## BLAS: /Library/Frameworks/R.framework/Versions/3.6/Resources/lib/libRblas.0.dylib
## LAPACK: /Library/Frameworks/R.framework/Versions/3.6/Resources/lib/libRlapack.dylib
##
## locale:
## [1] en_AU.UTF-8/en_AU.UTF-8/en_AU.UTF-8/C/en_AU.UTF-8/en_AU.UTF-8
##
## attached base packages:
## [1] stats graphics grDevices utils datasets methods base
##
## other attached packages:
## [1] gdtools_0.2.1 plotly_4.9.1 patchwork_1.0.0 ggiraph_0.7.0
## [5] forcats_0.4.0 stringr_1.4.0 dplyr_0.8.3 purrr_0.3.3
## [9] readr_1.3.1 tidyr_1.0.0 tibble_2.1.3 ggplot2_3.2.1
## [13] tidyverse_1.3.0
##
## loaded via a namespace (and not attached):
## [1] Rcpp_1.0.3 lubridate_1.7.4 lattice_0.20-38 assertthat_0.2.1
## [5] zeallot_0.1.0 digest_0.6.23 utf8_1.1.4 mime_0.7
## [9] R6_2.4.1 cellranger_1.1.0 backports_1.1.5 reprex_0.3.0
## [13] evaluate_0.14 httr_1.4.1 pillar_1.4.2 rlang_0.4.2
## [17] lazyeval_0.2.2 readxl_1.3.1 uuid_0.1-2 rstudioapi_0.10
## [21] data.table_1.12.6 rmarkdown_1.18 labeling_0.3 htmlwidgets_1.5.1
## [25] munsell_0.5.0 shiny_1.4.0 broom_0.5.2 httpuv_1.5.2
## [29] compiler_3.6.1 modelr_0.1.5 xfun_0.11 pkgconfig_2.0.3
## [33] systemfonts_0.1.1 base64enc_0.1-3 htmltools_0.4.0 tidyselect_0.2.5
## [37] fansi_0.4.0 viridisLite_0.3.0 later_1.0.0 crayon_1.3.4
## [41] dbplyr_1.4.2 withr_2.1.2 grid_3.6.1 xtable_1.8-4
## [45] nlme_3.1-142 jsonlite_1.6 gtable_0.3.0 lifecycle_0.1.0
## [49] DBI_1.0.0 magrittr_1.5 scales_1.1.0 cli_1.1.0
## [53] stringi_1.4.3 farver_2.0.1 promises_1.1.0 fs_1.3.1
## [57] xml2_1.2.2 generics_0.0.2 vctrs_0.2.0 Cairo_1.5-10
## [61] tools_3.6.1 glue_1.3.1 crosstalk_1.0.0 hms_0.5.2
## [65] fastmap_1.0.1 yaml_2.2.0 colorspace_1.4-1 rvest_0.3.5
## [69] knitr_1.26 haven_2.2.0