The following code works fine and produces the required graph as given below:
library(tidyverse)
library(ggiraphExtra)
library(moonBook)
ggPieDonut(data = acs, mapping = aes(pies = Dx, donuts = smoking), interactive = TRUE)
Wondering how to construct Pie Donut chart with facet functionality. My attempt is below:
ggPieDonut(data = acs, mapping = aes(pies = Dx, donuts = smoking), interactive = TRUE) +
facet_wrap(facets = vars(sex))
NULL
The code in your attempt doesn't work because when interactive = TRUE
, ggPieDonut()
doesn't return a ggplot, but a htmlwidget:
ggPieDonut(
data = acs,
mapping = aes(pies = Dx, donuts = smoking),
interactive = TRUE
) %>% class()
#> [1] "girafe" "htmlwidget"
And facet_wrap()
only works with ggplots.
If you change to interactive = FALSE
you get another problem:
ggPieDonut(
data = acs,
mapping = aes(pies = Dx, donuts = smoking),
interactive = FALSE
) +
facet_wrap(~sex)
#> Error in `combine_vars()`:
#> ! At least one layer must contain all faceting variables: `sex`.
The geoms doesn't contain both values of sex
, so facet_wrap()
doesn't know how to facet on it.
A solution is to create two plots on different subsets of the data, and use patchwork
to combine the two plots:
library(patchwork)
p1 <-
acs %>%
filter(sex == "Male") %>%
ggPieDonut(mapping = aes(pies = Dx, donuts = smoking), interactive = FALSE) +
labs(title = "Male")
p2 <-
acs %>%
filter(sex == "Female") %>%
ggPieDonut(mapping = aes(pies = Dx, donuts = smoking), interactive = FALSE) +
labs(title = "Female")
p1 + p2
Output:
As @MikkoMarttila suggested, it might be better to create this as a function. If I were to reuse the function, I would probably write it like this:
make_faceted_plot <- function(data, pie, donut, facet_by) {
data %>%
dplyr::pull( {{facet_by}} ) %>%
unique() %>%
purrr::map(
~ data %>%
dplyr::filter( {{facet_by}} == .x) %>%
ggiraphExtra::ggPieDonut(
ggplot2::aes(pies = {{pie}}, donuts = {{donut}}),
interactive = FALSE
) +
ggplot2::labs(title = .x)
) %>%
patchwork::wrap_plots()
}
This can then be used to facet on however many categories we want, and on any dataset, for example:
library(patchwork)
library(dplyr)
# Expandable example data
df <- data.frame(
eyes = sample(c("Blue", "Bown", "Green"), size = 100, replace = TRUE),
hair = sample(c("blonde", "brunette", "raven"), size = 100, replace = TRUE),
sex = sample(c("male", "female"), size = 100, replace = TRUE)
)
df %>%
make_faceted_plot(
pie = eyes,
donut = sex,
facet_by = hair
)
Again, as suggested by @MikkoMarttila, this can be piped into ggiraph::girafe(code = print(.))
to add some interactivity.
The OP wants the labels to be the same in the static and interactive plots.
The labels for both the static and interactive plots are stored inside <the plot object>$plot_env
. From here it's just a matter of looking around, and replacing the static labels with the interactive ones. Since the interactive labels contains HTML-tags, we do some cleaning first. I would wrap this in a function, as such:
change_label <- function(plot) {
plot$plot_env$Pielabel <-
plot$plot_env$data2$label %>%
stringr::str_replace_all("<br>", "\n") %>%
stringr::str_replace("\\(", " \\(")
plot$plot_env$label2 <-
plot$plot_env$dat1$label %>%
stringr::str_replace_all("<br>", "\n") %>%
stringr::str_replace("\\(", " \\(") %>%
stringr::str_remove("(NSTEMI\\n|STEMI\\n|Unstable Angina\n)")
plot
}
By adding this function to make_plot()
we get the labels we want:
make_faceted_plot <- function(data, pie, donut, facet_by) {
data %>%
dplyr::pull( {{facet_by}} ) %>%
unique() %>%
purrr::map(
~ data %>%
dplyr::filter( {{facet_by}} == .x) %>%
ggiraphExtra::ggPieDonut(
ggplot2::aes(pies = {{pie}}, donuts = {{donut}}),
interactive = FALSE
) +
ggplot2::labs(title = .x)
) %>%
purrr::map(change_label) %>% # <-- added change_label() here
patchwork::wrap_plots()
}
acs %>%
make_faceted_plot(
pie = Dx,
donut = smoking,
facet_by = sex
)