ggplot2: добавление вторично преобразованной оси X поверх графика
[ Изменить апрель 2016 года: решение в этой теме больше не отображает добавленную ось правильно - новая ветка по этой проблеме была открыта на ggplot2. 2.1.0 сломал мой код? Вторичная трансформированная ось теперь отображается неправильно ]
Я работаю с масштабированными данными х, и мне нужно добавить немасштабированную ось х в верхней части графика для облегчения интерпретации. Я сталкивался с подходом для добавления вторичной оси Y в Как я могу поместить преобразованную шкалу на правой стороне ggplot2?, Тем не менее, я не могу заставить его работать должным образом для оси X. Я уверен, что не понимаю какую-то часть кода, но я не могу понять, что это такое. Я попытался просмотреть файлы справки ggplot2, а также книгу Уикхема ggplot2: "Элегантная графика для анализа данных", но если кто-нибудь подскажет мне какую-нибудь соответствующую документацию, я был бы очень признателен!
Я работаю с данными о температуре, но я буду использовать данные о озере по ссылке выше, поскольку код был написан для этого. Вот код оригинала по этой ссылке:
library(ggplot2)
library(gtable)
library(grid)
LakeLevels<-data.frame(Day=c(1:365),Elevation=sin(seq(0,2*pi,2*pi/364))*10+100)
p1 <- ggplot(data=LakeLevels) + geom_line(aes(x=Day,y=Elevation)) +
scale_y_continuous(name="Elevation (m)",limits=c(75,125))
p2<-ggplot(data=LakeLevels)+geom_line(aes(x=Day, y=Elevation))+
scale_y_continuous(name="Elevation (ft)", limits=c(75,125),
breaks=c(80,90,100,110,120),
labels=c("262", "295", "328", "361", "394"))
#extract gtable
g1<-ggplot_gtable(ggplot_build(p1))
g2<-ggplot_gtable(ggplot_build(p2))
#overlap the panel of the 2nd plot on that of the 1st plot
pp<-c(subset(g1$layout, name=="panel", se=t:r))
g<-gtable_add_grob(g1, g2$grobs[[which(g2$layout$name=="panel")]], pp$t, pp$l, pp$b,
pp$l)
ia <- which(g2$layout$name == "axis-l")
ga <- g2$grobs[[ia]]
ax <- ga$children[[2]]
ax$widths <- rev(ax$widths)
ax$grobs <- rev(ax$grobs)
ax$grobs[[1]]$x <- ax$grobs[[1]]$x - unit(1, "npc") + unit(0.15, "cm")
g <- gtable_add_cols(g, g2$widths[g2$layout[ia, ]$l], length(g$widths) - 1)
g <- gtable_add_grob(g, ax, pp$t, length(g$widths) - 1, pp$b)
# draw it
grid.draw(g)
Чтобы протестировать метод добавления оси X вместо оси Y, я переключил оси X и Y и изменил axis-l
в axis-b
дать:
library(ggplot2)
library(gtable)
library(grid)
LakeLevels<-data.frame(Day=c(1:365),Elevation=sin(seq(0,2*pi,2*pi/364))*10+100)
p1 <- ggplot(data=LakeLevels) + geom_line(aes(x=Elevation,y=Day)) +
scale_x_continuous(name="Elevation (m)",limits=c(75,125))
p2<-ggplot(data=LakeLevels)+geom_line(aes(x=Elevation, y=Day))+
scale_x_continuous(name="Elevation (ft)", limits=c(75,125),
breaks=c(80,90,100,110,120),
labels=c("262", "295", "328", "361", "394"))
#extract gtable
g1<-ggplot_gtable(ggplot_build(p1))
g2<-ggplot_gtable(ggplot_build(p2))
#overlap the panel of the 2nd plot on that of the 1st plot
pp<-c(subset(g1$layout, name=="panel", se=t:r))
g<-gtable_add_grob(g1, g2$grobs[[which(g2$layout$name=="panel")]], pp$t, pp$l, pp$b,
pp$l)
ia <- which(g2$layout$name == "axis-b")
ga <- g2$grobs[[ia]]
ax <- ga$children[[2]]
ax$widths <- rev(ax$widths)
ax$grobs <- rev(ax$grobs)
ax$grobs[[1]]$x <- ax$grobs[[1]]$x - unit(1, "npc") + unit(0.15, "cm")
g <- gtable_add_cols(g, g2$widths[g2$layout[ia, ]$l], length(g$widths) - 1)
g <- gtable_add_grob(g, ax, pp$t, length(g$widths) - 1, pp$b)
# draw it
grid.draw(g)
Это создает новую ось X, но есть несколько проблем: 1) она находится в середине графика 2) она не создает новую X-метку для "Высота (футы)"
Мне нужно, чтобы ось появилась в верхней части графика, и мне нужна соответствующая метка оси. Может кто-нибудь сказать мне, что я делаю не так?
Кроме того, как уже упоминалось выше, я работаю с масштабированными данными о температуре, поэтому в идеале отметки не должны совпадать по верхней и нижней осям, как в этом примере. Есть ли способ сделать это в ggplot2? Произвольный пример из Интернета:
1 ответ
Корень вашей проблемы в том, что вы изменяете столбцы, а не строки.
Установка с масштабированными метками на оси X второго графика:
## 'base' plot
p1 <- ggplot(data=LakeLevels) + geom_line(aes(x=Elevation,y=Day)) +
scale_x_continuous(name="Elevation (m)",limits=c(75,125))
## plot with "transformed" axis
p2<-ggplot(data=LakeLevels)+geom_line(aes(x=Elevation, y=Day))+
scale_x_continuous(name="Elevation (ft)", limits=c(75,125),
breaks=c(90,101,120),
labels=round(c(90,101,120)*3.24084) ## labels convert to feet
)
## extract gtable
g1 <- ggplot_gtable(ggplot_build(p1))
g2 <- ggplot_gtable(ggplot_build(p2))
## overlap the panel of the 2nd plot on that of the 1st plot
pp <- c(subset(g1$layout, name=="panel", se=t:r))
g <- gtable_add_grob(g1, g2$grobs[[which(g2$layout$name=="panel")]], pp$t, pp$l, pp$b,
pp$l)
РЕДАКТИРОВАТЬ, чтобы линии сетки совпали с галочками нижней оси, замените вышеуказанную линию на: g <- gtable_add_grob(g1, g1$grobs[[which(g1$layout$name=="panel")]], pp$t, pp$l, pp$b, pp$l)
## steal axis from second plot and modify
ia <- which(g2$layout$name == "axis-b")
ga <- g2$grobs[[ia]]
ax <- ga$children[[2]]
Теперь вам нужно убедиться, что вы изменяете правильный размер. Поскольку новая ось является горизонтальной (строка, а не столбец), whatever_grob$heights
вектор, который нужно изменить, чтобы изменить количество вертикального пространства в данной строке. Если вы хотите добавить новое пространство, убедитесь, что добавили строку, а не столбец (т.е. используйте gtable_add_rows()
).
Если вы изменяете сами грабы (в этом случае мы меняем вертикальное выравнивание тиков), обязательно измените y
(вертикальное положение), а не x
(горизонтальная позиция).
## switch position of ticks and labels
ax$heights <- rev(ax$heights)
ax$grobs <- rev(ax$grobs)
ax$grobs[[2]]$y <- ax$grobs[[2]]$y - unit(1, "npc") + unit(0.15, "cm")
## modify existing row to be tall enough for axis
g$heights[[2]] <- g$heights[g2$layout[ia,]$t]
## add new axis
g <- gtable_add_grob(g, ax, 2, 4, 2, 4)
## add new row for upper axis label
g <- gtable_add_rows(g, g2$heights[1], 1)
g <- gtable_add_grob(g, g2$grob[[6]], 2, 4, 2, 4)
# draw it
grid.draw(g)
Попутно отмечу, что gtable_show_layout()
это очень, очень удобная функция для выяснения того, что происходит.
Ты можешь использовать sec_axis
или же dup_axis
,
library(ggplot2)
ggplot(mtcars, aes(x=disp, y=mpg, color=as.factor(cyl))) +
geom_point() +
labs(x="displacement (cubic inches)", col="# of cylinders") +
scale_x_continuous(sec.axis=sec_axis(trans=~ . * 0.0163871, name="displacement (L)"))
ggplot2
версия 3.1.1