directlabels:对同一地块中的不同面板使用不同的定位方法

directlabels: using different positioning methods for different panels in the same plot

我有一个双面板点阵线图。我想使用 directlabels 包自动标记每个图中的线条。但是我想对每个地块使用不同的定位方法。具体来说,我想对第一个面板使用 first.bumpup 方法,对第二个面板使用 last.bumpup 方法。这是一个最小的例子:

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')

此代码生成一个绘图,其中标签显示在每个面板的左侧:

我希望标签位于左侧面板的左侧(如本例所示),但位于右侧面板的右侧。生成这种图形的最简单方法是什么?

我检查了 advanced examples in the directlabels documentation,它们让我认为可以通过创建自定义定位方法或自定义面板对不同的面板使用不同的方法。但是我不太明白该怎么做。

我用 ggplot2 解决了这个问题(只是因为我对 ggplot2 的了解比对 lattice 的了解多得多)。让我知道你的想法。以下是两种方法。第一个实际上不使用 directlabels。放置规则比较简单,所以我只是用geom_text来放置label。第二种方法确实使用了directlabels,但更复杂。

使用 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)

在上面的代码中,在 geom_text 中,我们只保留第一个面板的最低 x 值和第二个面板的最高 x 值,然后将 group 标签位于与 x 值配对的 y 值处。 x + 0.07*(panel-mean(panel)) 只是让标签稍微远离行尾。

使用 mapplydirectlabels

放置标签

这里有一个使用 directlabels 的更复杂的方法。我的方法是使用 mapply 分别绘制每个 "facet",这样我就可以对每个面板使用不同的 directlabels 方法,然后将两个图放在一起,就好像它们是两个方面一样相同的整体情节。如果您喜欢这个结果,如果 none 的 ggplot2 版本满足您的需要,也许您可​​以将其调整为 lattice 图。

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)

因为我删除了面板 2 中的 y-axis 标题、标签和刻度,所以该面板比面板 1 宽。plot_grid 有一个 align 参数允许我们对齐两个地块,以便它们具有相同的宽度,但我不知道如何摆脱地块之间的 space 。 grid.arrange 也会布置该图,但我们必须手动调整宽度(您也可以使用 plot_grid 手动调整宽度)。

# 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))

这是对 eipi10 的第二个解决方案的改编,它在格子图中产生了预期的效果:

library(directlabels)
library(gridExtra)
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))

plotFunction <- function(panelNumber, labelMethod) {
  myPlot = xyplot(
    y ~ x, 
    groups = group, 
    data   = myDF[myDF$panel==panelNumber, ], 
    type   = 'l')
  direct.label(
    p      = myPlot,
    method = labelMethod)  
} 

panelList = mapply(
  FUN         = plotFunction, 
  panelNumber = unique(myDF$panel), 
  labelMethod = c('first.bumpup', 'last.bumpup'), 
  SIMPLIFY    = FALSE)

grid.arrange(grobs = panelList, ncol = 2)