How can I build with two different y axes?

I would like to overlay two scatterplots in R, so each set of points has its own (different) y axis (i.e., at positions 2 and 4 in the figure), but the points appear superimposed on the same figure.

Is it possible to do this with plot ?

Change Sample Code Showing Problem

 # example code for SO question y1 <- rnorm(10, 100, 20) y2 <- rnorm(10, 1, 1) x <- 1:10 # in this plot y2 is plotted on what is clearly an inappropriate scale plot(y1 ~ x, ylim = c(-1, 150)) points(y2 ~ x, pch = 2) 
+81
r plot
May 26 '11 at 17:53
source share
6 answers

update : copied material that was on the R wiki at http://rwiki.sciviews.org/doku.php?id=tips:graphics-base:2yaxes , the link is now broken: also accessible from the return path machine

Two different y axes in the same section

(some material originally Daniel Rydle 2006/03/31 15:26)

Please note that there are very few situations where it is advisable to use two different scales on the same site. It is very easy to mislead the viewer. Check out the following two examples and comments on this issue ( example1 , example2 from Unch Charts ), as well as in this article by Stephen Fuer (which concludes: “I certainly can’t conclude once and for all that double-scaled graphs will never useful, only I can’t come up with a situation that justifies them in the light of other best solutions. ") Also see point 4 in this cartoon ...

If you decide, the main recipe is to create your first graph, set par(new=TRUE) so that R doesn't clear the graphics device, create a second graph with axes=FALSE (and set xlab and ylab to be blank - ann=FALSE should also work), and then use axis(side=4) add a new axis to the right and mtext(...,side=4) to add an axis label to the right. Here is an example that uses some collected data:

 set.seed(101) x <- 1:10 y <- rnorm(10) ## second data set on a very different scale z <- runif(10, min=1000, max=10000) par(mar = c(5, 4, 4, 4) + 0.3) # Leave space for z axis plot(x, y) # first plot par(new = TRUE) plot(x, z, type = "l", axes = FALSE, bty = "n", xlab = "", ylab = "") axis(side=4, at = pretty(range(z))) mtext("z", side=4, line=3) 

twoord.plot() in the plotrix package automates this process, like doubleYScale() in the latticeExtra package.

Another example (adapted from Robert W. Baer’s mailing list R):

 ## set up some fake test data time <- seq(0,72,12) betagal.abs <- c(0.05,0.18,0.25,0.31,0.32,0.34,0.35) cell.density <- c(0,1000,2000,3000,4000,5000,6000) ## add extra space to right margin of plot within frame par(mar=c(5, 4, 4, 6) + 0.1) ## Plot first set of data and draw its axis plot(time, betagal.abs, pch=16, axes=FALSE, ylim=c(0,1), xlab="", ylab="", type="b",col="black", main="Mike test data") axis(2, ylim=c(0,1),col="black",las=1) ## las=1 makes horizontal labels mtext("Beta Gal Absorbance",side=2,line=2.5) box() ## Allow a second plot on the same graph par(new=TRUE) ## Plot the second plot and put axis scale on right plot(time, cell.density, pch=15, xlab="", ylab="", ylim=c(0,7000), axes=FALSE, type="b", col="red") ## a little farther out (line=4) to make room for labels mtext("Cell Density",side=4,col="red",line=4) axis(4, ylim=c(0,7000), col="red",col.axis="red",las=1) ## Draw the time axis axis(1,pretty(range(time),10)) mtext("Time (Hours)",side=1,col="black",line=2.5) ## Add Legend legend("topleft",legend=c("Beta Gal","Cell Density"), text.col=c("black","red"),pch=c(16,15),col=c("black","red")) 

enter image description here

Similar recipes can be used for overlaying charts of different types - bar charts, histograms, etc.

+78
May 26 '11 at 18:20
source share

As the name suggests, twoord.plot() in plotrix sections with two ordinate axes.

 library(plotrix) example(twoord.plot) 

enter image description here

enter image description here

enter image description here

enter image description here

enter image description here

+29
May 26 '11 at 18:15
source share

One option is to make two graphs side by side. ggplot2 provides a good option for this with facet_wrap() :

 dat <- data.frame(x = c(rnorm(100), rnorm(100, 10, 2)) , y = c(rnorm(100), rlnorm(100, 9, 2)) , index = rep(1:2, each = 100) ) require(ggplot2) ggplot(dat, aes(x,y)) + geom_point() + facet_wrap(~ index, scales = "free_y") 
+5
May 26 '11 at 18:00
source share

This is a FAQ. Here is one older solution that I provided almost six years ago to the R chart gallery

You can look, for example. in the plotVolumeBars() function, which combines absolute and relative scale in one diagram.

+4
May 26 '11 at 17:59
source share

If you can opt out of scale / axis labels, you can scale the data to a (0, 1) interval. This works, for example, for different “wiggle” paths on chromosomes, when you are usually interested in local correlations between tracks, and they have different scales (coverage in thousands, Fst 0-1).

 # rescale numeric vector into (0, 1) interval # clip everything outside the range rescale <- function(vec, lims=range(vec), clip=c(0, 1)) { # find the coeficients of transforming linear equation # that maps the lims range to (0, 1) slope <- (1 - 0) / (lims[2] - lims[1]) intercept <- - slope * lims[1] xformed <- slope * vec + intercept # do the clipping xformed[xformed < 0] <- clip[1] xformed[xformed > 1] <- clip[2] xformed } 

Then, having a data frame with the chrom , position , coverage and fst , you can do something like:

 ggplot(d, aes(position)) + geom_line(aes(y = rescale(fst))) + geom_line(aes(y = rescale(coverage))) + facet_wrap(~chrom) 

The advantage is that you are not limited to two tracks.

+2
Apr 2 '15 at 20:15
source share

I also suggest twoord.stackplot() in plotrix graphics packages with a large number of two ordinate axes.

 data<-read.table(text= "e0AL fxAL e0CO fxCO e0BR fxBR anos 51.8 5.9 50.6 6.8 51.0 6.2 1955 54.7 5.9 55.2 6.8 53.5 6.2 1960 57.1 6.0 57.9 6.8 55.9 6.2 1965 59.1 5.6 60.1 6.2 57.9 5.4 1970 61.2 5.1 61.8 5.0 59.8 4.7 1975 63.4 4.5 64.0 4.3 61.8 4.3 1980 65.4 3.9 66.9 3.7 63.5 3.8 1985 67.3 3.4 68.0 3.2 65.5 3.1 1990 69.1 3.0 68.7 3.0 67.5 2.6 1995 70.9 2.8 70.3 2.8 69.5 2.5 2000 72.4 2.5 71.7 2.6 71.1 2.3 2005 73.3 2.3 72.9 2.5 72.1 1.9 2010 74.3 2.2 73.8 2.4 73.2 1.8 2015 75.2 2.0 74.6 2.3 74.2 1.7 2020 76.0 2.0 75.4 2.2 75.2 1.6 2025 76.8 1.9 76.2 2.1 76.1 1.6 2030 77.6 1.9 76.9 2.1 77.1 1.6 2035 78.4 1.9 77.6 2.0 77.9 1.7 2040 79.1 1.8 78.3 1.9 78.7 1.7 2045 79.8 1.8 79.0 1.9 79.5 1.7 2050 80.5 1.8 79.7 1.9 80.3 1.7 2055 81.1 1.8 80.3 1.8 80.9 1.8 2060 81.7 1.8 80.9 1.8 81.6 1.8 2065 82.3 1.8 81.4 1.8 82.2 1.8 2070 82.8 1.8 82.0 1.7 82.8 1.8 2075 83.3 1.8 82.5 1.7 83.4 1.9 2080 83.8 1.8 83.0 1.7 83.9 1.9 2085 84.3 1.9 83.5 1.8 84.4 1.9 2090 84.7 1.9 83.9 1.8 84.9 1.9 2095 85.1 1.9 84.3 1.8 85.4 1.9 2100", header=T) require(plotrix) twoord.stackplot(lx=data$anos, rx=data$anos, ldata=cbind(data$e0AL, data$e0BR, data$e0CO), rdata=cbind(data$fxAL, data$fxBR, data$fxCO), lcol=c("black","red", "blue"), rcol=c("black","red", "blue"), ltype=c("l","o","b"), rtype=c("l","o","b"), lylab="Años de Vida", rylab="Hijos x Mujer", xlab="Tiempo", main="Mortalidad/Fecundidad:1950–2100", border="grey80") legend("bottomright", c(paste("Proy:", c("A. Latina", "Brasil", "Colombia"))), cex=1, col=c("black","red", "blue"), lwd=2, bty="n", lty=c(1,1,2), pch=c(NA,1,1) ) 
+2
Jul 29 '15 at 0:42
source share



All Articles