Home > Back-end >  Color X axis in ggplot2 bar plot
Color X axis in ggplot2 bar plot

Time:09-25

I would need help in order to color the x axis of a ggplot2 figure.

Here is what I can manage to do so far :

    head(data)
  x  y group Axis_color
1 A 25     F         G1
2 A 88     G         G1
3 A 88     H         G1
4 A 22     I         G1
5 A 18     J         G1
6 B 54     F         G3

color_list<- c("F"="orange", "G"="darkgreen", "H"="grey", "I"="pink", "J"="purple", "G1"="blue","G2"="red","G3"="green")
ggplot(data, aes(x = x, y = y, fill = group, label = y))   
  coord_flip() 
  geom_bar(stat = "identity")

Which gives:

enter image description here

But I would like to as the column "Axis_color" in order to add colors stored in the color_list to the x axis and get:

enter image description here

As you can see I get two different legends axis as well.

Here are the data if it can helps :

structure(list(x = c("A", "A", "A", "A", "A", "B", "B", "B", 
"B", "B", "C", "C", "C", "C", "C", "D", "D", "D", "D", "D", "E", 
"E", "E", "E", "E"), y = c(25, 88, 88, 22, 18, 54, 25, 37, 68, 
72, 36, 84, 17, 64, 48, 15, 17, 72, 61, 25, 66, 10, 18, 99, 63
), group = c("F", "G", "H", "I", "J", "F", "G", "H", "I", "J", 
"F", "G", "H", "I", "J", "F", "G", "H", "I", "J", "F", "G", "H", 
"I", "J"), Axis_color = c("G1", "G1", "G1", "G1", "G1", "G3", 
"G3", "G3", "G3", "G3", "G1", "G1", "G1", "G1", "G1", "G2", "G2", 
"G2", "G2", "G2", "G3", "G3", "G3", "G3", "G3")), row.names = c(NA, 
-25L), class = "data.frame")

CodePudding user response:

The most convenient solution I could come up with that includes a legend would be to use geom_text() to place fake axis labels. If the legend isn't needed I would've recommended ggtext.

By placing the text at x = -Inf, you place it at the axis' minimum and you can further nudge the text to the outside with hjust. You'd need to turn off clipping in the coordinates for this to work. Alternatively you can also set x = -10 or something, but you'd have to adjust the scale limits and tailor this value to every plot.

# data <- structure(...) # omitted for brevity

library(ggplot2)

color_list<- c("F"="orange", "G"="darkgreen", "H"="grey", "I"="pink", "J"="purple", "G1"="blue","G2"="red","G3"="green")

ggplot(data, aes(x = y, y = x, fill = group, label = x))   
  geom_col()  
  geom_text(data = ~ subset(.x, !duplicated(x)),
            aes(x = -Inf, colour = Axis_color), hjust = 2)  
  scale_fill_manual(values = color_list[1:5])  
  scale_colour_manual(values = color_list[-c(1:5)])  
  coord_cartesian(clip = "off")  
  theme(axis.text.y = element_text(colour = NA))

Small sidenote: I replaced geom_bar(stat = "identity") with geom_col() as that seems cleaner, and swapped the x and y aesthetics, removing the need for coord_flip().

CodePudding user response:

Another option to achieve your desired result would be to make use of the ggtext package which allows to color the axis labels via some HTML/CSS.

To get a second legend I make use of the ggnewscale package as in the approach by @teunbrand. However, to make this work we have to add a second geom, too. To this end I added a helper geom_col where I set y=0.


library(ggplot2)
library(ggtext)
library(dplyr)
library(tibble)

color_list <- c("F"="orange", "G"="darkgreen", "H"="grey", "I"="pink", "J"="purple", "G1"="blue","G2"="red","G3"="green")
axis_color <- dplyr::distinct(data, x, Axis_color) %>% 
  tibble::deframe()

ggplot(data, aes(x = x, y = y, fill = group, label = y))   
  coord_flip() 
  geom_bar(stat = "identity")  
  scale_fill_manual(values = color_list, limits = force, guide = guide_legend(order= 1))  
  scale_x_discrete(labels = ~ glue::glue("<span style='color: {color_list[axis_color[.x]]}'>{.x}</span>"))  
  ggnewscale::new_scale_fill()  
  geom_col(aes(y = 0, fill = Axis_color))  
  scale_fill_manual(values = color_list[unique(data$Axis_color)], guide = guide_legend(order= 2))  
  theme(axis.text.y = ggtext::element_markdown())

  • Related