I am trying to move subplots closer together with R.
What I am doing is basically not important, but just for the sake of fast reproducing, here is the code:
library(igraph)
library(plyr)
g<-graph.ring(10)
setEPS()
postscript( 'out.eps', horizontal=F, onefile=F, paper="special", fonts=c("serif", "Palatino"))
par( mfrow = c( 1, 5 ) )
for (i in 1:5){
plot(g)
title(main='title', cex.main=1.2)
}
dev.off()
and as an output I am getting:
I know that I can organize it in a 2x3 layout, not 1x5, but this is not important.
The thing is, that there is a lot of free space between each subplots, and I would like to place them as tight as possible.
Is there a way to achieve it?
P.S. this question sounds like relevant, but in fact it is not.
You just need to add:
par(mar = c(5,0,4,0))
to adjust the margins of each plot. There is another way of adjusting the margins by setting mai
What I usually do is use the omi ('c(bottom, left, top, right)') and plt ('c(x1, x2, y1, y2)') arguments in par. omi sizes the outer margins in inches and plt gives the coordinates of the plot region as a fraction of the figure region. Use ?par for a more detailed explanation and more arguments.
par(mfrow = c(2,3), omi=c(0.5,0.3,0,0), plt=c(0.1,0.9,0,0.7))
Related
I'm trying to plot half circles using R. My final aim is to draw a circle, divided in the middle by color. The only way I have found yet is to draw two half-circles with different colors.
So I have created my own functions:
upper.half.circle <- function(x,y,r,nsteps=100,...){
rs <- seq(0,pi,len=nsteps)
xc <- x+r*cos(rs)
yc <- y+r*sin(rs)
polygon(xc,yc,...)
}
lower.half.circle <- function(x,y,r,nsteps=100,...){
rs <- seq(0,pi,len=nsteps)
xc <- x-r*cos(rs)
yc <- y-r*sin(rs)
polygon(xc,yc,...)
}
However, for some reason my half-circles end up more like half-ellipses. For example, try running:
plot(1, type="n",axes=F,xlab="", ylab="",xlim=c(0,200),ylim=c(0,200))
upper.half.circle(15,170,10,nsteps=1000,col='red')
Does anyone know why I'm having this trouble, or alternatively, knows of a better way to do what I want?
Thanks!
The problem is the default aspect ratio is not 1:1.
To fix this, set asp=1 in plot:
Inspired by this Q & A. You could have sniffed out this was the case by turning on the axes and x/y labels.
If using the grid package would be also an opportunity for you, there is a much simpler solution:
library(grid)
vp <- viewport(width=0.5, height=0.5, clip = "on")
grid.circle(0.5,0,r=0.5, gp = gpar(fill = 'red'), vp = vp)
This creates a viewport with clipping, i.e., an appropriate positioning of the filled circle creates a half circle.
If you want to add your half circles to an existing plot (and therefore cannot control the aspect ratio directly) then one option for this specific case is to use the floating.pie function from the plotrix package.
A more general tool for creating custom symbols and adding them to plots (with the symbols having a different aspect ratio from the overall plot) is to use the my.symbols function from the TeachingDemos package.
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.
If I wanted to do this with the bars of the different calls to barplot(add=T) overlapping, that's fine and dandy. But say I want tthem to be plotted on the same plot, but with the first call having a ylim from 0:1 then the second call from 1:2 etc. I tried:
for(i in 1:length(files)) {
file <- as.matrix(read.table(files[i], header=F, sep=" ") )
if(i==1) barplot(file, beside=T, col=1:i, border=NA, ylim = c(0,length(files)))
if(i>1) barplot(file, beside=T, col=1:i, border=NA, ylim = c(i-1,i) ,xpd=T, add=T)
}
but that overlays them. How can I do it so that theyre on the same image but not overlapping if that makes sense. I envisage something like this http://img585.imageshack.us/img585/5439/romak13.png
If you're doing something like this, I'd recommend using ggplot2, as it's much easier.
Here's some sample code:
library(ggplot2)
data(diamonds)
ggplot(diamonds,aes(x=carat,y=price,fill=color))+
geom_histogram(stat='identity')+
facet_grid('cut~.',scale='free')+labs("Graph Title")
The output looks like this:
The interpretation of this particular graph is a bit strange, considering the nature of the data set, but if you follow the same format, you should be able to get a decent-looking graph. If anyone has any better data examples, let me know.
using xyplot from the lattice package, I plot a time series over a number of years. I would to add a shaded area for some of these years to indicate that this time period was "special" (e.g. war).
Please apologize if this is trivial, but I could not figure out how to do that, so I would be happy if someone could help me out, or at least point me in the right direction. I think my main problem is that I don't really know how to approach this problem. I am still relatively new to R, and to lattice in particular.
Here a minimal example:
xyplot( rnorm(100) ~ 1:100, type="l", col="black")
In the corresponding plot, I would like the color of the background (from say x-values of 45 until 65) from the bottom to the top of the plotting area be shaded in, say, light grey.
Note that solutions that I have found so far use base graphics and the polygon-function, but there the intention is to shade the area under or above a curve, which is different from what I would like to do. I don't "just" want to shade the area below my line, or above my line. Instead I would like to shade the entire background for a given time interval.
If anyone could help me out here, I would be very grateful!
See ?panel.xblocks in the latticeExtra package:
library(latticeExtra)
x <- 1:100
xyplot( rnorm(100) ~ x, type="l", col="black") +
layer_(panel.xblocks(x, x > 20, col = "lightgrey"))
Try this:
xyplot(
rnorm(100) ~ 1:100, type="l", col="black",
panel=function (x,y,...){
panel.rect(xleft=45, xright=65,ybottom=-3, ytop=3,col="grey")
panel.xyplot(x,y,...)
}
)
The panel.rect() function controls the rectangle and is the lattice equivalent of the rect() function. It has a variety of settings that you may find useful. It is called first and then the xyplot() is put on top of it. You many need to play around a little to get your ybottom and ytop parameters to look as you like them.
trellis.focus("panel", 1, 1)
grid.rect(x =.55, , y=.5, w = .2, height=6,
gp = gpar(fill = "light grey"))
trellis.unfocus()
This differs from #JohnPaul's solution in a couple of ways (and I think his answer is better). This uses the center of the desired X-band for placement in "native coordinates" and calculates the width as 'range(xlim)/range(band)' and it modifies an existing plot. the grid.rect function is the grid packages lower level function that is used by panel.rect. I sometimes find this useful when integrating lattice panels inside the xyplot system defeats me.
I want to plot a barplot of some data with some x-axis labels but so far I just keep running into the same problem, as the axis scaling is completely off limits and therefore my labels are wrongly positioned below the bars.
The most simple example I can think of:
x = c(1:81)
barplot(x)
axis(side=1,at=c(0,20,40,60,80),labels=c(20,40,60,80,100))
As you can see, the x-axis does not stretch along the whole plot but stops somewhere in between. It seems to me as if the problem is quite simple, but I somehow I am not able to fix it and I could not find any solution so far :(
Any help is greatly appreciated.
The problem is that barplot is really designed for plotting categorical, not numeric data, and as such it pretty much does its own thing in terms of setting up the horizontal axis scale. The main way to get around this is to recover the actual x-positions of the bar midpoints by saving the results of barplot to a variable, but as you can see below I haven't come up with an elegant way of doing what you want in base graphics. Maybe someone else can do better.
x = c(1:81)
b <- barplot(x)
## axis(side=1,at=c(0,20,40,60,80),labels=c(20,40,60,80,100))
head(b)
You can see here that the actual midpoint locations are 0.7, 1.9, 3.1, ... -- not 1, 2, 3 ...
This is pretty quick, if you don't want to extend the axis from 0 to 100:
b <- barplot(x)
axis(side=1,at=b[c(20,40,60,80)],labels=seq(20,80,by=20))
This is my best shot at doing it in base graphics:
b <- barplot(x,xlim=c(0,120))
bdiff <- diff(b)[1]
axis(side=1,at=c(b[1]-bdiff,b[c(20,40,60,80)],b[81]+19*bdiff),
labels=seq(0,100,by=20))
You can try this, but the bars aren't as pretty:
plot(x,type="h",lwd=4,col="gray",xlim=c(0,100))
Or in ggplot:
library(ggplot2)
d <- data.frame(x=1:81)
ggplot(d,aes(x=x,y=x))+geom_bar(stat="identity",fill="lightblue",
colour="gray")+xlim(c(0,100))
Most statistical graphics nerds will tell you that graphing quantitative (x,y) data is better done with points or lines rather than bars (non-data-ink, Tufte, blah blah blah :-) )
Not sure exactly what you wnat, but If it is to have the labels running from one end to the other evenly places (but not necessarily accurately), then:
x = c(1:81)
bp <- barplot(x)
axis(side=1,at=bp[1+c(0,20,40,60,80)],labels=c(20,40,60,80,100))
The puzzle for me was why you wanted to label "20" at 0. But this is one way to do it.
I run into the same annoying property of batplots - the x coordinates go wild. I would add one another way to show the problem, and that is adding more lines to the plot.
x = c(1:81)
barplot(x)
axis(side=1,at=c(0,20,40,60,80),labels=c(20,40,60,80,100))
lines(c(81,81), c(0, 100)) # this should cross the last bar, but it does not
The best I came with was to define a new barplot function that will take also the parameter "at" for plotting positions of the bars.
barplot_xscaled <- function(bar_heights, at = NA, width = 0.5, col = 'grey'){
if ( is.na(at) ){
at <- c(1:length(bar_heights))
}
plot(bar_heights, type="n", xlab="", ylab="",
ylim=c(0, max(bar_heights)), xlim=range(at), bty = 'n')
for ( i in 1:length(bar_heights)){
rect(at[i] - width, 0, at[i] + width, bar_heights[i], col = col)
}
}
barplot_xscaled(x)
lines(c(81, 81), c(0, 100))
The lines command crosses the last bar - the x scale works just as naively expected, but you could also now define whatever positions of the bars you would like (you could play more with the function a bit to have the same properties as other R plotting functions).