Come aggiungere un sottotitolo ggplot2 con dimensioni e colori diversi?


89

Sto usando ggplot2 per migliorare i grafici a barre delle precipitazioni.

Ecco un esempio riproducibile di ciò che voglio ottenere:

library(ggplot2)
library(gridExtra)
secu <- seq(1, 16, by=2)
melt.d <- data.frame(y=secu, x=LETTERS[1:8])
m <- ggplot(melt.d, aes(x=x, y=y)) +
  geom_bar(fill="darkblue") + 
  labs(x="Weather    stations", y="Accumulated Rainfall [mm]") +
  opts(axis.text.x=theme_text(angle=-45, hjust=0, vjust=1),
       title=expression("Rainfall"), plot.margin = unit(c(1.5, 1, 1, 1), "cm"),
       plot.title = theme_text(size = 25, face = "bold", colour = "black", vjust = 5))
z <- arrangeGrob(m, sub = textGrob("Location", x = 0, hjust = -3.5, vjust = -33, gp = gpar(fontsize = 18, col = "gray40"))) #Or guessing x and y with just option
z

Non so come evitare di indovinare i numeri su hjust e vjust su ggplot2? C'è un modo migliore per inserire un sottotitolo (non solo usando \ n, ma un sottotitolo con testo e dimensione del testo diversi)?

Devo essere in grado di utilizzare con ggsave per avere un file pdf.

Ecco due domande correlate:

Aggiungere una citazione della nota a piè di pagina al di fuori dell'area del tracciato in R?

Come posso aggiungere un sottotitolo e modificare la dimensione del carattere dei grafici ggplot in R?

Grazie per qualsiasi aiuto.


Il vjust = -33 ha funzionato per me su Linux. So che il sottotitolo doveva andare sotto la trama, ma era l'unico modo in cui ho ottenuto ciò che volevo.
Migue

per qualche motivo questo rende la mia trama davvero piccola e crea uno spazio enorme sotto il grafico
zazu

2
La risposta di @hrbrmstr sembra essere la strada da percorrere oggi
andschar

Risposte:


103

Le ultime build di ggplot2 (cioè 2.1.0.9000 o successive) hanno sottotitoli e didascalie sotto la trama come funzionalità integrate. Ciò significa che puoi farlo:

library(ggplot2) # 2.1.0.9000+ 

secu <- seq(1, 16, by=2)
melt.d <- data.frame(y=secu, x=LETTERS[1:8])

m <-  ggplot(melt.d, aes(x=x, y=y))
m <- m + geom_bar(fill="darkblue", stat="identity")
m <- m + labs(x="Weather    stations", 
              y="Accumulated Rainfall [mm]",
              title="Rainfall",
              subtitle="Location")
m <- m + theme(axis.text.x=element_text(angle=-45, hjust=0, vjust=1)) 
m <- m + theme(plot.title=element_text(size=25, hjust=0.5, face="bold", colour="maroon", vjust=-1))
m <- m + theme(plot.subtitle=element_text(size=18, hjust=0.5, face="italic", color="black"))
m

Errore in (function (el, elname): "plot.subtitle" non è un nome di elemento del tema valido.
Luís de Sousa,

1
Si prega di leggere le risposte: "ultime build di ggplot2 (cioè 2.1.0.9000 o più recenti)"
hrbrmstr

75

Ignora questa risposta la ggplot2 versione 2.2.0 ha funzionalità di titolo e sottotitolo. Vedi la risposta di @ hrbrmstr di seguito .


È possibile utilizzare atopfunzioni annidate all'interno di un expressionper ottenere dimensioni diverse.

EDIT Codice aggiornato per ggplot2 0.9.3

m <-  ggplot(melt.d, aes(x=x, y=y)) + 
     geom_bar(fill="darkblue", stat = "identity") + 
     labs(x="Weather    stations", y="Accumulated Rainfall [mm]") + 
     ggtitle(expression(atop("Rainfall", atop(italic("Location"), "")))) +
     theme(axis.text.x = element_text(angle=-45, hjust=0, vjust=1), 
     #plot.margin = unit(c(1.5, 1, 1, 1), "cm"), 
     plot.title = element_text(size = 25, face = "bold", colour = "black", vjust = -1))

inserisci qui la descrizione dell'immagine


10
Ciao, questa è una soluzione straordinaria. Vorrei usarlo, ma invece della atop(italic("Location")vorrei avere un oggetto: atop(italic(my_string_vector). L'ho provato ma poi il sottotitolo è stato valutato in (my_string_vector) . Come forzare questa espressione a utilizzare il valore stringa e non trattare letteralmente il testo fornito?
Konrad,

1
nel caso in cui tu abbia problemi con le variabili che dovresti usare al bquoteposto di expression, vedi qui
toto_tico

3
@Konrad di utilizzare gli oggetti, sostituire expressioncon bquotee avvolgere gli oggetti con .(), in questo modo, per un titolo principale memorizzato in un oggetto chiamato "main.title" e per sottotitolo memorizzato in un oggetto chiamato "sub.title": ggtitle(bquote(atop(.(main.title), atop(italic(.(sub.title)), "")))) il merito va a Didzis risposta qui di Elferts: stackoverflow.com/questions/19957536/...
COIP

10

Sembra optsessere deprecato a partire da ggplot 2 0.9.1 e non funziona più. Questo ha funzionato per me con le ultime versioni a partire da oggi: + ggtitle(expression(atop("Top line", atop(italic("2nd line"), "")))).


Funziona anche senza la finale , "": a cosa serve quella parte?
nought101

Mi batte. Potrei aver copiato un esempio che ho visto da qualche altra parte.
Aren Cambre

Probabilmente dalla risposta di @ SandyMuspratt sopra: P - Lo capisco ora, atop()è qualcosa come una frazione senza barre. Quindi mettere il secondo atop()all'interno del primo ti dà una sotto-frazione, con il testo proporzionalmente più piccolo. Il ""è il fondo della sub-frazione. Tuttavia, sembra non essere necessario: forse atop()ha una stringa vuota predefinita per il secondo parametro o qualcosa del genere.
nought101

Sembra che la risposta di @ SandyMuspratt sia stata modificata dopo che ho pubblicato la mia risposta per riflettere un codice simile al mio. :-)
Aren Cambre

9

non è troppo difficile aggiungere grob a gtable e creare un titolo di fantasia in questo modo,

library(ggplot2)
library(grid)
library(gridExtra)
library(magrittr)
library(gtable)

p <- ggplot() + 
  theme(plot.margin = unit(c(0.5, 1, 1, 1), "cm"))

lg <- list(textGrob("Rainfall", x=0, hjust=0, 
                    gp = gpar(fontsize=24, fontfamily="Skia", face=2, col="turquoise4")),
               textGrob("location", x=0, hjust=0, 
                        gp = gpar(fontsize=14, fontfamily="Zapfino", fontface=3, col="violetred1")),
           pointsGrob(pch=21, gp=gpar(col=NA, cex=0.5,fill="steelblue")))

margin <- unit(0.2, "line")
tg <- arrangeGrob(grobs=lg, layout_matrix=matrix(c(1,2,3,3), ncol=2),
                  widths = unit.c(grobWidth(lg[[1]]), unit(1,"null")),
                  heights = do.call(unit.c, lapply(lg[c(1,2)], grobHeight)) + margin)

grid.newpage()
ggplotGrob(p) %>%
  gtable_add_rows(sum(tg$heights), 0) %>%
  gtable_add_grob(grobs=tg, t = 1, l = 4)  %>%
  grid.draw()

inserisci qui la descrizione dell'immagine


8

Questa versione utilizza una gtablefunzione. Consente due righe di testo nel titolo. Il testo, la dimensione, il colore e il tipo di carattere di ciascuna riga possono essere impostati indipendentemente dall'altro. Tuttavia, la funzione modificherà un grafico con un solo pannello di trama.

Modifica minore: aggiornamento a ggplot2 v2.0.0

# The original plot
library(ggplot2)

secu <- seq(1, 16, by = 2)
melt.d <- data.frame(y = secu, x = LETTERS[1:8])

m <- ggplot(melt.d, aes(x = x, y = y)) + 
     geom_bar(fill="darkblue", stat = "identity") + 
     labs(x = "Weather    stations", y = "Accumulated Rainfall [mm]") + 
     theme(axis.text.x = element_text(angle = -45, hjust = 0, vjust = 1))


# The function to set text, size, colour, and face
plot.title = function(plot = NULL, text.1 = NULL, text.2 = NULL, 
   size.1 = 12,  size.2 = 12,
   col.1 = "black", col.2 = "black", 
   face.1 = "plain",  face.2 = "plain") {

library(gtable)
library(grid)

gt = ggplotGrob(plot)

text.grob1 = textGrob(text.1, y = unit(.45, "npc"), 
   gp = gpar(fontsize = size.1, col = col.1, fontface = face.1))
text.grob2 = textGrob(text.2,  y = unit(.65, "npc"), 
   gp = gpar(fontsize = size.2, col = col.2, fontface = face.2))

text = matrix(list(text.grob1, text.grob2), nrow = 2)
text = gtable_matrix(name = "title", grobs = text, 
   widths = unit(1, "null"), 
   heights = unit.c(unit(1.1, "grobheight", text.grob1) + unit(0.5, "lines"), unit(1.1,  "grobheight", text.grob2) + unit(0.5, "lines")))

gt = gtable_add_grob(gt, text, t = 2, l = 4)
gt$heights[2] = sum(text$heights)

class(gt) =  c("Title", class(gt))

gt
}

# A print method for the plot
print.Title <- function(x) {
   grid.newpage()   
   grid.draw(x)
}


# Try it out - modify the original plot
p = plot.title(m, "Rainfall", "Location", 
   size.1 = 20, size.2 = 15, 
   col.1 = "red", col.2 = "blue", 
   face.2 = "italic")

p

inserisci qui la descrizione dell'immagine


3

È possibile utilizzare avvolgere la trama in grid.arrange e passare un titolo basato su griglia personalizzato,

inserisci qui la descrizione dell'immagine

library(ggplot2)
library(gridExtra)

p <- ggplot() + 
  theme(plot.margin = unit(c(0.5, 1, 1, 1), "cm"))

tg <- grobTree(textGrob("Rainfall", y=1, vjust=1, gp = gpar(fontsize=25, face=2, col="black")),
               textGrob("location", y=0, vjust=0, gp = gpar(fontsize=12, face=3, col="grey50")),
               cl="titlegrob")
heightDetails.titlegrob <- function(x) do.call(sum,lapply(x$children, grobHeight))

grid.arrange(p, top = tg)

Le versioni attuali di ggplot usano rispettivamente theme e ed element_text invece di opts e theme_text. Inoltre, l'approccio ggplotGrob sembra fallire nella versione corrente di gridExtra (gridExtra_0.8.1) e ggplot2 (ggplot2_0.9.3.1)
russellpierce

2

Potreste aver notato che il codice di Sandy non produce un titolo in grassetto per "Rainfall" - le istruzioni per renderlo in grassetto dovrebbero verificarsi all'interno della funzione atop () piuttosto che nella funzione theme ().

ggplot(melt.d, aes(x=x, y=y)) + 
 geom_bar(fill="darkblue", stat = "identity") + 
 labs(x="Weather    stations", y="Accumulated Rainfall [mm]") + 
 ggtitle(expression(atop(bold("Rainfall"), atop(italic("Location"), "")))) +
 theme(axis.text.x = element_text(angle=-45, hjust=0, vjust=1),
 plot.title = element_text(size = 25, colour = "black", vjust = -1))

inserisci qui la descrizione dell'immagine

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.