【问题标题】:How to plot rectangles of equal width onto a map in ggplot如何在ggplot中的地图上绘制等宽的矩形
【发布时间】:2025-11-30 11:25:01
【问题描述】:

我有两个相关指标的全球人口数据,并想为地图上的每个位置制作迷你条形图。由于我每个人口只需要两个条形图,并且它们都有相似的比例,因此我打算只使用 geom_rect() 绘制它们。但是,条形宽度不一致,即使是同一群体的两个条形之间也是如此。

这是我用于此的简化 R 代码:

library("ggplot2")
theme_set(theme_bw())
library("sf")
library("rnaturalearth")
library("rnaturalearthdata")
library("rgeos")

world <- ne_countries(scale = "medium", returnclass = "sf")

pop_data <- data.frame(long=c(-63,-68,-108,86,64,129,114,174,143,90,64,-21,40,-4,38.7),
                   lat=c(-23,3,29,51,64,63,32,-41,-4,24,26,64,61,40,39),
                   measA=c(10,10,10,10,10,10,10,10,10,10,10,10,10,10,10),
                   measB=c(10,10,10,10,10,10,10,10,10,10,10,10,10,10,10))
ggplot(data = world) +
  geom_sf()+
  geom_rect(data = pop_data,fill="blue",
            aes(xmin = long-2,
                xmax = long-1,
                ymin = lat,
                ymax = lat+measA))+
  geom_rect(data = pop_data,fill="red",
            aes(xmin = long+1,
                xmax = long+2,
                ymin = lat,
                ymax = lat+measB))+
  theme(axis.title.x=element_blank(),axis.title.y=element_blank())

最终图中的条形高度不同,但这只是为了说明宽度差异。谁能解释为什么宽度不同,以及如何解决这个问题?我也愿意在地图上制作简单的迷你酒吧图的其他解决方案。我确实看到了制作迷你条形图的其他解决方案,但其中大多数使用的 ggplot 函数不再有效。

【问题讨论】:

  • 这可能是一个愚蠢的后续问题,但是......当您使用 Rstudio 渲染图形或将其保存为图像时,您是否观察到宽度的差异?我运行了您的代码,虽然 Rstudio 渲染确实显示了您所指的问题,但 pdf 版本没有显示出任何可观察到的列宽差异。
  • @davidnortes 是对的 - 这几乎可以肯定只是 RStudio 图形设备的问题 - pdf 导出清晰且所有内容都具有正确的宽度。
  • 最初我只是从 Rstudio 渲染导出的,但是如果我使用 jpeg() 或 png() 来生成图像,我仍然会看到一些宽度差异(尽管它不那么明显)。

标签: r ggplot2


【解决方案1】:

我建议您可以选择一个可以画线并通过size= 控制宽度的几何图形 - 它可能会让您看起来更加一致。正如其他人提到的,尝试使用不同的图形导出,因为jpeg()png()pdf() 的渲染器可能不同。这是geom_segment()geom_linerange() 的两个示例。请注意,我建议将您的 pop_data 数据框和收集/熔化/pivot_longer...ing measAmeasB 列放在一起,以简化您的 ggplot() 调用并避免重复几何。你会看到我是用geom_linerang() 做的,但是由于dodging not working correctly with geom_segment,我在没有修改pop_data 的情况下展示了那个。

geom_segment()

ggplot(data = world) +
  geom_sf() +
  geom_segment(
    data=pop_data, color='blue',
    aes(x= long-1, xend=long-1, y= lat, yend=lat+measA),
    size=1.2) +
  geom_segment(
    data=pop_data, color='red',
    aes(x= long+1, xend=long+1, y= lat, yend=lat+measB),
    size=1.2) +
  theme(axis.title.x=element_blank(),axis.title.y=element_blank())

geom_linerange() 与 pop_data 的收集

如前所述,我在这里使用dplyrtidyr::gather() 修改pop_data,然后只需调用geom_linerange()。我更喜欢这个解决方案,但结果非常相似:

pop_data1 <- pop_data %>%
  gather('measure', 'pop', -c(long,lat))

ggplot(data = world) +
  geom_sf() +
  geom_linerange(
    data=pop_data1,
    aes(x= long, ymin= lat, ymax=lat+pop,
      color=measure, group=measure),
    size=1.2, position=position_dodge(5)) +
  scale_color_manual(values=c('red','blue')) +
  theme(axis.title.x=element_blank(),axis.title.y=element_blank())

【讨论】: