comfortable way to use unicode characters in a ggplot graph - r

Is there a good practice to insert unicode characters in a ggplot title and also save it as pdf?
I am struggling with expression, paste and sprintf to get a nice title...
So, what works is
ggtitle(expression(paste('5', mu, 'g')))
This will print an ugly greek mu. By ugly I mean a different font, but overall, it will be printed as pdf without problems. But the problems start, if you want to have new lines in the title. Or maybe I didn't found a solution for this.
My preferred solution would be to use sprintf with the unicode number, so for example
ggtitle(sprintf('5\u03BCg'))
It shows a nice result on the screen but it is not possible to save as pdf with ggsave. PNG works fine, but I would like to use the pdf save option.
Is there a possibility to plot the unicode characters with ggsave? I read about the cairo_pdf device, but this messes up the fonts and I can not save the plot properly.
Thanks in advance for any help.
EDIT:
Example PDF
I just uploaded an example PDF... So maybe my problem is somewhere else...

Try
library(ggplot2)
p <- ggplot(df, aes(x=date, y=value))
p <- p + geom_line()
p + ggtitle(sprintf('5\u03BCg'))
library(Cairo)
ggsave("newfile.pdf", device=cairo_pdf)
data
set.seed(42)
df <- data.frame(date = 1:10 , value = cumsum(runif(10 , max = 10)) )

Using the emojifont package fixes this issue for me.
library(emojifont)

I am sharing the tricks to have Unicode characters properly displayed on PDF files. I am currently running R-4.0.5 for Windows.
library(ggplot2)
library(gridExtra)
library(grid)
library(png)
#--- The trick to get unicode characters being printed on pdf files:
#--- 1. Create a temporary file, say "temp.png"
#--- 2. Create the pdf file using pdf() or cairo_pdf(), say "UnicodeToPDF.pdf"
#--- 3. Combine the use of grid.arrange (from gridExtra), rasterGrob (from grid), and readPNG (from png) to insert the
# temp.png file into the UnicodeToPDF.pdf file
test.plot = ggplot() +
geom_point(data = data.frame(x=1, y=1), aes(x,y), shape = "\u2191", size=3.5) +
geom_point(data = data.frame(x=2, y=2), aes(x,y), shape = "\u2020", size=3.5) +
geom_point(data = data.frame(x=1.2, y=1.2), aes(x,y), shape = -10122, size=3.5, color="#FF7F00") +
geom_point(data = data.frame(x=1.4, y=1.4), aes(x,y), shape = -129322, size=3.5, color="#FB9A99") +
geom_point(data = data.frame(x=1.7, y=1.7), aes(x,y), shape = -128515, size=5, color="#1F78B4") +
ggtitle(sprintf('5\u03BCg'))
ggsave("temp.png", plot = test.plot, width = 80, height = 80, units = "mm")
#--- Refer to http://xahlee.info/comp/unicode_index.html to see more unicode character integers
pdf("UnicodeToPDF.pdf")
grid.arrange(
rasterGrob(
readPNG(
"temp.png",
native=F
)
)
)
dev.off()
file.remove("temp.png")

Related

Best way to export ggplot2 graphs to a Word document?

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.

What's the expression for partial derivative in ggplot()?

Is it possible to get the partial derivative symbol via expression() in ggplot2, e.g. to be used in axis labels?
I am talking about this symbol, often also refered to as 'del' or 'curly d': https://en.wikipedia.org/wiki/%E2%88%82
It has unicode number U+2202, but when I try to include it in ggplot, it fails:
a <- b <- rnorm(100)
plot.df <- data.frame(a,b)
ggplot(plot.df,aes(a,b)) +
geom_point() +
xlab(expression('\u2202'))
For comparison, using e.g. the plus/minus sign with unicode number U+00B1 works fine:
ggplot(plot.df,aes(a,b)) +
geom_point() +
xlab(expression('\u00b1'))
you can achieve this using the keyword partialdiff. using your example:
ggplot(plot.df,aes(a,b)) +
geom_point() +
xlab(expression(paste(partialdiff,"y","/",partialdiff,"x")))
This link provides some good reference on the matter.
Depending how far you want to go. You can eventually use TikzDevice library to save the plot directly as a tex.file. It might take longer to compile the graph but I find it more flexible.
library(tikzDevice)
tikz("/tmp/test.tex",standAlone = TRUE)
ggplot(plot.df,aes(a,b)) +
geom_point() +
xlab("$\\frac{\\partial{y}}{\\partial{x}}$")
dev.off()
With the ggtext package you can use HTML entities:
library(ggplot2)
library(ggtext)
a <- b <- rnorm(100)
plot.df <- data.frame(a,b)
ggplot(plot.df, aes(a,b)) +
geom_point() +
xlab("∂") +
theme(axis.title.x = element_markdown(size = 20))

tableGrob: resizing a table (changing font size) drawn on top of ggplot using annotation_custom

I'm having some issues resizing the text in a table drawn over a plot using tableGrob() and annotation_custom(). Essentially, I want the font size in the table to be smaller so that the overall table is smaller. I've checked the tableGrob() documentation and have followed it to the best of my ability, but I must be doing something wrong as it's throwing an error.
Here's a reproducible example:
library(ggplot2)
library(grid)
library(gridExtra)
df <- data.frame(x=seq(1,10),y=seq(11,20))
table <- data.frame(x=seq(1,3),y=seq(4,6))
ggplot(df,aes(x=x,y=y)) + geom_point() +
annotation_custom(tableGrob(table,rows=NULL),xmin=0,xmax=3,ymin=15,ymax=20) # plot drawn successfully without text resizing
ggplot(df,aes(x=x,y=y)) + geom_point() +
annotation_custom(tableGrob(table,rows=NULL,gpar.coretext = gpar(col = "black", cex = 0.8)),xmin=0,xmax=3,ymin=15,ymax=20)
# error when attempting to resize text following tableGrob documentation
This is the error I get when I run the second ggplot() command:
Error in gtable_table(d, name = "core", fg_fun = theme$core$fg_fun, bg_fun = theme$core$bg_fun, :
unused argument (gpar.coretext = list(col = "black", cex = 0.8))
Any help is much appreciated!
If you just want all the text to be smaller in your table, use base_size in ttheme_default:
library(ggplot2)
library(grid)
library(gridExtra)
df <- data.frame(x=seq(1,10),y=seq(11,20))
table <- data.frame(x=seq(1,3),y=seq(4,6))
ggplot(df,aes(x=x,y=y)) +
geom_point() +
annotation_custom(tableGrob(table,rows=NULL, theme = ttheme_default(base_size = 8)),
xmin=0,xmax=3,ymin=15,ymax=20)
Created on 2020-03-05 by the reprex package (v0.3.0)

Create A Custom Static Label Above Legend in R with GGPlot

I have found a lot of information regarding either changing a ggplot label or adding text to the plot itself. However, I want to add text above the legend. We currently use Python to do some data manipulation and then plot it using R. Our python file outputs the data needed by the plot as well as another text file containing the settings. I want to add these settings to the plot, preferably in a box above the legend. I am confident that I can figure out how to input the text file with the settings so I need to know is how to add, for example, "Settings Test" above the legend. We are using ggplot and I have no issue either changing the legend text or adding text to the plot area (the grey area) but I have not been able to find much on adding custom static text above the legend.
Thank you.
Here is an image that I reference
Here is the code that I have tried as suggested but the output graph did not change.
p <- ggplot(MAE_AUC, aes(x=mae, y=auc, color=file), environment()) + geom_point(
aes(size=count))
p2 <- p + geom_smooth(method=lm, fullrange=TRUE) +
theme(panel.background=element_rect(fill='white', colour='black')) +
theme(panel.grid.major=element_blank(), panel.grid.minor=element_blank()) +
scale_colour_discrete(label=filenames)
p2$labels$fill
p2 + labs(fill=paste("StackOverflow", p2$labels$fill, sep="\n"))
Here's one way to do this - basically just concatenating the contents of from labels$fill -- look at str(p) for more information.
library(ggplot2)
p <- ggplot(PlantGrowth, aes(x=group, y=weight, fill=group)) + geom_boxplot()
p$labels$fill
# [1] "group"
# If you just want to change the label to "test"
# p +
# labs(fill = "test")
p +
labs(fill = paste("StackOverflow", p$labels$fill, sep = "\n"))
Or you could make this more dynamic with:
my_static_label <- c("StackOverflow")
p +
labs(fill = paste(my_static_label, p$labels$fill, sep = "\n"))

Formatting output with Knitr, ggplot2 and xtable

I am trying to achieve the following task with Knitr, ggplot2 and xtables:
Generate several annotated plots of beta-distributions with ggplot2
Write the output in a layout such that I have a plot, and a corresponding summary Stats table following it, for every plot.
Write the code such that both PDF and HTML reports can be a generated in a presentable way
Here is my attempt at this task (Rnw file):
\documentclass{article}
\begin{document}
Test for ggplot2 with Knitr
<<Initialize, echo=FALSE>>=
library(ggplot2)
library(ggthemes)
library(data.table)
library(grid)
library(xtable)
library (plyr)
pltlist <- list()
statlist <- list()
#
The libraries are loaded. Now run the main loop
<<plotloop, echo=FALSE>>=
for (k in seq(1,7)){
x <- data.table(rbeta(100000,1.6,14+k))
xmean <- mean(x$V1, na.rm=T)
xqtl <- quantile(x$V1, probs = c(0.995), names=F)
xdiff <- xqtl - xmean
dens <- density(x$V1)
xscale <- (max(dens$x, na.rm=T) - min(dens$x, na.rm=T))/100
yscale <- (max(dens$y, na.rm=T))/100
y_max <- max(dens$y, na.rm=T)
y_intercept <- y_max-(10*yscale)
data <- data.frame(x)
y <- ggplot(data, aes(x=V1)) + geom_density(colour="darkgreen", size=2, fill="green",alpha=.3) +
geom_vline(xintercept = xmean, colour="blue", linetype = "longdash") +
geom_vline(xintercept = xqtl, colour="red", linetype = "longdash") +
geom_segment(aes(x=xmean, xend=xqtl, y=y_intercept, yend=y_intercept), colour="red", linetype = "solid", arrow = arrow(length = unit(0.2, "cm"), ends = "both", type = "closed")) +
annotate("text", x = xmean+xscale, y = y_max, label = paste("Val1:",round(xmean,4)), hjust=0) +
annotate("text", x = xqtl+xscale, y = y_max, label = paste("Val2:",round(xqtl,4))) +
annotate("text", x = xmean+10*xscale, y = y_max-15*yscale, label = paste("Val3:",round(xdiff,4))) +
xlim(min(dens$x, na.rm=T), xqtl + 9*xscale) +
xlab("Values") +
ggtitle("Beta Distribution") +
theme_bw() +
theme(plot.title = element_text(hjust = 0, vjust=2))
pltlist[[k]] <- y
statlist[[k]] <- list(mean=xmean, quantile=xqtl)
}
stats <- ldply(statlist, data.frame)
#
Plots are ready. Now Plot them
<<PrintPlots, warning=FALSE, results='asis', echo=FALSE, cache=TRUE, fig.height=3.5>>=
for (k in seq(1,7)){
print(pltlist[[k]])
print(xtable(stats[k,], caption="Summary Statistics", digits=6))
}
#
Plotting Finished.
\end{document}
I am faced with several issues after running this code.
When I run this code just as R code, Once I try to print the plots in the list, the horizontal line from the geom_segment part starts to move all over the place. However if I plot the figures individually, without putting them in a list, the figures are fine, as I would expect them to be.
Only the last plot is as I would expect the output to be, in all the other plots, the geom_segment line moves around randomly.
I am also unable to put a separate caption for the Plots as I can for the Tables.
Points to note :
I am storing the beta-random numbers in data.table since in our actual code, we are using data.table. However for the purposes of testing ggplot2 in this way, I convert the data.table into a data.frame, as ggplot2 requires.
I also need to generate the random numbers within the loop and generate the plots per iteration (so something like first generating the random numbers and then using melt would not work here), since generating the random numbers is emulating a complex database call per iteration of the loop.
I am using RStudio Version 0.98.1091 and
R version 3.1.2 (2014-10-31) on Windows 8.1
This is the expected Plot:
This is the plot I am getting when plotting from the list:
My output in PDF form :
PDF Output
Please advice if there are any ideas for solutions.
Thank you,
SG
I don't know why the horizontal line in geom_segment is "moving around" from plot to plot, rather than spanning xmean to xqtl. However, I was able to get the horizontal line in the correct location by getting the value from the stats data frame, rather than from direct calculation of the mean and quantile. You just have to create the stats data frame before the loop, rather than after, so that you can use it in the loop.
stats <- ldply(statlist, data.frame)
for (k in seq(1,7)){
...
y <- ggplot(data, aes(x=V1)) +
...
geom_segment(aes(x=stats[k,1], xend=stats[k,2], y=y_intercept, yend=y_intercept),
colour="red", linetype = "solid",
arrow = arrow(length = unit(0.2, "cm"), ends = "both", type = "closed")) +
...
pltlist[[k]] <- y
statlist[[k]] <- list(mean=xmean, quantile=xqtl)
}
Hopefully, someone else will be able to explain the anomalous behavior, but at least this seems to fix the problem.
For the figure caption, you can add a fig.cap argument to the chunk where you plot the figures, although this results in the same caption for each figure and causes the figures and tables to be plotted in separate groups, rather than interleaved:
<<PrintPlots, warning=FALSE, results='asis', echo=FALSE, cache=TRUE, fig.cap="Caption", fig.height=3.5>>=
for (k in seq(1,7)){
print(pltlist[[k]])
print(xtable(stats[k,], caption="Summary Statistics", digits=6))
}
You might want to use R Markdown and knitr which is easier than using LaTeX and R (as also zhaoy suggested).
You might also want to check out the ReporteRs package. I think it is actually easier to use than knitr. However, you cannot generate PDFs with it. But you can use pandoc to convert them into PDFs.

Resources