Automatic line break in ggtitle - r

Is there a way to force an automatic line break in the ggtitle command?
As part of a shiny application I use different plots with an input variable for the title.
Unfortunately, some of these variable values are too long to be displayed.
I came across one possibility by inserting \n (or a line break) manually in advance (Details here: Improve editing of multiline title in ggplot that uses \n and extends far to the right). There, something like ggtitle(paste("", title, "", sep = "\n")) would be suggested.
Since including \n would be error prone as well as not flexible for different plot sizes I´m looking for another possibility.
Here is an minimal working example (adapted from lawyeR question linked above):
DF <- data.frame(x = rnorm(400))
title_example <- "This is a very long title describing the plot in its details. The title should be fitted to a graph, which is itself not restricted by its size."
plot <- ggplot(DF, aes(x = x)) + geom_histogram() +
ggtitle(title_example)
You can find a image here: https://i.stack.imgur.com/6MMKF.jpg
Do you have an idea how to e.g. adapt the sep = operator to break lines automatically or are there maybe packages/ workarounds? Thanks!

The ggtext package's text elements could help solve this. element_textbox_simple() automatically wraps the text inside. Try resizing the graphics device window, it adapts!
library(ggplot2)
library(ggtext)
DF <- data.frame(x = rnorm(400))
title_example <- "This is a very long title describing the plot in its details. The title should be fitted to a graph, which is itself not restricted by its size."
ggplot(DF, aes(x = x)) + geom_histogram() +
ggtitle(title_example) +
theme(plot.title = element_textbox_simple())
#> `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

Related

Custom colors in ggplot2 subtitle feat. crayon and glue

I'd like to create a subtitle with a few custom colored words in ggplot2. We can use crayon::make_style, glue::glue, and glue::glue_col to make this happen in the console (see below). However, when implementing in the graphics device, the color doesn't render. I looked through the source code for a hint but failed to find one. Any thoughts?
library(glue)
library(crayon)
library(tidyverse)
# create data frame
myDat <- tibble(alpha = rnorm(50),
omega = runif(50))
# use crayon to create our custom colors
slate_g <- crayon::make_style("slategrey")
light_s <- make_style("lightsalmon")
# create custom subtitle NOTE it prints cleanly in the console
cust_subt <- glue("
{str_wrap(\"It is a wonder that this subtitle is so dangerously long. Good thing we can wrap it in glue.\", 75)}
Really makes me wonder
{glue_col(\'{bold({slate_g(\"NEVER\")})} vs. {bold({light_s(\"ENOUGH\")})}\')}
")
Here is how the cust_subt object prints in the console.
Once we try to plot, though, it fails.
# custom subtitle DOES NOT work in subtitle
ggplot(myDat, aes(alpha, omega)) +
geom_point() +
labs(subtitle = cust_subt)
#### regular glue works just fine though
cust_subt_no_col <- glue("
{str_wrap(\"It is a wonder that this subtitle is so dangerously long. Good thing we can wrap it in glue.\", 75)}
Really makes me wonder
")
ggplot(myDat, aes(alpha, omega)) +
geom_point() +
labs(subtitle = cust_subt_no_col)

Adding greek character and asterisk (*) to axis title

I want to add a greek character to the x-axis of my histogram plot in R.
I can write the greek character alone or with the hat, but the problem is that I need this character to be come with a hat and asterisk () together. More specifically, I want the something like hat(phi^). Here is what I have done:
x = rnorm(1000)
hist( x, nclass = 100, cex.lab=1.5, xlab = expression(hat(phi^*)),
ylab="Frequency", main="", cex.axis=1.5 )
Thanks.
What about using ggplot2 instead of base R. You can then use latex2exp::TeX to use (some) LaTeX expressions in the axes labels.
set.seed(2018)
x = rnorm(1000)
library(ggplot2)
library(latex2exp)
ggplot(data.frame(x = x), aes(x)) +
geom_histogram(bins = 100) +
theme_minimal() +
xlab(TeX("$\\widehat{\\phi^*}$"))
You need to escape the backslashes with an extra backslash and wrap math expressions inside $ delimiters (just as in regular LaTeX inline math). I used \widehat{}, but you can also use hat{} instead.
Here is the best looking solution that I found:
hist( x, nclass = 100, cex.lab=1.5, xlab = expression(hat(phi)~"*"),
ylab="Frequency", main="", cex.axis=1.5 )
To get the star under the hat, I don't know of any nice looking solution with base plot functions. I think #Maurits Evers' method is the best compromise between complexity and prettiness of the result.
But here is anyway a more "advanced" (and maybe a little bit over the top, but well...) solution. It is based on this blog post: http://iltabiai.github.io/tips/latex/2015/09/15/latex-tikzdevice-r.html
To make it work, you will need to install the tikzDevice package.
First, load the packages and create the data-set.
library(tikzDevice)
library(ggplot2)
dat <- data.frame(x = rnorm(1000))
Then create a TeX file that will contain the "translation" of your R plot in "tikz" language.
tikz(file = "plot_test.tex", width = 5, height = 5, standAlone = TRUE)
ggplot(dat, aes(x = x)) +
geom_histogram(color="white") + theme_bw() +
labs( x = "$\\widehat{\\phi^*}$")
dev.off()
Then, you can either directly copy or call the LaTeX code into your own LaTeX document (then the standAlone=TRUE argument is not necessary), or you can use these two very useful function to generate a pdf version and see the result.
tools::texi2dvi("plot_test.tex", pdf=TRUE)
system(paste(getOption('pdfviewer'), "plot_test.pdf"))

Automatically adjust plot title width using ggplot

I am fairly new to R/ggplot2 and still learning on the go. Hopefully I am not missing something obvious!
I am trying to create several different plots using ggplot2 that I am layouting using the function plot_grid from the cowplot package to make the plots visible side by side and add plot numeration and captions. The problem is that if the generated plots are displayed in a small window or I have many plots beside one another then the titles of the two plots sometimes overlap. To solve this problem I tried to automatically insert line breaks in my too long titles using code I found in another thread since I wanted the text size of the titles to stay constant.
Using the following code I can easily automatically insert the necessary line breaks to make my title a specific width, but the problem is that I always need to enter a numeric value for the width. Depending on the number of plots I am inserting this value would of course change. I could of course go through my code and manually set the width for each set of plots until it is the correct value, but I was hoping to automate this process so that the title width is adjusted automatically to match the width of the x-axis. Is there anyway to implement this in R?
#automatically line break and add titles
myplot_theme1 = function (plot, x.title = NULL, y.title = NULL, plot.title = NULL) {
plot +
labs(title = paste(strwrap(plot.title, width = 50), collapse = "\n"),
x = x.title,
y = y.title)
}
# generate an example plot
data_plot <- data.frame(x = rnorm(1000), y = rnorm (1000))
plot1 <- ggplot(data_plot, aes(x = x, y = y)) + geom_point()
title <- "This is a title that is very long and does not display nicely"
myplot_theme1(plot1, plot.title = title)
My test plot
I have tried searching but I haven't found any solutions that seem to address what I am looking for. The only solution I did find that looked promising was based on the package gridDebug. This packages doesn't seem to be supported by my operating system anymore though (macOS Sierra Version 10.12.6) since when I try to install it I get the following error message:
Warning in install.packages: dependencies ‘graph’, ‘Rgraphviz’ are not available
And on the CRAN package documentation it states that the package is not even available for macOS El Capitan which was my previous operating system. If someone knows what is causing this issue so that I could try the solution from the above thread that would of course be great as well.
One idea (but perhaps not an ideal solution) is to adjust the size of text based on the number of characters in the title. You can adjust ggplot properties using theme and in this case you want to adjust plot.title (the theme property, not your variable). plot.title has elements size and horizontal justification hjust, the latter is in range [0,1].
# generate an example plot
data_plot <- data.frame(x = rnorm(1000), y = rnorm (1000))
plot1 <- ggplot(data_plot, aes(x = x, y = y)) + geom_point()
title1 <- "This is a title that is very long and does not display nicely"
title2 <- "I'm an even longer sentence just test me out and see if I display the way you want or you'll be sorry"
myplot_theme1 = function (plot, x.title = NULL, y.title = NULL, plot.title = NULL) {
plot +
labs(title = plot.title,
x = x.title,
y = y.title) +
theme(plot.title = element_text(size=800/nchar(plot.title), hjust=0.5)) # 800 is arbitrarily chosen
}
myplot_theme1(plot1, plot.title = title1)
myplot_theme1(plot1, plot.title = title2)

Ggplot does not show plots in sourced function

I've been trying to draw two plots using R's ggplot library in RStudio. Problem is, when I draw two within one function, only the last one displays (in RStudio's "plots" view) and the first one disappears. Even worse, when I run ggsave() after each plot - which saves them to a file - neither of them appear (but the files save as expected). However, I want to view what I've saved in the plots as I was able to before.
Is there a way I can both display what I'll be plotting in RStudio's plots view and also save them? Moreover, when the plots are not being saved, why does the display problem happen when there's more than one plot? (i.e. why does it show the last one but not the ones before?)
The code with the plotting parts are below. I've removed some parts because they seem unnecessary (but can add them if they are indeed relevant).
HHIplot = ggplot(pergame)
# some ggplot geoms and misc. here
ggsave(paste("HHI Index of all games,",year,"Finals.png"),
path = plotpath, width = 6, height = 4)
HHIAvePlot = ggplot(AveHHI, aes(x = AveHHI$n_brokers))
# some ggplot geoms and misc. here
ggsave(paste("Average HHI Index of all games,",year,"Finals.png"),
path = plotpath, width = 6, height = 4)
I've already taken a look here and here but neither have helped. Adding a print(HHIplot) or print(HHIAvePlot) after the ggsave() lines has not displayed the plot.
Many thanks in advance.
Update 1: The solution suggested below didn't work, although it works for the answer's sample code. I passed the ggplot objects to .Globalenv and print() gives me an empty gray box on the plot area (which I imagine is an empty ggplot object with no layers). I think the issue might lie in some of the layers or manipulators I have used, so I've brought the full code for one ggplot object below. Any thoughts? (Note: I've tried putting the assign() line in all possible locations in relation to ggsave() and ggplot().)
HHIplot = ggplot(pergame)
HHIplot +
geom_point(aes(x = pergame$n_brokers, y = pergame$HHI)) +
scale_y_continuous(limits = c(0,10000)) +
scale_x_discrete(breaks = gameSizes) +
labs(title = paste("HHI Index of all games,",year,"Finals"),
x = "Game Size", y = "Herfindahl-Hirschman Index") +
theme(text = element_text(size=15),axis.text.x = element_text(angle = 0, hjust = 1))
assign("HHIplot",HHIplot, envir = .GlobalEnv)
ggsave(paste("HHI Index of all games,",year,"Finals.png"),
path = plotpath, width = 6, height = 4)
I'll preface this by saying that the following is bad practice. It's considered bad practice to break a programming language's scoping rules for something as trivial as this, but here's how it's done anyway.
So within the body of your function you'll create both plots and put them into variables. Then you'll use ggsave() to write them out. Finally, you'll use assign() to push the variables to the global scope.
library(ggplot2)
myFun <- function() {
#some sample data that you should be passing into the function via arguments
df <- data.frame(x=1:10, y1=1:10, y2=10:1)
p1 <- ggplot(df, aes(x=x, y=y1))+geom_point()
p2 <- ggplot(df, aes(x=x, y=y2))+geom_point()
ggsave('p1.jpg', p1)
ggsave('p2.jpg', p2)
assign('p1', p1, envir=.GlobalEnv)
assign('p2', p2, envir=.GlobalEnv)
return()
}
Now, when you run myFun() it will write out your two plots to .jpg files, and also drop the plots into your global environment so that you can just run p1 or p2 on the console and they'll appear in RStudio's Plot pane.
ONCE AGAIN, THIS IS BAD PRACTICE
Good practice would be to not worry about the fact that they're not popping up in RStudio. They wrote out to files, and you know they did, so go look at them there.

Combining `expression()` with `\n`

I have a ggplot where I have used expression(phantom(x) >=80) in the label text to get a proper greater-than-or-equal symbol.
However I also need to have (N=...) immediately underneath:
require(ggplot2)
.d <- data.frame(a = letters[1:6], y = 1:6)
labs <- c("0-9\n(N=10)","10-29\n(N=10)","30-49\n(N=10)", +
"50-64\n(N=10)","65-79\n(N=10)", expression(phantom(x) >=80))
ggplot(.d, aes(x=a,y=y)) + geom_point() +
scale_x_discrete(labels = labs)
How can I combine the expression() with the escape \n ?
As #otsaw said in his answer to your earlier question, plotmath (and therefore expression) doesn't allow linebreaks.
However, as a hack, you can use atop to let ≥80 appears on top of (N=10). But as you will soon see it doesn't match with the other labels:
labs <- c("0-9\n(N=10)","10-29\n(N=10)","30-49\n(N=10)",
"50-64\n(N=10)","65-79\n(N=10)",
expression(atop(phantom(x) >=80, (N==10))))
So, as a further hack, you can pass the other labels as expressions:
labs <- c(expression(atop(0-9,(N==10))),expression(atop(10-29,(N==10))),
expression(atop(30-49,(N==10))), expression(atop(50-64,(N==10))),
expression(atop(65-79,(N==10))), expression(atop(phantom(x) >=80, (N==10))))
But of course you have #otsaw solution (using Unicode) that is considerably less wordy:
labs <- c("0-9\n(N=10)","10-29\n(N=10)","30-49\n(N=10)",
"50-64\n(N=10)","65-79\n(N=10)",
"\u2265 80\n(N=10)")
Another approach would be to use the recently archived tikzDevice. This creates the plots as tikz which are latex friendly format.
This will allow you to pass any latex expression as a character string to your labels.
It has the added benefit that you can compile the documents with the same preamble as your whole document so that the fonts etc are consistent.
All this can be automated using knitr using opts_chunk$set(dev = 'tikz')

Resources