Come posso tracciare con 2 diversi assi y?


122

Vorrei sovrapporre due grafici a dispersione in R in modo che ogni insieme di punti abbia il proprio (diverso) asse y (cioè, nelle posizioni 2 e 4 sulla figura) ma i punti appaiono sovrapposti sulla stessa figura.

È possibile farlo con plot?

Modifica il codice di esempio che mostra il problema

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

Fornisci dati di esempio. Questa è generalmente una cattiva idea dal punto di vista estetico.
Inseguimento

3
risposte e discussione nel caso specifico di ggplot2: stackoverflow.com/questions/3099219/… (cercando SO per [r] two y-axeso [r] twoord.plot) - ci sono alcune altre risposte correlate, sebbene (con mia sorpresa poiché si tratta di una FAQ R) niente di identico
Ben Bolker

@chase: ho aggiunto un esempio funzionante del problema. Grazie per l'avvertimento sui problemi estetici.
DQdlM

Risposte:


126

aggiornamento : materiale copiato che era sul wiki R su http://rwiki.sciviews.org/doku.php?id=tips:graphics-base:2yaxes , collegamento ora interrotto: disponibile anche dalla macchina wayback

Due assi y diversi sullo stesso grafico

(del materiale originariamente di Daniel Rajdl 2006/03/31 15:26)

Si noti che ci sono pochissime situazioni in cui è opportuno utilizzare due scale diverse sullo stesso grafico. È molto facile indurre in errore lo spettatore della grafica. Controllare i seguenti due esempi e commenti su questo tema ( Example1 , example2 da Grafici Junk ), così come l'articolo di Stephen Few (che conclude “Io certamente non posso concludere, una volta per tutte, che i grafici con assi dual-scala non sono mai utile; solo che non riesco a pensare a una situazione che li giustifichi alla luce di altre soluzioni migliori. ") Vedi anche il punto 4 in questa vignetta ...

Se sei determinato, la ricetta di base è creare il tuo primo par(new=TRUE)grafico , impostato per impedire a R di cancellare il dispositivo grafico, creare il secondo grafico con axes=FALSE(e impostare xlabe ylabessere vuoto - ann=FALSEdovrebbe funzionare anche) e quindi utilizzare axis(side=4)per aggiungere un nuovo asse sul lato destro e mtext(...,side=4)per aggiungere un'etichetta dell'asse sul lato destro. Ecco un esempio che utilizza un po 'di dati inventati:

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()nel plotrixpacchetto automatizza questo processo, come fa doubleYScale()nel latticeExtrapacchetto.

Un altro esempio (adattato da un post di una mailing list R di 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"))

inserisci qui la descrizione dell'immagine

È possibile utilizzare ricette simili per sovrapporre grafici di diversi tipi: grafici a barre, istogrammi, ecc.


questo è il motivo per cui le risposte solo link sono una cattiva idea ... wiki.r-project.org sembra defunto, sto chiedendo su r-devel@r-project.org.
Ben Bolker

@ BenBolker la tua soluzione è geniale! tuttavia ho una domanda. Se è presente più di una riga su entrambi i lati, posso comunque utilizzare questo metodo ma solo con i simboli. Quando provo a usare line = plot, cerca di tracciarli continuamente. Ti capiterà di suggerire un trucco per risolvere questo problema?
wthimdh

1
@BenBolker E se l'ora fosse il formato della data del tipo: "2019-01-01". Come cambierai la axis(1,pretty(range(time),10))linea?
k.dkhk

35

Come suggerisce il nome, twoord.plot()nel pacchetto plotrix traccia con due assi delle ordinate.

library(plotrix)
example(twoord.plot)

inserisci qui la descrizione dell'immagine

inserisci qui la descrizione dell'immagine

inserisci qui la descrizione dell'immagine

inserisci qui la descrizione dell'immagine

inserisci qui la descrizione dell'immagine


3
chiazza di petrolio. grazie per il camion carico di esempi. Mi piacerebbe vedere anche uno di quegli esempi di linee e barre con valori negativi. Anche lo stacking sarebbe bello.
Matt Bannert

5

Un'opzione è creare due trame fianco a fianco. ggplot2fornisce una buona opzione per questo con 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")

4

Se puoi rinunciare alle scale / etichette degli assi, puoi ridimensionare i dati all'intervallo (0, 1). Questo funziona, ad esempio, per diversi trakc "oscillanti" sui cromosomi, quando sei generalmente interessato alle correlazioni locali tra le tracce e hanno scale diverse (copertura in migliaia, 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
}

Poi, avendo un frame di dati con chrom, position, coveragee fstle colonne, si può fare qualcosa di simile:

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

Il vantaggio di questo è che non sei limitato a due trakcs.


4

Anch'io suggerisce, twoord.stackplot()nel plotrixpacchetto, grafici con più di due assi di ordinate.

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) )

1

Un'altra alternativa che è simile alla risposta accettata da @BenBolker sta ridefinendo le coordinate del grafico esistente quando si aggiunge un secondo insieme di punti.

Ecco un esempio minimo.

Dati:

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

Tracciare:

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")

esempio

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.