可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
**Edit, there are two great solutions here, one is marked as the answer, but @hrbrmstr provides a great solution combining two ggplots which works well for this simple plot.*
Here's the code
breaks.major <- c(0,15,37.5,52.5,67.5,82.5,95,100) #defines the midpoints of the categories (label locations)
breaks.minor <- c(30,45,60,75,90) #defines the edges of the categories (second label set I need)
labels.minor <- c("","Extremely \nDissatisfied","Dissatisfied","Uncertain","Satisfied","Very \nSatisfied","Extremely \nSatisfied","")
lims =c(0,100)
g <- ggplot(mpg, aes(class))+
geom_bar()+
coord_flip()+
scale_y_continuous(limit = lims, minor_breaks = breaks.minor, breaks = breaks.major, labels = labels.minor) +
theme(panel.grid.major.x = element_blank()) +
theme(panel.grid.major.y = element_blank()) +
theme(axis.ticks.x=element_blank()) +
theme(axis.title= element_blank())
It produces this plot:
I need to have two sets of X-axis labels, one showing the category names (i.e. the "satisfied" etc. that are already there via labels.minor
), and one showing the values at the breaks.minor
locations (corresponding to the category limits, i.e. the vertical panel grid lines). I need the current labels.minor
labels to be below the required additional labels.
I currently do this with line breaks so that the numbers and categories are all in one long string, but the spacing gets funny with plot resizes.I could do this with text boxes (I assume), is there a way within ggplot?
Extra points if you get my current labels in the centre of their sections (e.g. "Extremely Satisfied" is off-centre)
This is my desired output (pardon my 'mspaint')
回答1:
Something like this, perhaps. Note the setting of expand
for both axes to deal with proper spacing, and positions of the category names.
The labels in your figure aren't really off-centre, they are in the centre of their category boundary. It's just that by default the axes are expanded a bit further.
If you want to get more fancy, you can draw outside of the plotting area too, but it requires a bit more fiddeling. This question should get you started.
ggplot(mpg, aes(class))+
geom_bar()+
geom_text(data = data.frame(br = breaks.minor), aes(y = br, label = br, x = 7.75),
size = 4, col = 'grey30') +
coord_flip()+
scale_y_continuous(limit = lims, minor_breaks = breaks.minor,
breaks = breaks.major, labels = labels.minor,
expand = c(0, 0)) +
scale_x_discrete(expand = c(0.05, 0)) +
theme(panel.grid.major.x = element_blank()) +
theme(panel.grid.major.y = element_blank()) +
theme(axis.ticks.x=element_blank()) +
theme(axis.title= element_blank())
回答2:
I think this does what you're looking for:
library(ggplot2)
library(grid)
library(gtable)
library(gridExtra)
breaks.major <- c(0, 15, 37.5, 52.5, 67.5, 82.5, 95, 100)
breaks.minor <- c(30, 45, 60, 75, 90)
labels.minor <- c("", "Extremely\nDissatisfied", "Dissatisfied", "Uncertain",
"Satisfied", "Very\nSatisfied", "Extremely\nSatisfied", "")
lims <- c(0, 100)
# build the main plot with the text axis
gg1 <- ggplot(mpg, aes(class))
gg1 <- gg1 + geom_bar()
gg1 <- gg1 + scale_y_continuous(expand=c(0,0), limit=lims,
minor_breaks=breaks.minor,
breaks=breaks.major,
labels=labels.minor)
gg1 <- gg1 + coord_flip()
gg1 <- gg1 + theme(panel.grid.major.x=element_blank())
gg1 <- gg1 + theme(panel.grid.major.y=element_blank())
gg1 <- gg1 + theme(axis.ticks.x=element_blank())
gg1 <- gg1 + theme(axis.title=element_blank())
# let ggplot2 do the work of building the second axis
gg2 <- ggplot(mpg, aes(class))
gg2 <- gg2 + scale_y_continuous(expand=c(0,0), limit=lims,
breaks=c(0, breaks.minor, 100))
gg2 <- gg2 + coord_flip()
gg2 <- gg2 + theme(axis.ticks.x=element_blank())
gg2 <- gg2 + theme(axis.text.x=element_text(hjust=c(0, 0.5, 0.5, 0.5, 0.5, 0.5, 1)))
gt1 <- ggplot_gtable(ggplot_build(gg1))
gt2 <- ggplot_gtable(ggplot_build(gg2))
axis2 <- grid.arrange(gt2$grobs[[5]])
gt <- gtable_add_rows(gt1, unit(0.1, "null"), 4)
grid.arrange(gtable_add_grob(gt, axis2, t=5, l=4, b=5, r=4))
回答3:
I wrote all labels as major-labels.
# OP's
breaks.major <- c(0,15,37.5,52.5,67.5,82.5,95,100) #defines the midpoints of the categories (label locations)
breaks.minor <- c(30,45,60,75,90) #defines the edges of the categories (second label set I need)
labels.minor <- c("","Extremely \nDissatisfied","Dissatisfied","Uncertain","Satisfied","Very \nSatisfied","Extremely \nSatisfied","")
lims =c(0,100)
breaks.major2 <- c(0,15,37.5,52.5,67.5,82.5,95)
breaks.minor2 <- c(30,45,60,75,90,100) # put 100 into minor from major
breaks.comb <- sort(c(breaks.major2, breaks.minor2 - 1.0E-6)) # avoid the just same value as minor
label.comb <- c(0, "\nExtremely \nDissatisfied", 30, "\nDissatisfied", 45, "\nUncertain", 60,
"\nSatisfied", 75, "\nVery \nSatisfied", 90, "\nExtremely \nSatisfied", 100)
library(ggplot2)
g <- ggplot(mpg, aes(class))+
geom_bar()+
coord_flip()+
scale_y_continuous(limit = lims, minor_breaks = breaks.minor2, breaks = breaks.comb,
labels = label.comb, expand = c(0,0)) +
theme(panel.grid.major.x = element_blank()) +
theme(panel.grid.major.y = element_blank()) +
theme(axis.ticks.x=element_blank()) +
theme(axis.title= element_blank()) +
theme(plot.margin = unit(c(0.5, 0.5, 0.5, 0.5), "lines"))