简体   繁体   English

在ggplot中标记段的中点

[英]Label the midpoint of a segment in ggplot

In the plot below I'd like to label the arrows with the text in bar$lbl . 在下面的图中,我想用bar$lbl的文本标记箭头。 I'd like to do so in a way that would keep any labels from overlapping (they wouldn't in the simple example below). 我希望这样做可以避免任何标签重叠(在下面的简单示例中不会)。 I'd prefer not to calculate the label position by hand. 我不希望手动计算标签位置。

I'm familiar with getting pretty, non-overlapping labels on points with ggrepel and curious if there is a similar way to label the midpoints of segments? 我熟悉使用ggrepel在点上获得漂亮的,不重叠的标签,并且好奇是否有类似的方式来标记线段的中点?

Any advice appreciated. 任何建议表示赞赏。

library(ggplot2)
foo <- data.frame(x=runif(50),y=runif(50))
bar <- data.frame(x1=c(0.2,0),x2=c(0.7,0.2),
                  y1=c(0.1,0.9),y2=c(0.6,0.5),
                  lbl=c("Arrow 1", "Arrow 2"))
p1 <- ggplot(data=foo,aes(x=x,y=y))
p1 <- p1 + geom_point(color="grey")
p1 <- p1 + geom_segment(data=bar,aes(x=x1, xend=x2, y=y1, yend=y2), 
                        size = 0.75,arrow = arrow(length = unit(0.5, "cm")))
p1

I know you would prefer not to calculate the mid points by hand, however, it is often easier to work with variables inside the aesthetics then with statistics, so I did it calculating the midpoints before hand and mapping to the axis 我知道您不希望手动计算中点,但是,在aesthetics内使用变量而不是在统计中进行操作通常会更容易,因此我在计算手工点并将其映射到轴之前进行了计算

library(ggplot2)
library(directlabels) # provides a geom_dl that works easier with labels

foo <- data.frame(x=runif(50),y=runif(50))
bar <- data.frame(x1=c(0.2,0),x2=c(0.7,0.2),
                  y1=c(0.1,0.9),y2=c(0.6,0.5),
                  midx = c(0.45, 0.1), # x mid points
                  midy = c(0.35, 0.7), # y midpoints
                  lbl=c("Arrow 1", "Arrow 2"))

p1 <- ggplot(data=foo,aes(x=x,y=y))
p1 <- p1 + geom_point(color="grey")
p1 <- p1 + geom_segment(data=bar,aes(x=x1, xend=x2, y=y1, yend=y2), 
                        size = 0.75,arrow = arrow(length = unit(0.5, "cm")))
p1 + geom_dl(data = bar, aes(x = midx, y = midy, label = lbl),
             method = list(dl.trans(x = unit(x, 'cm'), y = unit(y, 'cm'))))

在此处输入图片说明

Here are two ways to do it with a lot of tidying. 这是两种方法,可以让您进行大量整理。 You don't need to do anything by hand if you think about the fact that the midpoint has coordinates that are just the means of x values and the means of y values of the 2 endpoints. 如果考虑到中点的坐标只是两个端点的x值和y值的平均值,则无需执行任何操作。 First way is to tidy your data frame, calculate the midpoints, then make it wide again to have x and y columns. 第一种方法是整理数据框,计算中点,然后再次宽以具有x和y列。 That data frame goes into ggplot , so it's passed through all the geoms, but we override with data arguments to geom_point and geom_segment . 该数据帧进入ggplot ,因此它已通过所有geom传递,但我们使用了geom_pointgeom_segment data参数覆盖。 geom_segment gets just the original copy of the bar data frame. geom_segment仅获取bar数据框的原始副本。

library(tidyverse)
foo <- data.frame(x=runif(50),y=runif(50))
bar <- data.frame(x1=c(0.2,0),x2=c(0.7,0.2),
                                    y1=c(0.1,0.9),y2=c(0.6,0.5),
                                    lbl=c("Arrow 1", "Arrow 2"))

bar %>%
    gather(key = coord, value = value, -lbl) %>%
    mutate(coord = str_sub(coord, 1, 1)) %>%
    group_by(lbl, coord) %>%
    summarise(value = mean(value)) %>%
    ungroup() %>%
    spread(key = coord, value = value) %>%
    ggplot() +
        geom_point(aes(x = x, y = y), data = foo, color = "grey") +
        geom_segment(aes(x = x1, y = y1, xend = x2, yend = y2), data = bar, size = 0.75, arrow = arrow(length = unit(0.5, "cm"))) +
        geom_text(aes(x = x, y = y, label = lbl))

But maybe you don't want to do all that piping at the beginning, or you have to do this several times, so you want a function to calculate the midpoints. 但是也许您不想在一开始就做所有的管道,或者您必须做几次,所以您想要一个函数来计算中点。 For the second version, I wrote a function that does basically what was piped into ggplot in the first version. 对于第二个版本,我编写了一个函数,该函数基本上ggplot了第一个版本中通过ggplot的内容。 You supply it with the bare column name where your labels are kept, which is the column it will be grouped on. 您为其提供裸列名称,标签将保留在该列上,该列将被分组。 Then you can just use that in your geom_text . 然后,您可以在geom_text使用它。

## cool function!
tidy_midpt <- function(df, lbl_col) {
    lbl_quo <- enquo(lbl_col)

    df %>%
        gather(key = coord, value = value, -!!lbl_quo) %>%
        mutate(coord = str_sub(coord, 1, 1)) %>%
        group_by(lbl, coord) %>%
        summarise(value = mean(value)) %>%
        ungroup() %>%
        spread(key = coord, value = value)
}

ggplot(data = bar) +
    geom_point(aes(x = x, y = y), data = foo, color = "grey") +
    geom_segment(aes(x = x1, y = y1, xend = x2, yend = y2), size = 0.75, arrow = arrow(length = unit(0.5, "cm"))) +
    geom_text(aes(x = x, y = y, label = lbl), data = . %>% tidy_midpt(lbl))

Created on 2018-05-03 by the reprex package (v0.2.0). reprex软件包 (v0.2.0)创建于2018-05-03。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM