user1701545
user1701545

Reputation: 6220

R scatter pie plots with pattern in slices

This is a followup question to this post.

I have an R data.frame where each row describes a composition that I want to plot as a pie on an xy plane. I want to color-code the slices of each pie by their y.a_1, y.a_2, y.a_3, y.a_4, y.b_1, y.b_2, y.b_3, y.b_4, o.a_1, o.a_3, o.a_4, o.b_1, o.b_3, o.b_4, in the example df below. The class column used in this post is not included in df at this point because it is not a pie-specific property but rather a property of the slices, and is created below.

Here's the df:

library(dplyr)
set.seed(1)
df <- data.frame(x = runif(10, 0, 100), y = runif(10, 0, 100), id = paste0("id",1:10),
                 y.a_1 = as.integer(runif(10, 0, 100)), y.a_2 = as.integer(runif(10, 0, 100)), y.a_3 = as.integer(runif(10, 0, 100)), y.a_4 = as.integer(runif(10, 0, 100)),
                 y.b_1 = as.integer(runif(10, 0, 100)), y.b_2 = as.integer(runif(10, 0, 100)), y.b_3 = as.integer(runif(10, 0, 100)), y.b_4 = as.integer(runif(10, 0, 100)),
                 o.a_1 = as.integer(runif(10, 0, 100)), o.a_3 = as.integer(runif(10, 0, 100)), o.a_4 = as.integer(runif(10, 0, 100)),
                 o.b_1 = as.integer(runif(10, 0, 100)), o.b_3 = as.integer(runif(10, 0, 100)), o.b_4 = as.integer(runif(10, 0, 100))) %>%
  dplyr::mutate(size = runif(10,0.002,0.01)*(y.a_1 + y.a_2 + y.a_3 + y.a_4 + y.b_1 + y.b_2 + y.b_3 + y.b_4 + o.a_1 + o.a_3 + o.a_4 + o.b_1 + o.b_3 + o.b_4))

Following Allan Cameron's solution I define this function for creating pie polygons:

make_pie <- function(x, y, size, groups, n, 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, rownum = rownum)
  }, head(angles, -1), tail(angles, -1), groups))
}

Again, class is not included in this function because it was not part of df.

However, I add a class column to the data.frame created by running df through the make_pie function:

df <- df %>%
  mutate(r = row_number()) %>%
  rowwise() %>%
  group_map(~ with(.x, make_pie(x, y,
                                size, c("y.a_1", "y.a_2", "y.a_3", "y.a_4", "y.b_1", "y.b_2", "y.b_3", "y.b_4", "o.a_1", "o.a_3", "o.a_4", "o.b_1", "o.b_3", "o.b_4"),
                                c(y.a_1, y.a_2, y.a_3, y.a_4, y.b_1, y.b_2, y.b_3, y.b_4, o.a_1, o.a_3, o.a_4, o.b_1, o.b_3, o.b_4), r))) %>%
  bind_rows() %>%
  mutate(class = gsub("\\.a","",group) %>% gsub("\\.b","",.)) %>% unique()
df$group <- factor(df$group, levels = c("y.a_1", "y.a_2", "y.a_3", "y.a_4", "y.b_1", "y.b_2", "y.b_3", "y.b_4", "o.a_1", "o.a_3", "o.a_4", "o.b_1", "o.b_3", "o.b_4"))
df$class <- factor(df$class, levels = c("y_1", "y_2", "y_3", "y_4", "o_1", "o_3", "o_4"))

Then I use this ggplot2 and ggpattern function:

library(ggplot2)
library(ggpattern)

ggplot(df,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("#FFEFDE", "#FFBFB1", "#FF8F84", "#FF5550", "#B6EDFF", "#98D6F3", "#7CC0E1", "#5BA7CD",
                               "#D11110", "#AA0003", "#70000A", "#2B7196", "#1A5B81", "#0F4769")) +
  guides(pattern = guide_legend(override.aes = list(fill = "white"))) +
  coord_equal() +
  theme_void()

Which gives: enter image description here

It's close to what I want but I'm trying to figure out how to solve these issues:

  1. How do I get 7 different patterns (the number of unique classes I have) instead of the 3 it is currently giving?
  2. How do I remove the patterns from the group legend bar?
  3. How do I specify the pattern line color to black for the y_1, y_2, y_3, y_4 classes and white for the o_1, o_3, and o_4 classes?

Upvotes: 0

Views: 137

Answers (0)

Related Questions