在 R 中,有没有办法将我的所有标签从地图上移开(移到边距中)?

Is there a way in R to move all my labels off the map (into the margins)?

提问人:mkelley 提问时间:7/14/2022 最后编辑:tjebomkelley 更新时间:7/14/2022 访问量:306

问:

我正在努力在 R 中创建分区统计图,其中某些城市和某些提供商绘制为地图顶部的点。我坚持让提供商的名称从地图上移动到边缘(在顶部、右侧或底部)。

将所有提供程序保存在一个数据框中时,我无法弄清楚如何将某些标签移动到顶部、左侧和底部。我可以通过以下方式将它们全部移动到顶部:

Choropleth +
  geom_polygon(data=map, aes(x=long, y=lat, group= group), alpha=0, 
               color="black", size=1) + 
  geom_point(data=provider, aes(x=Longitude, y=Latitude, group=County), 
             color='red', 
             alpha=4, 
             size=3) +
  geom_point(data=city, aes(x=Longitude, y=Latitude, group=Name),
             color='yellow', 
             alpha=2, 
             size=2.5, 
             shape=8) +
  geom_text_repel(data=city, aes(x=Longitude, y=Latitude, group=Name, label=Name), 
                  min.segment.length = unit(0, 'lines')) +
  geom_label_repel(data=provider, aes(x=Longitude, y=Latitude, group=Name, label=Name), 
                  min.segment.length = unit(0, 'lines'), 
                  nudge_y = 40)

但是它看起来像这样,所有标签都放在一起:或者全部放在底部: enter image description here

Choropleth +
  geom_polygon(data=map, aes(x=long, y=lat, group= group), alpha=0, 
               color="black", size=1) + 
  geom_point(data=provider, aes(x=Longitude, y=Latitude, group=County), 
             color='red', 
             alpha=4, 
             size=3) +
  geom_point(data=city, aes(x=Longitude, y=Latitude, group=Name),
             color='yellow', 
             alpha=2, 
             size=2.5, 
             shape=8) +
  geom_text_repel(data=city, aes(x=Longitude, y=Latitude, group=Name, label=Name), 
                  min.segment.length = unit(0, 'lines')) +
  geom_label_repel(data=provider, aes(x=Longitude, y=Latitude, group=Name, label=Name), 
                  min.segment.length = unit(0, 'lines'), 
                  nudge_y = -40)

但是它看起来像这样,所有标签都放在一起:enter image description here

然后,我尝试将提供程序分离到它们自己的数据框中,并尝试手动移动位置,但我坚持从左到右移动,并且一些标签仍然相互重叠。

Choropleth +
  geom_polygon(data=map, aes(x=long, y=lat, group= group), alpha=0, 
               color="black", size=1) + 
  geom_point(data=provider, aes(x=Longitude, y=Latitude, group=County), 
             color='red', 
             alpha=4, 
             size=3) +
  geom_point(data=city, aes(x=Longitude, y=Latitude, group=Name),
             color='yellow', 
             alpha=2, 
             size=2.5, 
             shape=8) +
  geom_text_repel(data=city, aes(x=Longitude, y=Latitude, group=Name, label=Name), 
                  min.segment.length = unit(0, 'lines')) +
  geom_label_repel(data=North, aes(x=Longitude, y=Latitude, group=Name, label=Name), 
                   min.segment.length = unit(0, 'lines'), 
                   nudge_y = 40) +
  geom_label_repel(data=Central, aes(x=Longitude, y=Latitude, group=Name, label=Name), 
                   min.segment.length = unit(0, 'lines'), 
                   nudge_x = -40) +
  geom_label_repel(data=South, aes(x=Longitude, y=Latitude, group=Name, label=Name), 
                   min.segment.length = unit(0, 'lines'), 
                   nudge_y  = -40)

但是北方的标签是重叠的,我不能再把标签放在左边了。我尝试添加 xlim,但这会缩小图表,我想让它像我一样放大。上面的代码如下所示:enter image description here

我真的被这些标签困住了。我仍然需要清理地图,所以忽略其他部分

我只是需要帮助弄清楚如何获得我想要的标签。

分区统计数据来自 zip_choropleth + 我从美国人口普查局获得的数据帧,其中包括总人口为 60+ 的 ZCTA。


这是一个可重现的例子。

library(maps)
library(tidyverse)
library(ggrepel)

ohiocounty_map <- 
  map_data("county") %>%
  subset(region == "ohio") %>%
  mutate(County = str_to_sentence(subregion)) %>%
  group_by(County) %>% 
  filter(County %in% c("Butler", "Clermont", "Clinton", "Hamilton", "Warren"))

## make the name longer, so you can reproduce the problem.
Provider_Name <- sapply(letters[1:8], function(x) {
  paste(rep(x, each = 20), collapse = "")
}, USE.NAMES = F)
## change to numeric
Latitude_P <- as.numeric(c("39.18268", "39.09723", "39.06838", "39.13517", "39.243835", "39.323032", "39.445957", "39.505478"))
Longitude_P <- as.numeric(c("-84.48057", "-84.64043", "-84.10078", "-84.612465", "-84.463478", "-84.504646", "-84.27858", "-84.739334"))

provider <- data.frame(Provider_Name, Latitude_P, Longitude_P)

ggplot() +
  geom_polygon(data = ohiocounty_map, aes(x = long, y = lat, group = group), fill = NA, color = "black") +
  geom_point(data = provider, aes(x = Longitude_P, y = Latitude_P), color = "red", size = 3) +
  geom_label_repel(
    data = provider, aes(x = Longitude_P, y = Latitude_P, label = Provider_Name),
    nudge_y = 40
  )

创建于 2022-07-13 由 reprex 软件包 (v2.0.1)

r ggplot2 等值统计 geom-text choroplethr

评论

2赞 r2evans 7/14/2022
这是一个有趣的问题,我也试图解决(没有真正的成功)。您能否添加一些示例数据或简单的机制来重现此内容?我认为,如果更容易使用一些具有代表性的空间/标签数据,您可能会得到更多的响应/答案。
1赞 mkelley 7/14/2022
@r2evans我只是添加了一些额外的代码来复制带有县轮廓的地图(减去分区统计线的东西——来自几个大型 excel 文件)、一些城市数据和一些提供者。
2赞 tjebo 7/14/2022
我已将您的示例代码修改为适当的 MCVE(最小可重现示例)。我删除了建议的城市数据(标签和点),并删除了一些“情节美学”部分。

答:

3赞 tjebo 7/14/2022 #1

一个相当直接的解决方法是半手动定义标签位置并使用geom_label,然后添加区段。为了避免重叠,请每隔一个标签添加一个微移。基于示例(代码中的其他重要注释):

library(maps)
library(tidyverse)

ohiocounty_map <-
  map_data("county") %>%
  subset(region == "ohio") %>%
  mutate(County = str_to_sentence(subregion)) %>%
  group_by(County) %>%
  filter(County %in% c("Butler", "Clermont", "Clinton", "Hamilton", "Warren"))

Provider_Name <- sapply(letters[1:8], function(x) {
  paste(rep(x, each = 20), collapse = "")
}, USE.NAMES = F)
Latitude_P <- as.numeric(c("39.18268", "39.09723", "39.06838", "39.13517", "39.243835", "39.323032", "39.445957", "39.505478"))
Longitude_P <- as.numeric(c("-84.48057", "-84.64043", "-84.10078", "-84.612465", "-84.463478", "-84.504646", "-84.27858", "-84.739334"))

provider <- data.frame(Provider_Name, Latitude_P, Longitude_P)
## first define your absolute plot limits based on latitude range of your OHIO map.
y_lim <- range(ohiocounty_map$lat)
## you should also define an x, ideally evenly distributed across the x range
x_lim <- range(ohiocounty_map$long)
## now create x and y coordinates for the labels
## I am first defining a constant which will help adjusting the position
y_cons <- .1
provider <- provider %>%
  mutate(
    smaller_mean = Latitude_P < mean(y_lim),
    ## now create the positions for geom_label relativ to range of y
    ## points below or above the midpoint will be place below or above the plot, resp.
    lab_y = ifelse(smaller_mean, y_lim[1] - 3.5 * y_cons * diff(y_lim),
      y_lim[2] + y_cons * diff(y_lim)
    )
  ) %>%
  ## then nudge every second label higher or lower - per side
  ## also create x position relativ to number of labels per side
  ## in order to get the labels in a meaningful order, sort the data frame
  arrange(Longitude_P) %>%
  group_by(smaller_mean) %>%
  mutate(
    nudge_y = y_cons * diff(y_lim) * seq_along(Provider_Name) %% 2,
    lab_x = seq(x_lim[1], x_lim[2], len = n())
  )

ggplot() +
  geom_polygon(data = ohiocounty_map, aes(x = long, y = lat, group = group), fill = NA, color = "black") +
  ## you will need connecting lines between the labels and your points, draw them first
  geom_segment(
    data = provider, aes(
      x = Longitude_P, xend = lab_x,
      y = Latitude_P, yend = lab_y + nudge_y),
    ## dashed line for aesthetic reasons
    size = .3
  ) +
  geom_label(
    ## use the new label coordinates for the labels
    data = provider, aes(x = lab_x, y = lab_y, label = Provider_Name),
    ## add nudge_y - this requires the data frame to have unique rows for each label
    nudge_y = provider$nudge_y
  ) +
  ## I draw the points last for aesthetic reasons
  geom_point(data = provider, aes(x = Longitude_P, y = Latitude_P), color = "red", size = 3) +
  ## remove clipping, and add y limits so to allow labels to be outside the plot area
  coord_cartesian(clip = "off", ylim = y_lim) +
  ## adjust plot margins
  theme(plot.margin = margin(r = .8, l = .5, t = .6, b = .8, unit = "in"))

创建于 2022-07-14 由 reprex 软件包 (v2.0.1)

类似的方法适用于将标签推送到绘图的右侧或左侧。