Ярлыки многострочной оси с вложенными переменными группировки

Я хотел бы, чтобы уровни двух разных вложенных переменных группировки отображались на отдельных строках ниже графика, а не в легенде. Теперь у меня есть этот код:

data <- read.table(text = "Group Category Value S1 A 73 S2 A 57 S1 B 7 S2 B 23 S1 C 51 S2 C 87", header = TRUE) ggplot(data = data, aes(x = Category, y = Value, fill = Group)) + geom_bar(position = 'dodge') + geom_text(aes(label = paste(Value, "%")), position = position_dodge(width = 0.9), vjust = -0.25) 

введите описание изображения здесь

Я хотел бы иметь что-то вроде этого:

введите описание изображения здесь

Есть идеи?

Вы можете создать пользовательскую функцию элемента для axis.text.x

введите описание изображения здесь

 library(ggplot2) library(grid) ## create some data with asymmetric fill aes to generalize solution data <- read.table(text = "Group Category Value S1 A 73 S2 A 57 S3 A 57 S4 A 57 S1 B 7 S2 B 23 S3 B 57 S1 C 51 S2 C 57 S3 C 87", header=TRUE) # user-level interface axis.groups = function(groups) { structure( list(groups=groups), ## inheritance since it should be a element_text class = c("element_custom","element_blank") ) } # returns a gTree with two children: # the categories axis # the groups axis element_grob.element_custom <- function(element, x,...) { cat <- list(...)[[1]] groups <- element$group ll <- by(data$Group,data$Category,I) tt <- as.numeric(x) grbs <- Map(function(z,t){ labs <- ll[[z]] vp = viewport( x = unit(t,'native'), height=unit(2,'line'), width=unit(diff(tt)[1],'native'), xscale=c(0,length(labs))) grid.rect(vp=vp) textGrob(labs,x= unit(seq_along(labs)-0.5, 'native'), y=unit(2,'line'), vp=vp) },cat,tt) gX <- textGrob(cat, x=x) gTree(children=gList(do.call(gList,grbs),gX), cl = "custom_axis") } ## # gTrees don't know their size grobHeight.custom_axis = heightDetails.custom_axis = function(x, ...) unit(3, "lines") ## the final plot call ggplot(data=data, aes(x=Category, y=Value, fill=Group)) + geom_bar(position = position_dodge(width=0.9),stat='identity') + geom_text(aes(label=paste(Value, "%")), position=position_dodge(width=0.9), vjust=-0.25)+ theme(axis.text.x = axis.groups(unique(data$Group)), legend.position="none") 

Аргумент strip.position в facet_wrap() и аргументе switch в facet_grid() поскольку ggplot2 2.2.0 теперь делает создание простой версии этого графика довольно простым с помощью огранки. Чтобы придать сюжету непрерывный вид, установите для параметра panel.spacing значение 0.

Вот пример использования набора данных с различным количеством групп для каждой категории из ответа @ agtudy.

  • Я использовал scales = "free_x" чтобы удалить дополнительную группу из категорий, которые ее не имеют, хотя это не всегда будет желательно.
  • strip.position = "bottom" перемещает метки фасетов в нижнюю часть. Я удалил фон полосы вместе с strip.background , но я мог видеть, что оставление прямоугольника полосы полезно в некоторых ситуациях.
  • Я использовал width = 1 для создания баров в каждом касании категории – они имели бы промежутки между ними по умолчанию.

Я также использую strip.placement и strip.background в theme чтобы получить полоски внизу и удалить прямоугольник полосы.

Код для версий ggplot2_2.2.0 или новее:

 ggplot(data = data, aes(x = Group, y = Value, fill = Group)) + geom_bar(stat = "identity", width = 1) + geom_text(aes(label = paste(Value, "%")), vjust = -0.25) + facet_wrap(~Category, strip.position = "bottom", scales = "free_x") + theme(panel.spacing = unit(0, "lines"), strip.background = element_blank(), strip.placement = "outside") 

введите описание изображения здесь

Вы можете использовать space= "free_x" в facet_grid() если вы хотите, чтобы все бары были одинаковой ширины, независимо от того, сколько групп в категории. Обратите внимание, что вместо strip.position используется switch = "x" . Вы также можете изменить метку оси x; Я не был уверен, что это должно быть, может быть, Категория вместо группы?

 ggplot(data = data, aes(x = Group, y = Value, fill = Group)) + geom_bar(stat = "identity", width = 1) + geom_text(aes(label = paste(Value, "%")), vjust = -0.25) + facet_grid(~Category, switch = "x", scales = "free_x", space = "free_x") + theme(panel.spacing = unit(0, "lines"), strip.background = element_blank(), strip.placement = "outside") + xlab("Category") 

введите описание изображения здесь

Старые версии кода

Код ggplot2_2.0.0, когда эта функция была впервые введена, немного отличалась. Я сохранил его ниже для потомков:

 ggplot(data = data, aes(x = Group, y = Value, fill = Group)) + geom_bar(stat = "identity") + geom_text(aes(label = paste(Value, "%")), vjust = -0.25) + facet_wrap(~Category, switch = "x", scales = "free_x") + theme(panel.margin = unit(0, "lines"), strip.background = element_blank()) 

Альтернативой методу agstudy является редактирование gtable и вставка «оси», вычисленной ggplot2,

 p <- ggplot(data=data, aes(x=Category, y=Value, fill=Group)) + geom_bar(position = position_dodge(width=0.9),stat='identity') + geom_text(aes(label=paste(Value, "%")), position=position_dodge(width=0.9), vjust=-0.25) axis <- ggplot(data=data, aes(x=Category, y=Value, colour=Group)) + geom_text(aes(label=Group, y=0), position=position_dodge(width=0.9)) annotation <- gtable_filter(ggplotGrob(axis), "panel", trim=TRUE) annotation[["grobs"]][[1]][["children"]][c(1,3)] <- NULL #only keep textGrob library(gtable) g <- ggplotGrob(p) gtable_add_grobs <- gtable_add_grob # let's use this alias g <- gtable_add_rows(g, unit(1,"line"), pos=4) g <- gtable_add_grobs(g, annotation, t=5, b=5, l=4, r=4) grid.newpage() grid.draw(g) 

введите описание изображения здесь

Очень простое решение, которое дает аналогичный (хотя и не идентичный) результат, – использовать огранку. Недостатком является то, что метка категории выше, а не ниже.

 ggplot(data=data, aes(x=Group, y=Value, fill=Group)) + geom_bar(position = 'dodge', stat="identity") + geom_text(aes(label=paste(Value, "%")), position=position_dodge(width=0.9), vjust=-0.25) + facet_grid(. ~ Category) + theme(legend.position="none") 

Использование огранки для обеспечения вторичной метки

@agstudy уже ответил на этот вопрос, и я собираюсь использовать его сам, но если вы примете что-то более уродливое, но проще, это то, с чем я пришел перед его ответом:

 data <- read.table(text = "Group Category Value S1 A 73 S2 A 57 S1 B 7 S2 B 23 S1 C 51 S2 C 87", header=TRUE) p <- ggplot(data=data, aes(x=Category, y=Value, fill=Group)) p + geom_bar(position = 'dodge') + geom_text(aes(label=paste(Value, "%")), position=position_dodge(width=0.9), vjust=-0.25) + geom_text(colour="darkgray", aes(y=-3, label=Group), position=position_dodge(width=0.9), col=gray) + theme(legend.position = "none", panel.background=element_blank(), axis.line = element_line(colour = "black"), axis.line.x = element_line(colour = "white"), axis.ticks.x = element_blank(), panel.grid.major = element_blank(), panel.grid.minor = element_blank(), panel.border = element_blank(), panel.background = element_blank()) + annotate("segment", x = 0, xend = Inf, y = 0, yend = 0) 

Что даст нам:

введите описание изображения здесь

Давайте будем гением компьютера.