Wie kann ich mit 2 verschiedenen y-Achsen zeichnen?

121

Ich möchte zwei Streudiagramme in R überlagern, so dass jeder Satz von Punkten seine eigene (unterschiedliche) y-Achse hat (dh an den Positionen 2 und 4 in der Figur), aber die Punkte erscheinen auf derselben Figur überlagert.

Ist das möglich mit plot?

Bearbeiten Sie den Beispielcode, der das Problem zeigt

# 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)
DQdlM
quelle
Bitte geben Sie Beispieldaten an. Dies ist aus ästhetischer Sicht im Allgemeinen eine schlechte Idee.
Chase
3
Antworten und Diskussion im speziellen Fall von ggplot2: stackoverflow.com/questions/3099219/… (SO suchen nach [r] two y-axesoder [r] twoord.plot) - es gibt einige andere verwandte Antworten, obwohl (zu meiner Überraschung, da es sich um eine R-FAQ handelt) nichts identisch ist
Ben Bolker
@chase - Ich habe ein funktionierendes Beispiel für das Problem hinzugefügt. Vielen Dank für die Warnung zu den ästhetischen Fragen.
DQdlM

Antworten:

125

Update : Kopiertes Material, das sich im R-Wiki unter http://rwiki.sciviews.org/doku.php?id=tips:graphics-base:2yaxes befand , Link jetzt defekt: auch auf dem Wayback-Computer erhältlich

Zwei verschiedene y-Achsen auf demselben Plot

(etwas Material ursprünglich von Daniel Rajdl 31.03.2006 15:26)

Bitte beachten Sie, dass es nur sehr wenige Situationen gibt, in denen es angebracht ist, zwei verschiedene Skalen auf demselben Grundstück zu verwenden. Es ist sehr leicht, den Betrachter der Grafik irrezuführen. Überprüfen Sie die folgenden zwei Beispiele und Kommentare zu diesem Problem ( Beispiel 1 , Beispiel 2 aus Junk- Diagrammen ) sowie diesen Artikel von Stephen Few (der zu dem Schluss kommt: „Ich kann mit Sicherheit nicht ein für allemal schließen, dass Diagramme mit zwei skalierten Achsen niemals sind nützlich, nur dass ich mir keine Situation vorstellen kann, die sie angesichts anderer, besserer Lösungen rechtfertigt. “) Siehe auch Punkt 4 in diesem Cartoon ...

Wenn Sie fest entschlossen sind, besteht das Grundrezept darin, Ihr erstes Diagramm zu erstellen, par(new=TRUE)zu verhindern, dass R das Grafikgerät löscht, das zweite Diagramm mit zu erstellen axes=FALSE(und zu setzen xlabund ylableer zu sein - ann=FALSEsollte auch funktionieren) und dann axis(side=4)eine neue Achse hinzuzufügen auf der rechten Seite und mtext(...,side=4)zum Hinzufügen einer Achsenbeschriftung auf der rechten Seite. Hier ist ein Beispiel mit ein paar erfundenen Daten:

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()im plotrixPaket automatisiert diesen Prozess, wie doubleYScale()im latticeExtraPaket.

Ein weiteres Beispiel (angepasst aus einem R-Mailinglistenbeitrag von 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"))

Geben Sie hier die Bildbeschreibung ein

Ähnliche Rezepte können verwendet werden, um Diagramme verschiedener Typen zu überlagern - Balkendiagramme, Histogramme usw.

Ben Bolker
quelle
Aus diesem Grund sind Antworten nur mit Links eine schlechte Idee ... wiki.r-project.org scheint nicht mehr vorhanden zu sein. Ich frage auf [email protected].
Ben Bolker
@ BenBolker Ihre Lösung ist genial! Ich habe jedoch eine Frage. Wenn es auf beiden Seiten mehr als eine Zeile gibt, kann ich diese Methode weiterhin verwenden, jedoch nur mit Symbolen. Wenn ich versuche, line = plot zu verwenden, wird versucht, sie kontinuierlich zu zeichnen. Würden Sie zufällig einen Trick vorschlagen, um dies zu beheben?
wthimdh
1
@BenBolker Was ist, wenn die Uhrzeit ein Datumsformat vom Typ "2019-01-01" ist? Wie werden Sie die axis(1,pretty(range(time),10))Linie ändern ?
k.dkhk
35

Wie der Name schon sagt, werden twoord.plot()im Plotrix- Paket zwei Ordinatenachsen dargestellt.

library(plotrix)
example(twoord.plot)

Geben Sie hier die Bildbeschreibung ein

Geben Sie hier die Bildbeschreibung ein

Geben Sie hier die Bildbeschreibung ein

Geben Sie hier die Bildbeschreibung ein

Geben Sie hier die Bildbeschreibung ein

kmm
quelle
3
glatt. Vielen Dank für die LKW-Ladung von Beispielen. Ich würde gerne eines dieser Zeilen- und Balkenbeispiele mit negativen Werten sehen. Auch Stapeln wäre schön.
Matt Bannert
5

Eine Möglichkeit besteht darin, zwei Diagramme nebeneinander zu erstellen. ggplot2bietet eine schöne Option dafür mit 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")
Verfolgungsjagd
quelle
4

Wenn Sie die Skalen- / Achsenbeschriftungen aufgeben können, können Sie die Daten auf das Intervall (0, 1) neu skalieren. Dies funktioniert beispielsweise für verschiedene "Wackel" -Traks auf Chromosomen, wenn Sie im Allgemeinen an lokalen Korrelationen zwischen den Spuren interessiert sind und diese unterschiedliche Skalen haben (Abdeckung in Tausend, 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
}

Dann, mit einem Datenrahmen chrom, position, coverageund fstSpalten, können Sie etwas tun:

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

Dies hat den Vorteil, dass Sie nicht auf zwei Trakcs beschränkt sind.

liborm
quelle
4

Ich schlage auch vor, twoord.stackplot()in den plotrixPaketdiagrammen mit mehr als zwei Ordinatenachsen.

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) )
Juannes
quelle
1

Eine andere Alternative, die der von @BenBolker akzeptierten Antwort ähnelt, besteht darin, die Koordinaten des vorhandenen Diagramms neu zu definieren, wenn ein zweiter Satz von Punkten hinzugefügt wird.

Hier ist ein minimales Beispiel.

Daten:

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

Handlung:

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

Beispiel

Karolis Koncevičius
quelle