Multiple "Top" textGrob Titles - r

The following is a simple example of my issue (please forgive the repetitive plots - can't use my actual data)
Example:
#packages
library(grid)
library(gridExtra)
library(ggplot2)
#simple plot
p <- ggplot(mtcars, aes(wt,mpg))
# setting-up grid of plots...2 columns by 4 rows
sample <- grid.arrange(p + geom_point()+labs(title="Sample \nTitle One"),
p + geom_point()+labs(title="Sample \nTitle Two"),
p + geom_point(),
p + geom_point(),
p + geom_point(),
p + geom_point(),
p + geom_point(),
p + geom_point(),
ncol = 2)
Output:
Issue: The top two plots have been compressed. I attempted to use the textGrob, like follows:
top = textGrob("Sample Title One",hjust = 1,gp = gpar(fontfamily = "CM Roman", size = 12))
But, I am not seeing a way to incorporate two separate titles. I have yet to try using cowplot, which might be a more reasonable way to go, but was curious if there was a way to do this using textGrob.
Thanks for your time!

As stated by user20650, you can do the following:
grid.arrange(arrangeGrob(p,p,p,p,top=textGrob("Sample Title One"),
ncol=1), arrangeGrob(p,p,p,p,top=textGrob("Sample Title Two"), ncol=1),
ncol = 2)
To get the following:

Related

Fix Plot Size in ggplot2 relative to plot title

I'm using ggplot2 to create some figures with titles, but finding that when titles have a descender (e.g., lowercase p, q, g, y) the actual size of the plot shrinks slightly to accommodate the larger space needed by the title.
Are there ways within normal ggplot functionality to fix the plot size so that figures are in 100% consistent position regardless of title?
Here's some quick sample code that shows the issue; folks might need to run code locally to clearly see the differences in the images.
library(ggplot2)
# No letters with descenders in title
ggplot(data=mtcars,aes(x=disp,y=mpg)) +
geom_point() + ggtitle("Scatter Plot")
# Title has a descender (lowercase 'p')
ggplot(data=mtcars,aes(x=disp,y=mpg)) +
geom_point() + ggtitle("Scatter plot")
you can set the relevant height in the gtable,
library(ggplot2)
p1 <- ggplot() + ggtitle("a")
p2 <- ggplot() + ggtitle("a\nb")
gl <- lapply(list(p1,p2), ggplotGrob)
th <- do.call(grid::unit.pmax, lapply(gl, function(g) g$heights[3]))
gl <- lapply(gl, function(g) {g$heights[3] <- th; g})
gridExtra::grid.arrange(grobs = gl, nrow=1)
Edit: here's how to edit one plot for simplicity
g = ggplotGrob(qplot(1,1) + ggtitle('title'))
g$heights[3] = grid::unit(3,"line")
grid.draw(g)

Multi-line ggplot Title With Different Font Size, Face, etc [duplicate]

This question already has answers here:
How to add a ggplot2 subtitle with different size and colour?
(7 answers)
Closed 7 years ago.
I have scoured SO and other sites but cannot find a solution to my problem with my ggtitle(). I know there are other examples out there, but I haven't been able to apply them directly to my issue successfully.
What I am trying to do is make a multi-line plot title where the first line is bold, size = 10 and then underneath that first line is a second (and potentially third), more descriptive line(s) in non-bold, size=8. The kicker is that I'm trying to make this left justified over the y-axis. This left justification is what makes this question unique because previous answers, including the one linked by a moderator, use atop() which does not allow left justification or does not include it in the answer linked.
Here is what my plot currently looks like:
title <- paste("An analysis of the mtcars dataset ")
subheader <- paste("How does mpg change by \n number of cyl?")
ggplot(mtcars, aes(mpg,cyl))+
geom_smooth(aes(fill="Mean",level=0.095)) +
ggtitle(paste0(title,"\n",subheader)) +
scale_fill_grey(name='95% Confidence\n Interval',start=.65,end=.65) +
theme(plot.title = element_text(size = rel(2.0),hjust=-.1,face="bold"))
I have tried using bquote(), mtext(), atop(), and even a grungy paste() with extra spaces included to push the title....but I haven't been able to find a solution.
Please, let me know if you have any questions or need any clarification. I appreciate any and all help!
Here are three approaches using tableGrob to split a text into multiple lines,
title <- paste("An analysis of the mtcars dataset ")
subheader <- paste("How does mpg change by \nnumber of cyl?")
library(gridExtra)
library(grid)
table_label <- function(label, params=list()) {
params1 <- modifyList(list(hjust=0, x=0, fontsize=12, fontface=2), params)
params2 <- modifyList(list(hjust=0, x=0, fontsize=8, fontface=1), params)
mytheme <- ttheme_minimal(core = list(fg_params = params2),
colhead = list(fg_params = params1))
disect <- strsplit(label, "\\n")[[1]]
m <- as.matrix(disect[-1])
g <- tableGrob(m, cols=disect[1], theme=mytheme)
g$widths <- unit(1,"npc")
g
}
p <- ggplot(iris, aes(Sepal.Length, Sepal.Width)) +
geom_line()
## add a title, note: centering is defined wrt the whole plot
grid.arrange(p, top=table_label(paste0(title,"\n",subheader),
params=list(x=0.1)))
## to align precisely with the panel, use gtable instead
library(gtable)
titleify <- function(p, label, ...){
g <- ggplotGrob(p)
title <- table_label(label, ...)
g <- gtable_add_grob(g, title, t=1, l=4)
g$heights <- grid:::unit.list(g$heights)
g$heights[1] <-list(sum(title$heights))
grid.newpage()
grid.draw(g)
}
titleify(p, paste0(title,"\n",subheader))
## we can also hack ggplot2 to define a custom element for the title
## though be warned the hardware supporting your computer may be damaged by head banging
element_custom <- function() {
structure(list(), class = c("element_custom", "element_text"))
}
element_grob.element_custom <- function(element, label="", ...) {
table_label(label)
}
# default method is unreliable
heightDetails.gtable <- function(x) sum(x$heights)
ggplot(iris, aes(Sepal.Length, Sepal.Width)) +
geom_line() +
ggtitle(paste0(title,"\n",subheader))+
(theme_grey() %+replace% theme(plot.title = element_custom()))
Here's a way to use custom annotation. The justification is straightforward, but you have to determine the coordinates for the text placement by hand. Perhaps you could create some logic to automate this step if you're going to do this a lot.
library(grid)
title <- paste("An analysis of the mtcars dataset ")
subheader <- paste("How does mpg change by\nnumber of cyl?")
p1 = ggplot(mtcars, aes(mpg,cyl))+
geom_smooth(aes(fill="Mean",level=0.095)) +
scale_fill_grey(name='95% Confidence\n Interval',start=.65,end=.65)
p1 = p1 +
annotation_custom(grob=textGrob(title, just="left",
gp=gpar(fontsize=10, fontface="bold")),
xmin=9.8, xmax=9.8, ymin=11.7) +
annotation_custom(grob=textGrob(subheader, just="left",
gp=gpar(fontsize=8, lineheight=1)),
xmin=9.8, xmax=9.8, ymin=10.4) +
theme(plot.margin=unit(c(4,rep(0.5,3)), "lines"))
# Turn off clipping
p1 <- ggplot_gtable(ggplot_build(p1))
p1$layout$clip[p1$layout$name == "panel"] <- "off"
grid.draw(p1)
You can use this approach, but justification is unbelievably finicky. Because atop was designed to format equations, it automatically centers, so you need to hack around that by inserting spaces before the longer title and playing with hjust. There seems to be an upper limit on title size with this approach, too; there has to be space for the spaces to move off to the left.
What I managed:
library(ggplot2)
title <- paste(" An analysis of the mtcars dataset")
subheader <- paste("How does mpg change by number of cyl?")
ggplot(mtcars, aes(mpg,cyl)) +
geom_smooth(aes(fill="Mean",level=0.095)) +
ggtitle(bquote(atop(bold(.(title)), atop(.(subheader), "")))) +
scale_fill_grey(name='95% Confidence\n Interval',start=.65,end=.65) +
theme(plot.title = element_text(size = rel(1.3),hjust=-.6,face="bold"))
To go any further, you're probably going to need to break into grid.

Increase plot size (width) in ggplot2

Below is a plot that I want to include in a paper. The problem is the width of my plot which is to small (that make x-axix not readable at all)
Here is the ggplot2 code myCode.r :
require("ggplot2")
all <- read.csv(file="benchmark/bench.query.csv", head=TRUE, sep=";")
w <- subset(all, query %in% c("sort.q1", "sort.q2", "sort.q3", "sort.q4", "sort.q5"))
w$rtime <- as.numeric(sub(",", ".", w$rtime, fixed=TRUE))
p <- ggplot(data=w, aes(x=query, y=rtime, colour=triplestore, shape=triplestore))
p <- p + scale_shape_manual(values = 0:length(unique(w$triplestore)))
p <- p + geom_point(size=4)
p <- p + geom_line(size=1,aes(group=triplestore))
p <- p + labs(x = "Requêtes", y = "Temps d'exécution (log10(ms))")
p <- p + scale_fill_continuous(guide = guide_legend(title = NULL))
p <- p + facet_grid(trace~type)
p <- p + theme_bw()
ggsave(file="bench_query_sort.pdf")
print (p)
I've look around to see how to enlarge the plot, but I found nothing.
Any idea about what to add/delete/modify in my code ?
Inside a Jupyter notebook I found the following helpful:
# Make plots wider
options(repr.plot.width=15, repr.plot.height=8)
Probably the easiest way to do this, is by using the graphics devices (png, jpeg, bmp, tiff). You can set the exact width and height of an image as follows:
png(filename="bench_query_sort.png", width=600, height=600)
ggplot(data=w, aes(x=query, y=rtime, colour=triplestore, shape=triplestore)) +
scale_shape_manual(values = 0:length(unique(w$triplestore))) +
geom_point(size=4) +
geom_line(size=1,aes(group=triplestore)) +
labs(x = "Requêtes", y = "Temps d'exécution (log10(ms))") +
scale_fill_continuous(guide = guide_legend(title = NULL)) +
facet_grid(trace~type) +
theme_bw()
dev.off()
The width and height are in pixels. This is especailly useful when preparing images for publishing on the internet. For more info, see the help-page with ?png.
Alternatively, you can also use ggsave to get the exact dimensions you want. You can set the dimensions with:
ggsave(file="bench_query_sort.pdf", width=4, height=4, dpi=300)
The width and height are in inches, with dpi you can set the quality of the image.
If you are using RMD(R Markdown) this would be the easiest way to define width and height.
```{r fig.align="center", echo = FALSE,fig.width = 14}
<write the code for your plot here>
```
Note: options() not worked for me so I used this method

Multicolor titles with ggplot2 for R

I was trying to implement multicolor texts as shown here:
multicolor text on chart
which referenced this:
multicolor text in R
This is what I came up with (with help from here):
require(ggplot2)
require(grid)
png(file="multicolortitle.png",width=800,height=500)
qplot(x = hp,y = mpg,data = mtcars,color=factor(mtcars$cyl),size=2) +
scale_colour_manual(values = c("red3","green3","blue3")) +
theme_bw() +
opts(title = " \n ") +
opts(legend.position = "none")
spacing <- 20
grid.text(0.5, unit(1,"npc") - unit(1,"line"),
label=paste("4 cylinder,",paste(rep(" ",spacing*2), collapse='')),
gp=gpar(col="red3", fontsize=16,fontface="bold"))
grid.text(0.5, unit(1,"npc") - unit(1,"line"),
label=paste(paste(rep(" ",spacing), collapse=''),"6 cylinder,",
paste(rep(" ",spacing), collapse='')),
gp=gpar(col="green3", fontsize=16,fontface="bold"))
grid.text(0.5, unit(1,"npc") - unit(1,"line"),
label=paste(paste(rep(" ",spacing*2), collapse=''),"8 cylinder"),
gp=gpar(col="blue3", fontsize=16,fontface="bold"))
grid.text(0.5, unit(1,"npc") - unit(2,"line"),
label=paste(paste(rep(" ",spacing*0), collapse=''),
"- Horsepower versus Miles per Gallon"),
gp=gpar(col="black", fontsize=16,fontface="bold"))
dev.off()
Here's the resulting graph:
So, my question: is there a more elegant method to use for this? I'd like to be able to use ggsave for example, and creating the spacing for this is a highly manual process - not suited for scenarios where I need to automatically make hundreds of plots of this nature. I could see writing some functions on top of this, but maybe there's a better way to implement the methods utilized with the base plotting function?
Here's a more general approach that takes advantage of a few additional grid functions. It's not particularly well-polished, but it may give you some useful ideas:
library(grid)
library(ggplot2)
p <- ggplot(data=mtcars, aes(mpg,hp,color=factor(cyl),size=2)) +
geom_point() + theme_bw() +
opts(title = " \n ") + opts(legend.position="none")
## Get factor levels
levs <- levels(factor(mtcars$cyl))
n <- length(levs)
## Get factors' plotting colors
g <- ggplot_build(p)
d <- unique(g$data[[1]][c("colour", "group")])
cols <- d$colour[order(d$group)]
## Use widest label's width to determine spacing
labs <- paste(levs, "cylinder")
xlocs <- unit(0.5, "npc") +
1.1 * (seq_len(n) - mean(seq_len(n))) * max(unit(1, "strwidth", labs))
## Plot labels in top 10% of device
pushViewport(viewport(y=0.95, height=0.1))
grid.text(paste(levs, "cylinder"),
x = xlocs, y=unit(0.5, "lines"),
gp = gpar(col=cols, fontface="bold"))
grid.text("- Horsepower versus Miles per Gallon",
y = unit(-0.5, "lines"))
upViewport()
## Plot main figure in bottom 90% of device
pushViewport(viewport(y=0.45, height=0.9))
print(p, newpage=FALSE)
upViewport()
A possible strategy wrapping the words in a dummy table,
library(gridExtra)
library(grid)
library(ggplot2)
title = c('Concentration of ','affluence',' and ','poverty',' nationwide')
colors = c('black', '#EEB422','black', '#238E68','black')
grid.arrange(ggplot(),
top = tableGrob(t(title),
theme=ttheme_minimal(padding=unit(c(0,2),'mm'),
base_colour = colors)))
enter image description here

Add a footnote citation outside of plot area in R?

I'd like to add a footnote citation to my 3-panel facet grid plot produced in R. It's a footnote to credit the data source. I'd ideally like to have it below and external to all three axes---preferably in the lower left.
I'm using ggplot2 and also ggsave(). This means I can't use grid.text()-based solutions, because that only draws on the x11() window, and can't be added to the ggplot object.
Using instead png() ...code... dev.off() does not appear to be an option because I need ggsave's resizing parameters, and find this command produces better, clearer prints (that are also much faster, because I'm not printing to the screen).
Here's my basic code:
p1 <- ggplot(data, aes(date, value))
facet_grid(variable ~ .) + geom_point(aes(y =value), size=1) +
theme_bw() +
opts(title=mytitle)
print(p1)
ggsave("FILE.png",width=mywidth, height=myheight, p1, dpi=90)
I've tried:
p1 <- ggplot(data, aes(date, value))
facet_grid(variable ~ .) + geom_point(aes(y =value), size=1) +
theme_bw() +
opts(title=mytitle)
print(p1)
grid.text(unit(0.1,"npc"),0.025,label = "Data courtesy of Me")
grid.gedit("GRID.text", gp=gpar(fontsize=7))
ggsave("FILE.png",width=mywidth, height=myheight, p1, dpi=90)
This appropriately puts the footnote in the lower left corner on the x11() display, external to the plots, but unfortunately, since it isn't applied to the p1 object, it isn't saved by the ggsave command.
I've also tried:
p1 <- ggplot(data, aes(date, value))
facet_grid(variable ~ .) + geom_point(aes(y =value), size=1) +
theme_bw() +
opts(title=mytitle) +
annotate("text", label = "Footnote", x = 0, y = 10, size = 5, colour = "black") +
print(p1)
ggsave("FILE.png",width=mywidth, height=myheight, p1, dpi=90)
This successfully prints using ggsave, however it has the following problems:
It is repeated 3 times, in each of the 3 facets, rather than 1 time.
It is contained within the plots, rather than external to them.
Text is difficult to place---seems to be using plot units (my x-axis is date, so 0 puts it around 1970).
The text size doesn't seem to change despite my size parameter.
A couple of related links from when I explored this...
ggplot2 footnote
(doesn't work with ggsave)
How to label the barplot in ggplot with the labels in another test result?
(is inside the plot, not external/below plot)
Different font faces and sizes within label text entries in ggplot2
(doesn't work with ggsave)
problem saving pdf file in R with ggplot2
ggplot2 now has this ability natively with no need for additional packages. ... + labs(caption = "footnote", ...)
library(ggplot2)
ggplot(diamonds, aes(carat, price, color = clarity)) +
geom_point() +
labs(title = "Diamonds are forever...",
subtitle = "Carat weight by Price",
caption = "H. Wickham. ggplot2: Elegant Graphics for Data Analysis Springer-Verlag New York, 2009.")
library(gridExtra)
library(grid)
library(ggplot2)
g <- grid.arrange(qplot(1:10, 1:10, colour=1:10) + labs(caption="ggplot2 caption"),
bottom = textGrob("grid caption", x = 1,
hjust = 1, gp = gpar(fontface = 3L, fontsize = 9)))
ggsave("plot.pdf", g)
Edit: note that this solution is somewhat complementary to the recent caption argument added to ggplot2, since the textGrob can here be aligned with respect to the whole figure, not just the plot panel.
Adding to the answer of Brandon Bertelsen: if you want to have the caption in the left corner, add
theme(plot.caption = element_text(hjust = 0))

Resources