How to place legend inside caption area on R - r

I am using R studio / R Markdown to create plots, some with ggplot, some with base R function. I would like to insert a caption for each of my plots which contains the legend similar to the example shown here:
Can anyone suggest how to place the legend of my plots (built with ggplot and base R functions) within the caption as shown in this example?
I searched online and found out that it is possible to use something like:
p + labs(caption="Figure S1: This is the Figure Legend")
however, I could not find how to embed the legend into the caption, and I also could not find a solution for plots made using base R.
There are some solutions that require Latex, but I cannot use Latex for this project.

You could just push the legend to the bottom and add a custom title - inlcude a counter to get numbered Plots:
library(ggplot2)
# using the internal iris dataset
iris
# set counter to zero
NR <- 0
# Add counter and build plot
NR <- NR + 1
legend <- paste0("Fig. ", NR, ": This is a Plot about...:")
ggplot2::ggplot(iris, aes(Sepal.Length, Petal.Width, color = Species)) +
ggplot2::geom_point() +
ggplot2::labs(color= legend) +
ggplot2::theme(legend.position = "bottom")
# Add counter and build second plot
NR <- NR + 1
legend <- paste0("Fig. ", NR , ": This is a Plot about...:")
ggplot2::ggplot(iris, aes(Sepal.Width, Petal.Length, color = Species)) +
ggplot2::geom_point() +
ggplot2::labs(color= legend) +
ggplot2::theme(legend.position = "bottom")

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.

Multiple "Top" textGrob Titles

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:

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"))

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))

How can I use grid to edit a ggplot2 object to add math expressions to facet labels?

I need to put Greek letters into facet labels using facet_wrap() in ggplot2. I found a Link describing the same for facet_grid(). I applied this for my data, using the following code:
levels(parameters) <- c(expression(alpha), expression(beta))
p + facet_grid(.~parameters, labeller = label_parsed)
This works great and does exactly what I want. However, I need to use facet_wrap() instead (to get separate y-axes for both paramters, and also to plot even more parameters in different columns and rows). I tried the following:
p + facet_wrap(.~parameters, labeller = label_parsed) , or
p + facet_wrap(.~parameters)
but this didn't work because there is no "labeller" function in facet_wrap. How could this be done using grid?
This example should get you started:
library("ggplot2")
library("grid")
d <- ggplot(iris, aes(Sepal.Length, Sepal.Width)) +
geom_point() +
facet_wrap(~Species)
grob <- ggplotGrob(d)
strip_elem <- grid.ls(getGrob(grob, "strip.text.x", grep=TRUE, global=TRUE))$name
grob <- grid::editGrob(grob, strip_elem[1], label=expression(alpha[1]))
grob <- grid::editGrob(grob, strip_elem[2], label=expression(beta^2))
grob <- grid::editGrob(grob, strip_elem[3], label=expression(hat(gamma)))
grid.draw(grob)
Update: this works with ggplot2 version 0.9.3 (although using grid is a fragile way to modify ggplot2 graphics)
grob[["grobs"]][["strip_t.1"]][["children"]][[2]][["label"]] <- expression(alpha[1])
grob[["grobs"]][["strip_t.2"]][["children"]][[2]][["label"]] <- expression(beta^2)
grob[["grobs"]][["strip_t.3"]][["children"]][[2]][["label"]] <- expression(hat(gamma))
grid.draw(grob)
I tried it using the code below, and it works for me.
library("ggplot2")
library("grid")
## 1. Plot d and print d
d <- ggplot(iris, aes(Sepal.Length, Sepal.Width)) + geom_point() + facet_wrap(~Species)
d
## 2. Put Greek letters into facet labels using grid.edit function
grid.force()
grid.ls() #You should find the exact names for facet labels in the printed output!
grid.edit("GRID.text.77",label=expression(alpha[1])) #"GRID.text.77" = name for the first facet label
grid.edit("GRID.text.80",label=expression(beta^2)) #"GRID.text.80" = name for the second facet label
grid.edit("GRID.text.83",label=expression(hat(gamma))) #"GRID.text.83" = name for the third facet label

Resources