Transposing ggplot2 graph with x-axis at top [duplicate] - r

Anybody knows how to draw the X-axis tickmarks at the top of a single plot in R, using ggplot2? I ve been looking at tutorials and mail lists and Rhelp without success.
Thanks in advance.
Agus

Use position = 'top'
library(ggplot2)
# Generate some data
df = data.frame(x = 1:10, y = 1:10)
# x-axis breaks
breaks = 1:10
# base plot
p <- ggplot(df, aes(x,y)) + geom_point() +
scale_x_continuous(breaks = breaks, position = 'top') +
scale_y_continuous(limits = c(0, 11), expand = c(0,0)) +
theme_bw()
Original solution available using gtable (with some updating to ggplot 2.1.0). See here
library(ggplot2)
library(gtable)
library(grid)
# Generate some data
df = data.frame(x = 1:10, y = 1:10)
# x-axis breaks
breaks = 1:10
# base plot
p <- ggplot(df, aes(x,y)) + geom_point() +
scale_x_continuous(breaks = breaks) +
scale_y_continuous(limits = c(0, 11), expand = c(0,0)) +
theme_bw()
# Get ggplot grob
g1 <- ggplotGrob(p)
## Get the position of the plot panel in g1
pp <- c(subset(g1$layout, name == "panel", se = t:r))
# Title grobs have margins.
# The margins need to be swapped.
# Function to swap margins -
# taken from the cowplot package:
# https://github.com/wilkelab/cowplot/blob/master/R/switch_axis.R
vinvert_title_grob <- function(grob) {
heights <- grob$heights
grob$heights[1] <- heights[3]
grob$heights[3] <- heights[1]
grob$vp[[1]]$layout$heights[1] <- heights[3]
grob$vp[[1]]$layout$heights[3] <- heights[1]
grob$children[[1]]$hjust <- 1 - grob$children[[1]]$hjust
grob$children[[1]]$vjust <- 1 - grob$children[[1]]$vjust
grob$children[[1]]$y <- unit(1, "npc") - grob$children[[1]]$y
grob
}
# Get xlab and swap margins
index <- which(g1$layout$name == "xlab-b")
xlab <- g1$grobs[[index]]
xlab <- vinvert_title_grob(xlab)
# Put xlab at the top of g1
g1 <- gtable_add_rows(g1, g1$heights[g1$layout[index, ]$t], pp$t-1)
g1 <- gtable_add_grob(g1, xlab, pp$t, pp$l, pp$t, pp$r, clip = "off", name="topxlab")
# Get x axis (axis line, tick marks and tick mark labels)
index <- which(g1$layout$name == "axis-b")
xaxis <- g1$grobs[[index]]
# Swap axis ticks and tick mark labels
ticks <- xaxis$children[[2]]
ticks$heights <- rev(ticks$heights)
ticks$grobs <- rev(ticks$grobs)
# Move tick marks
# Get tick mark length
plot_theme <- function(p) {
plyr::defaults(p$theme, theme_get())
}
tml <- plot_theme(p)$axis.ticks.length # Tick mark length
ticks$grobs[[2]]$y <- ticks$grobs[[2]]$y - unit(1, "npc") + tml
# Swap tick mark labels' margins and justifications
ticks$grobs[[1]] <- vinvert_title_grob(ticks$grobs[[1]])
# Put ticks and tick mark labels back into xaxis
xaxis$children[[2]] <- ticks
# Add axis to top of g1
g1 <- gtable_add_rows(g1, g1$heights[g1$layout[index, ]$t], pp$t)
g1 <- gtable_add_grob(g1, xaxis, pp$t+1, pp$l, pp$t+1, pp$r, clip = "off", name = "axis-t")
# Remove original x axis and xlab
g1 = g1[-c(9,10), ]
# Draw it
grid.newpage()
grid.draw(g1)

Related

Shorter tick-marks for minor breaks in ggplot2

I am trying to duplicate/mirror y-axis tick-marks of different sizes for the secondary y-axis using ggplot2 and gtable libraries.
I have successfully shortened minor tick-marks for the primary(left) y-axis by referring to this answer.
Now, I am trying to duplicate or mirror them on secondary(right) y-axis.
I have tried two approaches but neither has produced the desired result.
In the first approach I apply the same method I used for the left axis:
library("ggplot2")
require("scales")
library("ggthemes")
library("grid")
library("gtable")
labs = seq(0,100,10)
labs[!!((seq_along(labs)-1)%%5)] = ''
g <- ggplot(data.frame(x = 1:10, y = (1:10)^2), aes(x,y)) +
geom_point() +
scale_y_continuous(breaks = seq(0,100,10), labels = labs, sec.axis = dup_axis(name = NULL, labels = NULL)) +
theme(axis.ticks.length=unit(10, "pt"), plot.margin = margin(10, 16, 0, 12),panel.grid = element_blank())
gg <- ggplotGrob(g)
yaxisR <- gg$grobs[[which(gg$layout$name == "axis-r")]]
yaxisL <- gg$grobs[[which(gg$layout$name == "axis-l")]]
ticksR <- yaxisR$children[[2]]
ticksL <- yaxisL$children[[2]]
marksR <- ticksR$grobs[[1]]
marksL <- ticksL$grobs[[2]]
marksR$x[c(2:5,7:10)*2-1] <- unit(1, "npc") - unit(5, "pt")
marksL$x[c(2:5,7:10)*2-1] <- unit(1, "npc") - unit(5, "pt")
ticksR$grobs[[1]] <- marksR
ticksL$grobs[[2]] <- marksL
yaxisR$children[[2]] <- ticksR
yaxisL$children[[2]] <- ticksL
gg$grobs[[which(gg$layout$name == "axis-r")]] <- yaxisR
gg$grobs[[which(gg$layout$name == "axis-l")]] <- yaxisL
grid.newpage()
grid.draw(gg)
But the right axis tick-marks get shortened from the wrong side: first result
In the second approach I try to mirror the primary y-axis tick-marks by using this answer :
library("ggplot2")
require("scales")
library("ggthemes")
library("grid")
library("gtable")
labs = seq(0,100,10)
labs[!!((seq_along(labs)-1)%%5)] = ''
g <- ggplot(data.frame(x = 1:10, y = (1:10)^2), aes(x,y)) +
geom_point() +
scale_y_continuous(breaks = seq(0,100,10), labels = labs) +
theme(axis.ticks.length=unit(10, "pt"), plot.margin = margin(10, 16, 0, 12), panel.grid = element_blank())
gg <- ggplotGrob(g)
panel <-c(subset(gg$layout, name=="panel", se=t:r))
yaxisL <- gg$grobs[[which(gg$layout$name == "axis-l")]]
ticksL <- yaxisL$children[[2]]
marksL <- ticksL$grobs[[2]]
marksL$x[c(2:5,7:10)*2-1] <- unit(1, "npc") - unit(5, "pt")
ticksL$grobs[[2]] <- marksL
yaxisL$children[[2]] <- ticksL
gg$grobs[[which(gg$layout$name == "axis-l")]] <- yaxisL
gg <- gtable_add_cols(gg, unit(0, "lines"), panel$r)
gg <- gtable_add_grob(gg, marksL, t = panel$t, l = panel$r+1, name = "ticks")
gg$layout[gg$layout$name == "ticks", ]$clip = "off"
grid.newpage()
grid.draw(gg)
This way results in the right axis tick marks pointing in the wrong direction: second result
Is there anything I can do to either code to have both y-axises identical and mirroring each other? Thank you!
I tried a few things, and I'm not sure I understand it fully, but here is a solution:
The object marksR$x consist of 2 elements per tick line. I think these are the left and right ends of the line. Which means, you only have to add:
marksR$x[c(2:5,7:10)*2] <- unit(0, "npc")
While also keeping
marksR$x[c(2:5,7:10)*2-1] <- unit(1, "npc") - unit(5, "pt")
Which works for me

Follow up on x-axis labels: Stagger axis labels, new feature in ggplot2

Stagger axis labels, new feature in ggplot2
I'm new at R and following the answer of #Sandy Muspratt to #spindoctor is a bit daunting. The answer works great for the y-axis labels. I tried some editing. For example I changed:
index <- which(g$layout$name == "axis-l") # Which grob
to:
index <- which(g$layout$name == "axis-b") # Which grob
But the x-axis labels remained as they were, unstaggered. Could you please indicate how to modify the code so that it works for the x-axis labels as well?
# Get the grob
g <- ggplotGrob(out.plot)
# Get the y axis
index <- which(g$layout$name == "axis-l") # Which grob
yaxis <- g$grobs[[index]]
# Get the ticks (labels and marks)
ticks <- yaxis$children[[2]]
# Get the labels
ticksL <- ticks$grobs[[1]]
# Make the edit
ticksL$children[[1]]$x <- rep(unit.c(unit(c(1,0,-1),"npc")), 27)
# Put the edited labels back into the plot
ticks$grobs[[1]] <- ticksL
yaxis$children[[2]] <- ticks
g$grobs[[index]] <- yaxis
# Make the relevant column a little wider
g$widths[3] <- unit(2.5, "cm")
# Draw the plot
grid.newpage()
grid.draw(g)
The output of the TableGrob is as follows:
>g
TableGrob (6 x 5) "layout": 8 grobs
z cells name grob
1 0 (1-6,1-5) background rect[plot.background..rect.507]
2 3 (3-3,3-3) axis-l absoluteGrob[GRID.absoluteGrob.498]
3 1 (4-4,3-3) spacer zeroGrob[NULL]
4 2 (3-3,4-4) panel gTree[GRID.gTree.484]
5 4 (4-4,4-4) axis-b absoluteGrob[GRID.absoluteGrob.491]
6 5 (5-5,4-4) xlab titleGrob[axis.title.x..titleGrob.501]
7 6 (3-3,2-2) ylab titleGrob[axis.title.y..titleGrob.504]
8 7 (2-2,4-4) title zeroGrob[plot.title..zeroGrob.505]
I tried identifying relevant x,y-axis values but navigating this structure is a bit foreign to me. Any suggestions or comments or resources to avoid time wasted guessing are greatly appreciated.
You just need to change height not width in this case. Also in editGrob you need to pass the y slot not the x since you are changing the coordinates wrt the y-axis not left to right on the x.
I kept everything the same but commented out the things I changed and put my changes directly under.
# Libraries
library(ggplot2)
library(gtable)
library(grid)
library(stringi)
# fake data
set.seed(12345)
var <- stri_rand_strings(81, 4, pattern = '[HrhEgeIdiFtf]')
var1 <- rnorm(81, mean = 175, sd = 75)
out <- data.frame(var, var1)
out$var <- factor(out$var, levels = out$var[order(out$var1, decreasing = FALSE)])
# Plot
# out.plot <- ggplot(out, aes(x = var, y = var1)) + geom_point() + coord_flip()
out.plot <- ggplot(out, aes(x = var1, y = var)) + geom_point() + coord_flip()
# Get the ggplot grob
g = ggplotGrob(out.plot)
# Get a hierarchical list of component grobs
grid.ls(grid.force(g))
# make the relevant column a little wider
# g$widths[3] = unit(2.5, "cm")
g$heights[4] = unit(1, "cm")
# The edit
g = editGrob(grid.force(g),
gPath("axis-b", "axis", "axis", "GRID.text"),
# x = unit(c(-1, 0, 1), "npc"),
y = unit(c(1, 0, -1), "npc"), ## or c(-1,0,1) etc to change order
grep = TRUE)
# Draw the plot
grid.newpage()
grid.draw(g)

ggplot2 2.1.0 broke my code? Secondary transformed axis now appears incorrectly

Some time ago, I inquired about adding a secondary transformed x-axis in ggplot, and Nate Pope provided the excellent solution described at ggplot2: Adding secondary transformed x-axis on top of plot.
That solution worked great for me, and I returned to it hoping it would work for a new project. Unfortunately, the solution doesn't work correctly in the most recent version of ggplot2. Now, running the exact same code leads to a "clipping" of the axis title, as well as overlap of the tick marks and labels. Here is an example, with the problems highlighted in blue:
This example can be reproduced with the following code (this is an exact copy of Nate Pope's code that previously worked marvelously):
library(ggplot2)
library(gtable)
library(grid)
LakeLevels<-data.frame(Day=c(1:365),Elevation=sin(seq(0,2*pi,2*pi/364))*10+100)
## 'base' plot
p1 <- ggplot(data=LakeLevels) + geom_line(aes(x=Elevation,y=Day)) +
scale_x_continuous(name="Elevation (m)",limits=c(75,125)) +
ggtitle("stuff") +
theme(legend.position="none", plot.title=element_text(hjust=0.94, margin = margin(t = 20, b = -20)))
## 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]]
## 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)
Running the above code leads to two critical problems, which I am trying to resolve:
1) How to adjust the x-axis added to the top of the plot to fix the "clipping" and overlap issues?
2) How to include the ggtitle("stuff") added to the first plot p1 in the final plot?
I've been trying to resolve these problems all afternoon, but cannot seem to solve them. Any help is much appreciated. Thanks!
Updated to ggplot2 v 2.2.1, but it is easier to use sec.axis - see here
Original
Moving axes in ggplot2 became more complex from version 2.1.0. This solution draws on code from older solutions and from code in the cowplot package.
With respect to your second issue, it was easier to construct a separate text grob for the "Stuff" title (rather than dealing with ggtitle with its margins).
library(ggplot2) #v 2.2.1
library(gtable) #v 0.2.0
library(grid)
LakeLevels <- data.frame(Day = c(1:365), Elevation = sin(seq(0, 2*pi, 2 * pi/364)) * 10 + 100)
## 'base' plot
p1 <- ggplot(data = LakeLevels) +
geom_path(aes(x = Elevation, y = Day)) +
scale_x_continuous(name = "Elevation (m)", limits = c(75, 125)) +
theme_bw()
## plot with "transformed" axis
p2 <- ggplot(data = LakeLevels) +
geom_path(aes(x = Elevation, y = Day))+
scale_x_continuous(name = "Elevation (ft)", limits = c(75, 125),
breaks = c(80, 90, 100, 110, 120),
labels = round(c(80, 90, 100, 110, 120) * 3.28084)) + ## labels convert to feet
theme_bw()
## Get gtable
g1 <- ggplotGrob(p1)
g2 <- ggplotGrob(p2)
## Get the position of the plot panel in g1
pp <- c(subset(g1$layout, name == "panel", se = t:r))
# Title grobs have margins.
# The margins need to be swapped.
# Function to swap margins -
# taken from the cowplot package:
# https://github.com/wilkelab/cowplot/blob/master/R/switch_axis.R
vinvert_title_grob <- function(grob) {
heights <- grob$heights
grob$heights[1] <- heights[3]
grob$heights[3] <- heights[1]
grob$vp[[1]]$layout$heights[1] <- heights[3]
grob$vp[[1]]$layout$heights[3] <- heights[1]
grob$children[[1]]$hjust <- 1 - grob$children[[1]]$hjust
grob$children[[1]]$vjust <- 1 - grob$children[[1]]$vjust
grob$children[[1]]$y <- unit(1, "npc") - grob$children[[1]]$y
grob
}
# Copy "Elevation (ft)" xlab from g2 and swap margins
index <- which(g2$layout$name == "xlab-b")
xlab <- g2$grobs[[index]]
xlab <- vinvert_title_grob(xlab)
# Put xlab at the top of g1
g1 <- gtable_add_rows(g1, g2$heights[g2$layout[index, ]$t], pp$t-1)
g1 <- gtable_add_grob(g1, xlab, pp$t, pp$l, pp$t, pp$r, clip = "off", name="topxlab")
# Get "feet" axis (axis line, tick marks and tick mark labels) from g2
index <- which(g2$layout$name == "axis-b")
xaxis <- g2$grobs[[index]]
# Move the axis line to the bottom (Not needed in your example)
xaxis$children[[1]]$y <- unit.c(unit(0, "npc"), unit(0, "npc"))
# Swap axis ticks and tick mark labels
ticks <- xaxis$children[[2]]
ticks$heights <- rev(ticks$heights)
ticks$grobs <- rev(ticks$grobs)
# Move tick marks
ticks$grobs[[2]]$y <- ticks$grobs[[2]]$y - unit(1, "npc") + unit(3, "pt")
# Sswap tick mark labels' margins
ticks$grobs[[1]] <- vinvert_title_grob(ticks$grobs[[1]])
# Put ticks and tick mark labels back into xaxis
xaxis$children[[2]] <- ticks
# Add axis to top of g1
g1 <- gtable_add_rows(g1, g2$heights[g2$layout[index, ]$t], pp$t)
g1 <- gtable_add_grob(g1, xaxis, pp$t+1, pp$l, pp$t+1, pp$r, clip = "off", name = "axis-t")
# Add "Stuff" title
titleGrob = textGrob("Stuff", x = 0.9, y = 0.95, gp = gpar(cex = 1.5, fontface = "bold"))
g1 <- gtable_add_grob(g1, titleGrob, pp$t+2, pp$l, pp$t+2, pp$r, name = "Title")
# Draw it
grid.newpage()
grid.draw(g1)
After some thought, I've confirmed that issue #1 originates from changes to recent versions of ggplot2, and I've also come up with a temporary workaround - installing an old version of ggplot2.
Following Installing older version of R package to install ggplot2 1.0.0, I installed ggplot2 1.0.0 using
packageurl <- "http://cran.r-project.org/src/contrib/Archive/ggplot2/ggplot2_1.0.0.tar.gz"
install.packages(packageurl, repos=NULL, type="source")
which I verified with
packageDescription("ggplot2")$Version
Then, re-running the exact code posted above, I was able to produce a plot with the added x-axis correctly displayed:
This is obviously not a very satisfying answer, but it at least works until someone smarter than I can explain why this approach doesn't work in recent versions of ggplot2. :)
So issue #1 from above has been resolved. I'm still haven't resolved issue #2 from above, so would appreciate any insight on that.
As suggested above, you can use sec_axis or dup_axis.
library(ggplot2)
LakeLevels <- data.frame(Day = c(1:365),
Elevation = sin(seq(0, 2*pi, 2 * pi/364)) * 10 + 100)
ggplot(data = LakeLevels) +
geom_path(aes(x = Elevation, y = Day)) +
scale_x_continuous(name = "Elevation (m)", limits = c(75, 125),
sec.axis = sec_axis(trans = ~ . * 3.28084, name = "Elevation (ft)"))
ggplot2 version 3.1.1

Log10 x-axis on top and y-axis geom_line

I have created a graph in ggplot2 that looks like this:
depth = c(1.6,2.6,3.6, 4.6,5.6,6.6,7.6,8.6)
ri <- c(0.790143779,1.485888068,2.682375391,1.728120227,0.948414515,71.43308158,4.416120653,0.125458801)
df = data.frame(depth,ri)
library(ggplot2)
m <- qplot(ri, depth, data=df)
m +
scale_x_log10("Richardson Number",breaks = c(0.1,0.25,0.5,1,5,10, 50)) +
scale_y_reverse("Depth (m)")
This is the output:
What I am trying to do is have the x-axis along the top, and also include a geom_line like the one I have added here (manually in Paint).
I understand that it is difficult to get ggplot2 to move the axes around, and I have tried to reproduce this graph in ggvis but I am unable to get the log10 scale I need. Is there any way I can use R to create the graph I am aiming for?
Updated solution
As of ggplot 2.2.0, axes can be drawn on the top of the panel (and/or on the right of the panel)
library(ggplot2)
depth = c(1.6,2.6,3.6, 4.6,5.6,6.6,7.6,8.6)
ri <- c(0.790143779,1.485888068,2.682375391,1.728120227,0.948414515,71.43308158,4.416120653,0.125458801)
df = data.frame(depth,ri)
m <- qplot(ri, depth, data=df) +
scale_x_log10("Richardson Number",breaks = c(0.1,0.25,0.5,1,5,10, 50),
position = "top") +
scale_y_reverse("Depth (m)")+
geom_path()
Original solution The original, after a little updating to ggplot version2.2.0.
Axes can be moved around using gtable functions. Adapting code from #Walter's answer here, the basic idea is to: get the axis (the axis text and the tick marks); reverse the axis text and tick marks; add a new row to the gtable layout immediately above the plot panel; insert the modified axis into the new row.
library(ggplot2)
library(gtable)
library(grid)
depth = c(1.6,2.6,3.6, 4.6,5.6,6.6,7.6,8.6)
ri <- c(0.790143779,1.485888068,2.682375391,1.728120227,0.948414515,71.43308158,4.416120653,0.125458801)
df = data.frame(depth,ri)
m <- qplot(ri, depth, data=df) +
scale_x_log10("Richardson Number",breaks = c(0.1,0.25,0.5,1,5,10, 50)) +
scale_y_reverse("Depth (m)")+
geom_path()
# Get ggplot grob
g1 <- ggplotGrob(m)
## Get the position of the plot panel in g1
pp <- c(subset(g1$layout, name == "panel", se = t:r))
# Title grobs have margins.
# The margins need to be swapped.
# Function to swap margins -
# taken from the cowplot package:
# https://github.com/wilkelab/cowplot/blob/master/R/switch_axis.R
vinvert_title_grob <- function(grob) {
heights <- grob$heights
grob$heights[1] <- heights[3]
grob$heights[3] <- heights[1]
grob$vp[[1]]$layout$heights[1] <- heights[3]
grob$vp[[1]]$layout$heights[3] <- heights[1]
grob$children[[1]]$hjust <- 1 - grob$children[[1]]$hjust
grob$children[[1]]$vjust <- 1 - grob$children[[1]]$vjust
grob$children[[1]]$y <- unit(1, "npc") - grob$children[[1]]$y
grob
}
# Get xlab and swap margins
index <- which(g1$layout$name == "xlab-b")
xlab <- g1$grobs[[index]]
xlab <- vinvert_title_grob(xlab)
# Put xlab at the top of g1
g1 <- gtable_add_rows(g1, g1$heights[g1$layout[index, ]$t], pp$t-1)
g1 <- gtable_add_grob(g1, xlab, pp$t, pp$l, pp$t, pp$r, clip = "off", name="topxlab")
# Get x axis (axis line, tick marks and tick mark labels)
index <- which(g1$layout$name == "axis-b")
xaxis <- g1$grobs[[index]]
# Swap axis ticks and tick mark labels
ticks <- xaxis$children[[2]]
ticks$heights <- rev(ticks$heights)
ticks$grobs <- rev(ticks$grobs)
# Move tick marks
# Get tick mark length
plot_theme <- function(p) {
plyr::defaults(p$theme, theme_get())
}
tml <- plot_theme(m)$axis.ticks.length # Tick mark length
ticks$grobs[[2]]$y <- ticks$grobs[[2]]$y - unit(1, "npc") + tml
# Swap tick mark labels' margins and justifications
ticks$grobs[[1]] <- vinvert_title_grob(ticks$grobs[[1]])
# Put ticks and tick mark labels back into xaxis
xaxis$children[[2]] <- ticks
# Add axis to top of g1
g1 <- gtable_add_rows(g1, g1$heights[g1$layout[index, ]$t], pp$t)
g1 <- gtable_add_grob(g1, xaxis, pp$t+1, pp$l, pp$t+1, pp$r, clip = "off", name = "axis-t")
# Remove original x axis and xlab
g1 = g1[-c(9,10), ]
# Draw it
grid.newpage()
grid.draw(g1)

x axis on top of the figure in ggplot [duplicate]

Anybody knows how to draw the X-axis tickmarks at the top of a single plot in R, using ggplot2? I ve been looking at tutorials and mail lists and Rhelp without success.
Thanks in advance.
Agus
Use position = 'top'
library(ggplot2)
# Generate some data
df = data.frame(x = 1:10, y = 1:10)
# x-axis breaks
breaks = 1:10
# base plot
p <- ggplot(df, aes(x,y)) + geom_point() +
scale_x_continuous(breaks = breaks, position = 'top') +
scale_y_continuous(limits = c(0, 11), expand = c(0,0)) +
theme_bw()
Original solution available using gtable (with some updating to ggplot 2.1.0). See here
library(ggplot2)
library(gtable)
library(grid)
# Generate some data
df = data.frame(x = 1:10, y = 1:10)
# x-axis breaks
breaks = 1:10
# base plot
p <- ggplot(df, aes(x,y)) + geom_point() +
scale_x_continuous(breaks = breaks) +
scale_y_continuous(limits = c(0, 11), expand = c(0,0)) +
theme_bw()
# Get ggplot grob
g1 <- ggplotGrob(p)
## Get the position of the plot panel in g1
pp <- c(subset(g1$layout, name == "panel", se = t:r))
# Title grobs have margins.
# The margins need to be swapped.
# Function to swap margins -
# taken from the cowplot package:
# https://github.com/wilkelab/cowplot/blob/master/R/switch_axis.R
vinvert_title_grob <- function(grob) {
heights <- grob$heights
grob$heights[1] <- heights[3]
grob$heights[3] <- heights[1]
grob$vp[[1]]$layout$heights[1] <- heights[3]
grob$vp[[1]]$layout$heights[3] <- heights[1]
grob$children[[1]]$hjust <- 1 - grob$children[[1]]$hjust
grob$children[[1]]$vjust <- 1 - grob$children[[1]]$vjust
grob$children[[1]]$y <- unit(1, "npc") - grob$children[[1]]$y
grob
}
# Get xlab and swap margins
index <- which(g1$layout$name == "xlab-b")
xlab <- g1$grobs[[index]]
xlab <- vinvert_title_grob(xlab)
# Put xlab at the top of g1
g1 <- gtable_add_rows(g1, g1$heights[g1$layout[index, ]$t], pp$t-1)
g1 <- gtable_add_grob(g1, xlab, pp$t, pp$l, pp$t, pp$r, clip = "off", name="topxlab")
# Get x axis (axis line, tick marks and tick mark labels)
index <- which(g1$layout$name == "axis-b")
xaxis <- g1$grobs[[index]]
# Swap axis ticks and tick mark labels
ticks <- xaxis$children[[2]]
ticks$heights <- rev(ticks$heights)
ticks$grobs <- rev(ticks$grobs)
# Move tick marks
# Get tick mark length
plot_theme <- function(p) {
plyr::defaults(p$theme, theme_get())
}
tml <- plot_theme(p)$axis.ticks.length # Tick mark length
ticks$grobs[[2]]$y <- ticks$grobs[[2]]$y - unit(1, "npc") + tml
# Swap tick mark labels' margins and justifications
ticks$grobs[[1]] <- vinvert_title_grob(ticks$grobs[[1]])
# Put ticks and tick mark labels back into xaxis
xaxis$children[[2]] <- ticks
# Add axis to top of g1
g1 <- gtable_add_rows(g1, g1$heights[g1$layout[index, ]$t], pp$t)
g1 <- gtable_add_grob(g1, xaxis, pp$t+1, pp$l, pp$t+1, pp$r, clip = "off", name = "axis-t")
# Remove original x axis and xlab
g1 = g1[-c(9,10), ]
# Draw it
grid.newpage()
grid.draw(g1)

Resources