How can I add a grob for both the x and y axis using cowplot?

29 Views Asked by At

I found how to easily insert pngs as axes tick labels, following this post. However, this seems to work only for a single axis. I am not quite sure how to draw both my y axis and x axis grob to my plot.

To plot one grob for either y or x axis one would do something like this...

library(ggplot2)
library(cowplot2)
library(png)
library(Rcurl)

data <- data.frame(
  pairType = c("assortative", "disassortative", "disassortative", "assortative", "disassortative", "disassortative", "assortative"),
  Male_Phenotype = c("metallic", "rufipennis", "metallic", "militaris-a", "metallic", "militaris-a", "rufipennis"),
  Female_Phenotype = c("metallic", "metallic", "militaris-a", "militaris-a", "rufipennis", "rufipennis", "rufipennis"),
  exp = c(0.10204082, 0.11224490, 0.28571429, 0.10204082, 0.02040816, 0.08163265, 0.29591837),
  obs = c(0.04081633, 0.02040816, 0.02040816, 0.03061224, 0.00000000, 0.00000000, 0.03061224)
)


rufiPNG<- "https://i.stack.imgur.com/Q8BqO.png"
rufipennis <- readPNG(getURLContent(rufiPNG))

militarisPNG<- "https://i.stack.imgur.com/EtdfR.png"
militaris_a <- readPNG(getURLContent(militarisPNG))


metallicPNG<- "https://i.stack.imgur.com/YIDoA.png"
metallic <- readPNG(getURLContent(metallicPNG))

#my crazy plot
p<- ggplot(chiMate, aes(x = `Male Phenotype`, y = `Female Phenotype`)) +
  geom_point(aes(color = pairType, size = 2.1*exp))+
  geom_point(color = "black", aes(size = 1.6*exp)) +
  geom_point(color = "white", aes(size = 1.3*exp)) +
  geom_point(aes(size = 1.25*obs), color= "salmon") +
  scale_color_manual("Pair type", values = c("assortative" = "cornflowerblue", "disassortative" = "aquamarine3")) +
  scale_size_continuous(range = c(10, 45))+
  scale_x_discrete(expand=c(.3,.3))+
  scale_y_discrete(expand=c(0.3,0.3))+
  geom_text(aes(label= round(obs, digits= 3)))+
  theme_minimal() +
  labs(x = "Male Phenotype", y = "Female Phenotype", size = "Mate Count")+
  theme(legend.position = 'bottom', legend.box.background = element_rect(color='black'),  axis.title = element_text(size= 14), axis.text = element_text(size= 10))+
  guides(color = guide_legend(override.aes = list(size = 12)),  size = "none")


#create canvas
ystrip <- axis_canvas(p, axis = 'y') + 
  draw_image(rufipennis, y = 2.35, scale = 4) +
  draw_image(militaris_a, y = 1.5, scale = 4) +
  draw_image(metallic, y = .65, scale = 4)

#'draw' grob onto ggplot, 'p'
ggdraw(insert_yaxis_grob(p, ystrip, position = "left",width = grid::unit(0.05, "null")))

I tried

ggdraw(p)+ 
insert_yaxis_grob(p, ystrip, position = "left",width = grid::unit(0.05, "null"))+
insert_xaxis_grob(p, xstrip, position = "bottom",height = grid::unit(0.1, "null"))

and

ggdraw(insert_yaxis_grob(p, ystrip, position = "left",width = grid::unit(0.05, "null")),
insert_xaxis_grob(p, xstrip, position = "bottom",height = grid::unit(0.1, "null")))

to no avail. Any ideas?

1

There are 1 best solutions below

0
stefan On

One option to add images to your axis text would be to use the ggtext package which allows to add images to the axis text using an <img> and by using ggtext::element_markdown() for the axis text. However, I haven't found an option to center align the text and the image for the y axis text. Instead, for the y axis I use geom_richtext to add the images:

library(ggplot2)
library(ggtext)

chiMate <- data.frame(
  pairType = c("assortative", "disassortative", "disassortative", "assortative", "disassortative", "disassortative", "assortative"),
  Male_Phenotype = c("metallic", "rufipennis", "metallic", "militaris-a", "metallic", "militaris-a", "rufipennis"),
  Female_Phenotype = c("metallic", "metallic", "militaris-a", "militaris-a", "rufipennis", "rufipennis", "rufipennis"),
  exp = c(0.10204082, 0.11224490, 0.28571429, 0.10204082, 0.02040816, 0.08163265, 0.29591837),
  obs = c(0.04081633, 0.02040816, 0.02040816, 0.03061224, 0.00000000, 0.00000000, 0.03061224)
)

labels <- c(
  rufipennis = "<img src='https://i.stack.imgur.com/Q8BqO.png'
    width='20' />",
  "militaris-a" = "<img src='https://i.stack.imgur.com/EtdfR.png'
    width='20' />",
  metallic = "<img src='https://i.stack.imgur.com/YIDoA.png'
    width='20' />"
)

p <- ggplot(chiMate, aes(x = Male_Phenotype, y = Female_Phenotype)) +
  geom_point(aes(color = pairType, size = 2.1 * exp)) +
  geom_point(color = "black", aes(size = 1.6 * exp)) +
  geom_point(color = "white", aes(size = 1.3 * exp)) +
  geom_point(aes(size = 1.25 * obs), color = "salmon") +
  scale_color_manual("Pair type",
    values = c(
      "assortative" = "cornflowerblue",
      "disassortative" = "aquamarine3"
    )
  ) +
  scale_size_continuous(range = c(10, 45)) +
  scale_x_discrete(
    expand = c(0, 1),
    labels = \(x) paste0(labels[x], "<br>", x)
  ) +
  scale_y_discrete(
    expand = c(0, .8)
  ) +
  geom_text(aes(label = round(obs, digits = 3))) +
  # Add images for the y axis using ggtext::geom_richtext
  # to vertically align with the axis text
  ggtext::geom_richtext(
    data = tibble::enframe(labels),
    aes(y = name, label = value), x = -Inf,
    fill = "white", label.color = NA, hjust = 0
  ) +
  theme_minimal() +
  labs(x = "Male Phenotype", y = "Female Phenotype", size = "Mate Count") +
  theme(
    legend.position = "bottom",
    legend.box.background = element_rect(color = "black"),
    axis.title = element_text(size = 14),
    axis.text = ggtext::element_markdown(
      size = 10, valign = 0
    ),
    axis.text.y.left = ggtext::element_markdown(
      size = 10, valign = 1
    )
  ) +
  coord_cartesian(clip = "off") +
  guides(color = guide_legend(
    override.aes = list(size = 12)
  ), size = "none")

p