web-dev-qa-db-fra.com

Comment puis-je tracer avec 2 axes y différents?

J'aimerais superposer deux diagrammes de dispersion dans R de sorte que chaque ensemble de points ait son propre axe y (différent) (c'est-à-dire aux positions 2 et 4 sur la figure) mais les points apparaissent superposés sur la même figure.

Est-il possible de faire cela avec plot?

Edit Exemple de code montrant le problème

# 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)
105
KennyPeanuts

update: éléments copiés qui se trouvaient sur le wiki R à l'adresse { http://rwiki.sciviews.org/doku.php?id=tips:graphics-base:2yaxes }, lien maintenant rompu: également disponible à partir de la machine à retourner

Deux axes y différents sur la même parcelle

(du matériel à l’origine par Daniel Rajdl le 2006/03/31 15:26)

Veuillez noter qu'il existe très peu de situations dans lesquelles il est approprié d'utiliser deux échelles différentes sur la même parcelle. Il est très facile d'induire le spectateur en erreur. Consultez les deux exemples et commentaires suivants sur ce problème ( exemple1 , exemple2 de Graphiques indésirables ), ainsi que cet article de Stephen Few (qui conclut: «Je ne peux certainement pas en conclure, une fois pour toutes, que les graphes avec des axes à deux échelles ne sont jamais utiles; seulement je ne peux pas penser à une situation qui les justifie à la lumière d'autres solutions meilleures».) Voir aussi le point # 4 dans cette caricature ...

Si vous êtes déterminé, la recette de base consiste à créer votre premier tracé, définissez par(new=TRUE) pour éviter que R n'efface le périphérique graphique, créez le deuxième tracé avec axes=FALSE (et définissez xlab et ylab sur blanc - ann=FALSE devrait également fonctionner), puis utilisez axis(side=4) pour ajouter un nouvel axe à droite et mtext(...,side=4) pour ajouter une étiquette d’axe à droite. Voici un exemple utilisant un peu de données inventées:

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() dans le package plotrix automatise ce processus, tout comme doubleYScale() dans le package latticeExtra.

Un autre exemple (adapté d'un courrier de la liste de diffusion R de Robert W. Baer):

## 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's 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

Des recettes similaires peuvent être utilisées pour superposer des tracés de différents types - tracés à barres, histogrammes, etc.

101
Ben Bolker

Comme son nom l’indique, twoord.plot() dans les tracés plotrix package avec deux axes en ordonnée.

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

33
kmm

Une option consiste à créer deux parcelles côte à côte. ggplot2 fournit une option intéressante pour cela avec 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
Chase

Si vous pouvez abandonner les étiquettes d'échelles/d'axes, vous pouvez redimensionner les données à un intervalle (0, 1). Cela fonctionne par exemple pour différentes trajectoires de 'wiggle' sur les chromosomes, lorsque vous vous intéressez généralement aux corrélations locales entre les pistes et qu'elles ont des échelles différentes (couverture en milliers, 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
}

Ensuite, en ayant un cadre de données avec des colonnes chrom, position, coverage et fst, vous pouvez effectuer les opérations suivantes:

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

L'avantage de ceci est que vous n'êtes pas limité à deux trakcs.

3
liborm

Moi aussi, je suggère twoord.stackplot() dans les tracés de package plotrix avec plus de deux axes ordinaux.

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
Juannes

Une autre alternative, similaire à la réponse acceptée par @BenBolker, consiste à redéfinir les coordonnées du tracé existant lors de l'ajout d'un deuxième ensemble de points.

Voici un exemple minimal.

Les données:

x  <- 1:10
y1 <- rnorm(10, 100, 20)
y2 <- rnorm(10, 1, 1)

Terrain:

par(mar=c(5,5,5,5)+0.1, las=1)

plot.new()
plot.window(xlim=range(x), ylim=range(y1))
points(x, y1, col="red", pch=19)
axis(1)
axis(2, col.axis="red")
box()

plot.window(xlim=range(x), ylim=range(y2))
points(x, y2, col="limegreen", pch=19)
axis(4, col.axis="limegreen")

 example

0