Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ggplot2: Adding secondary transformed x-axis on top of plot

Tags:

r

ggplot2

[ Edit April 2016: the solution in this thread no longer displays the added axis correctly - a new thread on this issue has been opened at ggplot2 2.1.0 broke my code? Secondary transformed axis now appears incorrectly ]

I am working with scaled x data, and need to add an unscaled x axis to the top of the plot for easier interpretation. I've come across an approach for adding a secondary a y-axis at How can I put a transformed scale on the right side of a ggplot2?. However, I can't get it to work properly for the x-axis. I'm sure i'm not understanding some part of the code, but I can't seem to figure out what it is. I've tried looking in the ggplot2 help files, and also the Wickham book ggplot2: Elegant Graphics For Data Analysis, but if anyone can point me towards some relevant documentation I would really appreciate it!

I am working with temperature data, but I will use the lake data from the link above as the code was written for that. Here is the orignal code from that link:

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)

To test a method for adding an x-axis instead of y-axis, I switched the x and y axes and changed axis-l to axis-b to give:

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)

This produces a new x-axis, but there are a couple of problems: 1) it is in the middle of the plot 2) it does not produce a new x-label for "Elevation (ft)"

I need the axis to appear at the top of the plot, and I need an associated axis label. Can anyone tell me what I am doing wrong?

Also, as mentioned above, I am working with scaled temperature data, so ideally the ticks would not align on the top and bottom axes as they do in this example. Is there any way to do this in ggplot2? An arbitrary example from the web is this:

Two x axes with different scales

like image 519
Thomas Avatar asked Jan 09 '14 17:01

Thomas


1 Answers

You can use sec_axis or 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)"))

enter image description here

ggplot2 version 3.1.1

like image 53
Megatron Avatar answered Oct 21 '22 04:10

Megatron