I am trying to create a plot title manually formatted on two lines which includes two italicized words, I have done some searching
on Stack Exchange but have not found a good solution to this seemingly simple problem.
The scientific names of the two species are fairly long, and thus the need for a multi-line title (ggplot2 doesn't format this).
Objective:
..........First Line of Title with Species
Second line words anotherItalicSpecies the end
ggplot(mtcars,aes(x=wt,y=mpg))+
geom_point()+
labs(title= expression(paste(atop("First line of title with ", atop((italic("Species")))),"
secondline words", italic("anotherSpecies"), "the end")))
Which yields the following mangled title:
Using a combination of atop, paste, italic and scriptstyle:
ggplot(mtcars, aes(x = wt, y = mpg)) +
geom_point() +
labs(title = ~ atop(paste('First line of title with ',italic("Species")),
paste(scriptstyle(italic("Species")),
scriptstyle(" secondline words "),
scriptstyle(italic("anotherSpecies")),
scriptstyle(" the end"))))
gives you the desired result:
Using scriptstyle is not a necessity, but imho it is nicer to have your subtitle in a smaller font than the main title.
See also ?plotmath for other usefull customizations.
As an alternative to inserting line breaks in title, you may use title together with subtitle (available from ggplot 2.2.0). Possibly this makes the plothmathing slightly more straightforward.
p <- ggplot(mtcars, aes(x = wt, y = mpg)) +
geom_point() +
labs(title = expression("First line: "*italic("Honorificabilitudinitatibus")),
subtitle = expression("Second line: "*italic("Honorificabilitudinitatibus praelongus")*" and more"))
p
If you wish the font size to be the same on both lines, set the desired size in theme.
p + theme(plot.title = element_text(size = 12),
plot.subtitle = element_text(size = 12))
Note that both title and subtitle are left-aligned by default in ggplot2 2.2.0. The text can be centered by adding hjust = 0.5 to element_text above.
We could also call cowplot::draw_label() two times (inspired from this discussion). However, we need to tweak a bit the position and make enough space for the custom title. I gave more explanations about this approach and also using ggplot2::annotation_custom() in ggplot2 two-line label with expression.
library(ggplot2)
library(cowplot)
#>
#> Attaching package: 'cowplot'
#> The following object is masked from 'package:ggplot2':
#>
#> ggsave
# The two lines we wish on the plot. The ~~ creates extra space between the
# expression's components, might be needed here.
line_1 <- expression("First Line of Title with" ~~ italic("Species"))
line_2 <- expression(italic("Species") ~~ "second line words" ~~ italic("anotherSpecies") ~~ "the end")
# Make enough space for the custom two lines title
p <- ggplot(mtcars, aes(x = wt, y = mpg)) +
geom_point() +
labs(title = "") + # empty title
# Force a wider top margin to make enough space
theme(plot.title = element_text(size = 10, # also adjust text size if needed
margin = margin(t = 10, r = 0, b = 0, l = 0,
unit = "mm")))
# Call cowplot::draw_label two times to plot the two lines of text
ggdraw(p) +
draw_label(line_1, x = 0.55, y = 0.97) +
draw_label(line_2, x = 0.55, y = 0.93)
Created on 2019-01-14 by the reprex package (v0.2.1)
Related
library(ggplot2)
my_title = "This is a really long title of a plot that I want to nicely wrap \n and fit onto the plot without having to manually add the backslash n, but at the moment it does not"
r <- ggplot(data = cars, aes(x = speed, y = dist))
r + geom_smooth() + #(left)
opts(title = my_title)
can I set the plot title to wrap around and shrink the text to fit the plot?
You have to manually choose the number of characters to wrap at, but the combination of strwrap and paste will do what you want.
wrapper <- function(x, ...)
{
paste(strwrap(x, ...), collapse = "\n")
}
my_title <- "This is a really long title of a plot that I want to nicely wrap and fit onto the plot without having to manually add the backslash n, but at the moment it does not"
r +
geom_smooth() +
ggtitle(wrapper(my_title, width = 20))
Just for an update as has been mentioned in the comments opts is deprecated. You need to use labs and you could do:
library(ggplot2)
my_title = "This is a really long title of a plot that I want to nicely wrap \n and fit onto the plot without having to manually add the backslash n, but at the moment it does not"
Option 1: Using str_wrap option from the stringr package and setting your ideal width:
library(stringr)
ggplot(data = cars, aes(x = speed, y = dist)) +
geom_smooth() +
labs(title = str_wrap(my_title, 60))
Option 2: Using the function provided by #Richie https://stackoverflow.com/a/3935429/4767610 like this:
wrapper <- function(x, ...)
{
paste(strwrap(x, ...), collapse = "\n")
}
ggplot(data = cars, aes(x = speed, y = dist)) +
geom_smooth() +
labs(title = wrapper(my_title, 60))
Option 3: Using the manual option (granted, this is what the OP wanted to avoid but it might be handy)
my_title_manual = "This is a really long title of a plot that I want to nicely wrap \n and fit onto the plot without having to manually add \n the backslash n, but at the moment it does not"
ggplot(data = cars, aes(x = speed, y = dist)) +
geom_smooth() +
labs(title = my_title_manual)
Option 4: Reduce the text size of the title (as in the accepted answer https://stackoverflow.com/a/2633773/4767610)
ggplot(data = cars, aes(x = speed, y = dist)) +
geom_smooth() +
labs(title = my_title) +
theme(plot.title = element_text(size = 10))
I do not think there is a text wrap option in ggplot2 (I have always just inserted \n manually). You can, however, shrink the size of the title's text by altering your code in the following way:
title.size<-10
r + geom_smooth() + opts(title = my_title,plot.title=theme_text(size=title.size))
In fact, you all aspects of text with the theme_text function.
I would like to put the following text behind the ggplot chart
And I thought it should be very easy to achieve. Unfortunately, all my attempts ended in a complete failure.
I have already read over a dozen posts on this forum that dealt with this topic. I have already made several dozen attempts and still do not manage to get the effect I expect.
By the way, I noticed a rather strange treatment of unicode symbols. Please compare the title and subtitle from the chart below.
library(tidyverse)
ggplot()+
labs(
title = expression("\u00AE \u00A9, \u00A2, \u00BC, \u00BD, \u00BE, \u00A5, \u00D8, \u00F8"),
subtitle = "\u00AE \u00A9, \u00A2, \u00BC, \u00BD, \u00BE, \u00A5, \u00D8, \u00F8"
)+
annotate(geom="text", label="\u00D828.15^{+0.15}", x=0, y=0.08,parse = TRUE, size=5)+
annotate(geom="text", label="\u00D8", x=0, y=0, size=5)+
annotate(geom="text", label="28.15^{+0.15}", x=0.03, y=0.001,parse = TRUE, size=5)+
xlim(c(-0.1, 0.1))+
ylim(c(-0.02, 0.1))+
theme_void()
Why do some unicode symbols lose some of their graphics when placed inside an expression function or when I use the parse option? This happens with the symbols ¢, ¥, ¼, ½, ¾, Ø. In my case, I particularly care about the symbol Ø. I finally got the effect on the track chart (annotation at the bottom of the chart) was created from the tedious setting of two annotations next to each other. However, it completely falls apart as soon as I change the size of the chart.
Does anyone know how this can be solved?
Thank you very much for your quick reply. Unfortunately, it still doesn't work for me! :-(
library(latex2exp)
library(ggplot2)
label <- TeX("$Ø28.15^{+0.15}$")
qplot(1, "A") +
annotate(geom = "text", label = label, x = 1, y = 1.1, size = 10) +
xlab(label)
You can use LaTeX syntax within a math ($) environment to auto-generate the plotmath expression:
library(latex2exp)
library(ggplot2)
label <- TeX("$Ø28.15^{+0.15}$")
label
#> expression(`$Ø28.15^{+0.15}$` = paste("", "Ø28", ".", "15",
#> phantom()^{
#> paste("+0", ".", "15")
#> }, ""))
qplot(1, "A") +
annotate(geom = "text", label = label, x = 1, y = 1.1, size = 10) +
xlab(label)
#> Warning in is.na(x): is.na() applied to non-(list or vector) of type
#> 'expression'
Created on 2021-10-18 by the reprex package (v2.0.1)
I know how to modify this solution above, maybe not so cute, but works everywhere
library(ggplot2)
label <- "\u00D828.15\U207A\u2070\U00B7\U00B9\u2075"
qplot(1, "A") +
annotate(geom = "text", label = label, x = 1, y = 1.1, size = 10) +
xlab(label)
I have created some awesome graphs that I want to export to my Word document. Yea, should write in Markdown but... you know... someday!
However, how do I resize the graphs to the right dimensions while labels stay "within" the perimeter? See the following examples (code is at the end of the document).
I want to insert the following graph into my word document:
Looks great! Not when I insert it into the document:
Labels are two tiny, and I would love to stretch it vertically, so the width is greater than the height. So I managed to produce this:
And this is were I am stuck. How do I keep the labels within the perimeters? And is there a better way to "fit" the word document than guessing correct dimensions?
Thanks!
This is the code:
library(ggplot2)
df <- mpg # Load sample data
# First test graph
ggplot(data = df, mapping = aes(cyl, hwy)) +
geom_smooth() +
geom_point() +
geom_point() +
labs(y = "This is just one very long label to prove a point ..... 1234",
x = "Cyl") +
theme_classic() +
theme(legend.title = element_blank())
ggsave("test1.png")
# Modified test graph to add fit the Word document
ggplot(data = df, mapping = aes(cyl, hwy)) +
geom_smooth() +
geom_point() +
geom_point() +
labs(y = "This is just one very long label to prove a point ..... 1234",
x = "Cyl") +
theme_classic(base_size = 12) + # SIZE CHANGED
theme(legend.title = element_blank())
ggsave("test2.png", width = 8, height = 4) # DIMENSIONS DEFINED
A solution I tend to use involves the officer package as mentioned above. This used to be able export graphs as vector objects to docx so you could change sizes and text in the graph when it's in the document. This seems to have been suspended in recent versions, but still works for powerpoint. The following code puts the graph as a grouped shape in a powerpoint slide where you can tweak it before copying into word:
library(ggplot2)
library(officer)
library(tidyverse)
df <- mpg # Load sample data
# First test graph
plot2 <- ggplot(data = df, mapping = aes(cyl, hwy)) +
geom_smooth() +
geom_point() +
geom_point() +
labs(y = "This is just one very long label to prove a point ..... 1234",
x = "Cyl") +
theme_classic(base_size = 12) + # SIZE CHANGED
theme(legend.title = element_blank())
pptx <- read_pptx()
pptx %>%
add_slide() %>%
# This first line puts it in as a static png image for comparison
ph_with(plot2, location = ph_location_type(type = "body")) %>%
add_slide() %>%
# This line puts in a shape object, which can be ungrouped and edited
ph_with(rvg::dml(ggobj = plot2),
width = 8,
height = 4,
location = ph_location_type(type = "body"))
#> pptx document with 2 slide(s)
print(pptx, "test_graph.pptx")
Created on 2020-12-08 by the reprex package (v0.3.0)
That's a sort of tweaky solution which at least allows you visual control over sizes. This used to be more easily provided through the export package (available on GitHub), but it's not on CRAN anymore and behind the scenes used the now defunct parts of officer to put vector graphics in docx documents.
Edit: See this issue on GitHub for an explanation of why vector graphics to docx is no longer an option through officer.
I'd like to write an axis label over two lines with an expression() statement. However, plotmath and expression won't allow this (e.g. subscripted text appears on the far right). I found this discussion circa 2005 of a similar issue but the work around that they offer doesn't translate to my application in ggplot2. A recent question addressed a different permutation of multi-line expression statements, but again the work around provided doesn't apply here.
Example:
p <- ggplot(mtcars,aes(x=wt,y=mpg))+
geom_point()+
xlab(expression(paste("A long string of text goes here just for the purpose \n of illustrating my point Weight "[reported])))
try(ggsave(plot=p,filename=<some file>,height=4,width=6))
yields an image where subscript "reported" is kicked out to the right when I'd like it to sit next to the previous word.
I think this is a bug. (Or a consequence of the fact that "multi-line expressions are not supported", as stated in the conversation you linked to).
The workaround that Gavin Simpson alluded to is:
#For convenience redefine p as the unlabeled plot
p <- ggplot(mtcars,aes(x=wt,y=mpg))+geom_point()
#Use atop to fake a line break
p + xlab(expression(atop("A long string of text for the purpose", paste("of illustrating my point" [reported]))))
It is possible to use true line breaks with subscripts. In the short example below, which has the same form as your example, the subscript is correctly placed adjacent to the rest of the text but the two lines of text are not centered correctly:
p + xlab(expression(paste("line1 \n line2 a" [b])))
I think that in both cases, the subscript is placed wrong when the upper line of text is longer than the lower line of text. Compare
p + xlab(expression(paste("abc \n abcd" [reported])))
p + xlab(expression(paste("abc \n ab" [reported])))
The subscript always ends up aligned just to the right of the right end of the upper line.
p + xlab(expression(paste("abcdefghijklmnop \n ab" [reported])))
1) Solution with cowplot::draw_label()
One could also use the annotation function draw_label() from the package cowplot (suggested in this discussion). We could call cowplot::draw_label() as many lines of text we have. When cowplot::draw_label() is used in combination with cowplot::ggdraw(), it can annotate anywhere on the canvas/sheet with the coordinates ranging from 0 to 1 (relative to the entire canvas).
One needs to tweak the annotation position and make enough space for the custom axis title.
Note that the cowplot package currently alters the default ggplot theme, therefore, if needed, use theme_set() after loading the package as mentioned here.
Note also that the function cowplot::draw_label() uses ggplot2::annotation_custom() under the hood. I'll mention more about this in the second part below.
library(ggplot2)
library(cowplot)
#>
#> Attaching package: 'cowplot'
#> The following object is masked from 'package:ggplot2':
#>
#> ggsave
# If needed, revert to default theme (cowplot modifies the theme);
# theme_set(theme_grey())
p <- ggplot(mtcars, aes(x = wt, y = mpg)) + geom_point()
# Make enough space for the custom two lines axis title
p <- p +
xlab("") + # empty label
# Tweak the margins (push the label down by forcing a wider top margin)
theme(axis.title.x = element_text(size = 10, # also adjust text size if needed
margin = margin(t = 10, r = 0, b = 0, l = 0,
unit = "mm")))
# The two lines we wish on the plot
line_1 <- "A long string of text for the purpose"
line_2 <- expression(paste("of illustrating my point" [reported]))
# Or avoid paste() (is not actually needed)
# line_2 <- expression("of illustrating my point" [reported])
# Call cowplot::draw_label two times to plot two lines of text
ggdraw(p) +
draw_label(line_1, x = 0.55, y = 0.075) + # use relative coordinates for positioning
draw_label(line_2, x = 0.55, y = 0.025)
Note that, cowplot::draw_label() can also be used in combination with setting the clipping off, coord_cartesian(clip = "off"), which allows plotting anywhere on the canvas. This time we do not use the relative coordinates anymore, but the ones from the plot/data (the absolute coordinates):
# Other two expressions
line_1b <- expression(bolditalic('First line'))
line_2b <- expression(integral(f(x)*dx, a, b))
p + coord_cartesian(clip = "off") + # allows plotting anywhere on the canvas
draw_label(line_1b, x = 3.5, y = 8.2) + # use absolute coordinates for positioning
draw_label(line_2b, x = 3.5, y = 6)
Created on 2019-01-14 by the reprex package (v0.2.1)
2) Solution with ggplot2::annotation_custom()
As mentioned, cowplot::draw_label() is a wrapper of ggplot2::annotation_custom(). So, instead of cowplot::draw_label(), we could use directly ggplot2::annotation_custom() in combination with setting the clipping off - coord_cartesian(clip = "off"), which became available with merging this pull request.
However, this approach is more verbose, with more coordinate arguments and we need to employ grid::textGrob().
# Some other two lines we wish on the plot as OX axis title
line_1c <- expression("Various fonts:" ~ bolditalic("bolditalic") ~ bold("bold") ~ italic("italic"))
line_2c <- expression("this" ~~ sqrt(x, y) ~~ "or this" ~~ sum(x[i], i==1, n) ~~ "math expression")
# the ~~ ads a bit more space than ~ between the expression's components
p + coord_cartesian(clip = "off") +
annotation_custom(grid::textGrob(line_1c), xmin = 3.5, xmax = 3.5, ymin = 7.3, ymax = 7.3) +
annotation_custom(grid::textGrob(line_2c), xmin = 3.5, xmax = 3.5, ymin = 5.5, ymax = 5.5)
Created on 2019-01-14 by the reprex package (v0.2.1)
The package ggtext offers a different option, by allowing for HTML tags to format/customise labels and text.
library(ggtext)
ggplot(mtcars, aes(wt, mpg)) +
geom_point() +
xlab("A long string of text goes here just for the purpose<br>of illustrating my point Weight<sub>reported</sub>") +
theme(axis.title.x = element_markdown())
You could use this trick,
library(gridExtra)
library(grid)
element_custom <- function() {
structure(list(), class = c("element_custom", "element_text"))
}
element_grob.element_custom <- function(element, label="", ...) {
mytheme <- ttheme_minimal(core = list(fg_params = list(parse=TRUE,
hjust=0, x=0.1)))
disect <- strsplit(label, "\\n")[[1]]
tableGrob(as.matrix(disect), theme=mytheme)
}
# default method is unreliable
heightDetails.gtable <- function(x) sum(x$heights)
ggplot(iris, aes(Sepal.Length, Sepal.Width)) +
geom_line() +
labs(x= "First~line \n italic('and a second') \n integral(f(x)*dx, a, b)")+
(theme_grey() %+replace% theme(axis.title.x = element_custom()))
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))