【问题标题】:R visualization: sensible repel points on map (beeswarm?)R 可视化:地图上的合理排斥点(蜂群?)
【发布时间】:2019-09-08 15:08:11
【问题描述】:

我正在尝试复制大约这样的地图。

它描绘了分布在一个区域内的少量项目(学校)。对于输入,我有一个区域地图,每个区域都有一个数字。我想把它放在该地区周围的许多点上。如果它们不跨越区域边界扩散会更好,但简单地分布它们就足够了。区域内一些不错的排斥点可能会起作用。

Beeswarm plots 做了一些非常相似的事情,这可以在地图上完成吗?额外的问题 - 事实上我一直在寻找动画,但只能想出非常复杂的方法来做到这一点,以便随着时间的增加和 nrs 添加新点。

下面的代码将点放在地图上的质心中,并将数字作为大小。 (我无法将地图正确导出为单个文件,所以坐标有点乱,但原理是一样的。)

places = st_read("https://gist.githubusercontent.com/peeter-t2/9646a4169e993948fa97f6f503a0688b/raw/cb4e910bf153e51e3727dc9d1c73dd9ef86d2556/kih1897m.geojson", stringsAsFactors = FALSE)

schools <- read_tsv("https://gist.github.com/peeter-t2/34467636b3c1017e89f33284d7907b42/raw/6ea7dd6c005ef8577b36f5e84338afcb6c76b707/school_nums.tsv")
schools_geo <- merge(places,schools,by.x="KIHELKOND",by.y="Kihelkond") #94 matches

p<- schools_geo %>% 
  ggplot()+
  geom_sf(data=schools_geo)+
  geom_sf(data=st_centroid(schools_geo),aes(size=value))+
  theme_bw()
p

谢谢!

【问题讨论】:

  • 您的 places 数据被读取为 lon/lat,但您的几何列看起来像不同的 crs。数据应该是什么crs?
  • 我不确定,但您找到了解决方案。我一直在使用一些非常旧的 .shp shapefile,但没有找到很好的保存方法。事实上,crs 最初表示没有 EPSG 代码,即使它显示正确。按照您的建议,使用 st_crs() &lt;- 3301 从 geojson 重新读取,也修复了一些其他错误。 Although coordinates are longitude/latitude, st_intersects assumes that they are planar, Error in CPL_geos_is_empty(st_geometry(x)) : Evaluation error: IllegalArgumentException: Points of LinearRing do not form a closed linestring. 但真的不知道发生了什么,非常感谢修复。

标签: r ggplot2 visualization sf beeswarm


【解决方案1】:

正如我在 cmets 中所指出的,当我在文件中读取时,它将 crs 设置为纬度/经度 (epsg: 4326),而几何列是不同的 crs。我猜到正确的crsespg: 3301 并在此基础上继续进行,这似乎工作正常。

st_crs(schools_geo) <- 3301

我们可以使用 st_sample 来获取多边形内与我们的“值”列相关的点样本:

# we can set type = 'hexagonal', 'regular' or 'random'
school_pts <- schools_geo %>% st_sample(size = .$value, type = 'hexagonal')


schools_geo %>% 
  ggplot()+
  geom_sf()+
  geom_sf(data=school_pts, size = .8)+
  theme_bw()

这会产生下面的图,我认为它看起来很乱,因为st_sample 将点扩展到多边形的范围内。

像您发布的示例中那样,使每个多边形中的点更居中可能看起来会更好。为此,我们可以根据要在其中绘制的点数重新缩放多边形。在下面的代码中,如果多边形内部的点数最少 (1),我将多边形缩小 90%,如果它们的点数最多 (27),则缩小 20%。

# put values on scale between 0 and 1
scale_fact <- (max(schools_geo$value) -  schools_geo$value) / (max(schools_geo$value) - min(schools_geo$value)) 
# re-scale between 0.2 and 0.9
scale_fact <- scale_fact * (0.9 - 0.2) + 0.2
# reverse the scale 
scale_fact <-  max(scale_fact) + min(scale_fact) - scale_fact 

# apply the scale factor
schools_centroid <- st_geometry(st_centroid(schools_geo))
schools_geo_rescaled <- (st_geometry(schools_geo) - schools_centroid) * scale_fact + schools_centroid

school_pts <- schools_geo_rescaled %>% 
  st_sf(crs = 3301) %>% 
  bind_cols(value = schools_geo$value) %>%
  st_sample(size = .$value, type = 'hexagonal')


# plot
schools_geo %>% 
  ggplot()+
  geom_sf()+
  geom_sf(data=school_pts, size = .8)+
  theme_bw()

【讨论】:

  • 这太棒了,也很漂亮。我应该玩一下缩放。目前,狭窄的区域将它们紧密地聚集在一起,而广阔的​​区域则将它们分散得很远,而在它们之间则恰到好处。知道为什么会这样吗?但确实是一个非常聪明的解决方案! PS评论了上面的crs。
  • 是的,玩弄缩放以及绘图中点的大小。间距不同的原因是st_sample 将填充给定的空间。如果在一个小空间中有很多点,它们将分布得更近。其中一些可以通过调整缩放的方式来改进,但有些只是数据(小空间中有很多点)。
  • @puslet88 也感谢您的编辑,我不知何故错过了几行!
【解决方案2】:

这不是一个简单的问题。我决定简化它,只选择一个区域而不是全部。理论上,该解决方案适用于您的所有领域。

我们首先导入我们的库

library(rgdal)
library(sf)
library(readr)
library(ggplot2)

我们使用建议的数据:

places <- st_read("https://gist.githubusercontent.com/peeter-t2/9646a4169e993948fa97f6f503a0688b/raw/cb4e910bf153e51e3727dc9d1c73dd9ef86d2556/kih1897m.geojson", stringsAsFactors = FALSE)

schools <- read_tsv("https://gist.github.com/peeter-t2/34467636b3c1017e89f33284d7907b42/raw/6ea7dd6c005ef8577b36f5e84338afcb6c76b707/school_nums.tsv")
schools_geo <- merge(places,schools,by.x="KIHELKOND",by.y="Kihelkond") #94 matches

我们选择一个状态

one <- places$geometry[[1]]

借助网格,我们将多边形分割成多个子多边形

grid <- st_make_grid(one, n = c(10, 10))
area <- st_area(grid)
grid <- st_as_sf(data.frame(ID=c(1:length(area)),
                            area=area,
                            geometry=grid))
tmp <- st_intersection(grid, one)
tmp$area <- st_area(tmp)

我们显示由小正方形组成的网格的所有质心

plot(st_geometry(tmp['area']))
plot(st_geometry(st_centroid(tmp['area'])),
     pch = 16, col = 'red', add = TRUE)

最后,我们只想保留您想要的分数,这在您的示例中相当于价值(学校数量)。

nbr <- 20
plot(st_geometry(one))
plot(st_geometry(st_centroid(tmp[order(tmp$area, decreasing = T),][1:nbr,])),
     pch = 16, col = 'red', add = TRUE)

希望对你有所帮助。

【讨论】:

  • 非常感谢!这确实是一个巧妙的解决方案。 @Chris 在上面写了一个非常优雅的,所以我接受了那个。我什至可能会考虑将两者结合起来。 st_sample() 是个不错的函数!
  • 我绝对同意st_sample() 是正确的解决方案。
猜你喜欢
  • 1970-01-01
  • 2018-09-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-03-20
  • 2019-10-19
  • 2018-09-07
  • 1970-01-01
相关资源
最近更新 更多