I'm using the R
scatterpie
package for plotting pie charts on an xy plane. Each one of the pies/groups also has a class
assignment which I would also like to convey in the plot and was thinking of using patterns for that.
Here's the example data.frame
:
library(ggplot2)
library(ggpattern)
library(scatterpie)
library(dplyr)
set.seed(1)
df <- data.frame(x = runif(50, 0, 100), y = runif(50, 0, 100), id = paste0("id",1:50),
g1 = as.integer(runif(50, 0, 100)), g2 = as.integer(runif(50, 0, 100)), g3 = as.integer(runif(50, 0, 100)),
class = sample(c("c1", "c2"), 50, replace = T)) %>%
dplyr::mutate(size = 0.02*(g1 + g2 + g3))
df$class <- factor(df$class)
Here's the code I tried with the ggpattern
package:
ggplot() + geom_scatterpie(data = df, aes(x = x, y = y, group = id, r = size),cols = paste0("g",1:3),color = "black", alpha = 0.8, size = 0.1) +
scale_fill_manual(values=c("#FFC9F8", "#ee9e77", "#895A44")) +
geom_col_pattern(aes(pattern_fill = class))+
xlim(-10,110) + ylim(-10,110) + coord_equal() + theme_void()
Which gives the error:
Don't know how to automatically pick scale for object of type function. Defaulting to continuous.
Error in `f()`:
! Aesthetics must be valid data columns. Problematic aesthetic(s): pattern_fill = class.
Did you mistype the name of a data column or forget to add after_stat()?
I tried playing around with the pattern
part of the command but with no success.
Currently, the only way I am able to encode the class
of each pie is with the linetype
aesthetics argument:
ggplot() + geom_scatterpie(data = df, aes(x = x, y = y, group = id, r = size, linetype = class),cols = paste0("g",1:3), color = "black", size = 1) +
scale_fill_manual(values=c("#FFC9F8", "#ee9e77", "#895A44")) +
xlim(-10,110) + ylim(-10,110) + coord_equal() + theme_void()
But it's not ideal.
Any idea how to make this work or alternative ways to encode class
?
I'm not convinced about the visualization, though it is possible via ggplot and ggpattern. I don't think you can use geom_scatterpie
, which, as Axeman points out, doesn't really work the way other ggplot geoms do.
If I had to do this, I would probably just make my own pie function and draw the result with geom_polygon_pattern
.
You could do that with the following helper function:
make_pie <- function(x, y, size, groups, n, class, rownum) {
angles <- c(0, 2*pi * cumsum(n)/sum(n))
do.call("rbind", Map(function(a1, a2, g) {
xvals <- c(0, sin(seq(a1, a2, len = 30)) * size, 0) + x
yvals <- c(0, cos(seq(a1, a2, len = 30)) * size, 0) + y
data.frame(x = xvals, y = yvals, group = g, class = class, rownum = rownum)
}, head(angles, -1), tail(angles, -1), groups))
}
You can then plot using your data as follows:
df %>%
mutate(r = row_number()) %>%
rowwise() %>%
group_map(~ with(.x, make_pie(x, y, size, c("g1", "g2", "g3"),
c(g1, g2, g3), class, r))) %>%
bind_rows() %>%
ggplot(aes(x, y, fill = group, group = interaction(group, rownum))) +
geom_polygon_pattern(aes(pattern = class), pattern_fill = "black",
pattern_angle = 45, pattern_spacing = 0.01,
pattern_density = 0.1) +
scale_fill_manual(values = c("#FFC9F8", "#ee9e77", "#895A44")) +
guides(pattern = guide_legend(override.aes = list(fill = "white"))) +
coord_equal() +
theme_void()
You could map the alpha channel as Axeman suggests like this:
df %>%
mutate(r = row_number()) %>%
rowwise() %>%
group_map(~ with(.x, make_pie(x, y, size, c("g1", "g2", "g3"),
c(g1, g2, g3), class, r))) %>%
bind_rows() %>%
ggplot(aes(x, y, fill = class, group = interaction(group, rownum),
alpha = group)) +
geom_polygon() +
scale_fill_manual(values = c("red4", "green4")) +
scale_alpha_manual(values = c(0.3, 0.7, 1)) +
coord_equal() +
theme_void()
Or just declare each fill color individually:
df %>%
mutate(r = row_number()) %>%
rowwise() %>%
group_map(~ with(.x, make_pie(x, y, size, c("g1", "g2", "g3"),
c(g1, g2, g3), class, r))) %>%
bind_rows() %>%
mutate(fill_class = paste0(group, " (class ", class, ")")) %>%
mutate(fill_class = factor(fill_class, unique(fill_class))) %>%
ggplot(aes(x, y, fill = fill_class, group = interaction(group, rownum))) +
geom_polygon() +
scale_fill_manual("Group (class)",
values = c("red3", "hotpink", "red",
"navy", "blue", "dodgerblue")) +
coord_equal() +
theme_void()