Multirow-Achsenbeschriftungen mit verschachtelten Gruppierungsvariablen

Ich möchte, dass die Ebenen von zwei verschiedenen geschachtelten Gruppierungsvariablen in separaten Zeilen unterhalb des Diagramms und nicht in der Legende angezeigt werden. Was ich gerade habe, ist dieser Code:

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) 

Bildbeschreibung hier eingeben

Was ich gerne hätte, ist etwa so:

Bildbeschreibung hier eingeben

Irgendwelche Ideen?

   

Sie können eine benutzerdefinierte Elementfunktion für axis.text.x .

Bildbeschreibung hier eingeben

 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") 

Das strip.position -Argument in facet_wrap() und das switch Argument in facet_grid() seit ggplot2 2.2.0 macht nun die Erstellung einer einfachen Version dieses Diagramms über Facettierung relativ einfach. Um dem Diagramm das ununterbrochene Aussehen zu geben, stellen Sie den panel.spacing des panel.spacing auf 0 ein.

Im folgenden Beispiel wird der Datensatz mit einer anderen Anzahl von Gruppen pro Kategorie aus der Antwort von @ agtudy verwendet.

  • Ich habe scales = "free_x" , um die zusätzliche Gruppe aus den Kategorien zu scales = "free_x" , die sie nicht haben, obwohl dies nicht immer wünschenswert ist.
  • Das Argument strip.position = "bottom" verschiebt die Facettenbeschriftungen nach unten. Ich entfernte den Streifenhintergrund alle zusammen mit strip.background , aber ich konnte sehen, dass das Verlassen des Streifenrechtecks ​​in einigen Situationen nützlich sein würde.
  • Ich habe width = 1 , um die Balken in jeder Kategorie zu berühren – sie hätten standardmäßig Leerzeichen dazwischen.

Ich verwende auch strip.placement und strip.background im theme , um die Streifen auf der Unterseite zu erhalten und das Streifenrechteck zu entfernen.

Der Code für Versionen von ggplot2_2.2.0 oder neuer:

 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") 

Bildbeschreibung hier eingeben

Sie könnten space= "free_x" in facet_grid() wenn Sie facet_grid() , dass alle Balken unabhängig von der facet_grid() der Gruppen pro Kategorie die gleiche Breite haben. Beachten Sie, dass dies switch = "x" anstelle von strip.position . Vielleicht möchten Sie auch die Beschriftung der X-Achse ändern; Ich war mir nicht sicher, was es sein sollte, vielleicht Kategorie statt Gruppe?

 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") 

Bildbeschreibung hier eingeben

Ältere Code-Versionen

Der Code für ggplot2_2.0.0, als dieses Feature erstmals eingeführt wurde, war etwas anders. Ich habe es unten für die Nachwelt gespeichert:

 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()) 

Eine Alternative zur Methode von agstudy besteht darin, den gtable zu editieren und eine von ggplot2 berechnete “Achse” einzufügen,

 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) 

Bildbeschreibung hier eingeben

Eine sehr einfache Lösung, die ein ähnliches (wenn auch nicht identisches) Ergebnis liefert, ist die Verwendung von Facetten. Der Nachteil ist, dass die Kategorie-Label über und nicht unter ist.

 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") 

Verwenden der Facettierung, um eine sekundäre Beschriftung bereitzustellen

@agstudy hat diese Frage bereits beantwortet und ich werde sie selbst benutzen, aber wenn du etwas hässlicheres, aber einfacheres akzeptierst, ist das genau das, womit ich vor seiner Antwort gekommen bin:

 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) 

Was uns geben wird:

Bildbeschreibung hier eingeben