Как я могу построить с двумя разными осями y?

Я бы хотел наложить два графика рассеяния в R, так что каждый набор точек имеет свою собственную (разную) ось y (т.е. в положениях 2 и 4 на рисунке), но точки появляются наложенными на один и тот же рисунок.

Можно ли сделать это с помощью plot?

Изменить Пример кода, показывающий проблему

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

Ответ 1

update: скопированный материал, который был на R wiki в http://rwiki.sciviews.org/doku.php?id=tips:graphics-base:2yaxes, ссылка теперь сломана: также доступна от машины обратного пути

Две разные оси y на одном и том же участке

(какой-то материал изначально Даниэль Райдл 2006/03/31 15:26)

Обратите внимание, что очень мало ситуаций, когда целесообразно использовать две разные шкалы на одном и том же участке. Это очень легко ввести в заблуждение зрителя. Проверьте следующие два примера и комментарии по этой проблеме (example1, example2 from Unch Charts), а также в этой статье Стивена Фьюера (который заключает: "Я, конечно, не могу завершить раз и навсегда, что графики с двойными масштабированными осями никогда не будут полезны, только я не могу придумать ситуацию, которая оправдывает их в свете других лучших решений".) Также см. пункт № 4 в этот мультфильм...

Если вы определились, основной рецепт состоит в том, чтобы создать ваш первый график, установите par(new=TRUE), чтобы R не очистил графическое устройство, создав второй график с помощью axes=FALSE (и установив xlab и ylab в be blank - ann=FALSE также должен работать), а затем с помощью axis(side=4) добавить новую ось в правую сторону и mtext(...,side=4), чтобы добавить метку оси справа. Вот пример, в котором используется немного собранных данных:

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() в пакете plotrix автоматизирует этот процесс, как и doubleYScale() в пакете latticeExtra.

Другой пример (адаптированный из почтового списка 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

Аналогичные рецепты могут использоваться для наложения графиков разных типов - штриховых графиков, гистограмм и т.д.

Ответ 2

Как следует из названия, twoord.plot() в разделах plotrix с двумя осями ординат.

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

Ответ 3

Один из вариантов - сделать два графика бок о бок. ggplot2 обеспечивает хороший вариант для этого с помощью 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

Это FAQ. Вот одно более давнее решение, которое я предоставил почти шесть лет назад в галерею графиков R

Вы можете посмотреть, например. в функции plotVolumeBars(), которая объединяет абсолютный и относительный масштаб в одной диаграмме.

Ответ 5

Если вы можете отказаться от меток масштаба/оси, вы можете масштабировать данные до (0, 1) интервала. Это работает, например, для разных траксов "шевелить" на хромосомах, когда вас обычно интересуют локальные корреляции между треками, и у них разные шкалы (охват в тысячах, 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
}

Затем, имея кадр данных с столбцами chrom, position, coverage и fst, вы можете сделать что-то вроде:

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

Преимущество состоит в том, что вы не ограничены двумя тракками.

Ответ 6

Я также предлагаю twoord.stackplot() в графических пакетах plotrix с большим количеством двух осей ординат.

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