Edit: This question has been marked as duplicated, but the responses here have been tried and did not work because the case in question is a line chart, not a bar chart. Applying those methods produces a chart with 5 lines, 1 for each year - not useful. Did anyone who voted to mark as duplicate actually try those approaches on the sample dataset supplied with this question? If so please post as an answer.
Original Question:
There's a feature in Excel pivot charts which allows multilevel categorical axes.I'm trying to find a way to do the same thing with ggplot
(or any other plotting package in R).
Consider the following dataset:
set.seed(1) df=data.frame(year=rep(2009:2013,each=4), quarter=rep(c("Q1","Q2","Q3","Q4"),5), sales=40:59+rnorm(20,sd=5))
If this is imported to an Excel pivot table, it is straightforward to create the following chart:
Note how the x-axis has two levels, one for quarter and one for the grouping variable, year. Are multilevel axes possible with ggplot
?
NB: There is a hack with facets that produces something similar, but this is not what I'm looking for.
library(ggplot2) ggplot(df) + geom_line(aes(x=quarter,y=sales,group=year))+ facet_grid(.~year,scales="free")
New labels are added using annotate(geom = "text",
. Turn off clipping of x axis labels with clip = "off"
in coord_cartesian
.
Use theme
to add extra margins (plot.margin
) and remove (element_blank()
) x axis text (axis.title.x
, axis.text.x
) and vertical grid lines (panel.grid.x
).
library(ggplot2) ggplot(data = df, aes(x = interaction(year, quarter, lex.order = TRUE), y = sales, group = 1)) + geom_line(colour = "blue") + annotate(geom = "text", x = seq_len(nrow(df)), y = 34, label = df$quarter, size = 4) + annotate(geom = "text", x = 2.5 + 4 * (0:4), y = 32, label = unique(df$year), size = 6) + coord_cartesian(ylim = c(35, 65), expand = FALSE, clip = "off") + theme_bw() + theme(plot.margin = unit(c(1, 1, 4, 1), "lines"), axis.title.x = element_blank(), axis.text.x = element_blank(), panel.grid.major.x = element_blank(), panel.grid.minor.x = element_blank())
See also the nice answer by @eipi10 here: Axis labels on two lines with nested x variables (year below months)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With