I'm struggling to build a dual-axis plot based on ggplot
objects. At baptiste's suggestion, I have broken down the problem into smaller parts. The present issue is:
- how to remove all of the data from the
grobs
, while keeping the axis, the axis labels, the axis tickmarks, and the grid lines? By 'data' I mean the data associated withgeom_line()
andgeom_points()
.
The reason for wanting to do this is that in the process of building a dual-axis plot, I ran into the following problem: the grid lines from one grob would overwrite the data from the other grob. By removing the data lines and points, there would be no overwriting.
Let me be clear: I do have workarounds that consist in adding a linetype to the aes() and setting scale_linetype_manual(values = c("solid", "blank") or, alternatively, sending the data 'off the grid', but I would like to post-process a plot object that has not been 'groomed' too much for the purpose at hand.
Below some code and figures.
# Data
df <- structure(list(Year = c(1950, 2013, 1950, 2013), Country = structure(c(1L,
1L, 2L, 2L), .Label = c("France", "United States"), class = "factor"),
Category = c("Hourly minimum wage", "Hourly minimum wage",
"Hourly minimum wage", "Hourly minimum wage"), value = c(2.14,
9.43, 3.84, 7.25), variable = c("France (2013 euros)",
"France (2013 euros)", "United States (2013 dollars)", "United States (2013 dollars)"
), Unit = c("2013 euros", "2013 euros", "2013 dollars", "2013 dollars"
)), .Names = c("Year", "Country", "Category", "value", "variable",
"Unit"), row.names = c(NA, 4L), class = "data.frame")
# Plot data with ggplot
library(ggplot2)
p <- ggplot(data = df, aes(x = Year, y = value, group = variable, colour = variable, shape = variable)) +
geom_line(size = 2) +
geom_point(size = 4) +
theme(panel.grid.major = element_line(size = 1, colour = "darkgreen"),
panel.grid.minor = element_line(size = 1, colour = "darkgreen", linetype = "dotted"))
# Manipulate grobs with gtable
library(gtable)
g <- ggplot_gtable(ggplot_build(p))
## Here remove the geom_line() and geom_point()
## g <- stripdata(g) # pseudo-code!
grid.newpage()
grid.draw(g)
In the plot below, I would like the lines gone!
Edit: Following baptiste's suggestion, I attempt to remove the data layers. However, as BondedDust points out in the comments section, this breaks the ggplot object:
# Remove the two layers of data
p$layers[[1]] <- NULL
p$layers[[1]] <- NULL
g <- ggplot_gtable(ggplot_build(p))
## Error: No layers in plot
Removing the data from the ggplot object destroys it. One workaround I have used in applications is to 'send the data off the grid', e.g. multiplying each cell by -999999 and cuting off the display with + scale_y_continuous(limits = c(1, 10))
, but I'd like to avoid this ugly hack, if feasible. I was hoping that the associated gtable would not be destroyed if I replaced every data point with NA or NULL, so that's why I was looking for a way to remove the data from inside the g object, rather than the p object.
After manipulation of the grobs (rather than hacking directly the ggplot object), the result of grid.draw(g)
would be:
FYI, the second plot was obtained with the following workaround.
p <- ggplot(data = within(df, value <- -999999), aes(x = Year, y = value, group = variable, colour = variable, shape = variable)) +
geom_line() +
geom_point() +
theme(panel.grid.major = element_line(size = 1, colour = "darkgreen"),
panel.grid.minor = element_line(size = 1, colour = "darkgreen", linetype = "dotted")) +
scale_y_continuous(limits = c(1, 10))
A more natural strategy would be to use invisible
geom_blank
layers, so that ggplot2 still trains the scales etc to build the plot but shows no data. Since you want to process already-formatted plots, however, you probably have to remove manually those grobs from the plot gTree. Here's an attempt,