3

I am trying to create a stacked bar plot containing three categorical variables and one discrete variable, where one of the categorical variables is “nested” within another. The “nesting” categorical variable would be visualized by color, and the “nested” categorical variable would be visualized by different textures (hashed lines, dots, etc.). The result would look like the image here: https://i.stack.imgur.com/vVm9q.jpg

I’ve had 2 main challenges doing this in R: 1) nesting one categorical variable within another, 2) symbolizing categories with textures. The closest solution I’ve found to “nest” one categorical variable within another is the script below. However, I would be looking to distinguish the category “sex” by texture using ggplot, not outline color. I would also prefer to have the discrete variable on the x-axis rather than the y-axis. This question shows that the “gridSVG” package may be useful, but I’m not sure how to incorporate this with ggplot.

# This  sample dataset is taken from https://stackoverflow.com/questions/31173931/point-plot-with-se-for-3-categorical-1-continuous-variable-in-r:
library(ggplot2)
library(tibble)

df <- tibble(
  mea = rep(c("PO_P", "Melaniz"), each = 6),
  tre = rep(c("a", "a", "b", "b", "c", "c"), 2),
  sex = rep(c("Male", "Female"), 6),
  len = c(10.66154, 10.58077, 10.29200, 10.60000, 10.28519, 10.65185,
          11.47857, 11.71538, 11.70833, 11.50000, 11.62143, 11.89231)
)

ggplot(df, aes(x = factor(mea), y = len, color = sex, fill = tre)) + 
  geom_bar(stat = "identity", size = 2)

Created on 2019-09-04 by the reprex package (v0.3.0)

Claus Wilke
  • 16,992
  • 7
  • 53
  • 104
Ellie
  • 33
  • 4

2 Answers2

2

You can do this with the ggtextures package. However, you'll need appropriate texture images that can tile. Creating such images is beyond the scope of this answer. I'm using simple animal icons here.

library(ggplot2)
library(tibble)
library(magick)
#> Linking to ImageMagick 6.9.9.39
#> Enabled features: cairo, fontconfig, freetype, lcms, pango, rsvg, webp
#> Disabled features: fftw, ghostscript, x11
library(ggtextures) # devtools::install_github("clauswilke/ggtextures")

textures = list(
  Male = image_read_svg("http://steveharoz.com/research/isotype/icons/horse.svg"),
  Female = image_read_svg("http://steveharoz.com/research/isotype/icons/fish.svg")
)

df <- tibble(
  mea = rep(c("PO_P", "Melaniz"), each = 6),
  tre = rep(c("a", "a", "b", "b", "c", "c"), 2),
  sex = rep(c("Male", "Female"), 6),
  len = c(10.66154, 10.58077, 10.29200, 10.60000, 10.28519, 10.65185,
          11.47857, 11.71538, 11.70833, 11.50000, 11.62143, 11.89231)
)

ggplot(df) +
  aes(
    x = mea, y = len, image = sex, fill = tre,
    group = interaction(sex, tre) # determines which variable should be stacked first, sex or tre
  ) + 
  geom_textured_bar(
    stat = "identity",
    img_width = unit(20, "pt") # adjust for appropriate scaling of textures, or remove
  ) +
  scale_image_manual(values = textures) +
  coord_flip() +
  theme(legend.position = "bottom")

Created on 2019-09-04 by the reprex package (v0.3.0)

Claus Wilke
  • 16,992
  • 7
  • 53
  • 104
1

ggplot doesn't have the texture option, but you can still get what you want using some code-heavy options (some useful links here). In my opinion, it's too much hassle and I prefer to just facet the plots and compare the results like that (use fill = tre and add facet_wrap(~sex) or vice versa, depending on what is more meaningful to you).

Arienrhod
  • 2,451
  • 1
  • 11
  • 19
  • 1
    Thank you for your response. This plot is for a manuscript that was sent back to us with reviewer comments, and one reviewer requested this very specific way of plotting the results. In my example there are only 2 “mea” levels (PO_P and Melaniz), but for our data we actually have 40 levels. So I do worry that using the facet_wrap() method would make the graph too crowded, although I agree that in general it would be a very good alternative. I figured this would require a lot of code to produce, but I’m wondering if anyone has done this in the past for a previous project? – Ellie Aug 30 '19 at 12:10
  • Sorry to hear about the demanding reviewers. From what I can tell, it's quite challenging to implement textures, especially for stacked bars. If you don't want to use `facet_wrap`, how about encoding the `sex` as an `alpha` level like in the example [here](http://jessicacorman.weebly.com/news--musings/how-to-make-a-stacked-bar-chart-with-color-shading)? – Arienrhod Aug 30 '19 at 13:46
  • Yes, this shading option looks like it could be a possible workaround! Thank you! – Ellie Aug 30 '19 at 16:45
  • @Arienrhod It can be done without too much effort, see [here.](https://stackoverflow.com/a/57798415/4975218) – Claus Wilke Sep 05 '19 at 04:33