Reputation: 348
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 geom_text() & color gradient.
library(ggplot2)
m.data <- data.frame(m.model = factor(c(1, 1, 2, 2, 4)),
mechanism = c("urban", "hot", "hot", "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")
m.map <- ggplot() +
geom_bar(data = m.data, aes(x = m.model, y = bar.height,
fill = factor(mechanism, levels = mechanism.order)),
stat = "identity") +
scale_fill_manual(values = mechanism.colors) +
scale_color_manual(values = text.colors)
# option 1:
m.map +
geom_text(data = m.data, aes(x = m.model, y = y.for.text,
color = mechanism, label = bar.height))
# option 2:
m.map +
geom_text(data = m.data, aes(x = m.model, y = y.for.text,
color = factor(mechanism, levels = mechanism.order),
label = bar.height))
Upvotes: 2
Views: 2022
Reputation: 78907
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)
Upvotes: 1
Reputation: 173793
To be explicit about the colours, pass them as a named vector.
A couple of other points here:
geom_bar
with stat = "identity"
is just a long way of writing geom_col
position_stack(vjust = 0.5)
inside geom_text
to have central bar labelsggplot
call and let the layers inherit themmechanism.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())
Upvotes: 2
Reputation: 1357
I'm not sure I understand your desired output, but maybe this helps:
I slightly updated your ggplot call: if you provide the aes()
in the initial ggplot call, you don't need to repeat afterwards. Furthermore, there is no need to add factor()
to the fill =
statement. In geom_text
, put color = mechanism
into aes(), so you can access it afterwards with scale_color_manual
to add your custom colors. Lastly, you can add position = position_stack
to get the text in the middle.
ggplot(m.data, aes(m.model, bar.height, fill = mechanism)) +
geom_bar(stat = "identity") +
scale_fill_manual(values = mechanism.colors) +
geom_text(aes(label = bar.height, color = mechanism), position = position_stack(.5)) +
scale_color_manual(values = c("black", "grey50 "))
Output:
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.
Upvotes: 3