Etichette multirotore degli assi con variabili di raggruppamento nidificate

Vorrei che i livelli di due diverse variabili di raggruppamento nidificati appaiano su linee separate sotto il grafico e non nella legenda. Quello che ho adesso è questo codice:

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) 

inserisci la descrizione dell'immagine qui

Quello che mi piacerebbe avere è qualcosa del genere:

inserisci la descrizione dell'immagine qui

Qualche idea?

È ansible creare una funzione di elemento personalizzata per axis.text.x

inserisci la descrizione dell'immagine qui

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

L’argomento strip.position in facet_wrap() e switch argomento switch in facet_grid() poiché ggplot2 2.2.0 ora rende la creazione di una versione semplice di questa trama abbastanza semplice tramite la sfaccettatura. Per dare alla trama l’aspetto ininterrotto, imposta il panel.spacing su 0.

Ecco l’esempio che utilizza il set di dati con un diverso numero di gruppi per categoria dalla risposta di @ agtudy.

  • Ho usato le scales = "free_x" per eliminare il gruppo extra dalle Categorie che non ce l’hanno, anche se questo non è sempre auspicabile.
  • L’ strip.position = "bottom" sposta le etichette delle sfaccettature in basso. Ho rimosso lo sfondo della striscia tutto insieme con strip.background , ma ho potuto vedere che lasciare il rettangolo della striscia sarebbe utile in alcune situazioni.
  • Ho usato width = 1 per rendere le barre all’interno di ogni touch di categoria – avrebbero di default degli spazi tra loro.

Io uso anche strip.placement e strip.background nel theme per ottenere le strisce sul fondo e rimuovere il rettangolo della striscia.

Il codice per le versioni di ggplot2_2.2.0 o più recenti:

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

inserisci la descrizione dell'immagine qui

È ansible utilizzare space= "free_x" in facet_grid() se si desidera che tutte le barre abbiano la stessa larghezza indipendentemente dal numero di gruppi per categoria. Nota che questo usa switch = "x" invece di strip.position . Potresti anche voler cambiare l’etichetta dell’asse x; Non ero sicuro di cosa avrebbe dovuto essere, forse Categoria invece di Gruppo?

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

inserisci la descrizione dell'immagine qui

Versioni di codice precedenti

Il codice per ggplot2_2.0.0, quando questa funzionalità è stata introdotta per la prima volta, era leggermente diverso. L’ho salvato sotto per i posteri:

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

Un’alternativa al metodo di agstudy è di modificare il gtable e inserire un “asse” calcolato da 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) 

inserisci la descrizione dell'immagine qui

Una soluzione molto semplice che dà un risultato simile (anche se non identico) è usare la sfaccettatura. Lo svantaggio è che l’etichetta di categoria è sopra anziché sotto.

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

Usare la sfaccettatura per fornire un'etichetta secondaria

@agstudy ha già risposto a questa domanda e io lo userò da solo, ma se accettassi qualcosa di più brutto, ma più semplice, questo è quello che ho trovato prima della sua risposta:

 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) 

Che ci darà:

inserisci la descrizione dell'immagine qui