问题
I would like to create a stacked bar chart where my axis.text
takes it's color values from a variable in the data frame that also provides the bar's fill
color. This is very important because the consumers of the final visuals will be viewing a series of these bar charts so I need to make sure the colors are consistent for each product type even though the Amount values (and thus the order) will vary. The below is the closest I can get.
# My data sample
df <- data.frame(x=1:4, Type = c("Metals", "Foodstuff", "Textiles", "Machinery"), myColour = c('blue', 'red', 'green', 'orange'), Amount = c(75, 50, 25, 5))
# Create factor to order by amount value
df$Type <- factor(df$Type, levels = df[order(df$Amount), "Type"])
# MAKE BAR
gg1 <- ggplot(df, aes(Type, Amount, fill = Type, color = myColour)) +
geom_bar(stat = 'identity', position = 'dodge', show.legend = FALSE, width = .85, colour = 'lightgrey', fill = df$myColour) +
#ggtitle("Exports Profile (%)") +
labs(x = NULL, y = NULL) +
scale_y_continuous(breaks = waiver(), limits = c(0,100)) +
theme(#plot.title = element_text(family= 'sans', color = 'black', size = 28),
#axis.title = element_text(family= 'sans', color = 'black', size = 24),
axis.text.y = element_text(colour = df$myColour, size = 18, face = 'bold'),
axis.ticks.y = element_blank(),
axis.text.x = element_text(colour = 'black', size = 16),
axis.ticks.x = element_line(colour = 'grey60'),
axis.ticks.length = unit(3, "mm"),
axis.line = element_line(NULL),
plot.background = element_rect(fill = NULL),
panel.background = element_rect(fill = 'white', colour = 'white'),
panel.grid.major.x = element_line(colour = 'grey60', linetype = 'dashed'),
panel.grid.major.y = element_line(colour = 'grey60', linetype = 'dashed'),
#panel.margin = unit(c(0,0,0,0), "mm"),
aspect.ratio = (600/450)) +
coord_flip()
gg1
Which produces:
回答1:
Your factor levels are not mapping with the changes to your factor order.
Note that I made a change to your df
so that it does indeed change when reordered, the change was in the Amount
column.
df <- data.frame(x=1:4, Type = c("Metals", "Foodstuff", "Textiles", "Machinery"),
myColour = c('blue', 'red', 'green', 'orange'), Amount = c(50, 75, 25, 5))
Do yourself a favor and load tidyverse.library(tidyverse)
Then use themesettheme_set(theme_classic()+
theme(panel.grid.major.x = element_line(colour = 'grey60', linetype = 'dashed'),
panel.grid.major.y = element_line(colour = 'grey60', linetype = 'dashed'),
axis.ticks.y = element_blank(),
axis.text.x = element_text(colour = 'black', size = 16),
axis.ticks.x = element_line(colour = 'grey60'),
axis.ticks.length = unit(3, "mm"),
aspect.ratio = (600/450),
axis.title.x=element_blank(),
axis.title.y=element_blank()))
You can then 'hack' and relevel the factors (maybe not the best method, but gets it done).
df %>% arrange(Amount) %>% mutate(myColour = factor(myColour, myColour), Type = factor(Type, Type)) -> df1
It is then easier to pull out the color levels as a vector for plotting.
mycols <- as.vector(levels(df1$myColour))
Then plot
ggplot(df1, aes(Type, Amount, color = myColour, fill = myColour)) +
geom_bar(stat = 'identity', position = 'dodge', show.legend = FALSE, width = .85)+
theme(axis.text.y = element_text(colour = mycols, size = 18, face = 'bold'))+
coord_flip()+
scale_fill_manual(values = mycols)+
scale_color_manual(values = mycols)
Hopefully that works for you.
This is the original edit that didn't work so can be ignore: Change the df$myColour
to myColour
in two instances in your code.
With that many theme tweaks you should really think about using theme_set
as well.
来源:https://stackoverflow.com/questions/39669663/matching-axis-text-labels-to-colors-contained-in-data-frame-variable-in-ggplot