直接标签包--标签不适合绘图区域

11

我想用ggplot的directlabels包探索。我试图在简单线图的端点处绘制标签;然而,标签被绘图面板裁剪了。(我打算在一个图中绘制约10个金融时间序列,我认为directlabels是最好的解决方案。)

我想象中可能还有另一种使用annotate或其他geoms的解决方案。但我想使用directlabels解决问题。请参见下面的代码和图片。谢谢。

library(ggplot2)
library(directlabels)
library(tidyr)

#generate data frame with random data, for illustration and plot:
x <- seq(1:100)
y <- cumsum(rnorm(n = 100, mean = 6, sd = 15))
y2 <- cumsum(rnorm(n = 100, mean = 2, sd = 4))
data <- as.data.frame(cbind(x, y, y2))
names(data) <- c("month", "stocks", "bonds")
tidy_data <- gather(data, month)
names(tidy_data) <- c("month", "asset", "value")
p <- ggplot(tidy_data, aes(x = month, y = value, colour = asset)) + 
geom_line() + 
geom_dl(aes(colour = asset, label = asset), method = "last.points") + 
theme_bw()

带有终点标签的折线图

关于数据可视化原则,我倾向于避免延长 x 轴来适应标签——这意味着会存在没有数据的数据空间。相反,我希望标签朝着图表框/面板之外的空白区域延伸(如果这样说可以理解的话)。


由于有更好的答案存在,下面的回答现在已经稍微过时了,因此需要重新排列文本。 - Ben Bolker
2个回答

13
在我看来,直接标签是可行的方式。实际上,我会将标签放置在行的开头和结尾,并利用expand()为标签创建空间。此外,请注意,有了标签,就不需要图例。
这类似于这里这里的答案。
library(ggplot2)
library(directlabels)
library(grid)
library(tidyr)

x <- seq(1:100)
y <- cumsum(rnorm(n = 100, mean = 6, sd = 15))
y2 <- cumsum(rnorm(n = 100, mean = 2, sd = 4))
data <- as.data.frame(cbind(x, y, y2))
names(data) <- c("month", "stocks", "bonds")
tidy_data <- gather(data, month)
names(tidy_data) <- c("month", "asset", "value")

ggplot(tidy_data, aes(x = month, y = value, colour = asset, group = asset)) + 
     geom_line() + 
     scale_colour_discrete(guide = 'none')  + 
     scale_x_continuous(expand = c(0.15, 0)) +
     geom_dl(aes(label = asset), method = list(dl.trans(x = x + .3), "last.bumpup")) +
     geom_dl(aes(label = asset), method = list(dl.trans(x = x - .3), "first.bumpup")) + 
     theme_bw() 

enter image description here

如果您希望将标签推入图形边缘,直接标签可以做到这一点。但是由于标签位于绘图面板外部,所以需要关闭裁剪。
p1 <- ggplot(tidy_data, aes(x = month, y = value, colour = asset, group = asset)) + 
     geom_line() + 
     scale_colour_discrete(guide = 'none')  + 
     scale_x_continuous(expand = c(0, 0)) +
     geom_dl(aes(label = asset), method = list(dl.trans(x = x + .3), "last.bumpup")) +
     theme_bw() +
     theme(plot.margin = unit(c(1,4,1,1), "lines")) 

# Code to turn off clipping
gt1 <- ggplotGrob(p1)
gt1$layout$clip[gt1$layout$name == "panel"] <- "off"
grid.draw(gt1)

enter image description here

这种效果也可以使用geom_text(可能还包括annotate)实现,而无需直接标记。
p2 = ggplot(tidy_data, aes(x = month, y = value, group = asset, colour = asset)) +
  geom_line() + 
  geom_text(data = subset(tidy_data, month == 100), 
      aes(label = asset, colour = asset, x = Inf, y = value), hjust = -.2) +
  scale_x_continuous(expand = c(0, 0)) +
  scale_colour_discrete(guide = 'none')  +  
  theme_bw() +  
  theme(plot.margin = unit(c(1,3,1,1), "lines"))  

# Code to turn off clipping
gt2 <- ggplotGrob(p2)
gt2$layout$clip[gt2$layout$name == "panel"] <- "off"
grid.draw(gt2)

enter image description here


很棒的答案。这些是最佳解决方案。 - Nick Becker
1
现在可以使用coord_cartesian(clip="off")更轻松地完成这项工作...我试图找出如何在文字后面放置一个白色矩形,以防单词跨越绘图框架,但没有成功(这样做更好)。 - Ben Bolker

3

由于您没有提供可重现的示例,很难说什么是最佳解决方案。不过,我建议尝试手动调整x轴比例尺。使用“缓冲区”来增加绘图区域。

#generate data frame with random data, for illustration and plot:
p <- ggplot(tidy_data, aes(x = month, y = value, colour = asset)) + 
geom_line() + 
geom_dl(aes(colour = asset, label = asset), method = "last.points") + 
theme_bw() +
xlim(minimum_value, maximum_value + buffer)

如果您想使用直接标签包,使用scale_x_discrete() 或 scale_x_continuous() 也可能很有效。另外,annotate或简单的geom_text也可以很好地实现此目的。


1
谢谢Nick。你的xlim解决方案很好用。不过,基于数据可视化原则,我想避免扩展x轴以适应标签。相反,我希望标签向图表框/面板之外的空白区域延伸(如果这有意义的话)。 - Juan Mier
顺便提一下,我编辑了原始问题以解释上下文并添加代码。 - Juan Mier
@JuanMier 我完全不反对。不幸的是,我不知道如何实现你所描述的内容。我知道你说你想使用directlabels,但我认为使用annotate并定位标签可能是一个不错的解决方案。 - Nick Becker

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接