Ellie
Ellie

Reputation: 33

Stacked bar plot with nested categorical variables and textured fill in R

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.sstatic.net/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)

Upvotes: 3

Views: 649

Answers (2)

Claus Wilke
Claus Wilke

Reputation: 17810

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)

Upvotes: 2

Arienrhod
Arienrhod

Reputation: 2581

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).

Upvotes: 1

Related Questions