Bagaimana cara memplot dengan 2 sumbu y yang berbeda?

122

Saya ingin menempatkan dua plot pencar di R sehingga setiap kumpulan titik memiliki sumbu y (berbeda) (yaitu, di posisi 2 dan 4 pada gambar) tetapi titik-titik tersebut tampak ditumpangkan pada gambar yang sama.

Apakah mungkin melakukan ini dengan plot?

Edit kode Contoh yang menunjukkan masalah

# 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
sumber
Berikan contoh data. Ini umumnya ide yang buruk dari sudut pandang estetika.
Mengejar
3
jawaban dan diskusi dalam kasus khusus ggplot2: stackoverflow.com/questions/3099219/… (mencari SO untuk [r] two y-axesatau [r] twoord.plot) - ada beberapa jawaban terkait lainnya, meskipun (yang mengejutkan saya karena ini adalah R FAQ) tidak ada yang identik
Ben Bolker
@ Chase - Saya menambahkan contoh kerja dari masalah tersebut. Terima kasih atas peringatannya tentang masalah estetika.
DQdlM

Jawaban:

126

pembaruan : Materi yang disalin di wiki R di http://rwiki.sciviews.org/doku.php?id=tips:graphics-base:2yaxes , tautan sekarang rusak: juga tersedia dari mesin wayback

Dua sumbu y berbeda di plot yang sama

(beberapa materi aslinya oleh Daniel Rajdl 2006/03/31 15:26)

Harap dicatat bahwa ada sangat sedikit situasi di mana penggunaan dua skala yang berbeda pada plot yang sama dapat dilakukan. Sangat mudah untuk menyesatkan pemirsa grafik. Periksa berikut dua contoh dan komentar tentang masalah ini ( example1 , example2 dari Charts Sampah ), serta artikel ini dengan Stephen Sedikit (yang menyimpulkan “Saya tentu tidak bisa menyimpulkan, sekali dan untuk semua, yang grafik dengan sumbu dual-skala tidak pernah berguna; hanya saja saya tidak dapat memikirkan situasi yang menjamin mereka sehubungan dengan solusi lain yang lebih baik. ”) Juga lihat poin # 4 dalam kartun ini ...

Jika Anda ditentukan, resep dasarnya adalah membuat plot pertama Anda, mengatur par(new=TRUE)untuk mencegah R dari membersihkan perangkat grafis, membuat plot kedua dengan axes=FALSE(dan pengaturan xlabdan ylabmenjadi kosong - ann=FALSEjuga harus berfungsi) dan kemudian menggunakan axis(side=4)untuk menambahkan sumbu baru di sisi kanan, dan mtext(...,side=4)untuk menambahkan label sumbu di sisi kanan. Berikut ini contoh penggunaan sedikit data yang dibuat-buat:

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()dalam plotrixpaket mengotomatiskan proses ini, seperti halnya doubleYScale()dalam latticeExtrapaket.

Contoh lain (diadaptasi dari pos milis R oleh 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"))

masukkan deskripsi gambar di sini

Resep serupa dapat digunakan untuk menempatkan plot dari berbagai jenis - plot batang, histogram, dll.

Ben Bolker
sumber
inilah mengapa jawaban hanya-tautan adalah ide yang buruk ... wiki.r-project.org tampaknya sudah tidak berfungsi, saya bertanya di [email protected].
Ben Bolker
@BenBolker solusi Anda adalah jenius! Namun saya punya satu pertanyaan. Jika lebih dari satu garis di kedua sisi, saya masih bisa menggunakan metode ini tetapi hanya dengan simbol. Ketika saya mencoba menggunakan line = plot, ia mencoba untuk memplotnya terus menerus. Apakah Anda akan menyarankan trik untuk memperbaikinya?
wthimdh
1
@BenBolker Bagaimana jika Waktu adalah format tanggal jenis: "2019-01-01". Bagaimana Anda akan mengubah axis(1,pretty(range(time),10))garis?
k.dkhk
35

Seperti namanya, twoord.plot()dalam paket plotrix dengan dua sumbu ordinat.

library(plotrix)
example(twoord.plot)

masukkan deskripsi gambar di sini

masukkan deskripsi gambar di sini

masukkan deskripsi gambar di sini

masukkan deskripsi gambar di sini

masukkan deskripsi gambar di sini

kmm
sumber
3
licin. terima kasih atas muatan truk contoh. Saya ingin melihat salah satu contoh garis dan batang dengan nilai negatif juga. Juga menumpuk akan menyenangkan.
Matt Bannert
5

Salah satu opsinya adalah membuat dua plot berdampingan. ggplot2memberikan opsi yang bagus untuk ini dengan 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")
Mengejar
sumber
4

Jika Anda dapat melepaskan label skala / sumbu, Anda dapat mengubah skala data ke interval (0, 1). Ini berfungsi misalnya untuk jalur 'goyangan' yang berbeda pada kromosom, saat Anda secara umum tertarik pada korelasi lokal antara jalur dan mereka memiliki skala yang berbeda (cakupan dalam ribuan, 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
}

Kemudian, memiliki frame data dengan chrom, position, coveragedan fstkolom, Anda dapat melakukan sesuatu seperti:

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

Keuntungannya adalah Anda tidak terbatas pada dua trak.

liborm
sumber
4

Saya juga menyarankan, twoord.stackplot()dalam plotrixplot paket dengan lebih dari dua sumbu ordinat.

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
sumber
1

Alternatif lain yang mirip dengan jawaban yang diterima oleh @BenBolker adalah mendefinisikan kembali koordinat plot yang ada saat menambahkan kumpulan poin kedua.

Berikut adalah contoh minimal.

Data:

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

Merencanakan:

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

contoh

Karolis Koncevičius
sumber