Home > OS >  How to map geom_text color to a variable
How to map geom_text color to a variable

Time:03-21

For a bar graph, I want to stack the bar components vertically in a custom order.  In the example below, the variable that should control the stacking order is “mechanism.”  The intended stacking order is neither alphabetical order nor the order in which the dataframe’s rows are sequenced.  Not all bars have all mechanisms. I manually set the sequence and use the sequence as levels for a factor.  The entirely missing factor level doesn't get handled right, for which a solution would be welcome but I can work around that.

To add text labels indicating each component’s magnitude, I calculate the labels’ y height values and add a geom_text.  I want the color of the text to be a consistent contrast to the color of the bar component:  white text on blue bar components, etc.  So I assign geom_text's color to the same variable as the geom_bar’s fill.  But the intended color pairings for background and text do not remain matched.  Ideas please?? (thank you to the editor who inserted the picture of the messed up graph.)

The desired outcome is that each bar component whose mechanism is "hot" would have red fill annotated with black text. Each component whose mechanism is "urban" would have tan4 fill annotated with grey50 text.

I also tried assigning the color without making the mapped variable into a factor (example option 1), as in enter image description here

However, as you can see, gray40 might not be the best color on a blue background, since the contrast is not very good. You might want to choose another color.

CodePudding user response:

To be explicit about the colours, pass them as a named vector.

A couple of other points here:

  1. A geom_bar with stat = "identity" is just a long way of writing geom_col
  2. You don't need to hand code y positions for text. Just use position_stack(vjust = 0.5) inside geom_text to have central bar labels
  3. If your layers all use the same data and x, y variables, pass them via the initial ggplot call and let the layers inherit them
mechanism.colors <- c(hot = "red", dry = "blue", urban = "tan4")
text.colors <- c(hot = "black", dry = "white", urban = "gray50")

ggplot(data = m.data, aes(x = m.model, y = bar.height))  
   geom_col(aes( fill = factor(mechanism, levels = mechanism.order)))  
   geom_text(aes(label = bar.height, color = mechanism),
             position = position_stack(vjust = 0.5), size = 8)  
   scale_fill_manual(values = mechanism.colors)  
   scale_color_manual(values = text.colors)  
   labs(fill = "mechanism")  
   guides(color = guide_none())

enter image description here

CodePudding user response:

Suggestion with modified data. Most of the procedure already presented by dear @Alan Cameron. New is to transform to factor before ggplot:

m.data <- data.frame(m.model = factor(c(1, 1, 2, 2, 4)),
                     mechanism = c("urban", "hot", "dry", "urban", "urban"),
                     bar.height = 1:5,
                     y.for.text = c(.5, 2, 1.5, 5, 2.5))
mechanism.order <- c("hot", "dry", "urban")
mechanism.colors <- c("red", "blue", "tan4")
text.colors <- c("black", "white", "grey50")
library(tidyverse)

m.data %>% 
  mutate(mechanism = factor(mechanism, levels = mechanism.order)) %>% 
  ggplot(aes(x=m.model, y=bar.height, fill=mechanism)) 
  geom_col() 
  geom_text(aes(label = bar.height, color = mechanism),
            position = position_stack(vjust = 0.5))  
  scale_fill_manual(values = mechanism.colors)  
  scale_color_manual(values = text.colors) 

enter image description here

  • Related