R: making plot title align with str_wrap [duplicate] - r

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.

Related

Why doesn't gplot2::labs() overwrite/update the name argument of scales functions (i.e. ggplot2::scale_*_(name =))?

Context: sometimes I need to change only the labels of a plot (e.g. to change the language) but I do not want to make the whole plot again as the code might be very long in some cases.
Problem: they are at least two ways to define the aesthetics labels:
With the function ggpot2::labs(x = ..., y = ...) and,
With the name argument of the scales functions ggplots::scale_*_*(name = ...)
According to the example below, it seems that, for a plot p, p + labs() can overwrite labs defined with the labs() function but not labs defined with scale_*_*(name = ...).
Question: How to avoid this behavior? Is it a bug or am I doing something wrong?
Example:
This is working as intended:
library(ggplot2)
# This is working as expected
p1 <- ggplot(data = iris, aes(x = Sepal.Width, y = Petal.Width)) +
scale_x_continuous() +
scale_y_continuous() +
labs(x = "A name",
y = "Another name")
p1
# trying to change the labs without making the plot again
p1 + labs(
x = "The new x title",
y = "The new y title"
)
While this does not:
library(ggplot2)
# This is not working
p2 <- ggplot(data = iris, aes(x = Sepal.Width, y = Petal.Width)) +
scale_x_continuous(name = "A name") +
scale_y_continuous(name = "Another name")
p2
p2 + labs(
x = "The new x title",
y = "The nex y title"
)
This is just explaining what is happening. There are multiple ways to set labels in a plot, which take different priorities. Here are the priorities from highest to lowest.
(0. In some scale extensions, the make_title() method can be overwritten. This generally doesn't apply to the vast majority of scales though. I know of exactly 0 such scales, but it is a theoretical possibility.)
The guide title.
The scale name.
The labs() function.
The captured expression in aes().
Most of the disambiguation happens in this line of ggplot2 source code, where priorities 1-3 are resolved. What the labs() function in essence does is to override the automatically generated label from the captured expression, thereby giving (3) precedence over (4).
Try commenting out some parts of the plot below to double check yourself.
library(ggplot2)
df <- iris
names(df)[1] <- "Last Priority"
ggplot(df, aes(`Last Priority`, Sepal.Width)) +
scale_x_continuous(
name = "Second Priority",
guide = guide_axis(title = "First priority")
) +
labs(x = "Third Priority")
So your best bet to override the title for the x-axis is to use:
plot + guides(x = guide_axis(title = "My new title"))
Since the axis guide is typically guide_axis() or guide_none(), you have a decent chance of this working most of the time (except when the plot doesn't have an axis). Moreover, if you have a function generating a plot with a predefined scale for x, this should be fine (unless they set specific options in the guide).

unable to wrap text in y axis title on R Shiny using ggplot

I'm trying to plot a graph in r shiny, where the values for x-axis and y-axis come from dropdown.
On y-axis, the title is very huge and i need to wrap it. But none of the wrap function is working.
y-axis title = thistextisnumerator/thistextisdenominator, this needs to displayed, but i'm unable to wrap it
**Possible y-axis titles:**
y-axis title = this text is very very long
y-axis title = this text is very long (and very large) hence going outside the plot
code:
ggplot(data=fin, aes(x = color_var, y = ratio,fill=color_var))+
geom_boxplot()+
geom_point(aes(text = paste0(paste0("number: ",number),
paste0("<br>",isolate(input$Y),": ",round(ratio,2))))) +
theme_grey(base_size=10)+
ylim(min(fin$ratio),max(fin$ratio))+
labs(title =paste0("Box Plot ",' '),y=(paste0(isolate(input$X)," / ",isolate(input$Y))),x=x_value) +
theme(axis.text.y = element_text(size=1),axis.title.y = element_text(size=1)) +
guides(fill=guide_legend(title=x_value_legend))
You did not provide any data to help us help you so I'm building a dummy graph with the database mtcars. Let's see if this helps you:
#building dummy graph p
library(ggplot2)
p <- ggplot(mtcars,aes(x=wt,y=mpg))+geom_point()
Now insofar as you seem to want your text in a mathematical annotation, I'd suggest to use the function expression():
p + labs(y = expression(frac("thistextisnumerator", "thistextisdenominator")))
Which will result into the following graph:
If you do not want the line, you can use either one of the following codes:
p + labs(y = expression(atop("thistextisnumerator", "thistextisdenominator")))
p + labs(y = expression(over("thistextisnumerator", "thistextisdenominator")))
Or even easier:
p + labs(y = paste0("thistextisnumerator", "\n", "thistextisdenominator"))
Where \n is the character for line break.

Multi line title in ggplot 2 with multiple italicized words

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)

facet_wrap Title wrapping & Decimal places on free_y axis (ggplot2)

I have a set of code that produces multiple plots using facet_wrap:
ggplot(summ,aes(x=depth,y=expr,colour=bank,group=bank)) +
geom_errorbar(aes(ymin=expr-se,ymax=expr+se),lwd=0.4,width=0.3,position=pd) +
geom_line(aes(group=bank,linetype=bank),position=pd) +
geom_point(aes(group=bank,pch=bank),position=pd,size=2.5) +
scale_colour_manual(values=c("coral","cyan3", "blue")) +
facet_wrap(~gene,scales="free_y") +
theme_bw()
With the reference datasets, this code produces figures like this:
I am trying to accomplish two goals here:
Keep the auto scaling of the y axis, but make sure only 1 decimal place is displayed across all the plots. I have tried creating a new column of the rounded expr values, but it causes the error bars to not line up properly.
I would like to wrap the titles. I have tried changing the font size as in Change plot title sizes in a facet_wrap multiplot, but some of the gene names are too long and will end up being too small to read if I cram them on a single line. Is there a way to wrap the text, using code within the facet_wrap statement?
Probably cannot serve as definite answer, but here are some pointers regarding your questions:
Formatting the y-axis scale labels.
First, let's try the direct solution using format function. Here we format all y-axis scale labels to have 1 decimal value, after rounding it with round.
formatter <- function(...){
function(x) format(round(x, 1), ...)
}
mtcars2 <- mtcars
sp <- ggplot(mtcars2, aes(x = mpg, y = qsec)) + geom_point() + facet_wrap(~cyl, scales = "free_y")
sp <- sp + scale_y_continuous(labels = formatter(nsmall = 1))
The issue is, sometimes this approach is not practical. Take the leftmost plot from your figure, for example. Using the same formatting, all y-axis scale labels would be rounded up to -0.3, which is not preferable.
The other solution is to modify the breaks for each plot into a set of rounded values. But again, taking the leftmost plot of your figure as an example, it'll end up with just one label point, -0.3
Yet another solution is to format the labels into scientific form. For simplicity, you can modify the formatter function as follow:
formatter <- function(...){
function(x) format(x, ..., scientific = T, digit = 2)
}
Now you can have a uniform format for all of plots' y-axis. My suggestion, though, is to set the label with 2 decimal places after rounding.
Wrap facet titles
This can be done using labeller argument in facet_wrap.
# Modify cyl into factors
mtcars2$cyl <- c("Four Cylinder", "Six Cylinder", "Eight Cylinder")[match(mtcars2$cyl, c(4,6,8))]
# Redraw the graph
sp <- ggplot(mtcars2, aes(x = mpg, y = qsec)) + geom_point() +
facet_wrap(~cyl, scales = "free_y", labeller = labeller(cyl = label_wrap_gen(width = 10)))
sp <- sp + scale_y_continuous(labels = formatter(nsmall = 2))
It must be noted that the wrap function detects space to separate labels into lines. So, in your case, you might need to modify your variables.
This only solved the first part of the question. You can create a function to format your axis and use scale_y_continous to adjust it.
df <- data.frame(x=rnorm(11), y1=seq(2, 3, 0.1) + 10, y2=rnorm(11))
library(ggplot2)
library(reshape2)
df <- melt(df, 'x')
# Before
ggplot(df, aes(x=x, y=value)) + geom_point() +
facet_wrap(~ variable, scale="free")
# label function
f <- function(x){
format(round(x, 1), nsmall=1)
}
# After
ggplot(df, aes(x=x, y=value)) + geom_point() +
facet_wrap(~ variable, scale="free") +
scale_y_continuous(labels=f)
scale_*_continuous(..., labels = function(x) sprintf("%0.0f", x)) worked in my case.

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