I have a two-panel lattice lineplot. I want to use the directlabels
package to automatically label the lines in each plot. But I want to use a different positioning method for each plot. Specifically, I want to use the first.bumpup
method for the first panel, and the last.bumpup
method for the second panel. Here is a minimal example:
library(directlabels)
library(lattice)
myDF <- data.frame(
y = rep(1:4, 2),
x = rep(rep(1:2, 2), 2),
group = rep(c('a', 'b'), each = 2),
panel = rep(1:2, each = 4))
myPlot <- xyplot(y ~ x | panel, groups = group, data = myDF, type = 'l')
direct.label(
p = myPlot,
method = 'first.bumpup')
This code produces a plot in which labels appear on the left-hand side of each panel:
I want labels on the left-hand side of the left-hand panel (as in this example), but on the right-hand side of the right-hand panel. What is the simplest way to produce that sort of figure?
I've checked the advanced examples in the directlabels
documentation, and they make me think that it may be possible to use different methods for different panels by creating a custom positioning method or a custom panel. But I cannot quite see how to do it.
I took a crack at this with ggplot2
(only because I know ggplot2
much better than I know lattice
). Let me know what you think. Below are two approaches. The first actually doesn't use directlabels
. The placement rule is relatively simple, so I just used geom_text
for label placement. The second method does use directlabels
, but is more complicated.
geom_text
library(dplyr) # For chaining operator (%>%)
library(ggplot2)
library(cowplot) # For cowplot theme
ggplot(myDF, aes(x, y, colour=group)) +
geom_line() +
geom_text(data=myDF %>% group_by(panel) %>%
filter(ifelse(panel==1, x==min(x), x==max(x))),
aes(x + 0.07*(panel-mean(panel)), y, label=group)) +
facet_grid(~panel) +
scale_x_continuous(breaks=seq(1,2,0.2)) +
theme_cowplot() +
guides(colour=FALSE)
In the code above, inside geom_text
we keep only the lowest x
value for the first panel and the highest x
value in the second panel and then place the group
labels at the y
values that pair with the x
values. The x + 0.07*(panel-mean(panel))
is just to move the labels slightly away from the ends of the lines.
mapply
and directlabels
Here's a more complicated method using directlabels
. My approach was to plot each "facet" separately using mapply
, so that I could use a different directlabels
method for each panel, but then lay the two plots out together as if they were two facets of the same overall plot. If you like the result, maybe you can adapt it to a lattice
plot if none of the ggplot2 versions meet your needs.
library(directlabels)
library(ggplot2)
library(gridExtra)
library(cowplot)
pl = mapply(function(pnl, m) {
# Create plot for each level of panel
p = ggplot(myDF[myDF$panel==pnl, ], aes(x, y, colour=group)) +
geom_line() +
facet_grid(~panel) +
scale_x_continuous(breaks=seq(1,2,0.2)) +
theme_cowplot()
# # Tweak margins of panel 1
# if(pnl==1) p = p + theme(plot.margin=unit(rep(0,4),"lines"))
# Remove y-axis title, labels and ticks for panel 2 and tweak margins
if(pnl==2) p = p + theme(axis.title.y=element_blank(),
axis.text.y=element_blank(),
axis.ticks.y=element_blank())
# Add directlabels with different method for each panel
direct.label(p, method=m)
},
pnl=unique(myDF$panel), m=c("first.bumpup", "last.bumpup"), SIMPLIFY=FALSE)
Because I removed the y-axis title, labels, and ticks in panel 2, that panel is wider than panel 1. plot_grid
has an align
argument that allows us to align the two plots so that they have the same width, but I don't know of a way to get rid of the space between the plots. grid.arrange
will also lay out that plots, but we have to adjust the widths manually (you can adjust the widths manually with plot_grid
as well).
# Lay out each panel using plot_grid from cowplot package
plot_grid(plotlist=pl, ncol=2, align="v")
# Lay out each panel using grid.arrange from gridExtra package
grid.arrange(grobs=pl, ncol=2, widths=c(10,9))