Как я могу построить с двумя разными осями 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) )