Как мне вертикально сложить два графика с одинаковым масштабом x, но с другим масштабом y в R?

9

Приветствую,

В настоящее время я делаю следующее в R:

require(zoo)
data <- read.csv(file="summary.csv",sep=",",head=TRUE)
cum  = zoo(data$dcomp, as.Date(data$date))
data = zoo(data$compressed, as.Date(data$date))
data <- aggregate(data, identity, tail, 1)
cum  <- aggregate(cum, identity, sum, 1)
days = seq(start(data), end(data), "day")
data2 = na.locf(merge(data, zoo(,days)))

plot(data2,xlab='',ylab='compressed bytes',col=rgb(0.18,0.34,0.55))
lines(cum,type="h",col=rgb(0,0.5,0))

Snip of summary.csv:

date,revision,file,lines,nclass,nattr,nrel,bytes,compressed,diff,dcomp
2007-07-25,16,model.xml,96,11,22,5,4035,991,0,0
2007-07-27,17,model.xml,115,16,26,6,4740,1056,53,777
2007-08-09,18,model.xml,106,16,26,7,4966,1136,47,761
2007-08-10,19,model.xml,106,16,26,7,4968,1150,4,202
2007-09-06,81,model.xml,111,16,26,7,5110,1167,13,258
...

Последние две строки отображают нужную мне информацию, и результат напоминает следующее: альтернативный текст Синяя линия - это энтропия в байтах интересующего меня артефакта. Зеленые линии представляют энтропию изменений.

Теперь, на этом графике, это работает хорошо, потому что нет большой разницы в масштабах. Но у меня есть другие графики, где зеленые линии становятся такими маленькими, что их не видно.

Решение, которое я искал, включало две вещи:

  1. Чтобы переместить зеленые вертикальные линии на второй график, чуть ниже первого, с собственной осью y, но с общей осью x.
  2. Чтобы обеспечить это логарифмическая шкала, так как меня больше интересует «величина», чем конкретные значения.

Заранее спасибо!

PS Если кто-то также может сказать мне, как я могу поставить «мелкие галочки» в шкале х, относящиеся к месяцам, я ценю :-) Если это слишком много вопросов для одного поста, я могу разделить их дальше.

Уго Серено Феррейра
источник

Ответы:

15

Вы можете использовать par(new=TRUE)для построения на одном графике, используя две разные оси Y! Это также должно решить вашу проблему.

Далее вы найдете простой пример, который отображает две случайные нормальные переменные, одну на среднее значение 0, другую на среднее значение 100 (обе sd s = 1) на одном графике. Первый в красном на левой оси Y, второй в синем на правой оси Y. Затем добавляются метки оси.

Ну вот:

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

plot(x,y1,pch=0,type="b",col="red",yaxt="n",ylim=c(-8,2))
par(new=TRUE)
plot(x,y2,pch=1,type="b",col="blue",yaxt="n",ylim=c(98,105))

axis(side=2)
axis(side=4)

выглядит так (помните, красный на левой оси, синий на правой оси): альтернативный текст

ОБНОВЛЕНИЕ:
Основываясь на комментариях, я выпустил обновленную версию моего графика. Теперь я немного углублюсь в функциональность базового графа, используя par(mar=c(a,b,c,d))для создания большего поля вокруг графика (необходимого для метки правой оси), mtextдля отображения меток оси и расширенного использования axisфункции:

x <- 1:100
y1 <- rnorm(100)
y2 <- rnorm(100)+100

par(mar=c(5,5,5,5))

plot(x,y1,pch=0,type="b",col="red",yaxt="n",ylim=c(-8,2),ylab="")
axis(side=2, at=c(-2,0,2))
mtext("red line", side = 2, line=2.5, at=0)

par(new=TRUE)
plot(x,y2,pch=1,type="b",col="blue",yaxt="n",ylim=c(98,108), ylab="")
axis(side=4, at=c(98,100,102), labels=c("98%","100%","102%"))
mtext("blue line", side=4, line=2.5, at=100)

альтернативный текст

Как видите, это довольно просто. Вы можете определить положение ваших данных ylimв plotфункции, а затем использовать atв axisфункции, чтобы выбрать, какие отметки оси вы хотите видеть. Кроме того, вы можете даже представить метки для клещи оси (очень полезно для номинальной оси х) с помощью labelsв axisфункции (сделано здесь , на правой оси). Чтобы добавить метки оси, используйте mtextс atдля вертикального позиционирования ( lineдля горизонтального позиционирования).

Убедитесь в том , чтобы проверить ?plot, ?par, ?axisи ?mtextдля получения дополнительной информации.
Хорошие веб-ресурсы: Quick-R для графиков: 1 , 2 и 3 .

Хенрик
источник
Это интересно, но как нам сказать читателю, какой масштаб соответствует какой линии?
Уго Серено Феррейра
Посмотрите на этот график: imgur.com/K8BCr.png Там мы представляем метки и метки оси Y только там, где они применяются к данным (т. Е. Для левой оси в верхней части графика, как соответствующие данные, и для правой оси в нижней части графика, как данные для расшифровки). Кроме того, мы использовали разные цвета (как в примере выше) и типы линий и объяснили это в подписи. Вы также можете использовать линейный график слева и гистограмму справа, чтобы сделать различие более четким.
Хенрик
Приведенный вами пример очень хорош ... Как вам удалось сместить по вертикали каждую ось?
Уго Серено Феррейра
2
Действительно хороший пример. Единственная проблема с вашим графиком, это то, что оба имени переменных Y перекрываются. В этом случае вам понадобится один слева, а другой справа (возможно, даже в вертикальном положении). Чтобы обновить ваш пример с «действительно хорошего» до «идеального», вы можете использовать функцию mtext из R для имен переменных
Дейв Келлен,
@Hugo @Dave: Смотрите мое обновление для включения обоих комментариев.
Хенрик
12

Я думаю, что вы можете получить то, что вы хотите, используя ggplot2. Используя приведенный ниже код, я могу произвести:

альтернативный текст

Очевидно, что такие вещи, как цвета линий могут быть изменены на то, что вы хотите. На оси х я указал основные линии по годам и второстепенные по месяцам.

require(ggplot2)
t = as.Date(0:1000, origin="2008-01-01")  
y1 = rexp(1001)
y2 = cumsum(y1)
df = data.frame(t=t, values=c(y2,y1), type=rep(c("Bytes", "Changes"), each=1001))

g = ggplot(data=df, aes(x=t, y=values)) +
  geom_line() +
  facet_grid(type ~ ., scales="free") +
  scale_y_continuous(trans="log10") +
  scale_x_date(major="years", minor="months") +
  ylab("Log values")
g
csgillespie
источник
Я пытался настроить df = data.frame (t = days, values ​​= c (data2, cum), type = rep (c ("Bytes", "Changes"), каждый = 1001)), но это дает Ошибка в rbind.zoo (...): индексы перекрываются
Уго Серено Феррейра
Это потому, что data2 и cum являются объектами зоопарка. Используйте as.vector (data2), чтобы получить необработанные значения. Кроме того, я использовал 1001, потому что у меня было 1001 наблюдение. Вам нужно что-то другое.
csgillespie
Пользователь Noob R здесь: Ошибка в data.frame (t = days, values ​​= c (as.vector (data2), as.vector (cum)),: аргументы подразумевают различное количество строк: 1063, 1300, 2
Уго Серено Феррейра
Введите «days», «data2» и «cum», чтобы просмотреть ваши данные. Затем посмотрите на «продолжительность (дни)» и т. Д. Вам нужно сопоставить временные точки со значениями.
csgillespie