在行尾绘制标签

Posted

技术标签:

【中文标题】在行尾绘制标签【英文标题】:Plot labels at ends of lines 【发布时间】:2015-06-04 03:23:49 【问题描述】:

我有以下数据(temp.dat完整数据见尾注)

   Year State     Capex
1  2003   VIC  5.356415
2  2004   VIC  5.765232
3  2005   VIC  5.247276
4  2006   VIC  5.579882
5  2007   VIC  5.142464
...

我可以生成以下图表:

ggplot(temp.dat) + 
  geom_line(aes(x = Year, y = Capex, group = State, colour = State))

我想要标签而不是图例

    颜色与系列相同 每个系列的最后一个数据点的右侧

我在以下链接的答案中注意到 baptiste 的 cmets,但是当我尝试调整他的代码 (geom_text(aes(label = State, colour = State, x = Inf, y = Capex), hjust = -1)) 时,文本没有出现。

ggplot2 - annotate outside of plot

temp.dat <- structure(list(Year = c("2003", "2004", "2005", "2006", "2007", 
"2008", "2009", "2010", "2011", "2012", "2013", "2014", "2003", 
"2004", "2005", "2006", "2007", "2008", "2009", "2010", "2011", 
"2012", "2013", "2014", "2003", "2004", "2005", "2006", "2007", 
"2008", "2009", "2010", "2011", "2012", "2013", "2014", "2003", 
"2004", "2005", "2006", "2007", "2008", "2009", "2010", "2011", 
"2012", "2013", "2014"), State = structure(c(1L, 1L, 1L, 1L, 
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 
2L, 2L, 2L, 2L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 
4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L), .Label = c("VIC", 
"NSW", "QLD", "WA"), class = "factor"), Capex = c(5.35641472365348, 
5.76523240652641, 5.24727577535625, 5.57988239709746, 5.14246402568366, 
4.96786288162828, 5.493190785287, 6.08500616799372, 6.5092228474591, 
7.03813541623157, 8.34736513875897, 9.04992300432169, 7.15830329914056, 
7.21247045701994, 7.81373928617117, 7.76610217197542, 7.9744994967006, 
7.93734452080786, 8.29289899132255, 7.85222269563982, 8.12683746325074, 
8.61903784301649, 9.7904327253813, 9.75021175267288, 8.2950673974226, 
6.6272705639724, 6.50170524635367, 6.15609626379471, 6.43799637295979, 
6.9869551384028, 8.36305663640294, 8.31382617231745, 8.65409824343971, 
9.70529678167458, 11.3102788081848, 11.8696420977237, 6.77937303542605, 
5.51242844820827, 5.35789621712839, 4.38699327451101, 4.4925792218211, 
4.29934654081527, 4.54639175257732, 4.70040615159951, 5.04056109514957, 
5.49921208937735, 5.96590909090909, 6.18700407463007)), class = "data.frame", row.names = c(NA, 
-48L), .Names = c("Year", "State", "Capex"))

【问题讨论】:

我只会创建一个单独的数据框,其中只包含您想要绘制的数据,就像 geom_text(data = temp.dat[cumsum(table(temp.dat$State)), ], aes(label = State, colour = State, x = Year, y = Capex)) 一样,但可能有更多的 gg 方式来做事 【参考方案1】:

要使用 Baptiste 的想法,您需要关闭剪辑。但是当你这样做时,你会得到垃圾。此外,您需要隐藏图例,对于 geom_text,选择 2014 年的 Capex,并增加边距以便为标签留出空间。 (或者您可以调整hjust 参数以在绘图面板内移动标签。)像这样:

library(ggplot2)
library(grid)

p = ggplot(temp.dat) + 
  geom_line(aes(x = Year, y = Capex, group = State, colour = State)) + 
  geom_text(data = subset(temp.dat, Year == "2014"), aes(label = State, colour = State, x = Inf, y = Capex), hjust = -.1) +
  scale_colour_discrete(guide = 'none')  +    
  theme(plot.margin = unit(c(1,3,1,1), "lines")) 

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

但是,这种情节非常适合directlabels

library(ggplot2)
library(directlabels)

ggplot(temp.dat, aes(x = Year, y = Capex, group = State, colour = State)) + 
  geom_line() +
  scale_colour_discrete(guide = 'none') +
  scale_x_discrete(expand=c(0, 1)) +
  geom_dl(aes(label = State), method = list(dl.combine("first.points", "last.points")), cex = 0.8) 

编辑增加端点和标签之间的空间:

ggplot(temp.dat, aes(x = Year, y = Capex, group = State, colour = State)) + 
  geom_line() +
  scale_colour_discrete(guide = 'none') +
  scale_x_discrete(expand=c(0, 1)) +
  geom_dl(aes(label = State), method = list(dl.trans(x = x + 0.2), "last.points", cex = 0.8)) +
  geom_dl(aes(label = State), method = list(dl.trans(x = x - 0.2), "first.points", cex = 0.8)) 

【讨论】:

不知道directlabels 包。我在文档中看不到手动增加端点和文本标签之间的水平空间的方法。最好的方法是什么? 我添加了一个编辑。请参阅http://directlabels.r-forge.r-project.org/ 的常见问题解答(第 5 号) 尝试安装包:package ‘directlabels’ is not available (for R version 3.3.2)。我也找不到该软件包的常见问题解答网站。它还活着吗? @MERose 嗯。我不确定发生了什么。该链接仍然有效。 “常见问题”在首页。而且我刚刚检查过 cran - directlabels 可用。 @slhck,好像还没有安装。你试过安装quadprog吗?【参考方案2】:

较新的解决方案是使用ggrepel

library(ggplot2)
library(ggrepel)
library(dplyr)

temp.dat %>%
  mutate(label = if_else(Year == max(Year), as.character(State), NA_character_)) %>%
  ggplot(aes(x = Year, y = Capex, group = State, colour = State)) + 
  geom_line() + 
  geom_label_repel(aes(label = label),
                  nudge_x = 1,
                  na.rm = TRUE)

【讨论】:

完美 - 但我添加了“scale_color_discrete(guide = FALSE)”以从图表外部删除现在不必要的图例(节省一些重要的屏幕空间) 你好,能不能扩展成这个案例:***.com/questions/48487713/…?【参考方案3】:

这个问题很老但是很金,我为疲惫的 ggplot 人提供了另一个答案。

这个解决方案的原理可以相当普遍地应用。

Plot_df <- 
  temp.dat %>% mutate_if(is.factor, as.character) %>%  # Who has time for factors..
  mutate(Year = as.numeric(Year))

现在,我们可以对数据进行子集化

ggplot() + 
geom_line(data = Plot_df, aes(Year, Capex, color = State)) +
geom_text(data = Plot_df %>% filter(Year == last(Year)), aes(label = State, 
                                                           x = Year + 0.5, 
                                                           y = Capex, 
                                                           color = State)) + 
          guides(color = FALSE) + theme_bw() + 
          scale_x_continuous(breaks = scales::pretty_breaks(10))

最后的 pretty_breaks 部分只是为了修复下面的轴。

【讨论】:

【参考方案4】:

不确定这是否是最好的方法,但您可以尝试以下方法(与xlim 一起玩一下以正确设置限制):

library(dplyr)
lab <- tapply(temp.dat$Capex, temp.dat$State, last)
ggplot(temp.dat) + 
    geom_line(aes(x = Year, y = Capex, group = State, colour = State)) +
    scale_color_discrete(guide = FALSE) +
    geom_text(aes(label = names(lab), x = 12, colour = names(lab), y = c(lab), hjust = -.02))

【讨论】:

这会产生一条错误消息:“错误:美学必须是长度 1 或与数据 (48) 相同:x、y、标签、hjust”【参考方案5】:

我想为标签名称较长的情况添加一个解决方案。在提供的所有解决方案中,标签都在绘图画布内,但如果您的名称较长,它们将被截断。以下是我解决该问题的方法:

library(tidyverse)

# Make the "State" variable have longer levels
temp.dat <- temp.dat %>% 
    mutate(State = paste0(State, '-a-long-string'))

ggplot(temp.dat, aes(x = Year, y = Capex, color = State, group = State)) + 
    geom_line() +
    # Add labels at the end of the line
    geom_text(data = filter(temp.dat, Year == max(Year)),
              aes(label = State),
              hjust = 0, nudge_x = 0.1) +
    # Allow labels to bleed past the canvas boundaries
    coord_cartesian(clip = 'off') +
    # Remove legend & adjust margins to give more space for labels
    # Remember, the margins are t-r-b-l
    theme(legend.position = 'none',
          plot.margin = margin(0.1, 2.6, 0.1, 0.1, "cm")) 

【讨论】:

如果我想在较低的一个点上放置一些标记或 X 或坐标,我将不胜感激(在这种情况下,我如何在 (2008, 5) 放置一些标签在 WA-a-long-string 中?感谢您的回复! 在我的解决方案中,我过滤数据以选择我想要的标签的确切 x 和 y 坐标。由于我希望它们位于行尾,因此我在 geom_text() 调用中使用了 data = filter(temp.dat, Year == max(Year))。在您的情况下,您可以将过滤器更改为data = filter(temp.dat, Year == 2008, State = "WA"),这只会在2008年的x位置为您提供“WA”标签,您可以通过调整nudge_y中的nudge_y参数来调整y位置@ 我不认为这是一种改进,因为硬设置边距是不切实际的。按照我下面的解决方案: temp.dat % mutate(State = paste0(State, '-a-long-string')) Plot_df % mutate_if(is.factor, as .character) %>% mutate(Year = as.numeric(Year)) ggplot() + geom_line(data = Plot_df, aes(Year, Capex, color = State)) + geom_text(data = Plot_df %>% filter(Year == last(Year)), aes(label = State, x = Year + 3, y = Capex, color = State), hjust = 1) + guides(color = FALSE) + theme_bw() + scale_x_continuous(breaks = scales ::pretty_breaks(10)) 不确定是什么让硬设置边距不如硬设置比例限制实用。排名靠前的解决方案修改了绘图边距。我在我的解决方案和您的解决方案之间看到的更大区别是,在我的解决方案中,x 轴在最后一个数据点处停止,而在您的解决方案中,它会根据需要继续延伸,以便标签名称适合没有数据的绘图边界内点。 @jhelvy 两件事。首先,硬设置边距并不比增加 x 边距更简单(一个输入 - 3 年,直观且简单。边距为 4 个输入且不直观)。最后一点,您希望图形的 x 轴扩展 - 否则您的名称会超出您的解决方案中的主题(正是您不想要的)。在我的解决方案中-名称仍在您的主题中,而您的则在外面。这当然不理想。评分最高的解决方案已过时(比此处的其他解决方案繁琐得多)-并且名称超出了主题选择范围。【参考方案6】:

我来这个问题是为了在最后一个拟合点而不是最后一个数据点直接标记一条拟合线(例如loess())。我最终制定了一种方法来做到这一点,主要基于 tidyverse 它也应该适用于带有一些模型的线性回归,所以我把它留在这里留给后代。

library(tidyverse)

temp.dat$Year <- as.numeric(temp.dat$Year)
temp.dat$State <- as.character(temp.dat$State)

#example of loess for multiple models
#https://***.com/a/55127487/4927395

models <- temp.dat %>%
  tidyr::nest(-State) %>%
  dplyr::mutate(
    # Perform loess calculation on each CpG group
    m = purrr::map(data, loess,
                   formula = Capex ~ Year, span = .75),
    # Retrieve the fitted values from each model
    fitted = purrr::map(m, `[[`, "fitted")
  )

# Apply fitted y's as a new column
results <- models %>%
  dplyr::select(-m) %>%
  tidyr::unnest()

#find final x values for each group
my_last_points <- results %>% group_by(State) %>% summarise(Year = max(Year, na.rm=TRUE))

#Join dataframe of predictions to group labels
my_last_points$pred_y <- left_join(my_last_points, results)

# Plot with loess line for each group
ggplot(results, aes(x = Year, y = Capex, group = State, colour = State)) +
  geom_line(alpha = I(7/10), color="grey", show.legend=F) +
  #stat_smooth(size=2, span=0.3, se=F, show_guide=F)
  geom_point(size=1) +
  geom_smooth(se=FALSE)+
  geom_text(data = my_last_points, aes(x=Year+0.5, y=pred_y$fitted, label = State))

【讨论】:

【参考方案7】:

您没有 100% 效仿 @Baptiste 的解决方案。您需要使用annotation_custom 并遍历您所有的Capex

library(ggplot2)
library(dplyr)
library(grid)

temp.dat <- structure(list(Year = c("2003", "2004", "2005", "2006", "2007", 
"2008", "2009", "2010", "2011", "2012", "2013", "2014", "2003", 
"2004", "2005", "2006", "2007", "2008", "2009", "2010", "2011", 
"2012", "2013", "2014", "2003", "2004", "2005", "2006", "2007", 
"2008", "2009", "2010", "2011", "2012", "2013", "2014", "2003", 
"2004", "2005", "2006", "2007", "2008", "2009", "2010", "2011", 
"2012", "2013", "2014"), State = structure(c(1L, 1L, 1L, 1L, 
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 
2L, 2L, 2L, 2L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 
4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L), .Label = c("VIC", 
"NSW", "QLD", "WA"), class = "factor"), Capex = c(5.35641472365348, 
5.76523240652641, 5.24727577535625, 5.57988239709746, 5.14246402568366, 
4.96786288162828, 5.493190785287, 6.08500616799372, 6.5092228474591, 
7.03813541623157, 8.34736513875897, 9.04992300432169, 7.15830329914056, 
7.21247045701994, 7.81373928617117, 7.76610217197542, 7.9744994967006, 
7.93734452080786, 8.29289899132255, 7.85222269563982, 8.12683746325074, 
8.61903784301649, 9.7904327253813, 9.75021175267288, 8.2950673974226, 
6.6272705639724, 6.50170524635367, 6.15609626379471, 6.43799637295979, 
6.9869551384028, 8.36305663640294, 8.31382617231745, 8.65409824343971, 
9.70529678167458, 11.3102788081848, 11.8696420977237, 6.77937303542605, 
5.51242844820827, 5.35789621712839, 4.38699327451101, 4.4925792218211, 
4.29934654081527, 4.54639175257732, 4.70040615159951, 5.04056109514957, 
5.49921208937735, 5.96590909090909, 6.18700407463007)), class = "data.frame", row.names = c(NA, 
-48L), .Names = c("Year", "State", "Capex"))

temp.dat$Year <- factor(temp.dat$Year)

color <- c("#8DD3C7", "#FFFFB3", "#BEBADA", "#FB8072")

gg <- ggplot(temp.dat) 
gg <- gg + geom_line(aes(x=Year, y=Capex, group=State, colour=State))
gg <- gg + scale_color_manual(values=color)
gg <- gg + labs(x=NULL)
gg <- gg + theme_bw()
gg <- gg + theme(legend.position="none")

states <- temp.dat %>% filter(Year==2014)

for (i in 1:nrow(states))  
  print(states$Capex[i])
  print(states$Year[i])
  gg <- gg + annotation_custom(
    grob=textGrob(label=states$State[i], 
                    hjust=0, gp=gpar(cex=0.75, col=color[i])),
    ymin=states$Capex[i],
    ymax=states$Capex[i],
    xmin=states$Year[i],
    xmax=states$Year[i])
    

gt <- ggplot_gtable(ggplot_build(gg))
gt$layout$clip[gt$layout$name == "panel"] <- "off"
grid.newpage()
grid.draw(gt)

(如果你保持白色背景,你会想要改变黄色。)

【讨论】:

以上是关于在行尾绘制标签的主要内容,如果未能解决你的问题,请参考以下文章

在行选择Swift 3上设置TableViewCell标签颜色

css #CSS:在行尾显示三个点(...)

使用 notepad++ 编辑器在行首行尾添加字符

LazyStruct:在行尾检测到额外字节!忽略类似问题

Mac 终端 Vim 只会在行尾使用退格

请问DW里怎么设置简写标签后按TAB键后补全尾标签