Using patterns instead of colours in mosaic plot with `ggmosaic` in `R`

75 Views Asked by At

Following THIS POST I was wondering if ggmosaic allows use of patterns rather than colours, maybe with ggpatterns?

From that previous post, the example dataset is:

dat = data.frame(
    Correct=c('no','yes','no','yes','no','yes','no','yes',
        'no','yes','no','yes','no','yes','no','yes'),
    Type=c('A','A','B','B','A','A','B','B',
        'A','A','B','B','A','A','B','B'),
    Level=c('1st','1st','1st','1st','2nd','2nd','2nd','2nd',
        '1st','1st','1st','1st','2nd','2nd','2nd','2nd'),
    Class=c('X','X','X','X','X','X','X','X',
        'Y','Y','Y','Y','Y','Y','Y','Y'),
    Percent=c(69.98,30.02,71.17,28.83,42.17,57.83,69.47,30.53,
        18.68,81.32,26.92,73.08,13.48,86.52,22.65,77.35)
)

Then, combine the original code with that from stefan:


library(ggmosaic)

mosaic1 <- ggplot(data=dat) +
    geom_mosaic(aes(weight=Percent, 
        x=product(Type, Level),
        conds=product(Class),
        fill=Correct)) +
    scale_y_productlist(breaks=c(.25,.75), labels=c('1st','2nd'),
        expand = c(0, 0.01)) +
  scale_x_productlist(expand=c(0,0.01)) +
    ggtitle('TITLE') +
    theme_tufte(base_family='sans') +
    theme(axis.text.x=element_text(angle=45, hjust=1, vjust=1, size=10),
        axis.title=element_text(size=11),
        legend.text=element_text(size=10),
        legend.title=element_text(size=11))
mosaic1

How can one replace colours with patterns, e.g., using ggpattern?

2

There are 2 best solutions below

2
On BEST ANSWER

Another option would be to use the new features introduced with ggplot2 3.5.0 (and R >= 4.2.0) which bring native support of patterns to ggplot2. There is still some room for a more user-friendly API to specify patterns, i.e. as of the moment we have to specify the patterns from scratch using grobs, but it works well with the default geoms and scales, and also with ggmosaic.

library(ggplot2)
library(ggmosaic)
library(ggthemes)
library(grid)

packageVersion("ggplot2")
#> [1] '3.5.0'
packageVersion("ggmosaic")
#> [1] '0.3.4'

patterns <- list(
  pattern(
    rectGrob(x = c(0, 1), y = c(0.25, 0.75), width = 1, height = 0.5),
    height = unit(5, "mm"), 
    extend = "repeat",
    gp = gpar(fill = "#b2182b")
  ),
  pattern(
    rectGrob(x = c(0.25, 0.75), y = c(0.25, 0.75), width = 0.5, height = 0.5),
    width = unit(5, "mm"), height = unit(5, "mm"), extend = "repeat",
    gp = gpar(fill = "#1b7837")
  )
)

ggplot(data = dat) +
  geom_mosaic(aes(
    weight = Percent,
    x = product(Type, Level),
    conds = product(Class),
    fill = Correct
  ), color = "grey40") +
  scale_fill_manual(
    values = patterns
  ) +
  scale_y_productlist(
    breaks = c(.25, .75), 
    labels = c("1st", "2nd"),
    expand = c(0, 0.01)
  ) +
  scale_x_productlist(expand = c(0, 0.01)) +
  ggtitle("TITLE") +
  theme_tufte(base_family = "sans") +
  theme(
    axis.text.x = element_text(
      angle = 45, hjust = 1,
      vjust = 1, size = 10
    ),
    axis.title = element_text(size = 11),
    legend.text = element_text(size = 10),
    legend.title = element_text(size = 11)
  )

UPDATE Using linesGrob for the patterns we could get vertical and horizontal lines using this specification for the patterns:

patterns <- list(
  pattern(
    linesGrob(
      x = c(0, 1), y = c(0.5, 0.5)
    ),
    height = unit(3, "mm"),
    extend = "repeat",
    gp = gpar(col = "#b2182b", lwd = unit(5, "mm"), fill = NA)
  ),
  pattern(
    linesGrob(
      x = c(0.5, 0.5), y = c(0, 1)
    ),
    width = unit(3, "mm"),
    extend = "repeat",
    gp = gpar(col = "#1b7837", lwd = unit(5, "mm"), fill = NA)
  )
)

enter image description here

0
On

It seems geom_mosiac_pattern() is not an option, so here is a workaround. I've included a comprehensive (but not exhaustive) amount of pattern variables for you to adapt at your leisure.

library(dplyr)
library(ggplot2)
library(ggpattern)

dat <- data.frame(
  Correct=c('no','yes','no','yes','no','yes','no','yes',
            'no','yes','no','yes','no','yes','no','yes'),
  Type=c('A','A','B','B','A','A','B','B',
         'A','A','B','B','A','A','B','B'),
  Level=c('1st','1st','1st','1st','2nd','2nd','2nd','2nd',
          '1st','1st','1st','1st','2nd','2nd','2nd','2nd'),
  Class=c('X','X','X','X','X','X','X','X',
          'Y','Y','Y','Y','Y','Y','Y','Y'),
  Percent=c(69.98,30.02,71.17,28.83,42.17,57.83,69.47,30.53,
            18.68,81.32,26.92,73.08,13.48,86.52,22.65,77.35))

dat <- dat %>%
  mutate(xlabels = factor(paste0(Type, ":", Class), 
                          levels = c("A:X", "B:X", "A:Y", "B:Y")),
         Level = factor(Level, levels = c("2nd", "1st")))

ggplot(data = dat) +
  geom_col_pattern(aes(x = xlabels, y = Percent, pattern = Correct, group = Level),
                   colour = "black",
                   width = 1,
                   fill = NA,
                   pattern_density = 0.5,
                   pattern_spacing = .03,
                   pattern_fill = NA,
                   pattern_colour = "grey50",
                   pattern_key_scale_factor = 0.6,
                   inherit.aes = FALSE) +
  scale_pattern_manual(values = c("stripe", "crosshatch")) +
  scale_x_discrete(expand = c(0,0)) +
  scale_y_continuous(breaks = c(50, 150),
                     labels = c("1st", "2nd"),
                     expand = c(0,0)) +
  coord_cartesian(clip = "off") +
  labs(title = "TITLE", x = "Type:Class", y = "Correct:Level") +
  theme(panel.background = element_blank(),
        axis.text.x=element_text(angle=45, hjust=1, vjust=1, size=10),
        axis.title=element_text(size=11),
        legend.text=element_text(size=10),
        legend.title=element_text(size=11))

result