Comment ajouter un sous-titre ggplot2 avec une taille et une couleur différentes?

88

J'utilise ggplot2 pour améliorer les barplots de précipitations.

Voici un exemple reproductible de ce que je souhaite réaliser:

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

Je ne sais pas comment éviter de deviner des nombres sur hjust et vjust sur ggplot2? Existe-t-il une meilleure façon de mettre un sous-titre (pas seulement en utilisant \ n, mais un sous-titre avec une couleur et une taille de texte différentes)?

J'ai besoin de pouvoir utiliser avec ggsave pour avoir un fichier pdf.

Voici deux questions liées:

Ajouter une citation de note en dehors de la zone de tracé dans R?

Comment puis-je ajouter un sous-titre et modifier la taille de la police des tracés ggplot dans R?

Merci pour toute aide.

Migue
la source
Le vjust = -33 a fonctionné pour moi sous Linux. Je sais que ce sous-marin est destiné à aller en dessous de l'intrigue, mais c'était la seule façon d'obtenir ce que je voulais.
Migue
pour une raison quelconque, cela rend mon intrigue vraiment petite et crée un espace énorme sous le graphique
zazu
2
La réponse de @hrbrmstr semble être la voie à suivre de nos jours
andschar

Réponses:

102

Les dernières versions de ggplot2 (c'est-à-dire 2.1.0.9000 ou plus récent) ont des sous-titres et des légendes sous-tracé comme fonctionnalité intégrée. Cela signifie que vous pouvez faire ceci:

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
hrbrmstr
la source
Erreur dans (function (el, elname): "plot.subtitle" n'est pas un nom d'élément de thème valide.
Luís de Sousa
1
Veuillez lire les réponses: "dernières versions de ggplot2 (c'est-à-dire 2.1.0.9000 ou plus récent)"
hrbrmstr
75

Ignorer cette réponse, la ggplot2 version 2.2.0 a des fonctionnalités de titre et de sous-titre. Voir la réponse de @ hrbrmstr ci-dessous .


Vous pouvez utiliser des atopfonctions imbriquées dans un expressionpour obtenir différentes tailles.

EDIT Mise à jour du code pour 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))

entrez la description de l'image ici

Sandy Muspratt
la source
10
Salut, c'est une solution incroyable. Je voudrais l' utiliser , mais au lieu de atop(italic("Location")je voudrais avoir un objet: atop(italic(my_string_vector). J'ai essayé cela, mais ensuite le sous-titre évalué à (my_string_vector) . Comment forcer cette expression à utiliser la valeur de chaîne et à ne pas traiter le texte fourni littéralement?
Konrad le
1
au cas où vous auriez des problèmes en utilisant des variables que vous devriez utiliser à la bquoteplace de expression, voir ici
toto_tico
3
@Konrad à des objets d'utilisation, remplacer expressionavec bquoteet envelopper les objets avec .(), comme celui - ci, pour un titre principal stocké dans un objet appelé « main.title » et un sous - titre stocké dans un objet appelé « sub.title »: Le ggtitle(bquote(atop(.(main.title), atop(italic(.(sub.title)), "")))) crédit va à Didzis Réponse d'Elferts ici: stackoverflow.com/questions/19957536/…
coip le
10

Il semble optsêtre obsolète à partir de ggplot 2 0.9.1 et n'est plus fonctionnel. Cela a fonctionné pour moi avec les dernières versions d'aujourd'hui: + ggtitle(expression(atop("Top line", atop(italic("2nd line"), "")))).

Aren Cambre
la source
Cela fonctionne également sans la finale , ""- à quoi sert cette partie?
rien101
Me bat. J'ai peut-être copié un exemple que j'ai vu ailleurs.
Aren Cambre
Probablement de la réponse de @ SandyMuspratt ci-dessus: P - Je le comprends maintenant, atop()c'est quelque chose comme une fraction sans barres. Donc, mettre le second atop()à l'intérieur du premier vous donne une sous-fraction, avec un texte proportionnellement plus petit. Le ""est le bas de la sous-fraction. Cela semble inutile cependant - a peut-être atop()une chaîne vide par défaut pour le deuxième paramètre, ou quelque chose.
naught101
Il semble que la réponse de @ SandyMuspratt ait été modifiée après avoir publié ma réponse pour refléter un code similaire au mien. :-)
Aren Cambre
9

ce n'est pas trop difficile d'ajouter des grobs à la table et de créer un titre sophistiqué de cette façon,

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

entrez la description de l'image ici

baptiste
la source
8

Cette version utilise une gtablefonction. Il autorise deux lignes de texte dans le titre. Le texte, la taille, la couleur et la police de chaque ligne peuvent être définis indépendamment de l'autre. Cependant, la fonction modifie un tracé avec un seul panneau de tracé uniquement.

Modification mineure: mise à jour vers 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

entrez la description de l'image ici

Sandy Muspratt
la source
3

Vous pouvez utiliser envelopper le tracé dans grid.arrange et passer un titre personnalisé basé sur une grille,

entrez la description de l'image ici

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)
baptiste
la source
Les versions actuelles de ggplot utilisent respectivement theme et et element_text au lieu de opts et theme_text. De plus, l'approche ggplotGrob semble échouer dans la version actuelle de gridExtra (gridExtra_0.8.1) et ggplot2 (ggplot2_0.9.3.1)
russellpierce
2

Vous avez peut-être remarqué que le code de Sandy ne produit pas de titre en gras pour "Rainfall" - l'instruction pour mettre ce gras devrait se produire dans la fonction atop () plutôt que dans la fonction 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))

entrez la description de l'image ici

Nathan
la source