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)
Quello che mi piacerebbe avere è qualcosa del genere:
Qualche idea?
È ansible creare una funzione di elemento personalizzata per 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")
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.
scales = "free_x"
per eliminare il gruppo extra dalle Categorie che non ce l’hanno, anche se questo non è sempre auspicabile. 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. 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")
È 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")
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)
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")
@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à: