When using the pdf() function in R for saving a plot in an external file, we can specify width and/or height to adjust the size of the plot. However, there are situations when we obtain multiple plot (say using par(mfrow=c(2,4))). In this situation, it's kind of difficult to determine what is the best width and height for the PDF file in order to have all plots displayed properly. Is there a way to let R automatically "fit the plots" in the PDF file? I searched the arguments in pdf() and tried some, but the results are not satisfactory. Thank you very much!
How about something using ggplot?
require(ggplot2)
# Bogus data
x <- rnorm(10000)
y <- as.factor(round(rnorm(10000, mean=10, sd=2), 0))
df <- data.frame(vals=x, factors=y)
myplot <- ggplot(data=df, aes(x=vals)) +
geom_density() +
facet_wrap(~ factors)
ggsave(filename="~/foo.pdf", plot=myplot, width=8, height=10, units="in")
EDIT: Should you need to print over multiple pages, see this question.
Related
I have two graphs that I plotted in R and I want to export it as a high-resolution picture for publication.
For example:
a<-c(1,2,3,4,5,6,7)
b<-c(2,3,4,6,7,8,9)
par(mfrow=c(2,1))
plot (a,b)
plot(a,b)
I usually export this graph by:
dev.copy(jpeg,'test.jpeg',width=80,height=150,units="mm",res=200)
dev.off()
However I always find this process a bit troublesome. The graph that was plotted in R does not necessarily look like the one that I exported. Therefore, I am wondering if there is a way to specifiy the dimensions and resolution of graphs before I plot them so that I can visually inspect the graphs before I export them?
Thank you
You can try:
png('out.png')
a<-c(1,2,3,4,5,6,7)
b<-c(2,3,4,6,7,8,9)
par(mfrow=c(2,1))
plot (a,b)
plot(a,b)
dev.off()
As baptiste said, jpeg is the worst format you can choose. You should take a look at the help for the bmp and png functions (with ?bmp and ?png). Both bmp and png have height, width, and res arguments that you can use to specifiy the dimensions and resolution of the output. Also, I wouldn't recommend the use of dev.copy. As you could see, the result of the output is not always what you expect.
To add to Bonifacio2's answer, you if you call the function first to make the plot, you can also define your margins and window size etc before doing any actual plotting. That way you have full control over all fig specs.
pdf(file='test.jpeg',width=80,height=150,units="mm") #I prefer pdf, because they are editable files
a<-c(1,2,3,4,5,6,7)
b<-c(2,3,4,6,7,8,9)
par(mfrow=c(2,1))
plot (a,b)
plot(a,b)
dev.off()
You can use cowplot package to combine multiple panels in several different ways. For example, in your case, we export one plot with two panels arranged in two rows and one column. I assume that you prefer to use base-R 'plot' function instead of ggplot.
library(cowplot)
p1 <- ~{
plot(a,b)
}
p2 <- ~{
plot(b,a)
}
png("plot.png",
width = 3.149606, # 80 mm
height = 5.905512, # 150 mm
units = 'in',
res = 500)
plot_grid(p1, p2, labels = "AUTO", nrow = 2, ncol = 1)
dev.off()
Note that you can either remove the labels if not needed or print small letters by using "auto". Regarding size of the text, axis-labels etc, use the standard arguments for generic plot function of base-R. I hope this answer helps you. Best wishes.
I'd like to save a histogram as .pdf but when I do it not all x-axis labels are visible. Is it there a way to automatically adjust the size of the plot so that all labels fit nicely and can be read? Thanks a lot in advance for your help!!
# Example data
dd <- iris
dd$Species <- as.character(dd$Species)
dd$Species[dd$Species=="setosa"] <- "setosa and more text that should also fit in the pdf"
dd$Species[dd$Species=="versicolor"] <- "versicolor and more text that should also fit in the pdf"
dd$Species[dd$Species=="virginica"] <- "virginica and more text that should also fit in the pdf"
dd$Species <- as.factor(dd$Species)
# Plotting & saving as .pdf
windows()
plot(dd$Species)
dev.copy(pdf, file="%/test.pdf") # % is the directory in my computer
dev.off()
If the problem is you need give more information on each label with more text, you can use next line
dd <- iris
dd$Species <- as.character(dd$Species)
dd$Species[dd$Species=="setosa"] <- "setosa is the name \n of iris-more text"
dd$Species[dd$Species=="versicolor"] <- "versicolor is the name \n of iris-more text "
dd$Species[dd$Species=="virginica"] <- "virginica is the name \n of iris-more text"
dd$Species <- as.factor(dd$Species)
plot(dd$Species)
When you print to pdf, what matters is the size of the pdf rather than the plot, for the labels to fit. In other words if you use
pdf("filename.pdf", width = W)
plot(dd$Species)
dev.off()
and the width parameter W is large enough, you should get a pdf in which the bars are wide enough so that all labels are visible.
This, however, may not be aesthetically pleasing, in which case you may want to try using ggplot2. This will enable you to play around with the labels more easily. For example, you can rotate all labels by an angle so that they all fit nicely
library(ggplot2)
ggplot(dd, aes(Species)) +
theme(axis.text.x = element_text(angle = 90)) +
geom_bar()
ggsave("filename.pdf")
You can also adjust the size of the font of the labels, or use a legend (which may be a neater way of listing all your labels in order, if there are too many - you can also colour each label differently if you use fill = Species in aes). You can find out how to set these parameters by typing ?theme, and ggplot2 also has excellent documentation with lots of examples at http://docs.ggplot2.org.
The R package wordcloud has a very useful function which is called wordlayout. It takes initial positions of words and their respective sizes an rearranges them in a way that they do not overlap. I would like to use the results of this functions to do a geom_text plot in ggplot.
I came up with the following example but soon realized that there seems to be a big difference betweetn cex (wordlayout) and size (geom_plot) since words in graphics package appear way larger.
here is my sample code. Plot 1 is the original wordcloud plot which has no overlaps:
library(wordcloud)
library(tm)
library(ggplot2)
samplesize=100
textdf <- data.frame(label=sample(stopwords("en"),samplesize,replace=TRUE),x=sample(c(1:1000),samplesize,replace=TRUE),y=sample(c(1:1000),samplesize,replace=TRUE),size=sample(c(1:5),samplesize,replace=TRUE))
#plot1
plot.new()
pdf(file="plot1.pdf")
textplot(textdf$x,textdf$y,textdf$label,textdf$size)
dev.off()
#plot2
ggplot(textdf,aes(x,y))+geom_text(aes(label = label, size = size))
ggsave("plot2.pdf")
#plot3
new_pos <- wordlayout(x=textdf$x,y=textdf$y,words=textdf$label,cex=textdf$size)
textdf$x <- new_pos[,1]
textdf$y <- new_pos[,2]
ggplot(textdf,aes(x,y))+geom_text(aes(label = label, size = size))
ggsave("plot3.pdf")
#plot4
textdf$x <- new_pos[,1]+0.5*new_pos[,3]#this is the way the wordcloud package rearranges the positions. I took this out of the textplot function
textdf$y <- new_pos[,2]+0.5*new_pos[,4]
ggplot(textdf,aes(x,y))+geom_text(aes(label = label, size = size))
ggsave("plot4.pdf")
is there a way to overcome this cex/size difference and reuse wordlayout for ggplots?
cex stands for character expansion and is the factor by which text is magnified relative the default, specified by cin - set on my installation to 0.15 in by 0.2 in: see ?par for more details.
#hadley explains that ggplot2 sizes are measured in mm. Therefore cex=1 would correspond to size=3.81 or size=5.08 depending on if it is being scaled by the width or height. Of course, font selection may cause differences.
In addition, to use absolute sizes, you need to have the size specification outside the aes otherwise it considers it a variable to map to and choose the scale itself, eg:
ggplot(textdf,aes(x,y))+geom_text(aes(label = label),size = textdf$size*3.81)
Sadly I think you're going to find the short answer is no! I think the package handles the text vector mapping differently from ggplot2, so you can tinker with size and font face/family, etc. but will struggle to replicate exactly what the package is doing.
I tried a few things:
1) Try to plot the grobs from textdata using annotation_custom
require(plyr)
require(grid)
# FIRST TRY PLOT INDIVIDUAL TEXT GROBS
qplot(0:1000,0:1000,geom="blank") +
alply(textdf,1,function(x){
annotation_custom(textGrob(label=x$label,0,0,c("center","center"),gp=gpar(cex=x$size)),x$x,x$x,x$y,x$y)
})
2) Run the wordlayout() function which should readjust the text, but difficult to see for what font (similarly doesn't work)
# THEN USE wordcloud() TO GET CO-ORDS
plot.new()
wordlayout(textdf$x,textdf$y,words=textdf$label,cex=textdf$size,xlim=c(min(textdf$x),max(textdf$x)),ylim=c(min(textdf$y),max(textdf$y)))
plotdata<-cbind(data.frame(rownames(w)),w)
colnames(plotdata)=c("word","x","y","w","h")
# PLOT WORDCLOUD DATA
qplot(0:1000,0:1000,geom="blank") +
alply(plotdata,1,function(x){
annotation_custom(textGrob(label=x$word,0,0,c("center","center"),gp=gpar(cex=x$h*40)),x$x,x$x,x$y,x$y)
})
Here's a cheat if you just want to overplot other ggplot functions on top of it (although the co-ords don't seem to match up exactly between the data and the plot). It basically images the wordcloud, removes the margins, and under-plots it at the same scale:
# make a png file of just the panel
plot.new()
png(filename="bgplot.png")
par(mar=c(0.01,0.01,0.01,0.01))
textplot(textdf$x,textdf$y,textdf$label,textdf$size,xaxt="n",yaxt="n",xlab="",ylab="",asp=1)
dev.off()
# library to get PNG file
require(png)
# then plot it behind the panel
qplot(0:1000,0:1000,geom="blank") +
annotation_custom(rasterGrob(readPNG("bgplot.png"),0,0,1,1,just=c("left","bottom")),0,1000,0,1000) +
coord_fixed(1,c(0,1000),c(0,1000))
I want to create a single pdf file and put several plots in it using package ggplot2. However I need to reduce the width of one specific plot, among all. Here is the code:
invisible(pdf("foo.pdf"))
foo <- data.frame(x=rnorm(100), y=rnorm(100), class=factor(sample(2,1000,T)))
ggplot(foo, aes(x=x,y=y))+geom_point() # first plot
# For next plot I want to reduce the width
ggplot(foo, aes(x=class,y=y)) + geom_boxplot()
invisible(dev.off())
How to do it?
You can print in a viewport smaller than the full page,
library(grid)
grid.rect(width=unit(0.8, "npc"), gp=gpar(lty=2))
print(qplot(1,1), vp=viewport(width=unit(0.8, "npc")))
I wanted to ask for any general idea about plotting this kind of plot in R which can compare for example the overlaps of different methods listed on the horizontal and vertical side of the plot? Any sample code or something
Many thanks
A ggplot2-example:
# data generation
df <- matrix(runif(25), nrow = 5)
# bring data to long format
require(reshape2)
dfm <- melt(df)
# plot
require(ggplot2)
ggplot(dfm, aes(x = Var1, y = Var2)) +
geom_tile(aes(fill = value)) +
geom_text(aes(label = round(value, 2)))
The corrplot package and corrplot function in that package will create plots similar to what you show above, that may do what you want or give you a starting point.
If you want more control then you could plot the colors using the image function, then use the text function to add the numbers. You can either create the margins large enough to place the text in the margins, see the axis function for the common way to add text labels in the margin. Or you could leave enough space internally (maybe use rasterImage instead of image) and use text to do the labelling. Look at the xpd argument to par if you want to add the lines and the grconvertX and grconvertY functions to help with the coordinates of the line segents.