I have code that produces two separate ggplots and combines them into a single figure using gridExtra::grid.arrange.
I can save this combined figure as a PNG using ggsave(), but if I try to save it as an SVG file, I get only the second figure. How can I get both figures in one SVG file?
Edit:
This question goes beyond that addressed in How to save a plot made with ggplot2 as SVG. ggsave() for SVG works well for single images, but DOES NOT WORK with SVG for images composed with grid.arrange.
Here is the figure I'm trying to create. Code for this example is below.
library(ggplot2)
library(gridExtra)
data(EastIndiesTrade,package="GDAdata")
c1 <- ggplot(EastIndiesTrade, aes(x=Year, y=Exports)) +
ylim(0,2000) +
geom_line(colour="black", size=2) +
geom_line(aes(x=Year, y=Imports), colour="red", size=2) +
geom_ribbon(aes(ymin=Exports, ymax=Imports), fill="pink",alpha=0.5) +
ylab("Exports and Imports (millions of pounds)") +
annotate("text", x = 1710, y = 0, label = "Exports", size=5) +
annotate("text", x = 1770, y = 1620, label = "Imports", color="red", size=5) +
annotate("text", x = 1732, y = 1950, label = "Balance of Trade to the East Indies", color="black", size=6) +
theme_bw()
c2 <- ggplot(EastIndiesTrade, aes(x=Year,
y=Imports-Exports)) + geom_line(colour="blue", size=2) +
ylab("Balance = Imports - Exports (millions of pounds)") +
geom_ribbon(aes(ymin=Imports-Exports, ymax=0), fill="pink",alpha=0.5) +
annotate("text", x = 1711, y = 30, label = "Our Deficit", color="black", size=6) +
theme_bw()
grid.arrange(c1, c2, nrow=1)
Now, I try to save them with ggsave():
ggsave("east-indies-ggplot2.png", width=10, height=4) # OK
ggsave("east-indies-ggplot2.svg", width=10, height=4) # not OK -- only get the right panel
you probably can try to use patchwork package
https://patchwork.data-imaginist.com
instead of grid.arrange
Then you need to just use
c3=c1+c2
ggsave("~/Desktop/plotdm.svg")
This worked for me
Best
You can do this if you put the grid.arrange call into the ggsave function as follows:
ggsave("east-indies-ggplot2.svg", plot = grid.arrange(c1, c2, nrow=1), width=10, height=4)
It will call grid.arrange and simultaneously save the svg.
Related
I am trying to plot data using ggplot2 in R.
The datapoints occur for each 2^i-th x-value (4, 8, 16, 32,...). For that reason, I want to scale my x-Axis by log_2 so that my datapoints are spread out evenly. Currently most of the datapoints are clustered on the left side, making my plot hard to read (see first image).
I used the following command to get this image:
ggplot(summary, aes(x=xData, y=yData, colour=groups)) +
geom_errorbar(aes(ymin=yData-se, ymax=yData+se), width=2000, position=pd) +
geom_line(position=pd) +
geom_point(size=3, position=pd)
However trying to scale my x-axis with log2_trans yields the second image, which is not what I expected and does not follow my data.
Code used:
ggplot(summary, aes(x=settings.numPoints, y=benchmark.costs.average, colour=solver.name)) +
geom_errorbar(aes(ymin=benchmark.costs.average-se, ymax=benchmark.costs.average+se), width=2000, position=pd) +
geom_line(position=pd) +
geom_point(size=3, position=pd) +
scale_x_continuous(trans = log2_trans(),
breaks = trans_breaks("log2", function(x) 2^x),
labels = trans_format("log2", math_format(2^.x)))
Using scale_x_continuous(trans = log2_trans()) only doesn't help either.
EDIT:
Attached the data for reproducing the results:
https://pastebin.com/N1W0z11x
EDIT 2:
I have used the function pd <- position_dodge(1000) to avoid overlapping of my error bars, which caused the problem.
Removing the position=pd statements solved the issue
Here is a way you could format your x-axis:
# Generate dummy data
x <- 2^seq(1, 10)
df <- data.frame(
x = c(x, x, x),
y = c(0.5*x, x, 1.5*x),
z = rep(letters[seq_len(3)], each = length(x))
)
The plot of this would look like this:
ggplot(df, aes(x, y, colour = z)) +
geom_point() +
geom_line()
Adjusting the x-axis would work like so:
ggplot(df, aes(x, y, colour = z)) +
geom_point() +
geom_line() +
scale_x_continuous(
trans = "log2",
labels = scales::math_format(2^.x, format = log2)
)
The labels argument is just so you have labels in the format 2^x, you could change that to whatever you like.
I have used the function pd <- position_dodge(1000) to avoid overlapping of my error bars, which caused the problem.
Adjusting the amount of position dodge and the with of the error bars according to the new scaling solved the problem.
pd <- position_dodge(0.2) # move them .2 to the left and right
ggplot(summary, aes(x=settings.numPoints, y=benchmark.costs.average, colour=algorithm)) +
geom_errorbar(aes(ymin=benchmark.costs.average-se, ymax=benchmark.costs.average+se), width=0.4, position=pd) +
geom_line(position=pd) +
geom_point(size=3, position=pd) +
scale_x_continuous(
trans = "log2",
labels = scales::math_format(2^.x, format = log2)
)
Adding scale_y_continuous(trans="log2") yields the results I was looking for:
I have a Generalized Linear Model (GLM) that I'm plotting diagnostics for using the glm.diag.plots function in the MASS package. But it tends to plot rectangular instead of square, which is very ugly for publication.
Below is some sample code that shows the problem in an .Rmd file. In Rstudio, you can just drag the window around until it's square, but not possible in Rmarkdown documents, and I'd like to enforce square manually.
I checked in the ggplot documentation for ways to enforce square plotting, but could not find anything. glm.diag.plot() appears to use split.screen(), which doesn't provide any documentation for enforcing aspect ratios, either.
#rawr's comment is spot-on; this is a knitr/markdown issue, not glm.diag or ggplot or anything else. All you need to do is specify the desired height and width of the output (in inches, by default) using fig.width and fig.height.
It looks like you are using glm.diag.plots from package boot to acquire plots.
You could recreate them using ggplot if you wish. Here is an example:
some model:
data(anorexia, package = "MASS")
anorex.1 <- glm(Postwt ~ Prewt + Treat + offset(Prewt),
family = gaussian, data = anorexia)
the glm.diag.plots output
library(boot)
glm.diag.plots(anorex.1)
To create each plot in ggplot first get an object from glm.diag.plots
z <- glm.diag.plots(anorex.1, ret = T)
then plot each plot:
library(ggplot2)
plot1 <- ggplot(data.frame(x = predict(anorex.1),
y = z$res))+
geom_point(aes(x, y)) +
xlab("Linear predictor") +
ylab("Residuals") +
theme_bw()+
theme(aspect.ratio=1)
plot2 <- ggplot(data.frame(x = qnorm(ppoints(length(z$rd)))[rank(z$rd)],
y = z$rd)) +
geom_point(aes(x, y)) +
xlab("Ordered deviance residuals") +
ylab("Quantiles of standard normal") +
geom_abline(intercept = 0, slope = 1, lty =2) +
theme_bw()+
theme(aspect.ratio=1)
plot3 <- ggplot(data.frame(x = z$h/(1-z$h),
y = z$cook)) +
geom_point(aes(x, y)) +
xlab("h/(h-1)") +
ylab("Cook statistic") +
theme_bw()+
theme(aspect.ratio=1)
plot4 <- ggplot(data.frame(x = 1:length(z$cook),
y = z$cook)) +
geom_point(aes(x, y)) +
xlab("Case") +
ylab("Cook statistic") +
theme_bw()+
theme(aspect.ratio=1)
then combine them
library(cowplot)
plot_grid(plot1, plot2, plot3, plot4, ncol = 2)
Now you can customize each plot the way you wish.
I am trying to plot multiple lines with surrounding area, using ggplot2, with geom_ribbon for the are, and a centerline with geom_line. The values are overlapping, but I'd like each ribbon/line combination to be either bottom or top as a combination.
Here's a reproducible example:
library(ggplot2)
x <- 1:10
y <- c(1+x/100, 2-x, .1*x^2)
data <- data.frame(x=rep(x,3), y=y, lower=y-1, upper=y+1, color=rep(c('green', 'blue', 'yellow'), each=10))
In the example I can get the plot I want by using this code:
ggplot() +
geom_ribbon(data=data[data$color=='green',],aes(x=x, ymin=lower, ymax=upper, fill=paste0('light',color))) +
geom_line(data=data[data$color=='green',],aes(x=x, y=y, col=color)) +
geom_ribbon(data=data[data$color=='blue',],aes(x=x, ymin=lower, ymax=upper, fill=paste0('light',color))) +
geom_line(data=data[data$color=='blue',],aes(x=x, y=y, col=color)) +
geom_ribbon(data=data[data$color=='yellow',],aes(x=x, ymin=lower, ymax=upper, fill=paste0('light',color))) +
geom_line(data=data[data$color=='yellow',],aes(x=x, y=y, col=color)) +
scale_color_identity() +
scale_fill_identity()
But when I keep it simple and us this this code
plot <- ggplot(data=data) +
geom_ribbon(aes(x=x, ymin=lower, ymax=upper, fill=paste0('light',color))) +
geom_line(aes(x=x, y=y, col=color)) +
scale_color_identity() +
scale_fill_identity()
the lines of the background data go over the 'top' ribbons, or if I switch the geom_line and geom_ribbon, my middle-lines are no longer visible.
For this example, the lengthy call works, but in my real data, I have a lot more lines, and I'd like to be able to switch lines from background to foreground dynamically.
Is there any way that I can tell ggplot2 that there is an ordering that has to switch between my different geoms?
P.S. I can't post images yet, sorry if my question seems unclear.
You could save some typing with a loop
ggplot(data=data) +
purrr::map(.x = split(data, f = data$color),
.f = function(d){
list(geom_ribbon(data=d,aes(x=x, ymin=lower, ymax=upper), fill=paste0('light',unique(d$color))),
geom_line(data=d,aes(x=x, y=y), col=unique(d$color)))
})
I'm having issues with changing the size of the title, X-Y labels, X-Y axis text for my ggplot2. I'm using ggsave to save the plot as a jpg.
p <- ggplot()
p + theme(axis.title = element_text(size=30), axis.text.y = element_text(size=30),
axis.text.x = element_text(size=30))
but changing the sizes of these texts doesn't change anything on the plot. Would anyone know how to properly change the text sizes?
So I fixed the issue I was having so the changes I make to theme are not affecting the plot (I've tested with changing text color), however the size of the axis text still does not change.
p <- ggplot(d[d$user==i,], aes(x=date, y=url, group=user, label=user)) + geom_line() + geom_point() +
labs(list(title=i, x="Date and Time", y = "URL")) + # Plot labels
axis.POSIXct(1, at=seq(daterange[1], daterange[2], by="hour")) # Set x axis range to first and last date-time in data
p <- p + modifiedtheme
ggsave(plot = p, filename = "sample.jpg", height=2, width=6)
Here is a minimal, fully reproducible version of the problem (or lack of any problem, as comments have pointed out). Your own posted code appears to be correct, but maybe this example will help you solve whatever the real problem is:
library(ggplot2)
p1 = ggplot(iris, aes(x=Sepal.Length, y=Sepal.Width, colour=Species)) +
geom_point()
p2 = ggplot(iris, aes(x=Sepal.Length, y=Sepal.Width, colour=Species)) +
geom_point() +
theme(axis.title=element_text(size=30))
ggsave("figure1.jpg", plot=p1, height=3, width=4, units="in", dpi=150)
ggsave("figure2.jpg", plot=p2, height=3, width=4, units="in", dpi=150)
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))