Related
While par() has been very useful in defining the number of plots in a single page, I was wondering if there would be a nice and quick trick to set the proper margins for multiplot pages. For instance,
dev.off()
par(mfrow =c(3,3),mar=c(0,0,0,0),pty="s")
x <- c(1:10)
y <- c(1:10)
for (i in 1:9){
plot(x,y)
}
In this rough example, the x and y labels don't appear and the distance between plots is very close.
In the end, it becomes a rule of thumb trying to fix with mar=c() that all elements of the plot are visually set in one page. So, is there any quicker way to determine the margins depending on the size of the labels, axes, and number of plots?
Thanks!
For educational purpose I'm trying to plot a singel horizontal "numberline" with some datapoints with labels in R. I came this far;
library(plotrix)
source("spread.labels.R")
plot(0:100,axes=FALSE,type="n",xlab="",ylab="")
axis(1,pos=0)
spread.labels(c(5,5,50,60,70,90),rep(0,6),ony=FALSE,
labels=c("5","5","50","60","70","90"),
offsets=rep(20,6))
This gave me a numberline with smaller lines pointing up to (and a little bit "in") the labels from where the datapoints should lie on the numberline - but without the points itself. Can anyone give me additional or alternative R-codes for solving thess problems:
- datapoints itself still missing are not plotted,
- and labels maybe not evenly divided over the whole numberline,
- and lines come into the labels and not merely point to the labels
Thank a lot,
Benjamin Telkamp
I usually like to create plots using primitive base R graphics functions, such as points(), segments(), lines(), abline(), rect(), polygon(), text(), and mtext(). You can easily create curves (e.g. for circles) and more complex shapes using segments() and lines() across granular coordinate vectors that you define yourself. For example, see Plot angle between vectors. This provides much more control over the plot elements you create, however, it often takes more work and careful coding than more "pre-packaged" solutions, so it's a tradeoff.
For your case, it sounds to me like you're happy with what spread.labels() is trying to do, you just want the following changes:
add point symbols at the labelled points.
prevent overlap between labels and lines.
Here's how this can be done:
## define plot data
xlim <- c(0,100);
ylim <- c(0,100);
px <- c(5,5,50,60,70,90);
py <- c(0,0,0,0,0,0);
lx.buf <- 5;
lx <- seq(xlim[1]+lx.buf,xlim[2]-lx.buf,len=length(px));
ly <- 20;
## create basic plot outline
par(xaxs='i',yaxs='i',mar=c(5,1,1,1));
plot(NA,xlim=xlim,ylim=ylim,axes=F,ann=F);
axis(1);
## plot elements
segments(px,py,lx,ly);
points(px,py,pch=16,xpd=NA);
text(lx,ly,px,pos=3);
I'm trying to create a scatter plot + linear regression line in R 3.0.3. I originally tried to create it with the following simple call to plot:
plot(hops$average.temperature, hops$percent.alpha.acids)
This created this first plot:
As you can see, the scales of the Y and X axes differ. I tried fixing this using the asp parameter, as follows:
plot(hops$average.temperature, hops$percent.alpha.acids, asp=1, xaxp=c(13,18,5))
This produced this second plot:
Unfortunately, setting asp to 1 appears to have compressed the X axis while using the same amount of space, leaving large areas of unused whitespace on either side of the data. I tried using xlim to constrain the size of the X-axis, but asp seemed to overrule it as it didn't have any effect on the plot.
plot(hops$average.temperature, hops$percent.alpha.acids, xlim=c(13,18), asp=1, xaxp=c(13,18,5))
Any suggestions as to how I could get the axes to be on the same scale without creating large amounts of whitespace?
Thanks!
One solution would be to use par parameter pty and set it to "s". See ?par:
pty
A character specifying the type of plot region to be used; "s"
generates a square plotting region and "m" generates the maximal
plotting region.
It forces the plot to be square (thus conteracting the side effect of asp).
hops <- data.frame(a=runif(100,13,18),b=runif(100,2,6))
par(pty="s")
plot(hops$a,hops$b,asp=1)
I agree with plannapus that the issue is with your plotting area. You can also fix this within the device size itself by ensuring that you plot to a square region. The example below opens a plotting device with square dimension; then the margins are also set to maintain these proportions:
Example:
n <- 20
x <- runif(n, 13, 18)
y <- runif(n, 2, 6)
png("plot.png", width=5, height=5, units="in", res=200)
par(mar=c(5,5,1,1))
plot(x, y, asp=1)
dev.off()
I've run a 2d simulation in some modelling software from which i've got an export of x,y point locations with a set of 6 attributes. I wish to recreate a figure that combines the data, like this:
The ellipses and the background are shaded according to attribute 1 (and the borders of these are of course representing the model geometry, but I don't think I can replicate that), the isolines are contours of attribute 2, and the arrow glyphs are from attributes 3 (x magnitude) and 4 (y magnitude).
The x,y points are centres of the triangulated mesh I think, and look like this:
I want to know how I can recreate a plot like this with R. To start with I have irregularly-spaced data due to it being exported from an irregular mesh. That's immediately where I get stuck with R, having only ever used it for producing box-and-whisper plots and the like.
Here's the data:
https://dl.dropbox.com/u/22417033/Ellipses_noheader.txt
Edit: fields: x, y, heat flux (x), heat flux (y), thermal conductivity, Temperature, gradT (x), gradT (y).
names(Ellipses) <- c('x','y','dfluxx','dfluxy','kxx','Temps','gradTx','gradTy')
It's quite easy to make the lower plot (making the assumption that there is a dataframe named 'edat' read in with:
edat <- read.table(file=file.choose())
with(edat, plot(V1,V2), cex=0.2)
Things get a bit more beautiful with:
with(edat, plot(V1,V2, cex=0.2, col=V5))
So I do not think your original is being faithfully represented by the data. The contour lines are NOT straight across the "conductors". I call them "conductors" because this looks somewhat like iso-potential lines in electrostatics. I'm adding some text here to serve as a search handle for others who might be searching for plotting problems in real world physics: vector-field (the arrows) , heat equations, gradient, potential lines.
You can then overlay the vector field with:
with(edat, arrows(V1,V2, V1-20*V6*V7, V2-20*V6*V8, length=0.04, col="orange") )
You could"zoom in" with xlim and ylim:
with(edat, plot(V1,V2, cex=0.3, col=V5, xlim=c(0, 10000), ylim=c(-8000, -2000) ))
with(edat, arrows(V1,V2, V1-20*V6*V7, V2-20*V6*V8, length=0.04, col="orange") )
Guessing that the contour requested if for the Temps variable. Take your pick of contourplots.
require(akima)
intflow<- with(edat, interp(x=x, y=y, z=Temps, xo=seq(min(x), max(x), length = 410),
yo=seq(min(y), max(y), length = 410), duplicate="mean", linear=FALSE) )
require(lattice)
contourplot(intflow$z)
filled.contour(intflow)
with( intflow, contour(x=x, y=y, z=z) )
The last one will mix with the other plotting examples since those were using base plotting functions. You may need to switch to points instead of plot.
There are several parts to your plot so you will probably need several tools to make the different parts.
The background and ellipses can be created with polygon (once you figure where they should be).
The contourLines function can calculate the contour lines for you which you can add with the lines function (or contour has and add argument and could probably be used to add the lines directly).
The akima package has a function interp which can estimate values on a grid given the values ungridded.
The my.symbols function along with ms.arrows, both from the TeachingDemos package, can be used to draw the vector field.
#DWin is right to say that your graph don't represent faithfully your data, so I would advice to follow his answer. However here is how to reproduce (the closest I could) your graph:
Ellipses <- read.table(file.choose())
names(Ellipses) <- c('x','y','dfluxx','dfluxy','kxx','Temps','gradTx','gradTy')
require(splancs)
require(akima)
First preparing the data:
#First the background layer (the 'kxx' layer):
# Here the regular grid on which we're gonna do the interpolation
E.grid <- with(Ellipses,
expand.grid(seq(min(x),max(x),length=200),
seq(min(y),max(y),length=200)))
names(E.grid) <- c("x","y") # Without this step, function inout throws an error
E.grid$Value <- rep(0,nrow(E.grid))
#Split the dataset according to unique values of kxx
E.k <- split(Ellipses,Ellipses$kxx)
# Find the convex hull delimiting each of those values domain
E.k.ch <- lapply(E.k,function(X){X[chull(X$x,X$y),]})
for(i in unique(Ellipses$kxx)){ # Pick the value for each coordinate in our regular grid
E.grid$Value[inout(E.grid[,1:2],E.k.ch[names(E.k.ch)==i][[1]],bound=TRUE)]<-i
}
# Then the regular grid for the second layer (Temp)
T.grid <- with(Ellipses,
interp(x,y,Temps, xo=seq(min(x),max(x),length=200),
yo=seq(min(y),max(y),length=200),
duplicate="mean", linear=FALSE))
# The regular grids for the arrow layer (gradT)
dx <- with(Ellipses,
interp(x,y,gradTx,xo=seq(min(x),max(x),length=15),
yo=seq(min(y),max(y),length=10),
duplicate="mean", linear=FALSE))
dy <- with(Ellipses,
interp(x,y,gradTy,xo=seq(min(x),max(x),length=15),
yo=seq(min(y),max(y),length=10),
duplicate="mean", linear=FALSE))
T.grid2 <- with(Ellipses,
interp(x,y,Temps, xo=seq(min(x),max(x),length=15),
yo=seq(min(y),max(y),length=10),
duplicate="mean", linear=FALSE))
gradTgrid<-expand.grid(dx$x,dx$y)
And then the plotting:
palette(grey(seq(0.5,0.9,length=5)))
par(mar=rep(0,4))
plot(E.grid$x, E.grid$y, col=E.grid$Value,
axes=F, xaxs="i", yaxs="i", pch=19)
contour(T.grid, add=TRUE, col=colorRampPalette(c("blue","red"))(15), drawlabels=FALSE)
arrows(gradTgrid[,1], gradTgrid[,2], # Here I multiply the values so you can see them
gradTgrid[,1]-dx$z*40*T.grid2$z, gradTgrid[,2]-dy$z*40*T.grid2$z,
col="yellow", length=0.05)
To understand in details how this code works, I advise you to read the following help pages: ?inout, ?chull, ?interp, ?expand.grid and ?contour.
The following code creates 3 vectors, and displays them as interlaced histograms:
a <- c(1,2,3)
b <- c(1,1,2)
c <- c(1,1,1)
l <- list(a,b,c)
multhist(l, col=c("red","green","blue"),xlim=c(0,5))
However, when I specify this xlim=c(0,5), I would expect this to set the x axis range, but it does not seem to do so. The x-axis appears to only range between about 1.0 and 1.4. Is there a different way to specify the x-axis range for a multhist?
Maybe not perfect, but a start:
edit: remove x-axis labels, add box
multhist(l, col=c("red","green","blue"),
breaks=seq(0,5,by=0.2),names.arg=rep("",25))
box(bty="l") ## add box around bottom and left edges
multhist is a bit of a hack (I know, I wrote it!) -- it uses barplot internally, so the x axis is indexing the positions of the bars rather than the actual values.
See also
http://www.math.mcmaster.ca/bolker/R/misc/multhist.pdf
http://www.math.mcmaster.ca/bolker/R/misc/multhist.Rnw
for some other ideas about how to display binned data from multiple groups.