Home > Software design >  How can I add a color-based annotation panel between axis labels and data?
How can I add a color-based annotation panel between axis labels and data?

Time:01-13

I have a horizontal barplot and I want to add an annotation related to the y axis ticks between the y axis tick label and the y axis tick, or between the axis tick and the actual plot. Something similar to this:enter image description here

I did some trick adding a geom_point somewhere just before the 0, but this approach has 2 main problems. 1) It is iterative, you have to pick a distance and a point size, then plot to see how it looks like and then readjust the distance and point size. 2) The axis ticks end up being extremely far of the "annotation", it is pretty clear that the annotation is actually inside the plot.

I provide this mock data and plot where I'd like to add boxes with colors corresponding to a y axis (group) property.

# Create sample data
data <- runif(5, 1,10)
data<-cbind.data.frame(data, c("Group1", "Group2", "Group3", "Group4", "Group5"))
colnames(data) <- c("number", "group")
# Plot
ggplot(data) 
  geom_col(aes(y=group, x=number)) 
  coord_cartesian(xlim = c(0,NA), expand=F)

I think this will be very useful to help identify the y axis labels quicker. Thanks

Update: I find a way to make it better, but still I think there might be a more straightforward universal option. This approach consists on creating two barplots that go from 0 to -x. The longest contains the color of the annotation and the short is completely turned to white.

  ggnewscale::new_scale_fill() 
  geom_col(aes(x=-0.25, y=tissue_abbrv, fill=tissue_abbrv)) 
  scale_fill_manual(values=tisscol) 
  guides(fill="none") 
  coord_cartesian(xlim = c(-0.5,NA), expand=F) 
  geom_vline(aes(xintercept=0)) 
  ggnewscale::new_scale_fill() 
  geom_col(aes(x=-0.05, y=tissue_abbrv), fill="white", col="white") 
  geom_vline(aes(xintercept=0), color="white")

enter image description here

CodePudding user response:

I think your approach with two bars is rather clever. Here a solution that uses that idea but avoids the use of two bars and the need for ggnewscale, but using patchwork to bind the plots. It's not exactly much shorter.

library(tidyverse)
library(patchwork)

set.seed(42) ## always better to set seed for better reproducibiltiy
data <- runif(5, 1, 10)
data <- data.frame(
  number = data,
  group = c("Group1", "Group2", "Group3", "Group4", "Group5"),
  color = RColorBrewer::brewer.pal(5, "Set1")
)

p_y <-
ggplot(data)  
  geom_col(aes(y = group, x = 1, fill = color))  
  scale_fill_identity()  
  coord_cartesian(expand = F)  
  theme(axis.text.x = element_blank(), 
        axis.title.x = element_blank(), 
        axis.ticks.x = element_blank(), 
        panel.background = element_blank(), 
        plot.background = element_blank())

p_data <-
ggplot(data)  
  geom_col(aes(y = group, x = number))  
  coord_cartesian(expand = F)  
  theme(axis.text.y = element_blank(), 
        axis.title.y = element_blank(), 
        axis.ticks.y = element_blank())

p_y   p_data  
  plot_layout(widths = c(.1, 1))

Created on 2023-01-11 with reprex v2.0.2

  • Related