2016-01-12 28 views
14

Sto utilizzando facet_grid() per visualizzare alcuni dati e ho etichette facet che si estendono su più righe di testo (contengono il carattere "\ n").ggplot2: Come giustificare a sinistra il testo dalle etichette di sfaccettatura su più righe?

require(ggplot2) 

#Generate example data 
set.seed(3) 
df = data.frame(facet_label_text = rep(c("Label A", 
             "Label B\nvery long label", 
             "Label C\nshort", 
             "Label D"), 
             each = 5), 
       time = rep(c(0, 4, 8, 12, 16), times = 4), 
       value = runif(20, min=0, max=100)) 

#Plot test data 
ggplot(df, aes(x = time, y = value)) + 
    geom_line() + 
    facet_grid(facet_label_text ~ .) + 
    theme(strip.text.y = element_text(angle = 0, hjust = 0)) 

Quindi, utilizzando l'argomento hjust = 0, posso allineare il testo dell'etichetta sfaccettatura sinistro come un'unità.

enter image description here

Quello che vorrei fare è sinistra-allineare ogni singola riga di testo. Quindi "Etichetta B" e "etichetta molto lunga" sono entrambe allineate lungo il lato sinistro, piuttosto che centrate l'una rispetto all'altra (idem per "Etichetta C" e "breve"). È possibile in ggplot2? Grazie in anticipo per il vostro aiuto.

risposta

8

Ciò è molto semplice usando la funzione di griglia grid.gedit per modificare le strisce.

library(ggplot2) # v2.1.0 
library(grid) 

# Your data 
set.seed(3) 
df = data.frame(facet_label_text = rep(c("Label A", 
             "Label B\nvery long label", 
             "Label C\nshort", 
             "Label D"), 
             each = 5), 
       time = rep(c(0, 4, 8, 12, 16), times = 4), 
       value = runif(20, min=0, max=100)) 

# Your plot 
p = ggplot(df, aes(x = time, y = value)) + 
    geom_line() + 
    facet_grid(facet_label_text ~ .) + 
    theme(strip.text.y = element_text(angle = 0, hjust = 0)) 
p 

# Get a list of grobs in the plot 
grid.ls(grid.force()) 

# It looks like we need the GRID.text grobs. 
# But some care is needed: 
# There are GRID.text grobs that are children of the strips; 
# but also there are GRID.text grobs that are children of the axes. 
# Therefore, a gPath should be set up 
# to get to the GRID.text grobs in the strips 

# The edit 
grid.gedit(gPath("GRID.stripGrob", "GRID.text"), 
     just = "left", x = unit(0, "npc")) 

Oppure, un paio di righe di codice per lavorare con un oggetto Grob (in luogo di editing sullo schermo come sopra):

# Get the ggplot grob 
gp = ggplotGrob(p) 
grid.ls(grid.force(gp)) 

# Edit the grob 
gp = editGrob(grid.force(gp), gPath("GRID.stripGrob", "GRID.text"), grep = TRUE, global = TRUE, 
      just = "left", x = unit(0, "npc")) 

# Draw it 
grid.newpage() 
grid.draw(gp) 

enter image description here

+0

Grazie per l'ottima risposta. Sembra che ci sia molto potere sapere come modificare gli oggetti grid e grob sottostanti ggplot. Puoi consigliare una buona risorsa per principianti o una guida per la modifica di grid/grob? Grazie ancora. –

+1

Dopo aver giocato un po 'con questo, penso che puoi ottenere il grob senza doverlo prima visualizzare usando questo piccolo tweak: 'grab = grid.grabExpr (grid.draw (gp))' –

+0

@Brain_Food AFAIK, non c'è niente che riunisce la modifica della griglia dei grafici ggplot2 in modo completo. Per 'grid', controlla i riferimenti sulla pagina info del tag' r-grid' su SO. [Workshop 2015 sull'uso di Paul Murrell] (https://www.stat.auckland.ac.nz/~paul/useR2015-grid/) fornisce alcuni dettagli sulla modifica di ggplot usando le funzioni di griglia. Altrimenti, SO risponde. Inoltre, le funzioni di 'gtable' sono utili. Baptiste ha messo insieme [alcune note su 'gtable'] (https://github.com/baptiste/gtable/wiki/Description) –

7

Fino a quando qualcuno arriva con una soluzione reale, ecco un trucco: aggiungi spazio nelle etichette per ottenere la giustificazione desiderata.

require(ggplot2) 

#Generate example data 
set.seed(3) 
df = data.frame(facet_label_text = rep(c("Label A", 
             "Label B   \nvery long label", 
             "Label C\nshort  ", 
             "Label D"), 
             each = 5), 
       time = rep(c(0, 4, 8, 12, 16), times = 4), 
       value = runif(20, min=0, max=100)) 

#Plot test data 
ggplot(df, aes(x = time, y = value)) + 
    geom_line() + 
    facet_grid(facet_label_text ~ .) + 
    theme(strip.text.y = element_text(angle = 0, hjust = 0)) 

enter image description here

5

Ci può essere un modo più pulito per fare questo, ma non ho trovato un modo per fare questo all'interno ggplot2. La funzione padwrap potrebbe essere più generalizzata in quanto fondamentalmente fa proprio quello che hai richiesto. Per ottenere la giustificazione corretta, ho dovuto usare un font mono-spaziato.

# Wrap text with embedded newlines: space padded and lef justified. 
# There may be a cleaner way to do this but this works on the one 
# example. If using for ggplot2 plots, make the font `family` 
# a monospaced font (e.g. 'Courier') 
padwrap <- function(x) { 
    # Operates on one string 
    padwrap_str <- function(s) { 
     sres <- strsplit(s, "\n") 
     max_len <- max(nchar(sres[[1]])) 
     paste(sprintf(paste0('%-', max_len, 's'), sres[[1]]), collapse = "\n") 
    } 
    # Applys 'padwrap' to a vector of strings 
    unlist(lapply(x, padwrap_str)) 
} 

require(ggplot2) 

facet_label_text = rep(c("Label A", 
         "Label B\nvery long label", 
         "Label C\nshort", 
         "Label D"), 5) 
new_facet_label_text <- padwrap(facet_label_text) 

#Generate example data 
set.seed(3) 
df = data.frame(facet_label_text = new_facet_label_text, 
       time = rep(c(0, 4, 8, 12, 16), times = 4), 
       value = runif(20, min=0, max=100)) 

#Plot test data 
ggplot(df, aes(x = time, y = value)) + 
    geom_line() + 
    facet_grid(facet_label_text ~ .) + 
    theme(strip.text.y = element_text(angle = 0, hjust = 0, family = 'Courier')) 

Il testo striscia è giustificato a sinistra nell'immagine qui

enter image description here

+0

idea intelligente. Forse potresti generalizzare i caratteri non mono-spaziati. Usa 'strwidth' per ottenere le dimensioni relative di ogni carattere e poi usalo per impostare la quantità di padding necessaria per ogni stringa. Ad esempio: 'strwidth (c (LETTERS, letters," "), units =" inches ", family =" Times ")' ti darà la larghezza di tutte le lettere maiuscole e minuscole più uno spazio nel carattere * Times * . – eipi10

+0

@ eipi10 Non sapevo di 'strwidth'. Quando avrò un po 'di tempo, lo implementerò e vedrò come funziona (a meno che qualcuno non mi picchi). Mi stavo chiedendo come si otterrebbe la larghezza dei caratteri non mono distanziati; il tuo suggerimento risolve ciò (supponendo che 'strwidth' funzioni come speriamo). – steveb

+0

Prova questo 'plot (strwidth (c (LETTERS, letters," "), units =" inches ", family =" Times "), 1:53, pch = c (LETTERS, letters," "))' e questo 'trama (strwidth (c (LETTERS, letters," "), units =" inches ", family =" Courier "), 1:53, pch = c (LETTERS, letters," "))' e alcuni altri tipi di carattere e puoi vedere la variazione della larghezza del carattere (o meno per Courier). – eipi10

Problemi correlati