简体   繁体   English

使用ggplot2在点周围创建阴影多边形

[英]Create shaded polygons around points with ggplot2

I saw yesterday this beautiful map of McDonalds restaurants in USA. 昨天我看到了这张美丽的麦当劳美国餐厅地图 I wanted to replicate it for France (I found some data that can be downloaded here ). 我想将其复制到法国(我发现了一些可以在此处下载的数据)。

I have no problem plotting the dots: 我没有问题画点:

library(readxl)
library(ggplot2)
library(raster)

#open data
mac_do_FR <- read_excel("./mcdo_france.xlsx")
mac_do_FR_df <- as.data.frame(mac_do_FR)

#get a map of France
mapaFR <- getData("GADM", country="France", level=0)

#plot dots on the map
ggplot() +
    geom_polygon(data = mapaFR, aes(x = long, y = lat, group = group), 
                 fill = "transparent", size = 0.1, color="black") +
    geom_point(data = mac_do_FR_df, aes(x = lon, y = lat), 
               colour = "orange", size = 1)

I tried several methods (Thiessen polygons, heat maps, buffers), but the results I get are very poor. 我尝试了几种方法(Thiessen多边形,热图,缓冲区),但得到的结果非常差。 I can't figure out how the shaded polygons were plotted on the American map. 我不知道如何在美国地图上绘制阴影多边形。 Any pointers? 有指针吗?

情节

Here's my result, but it did take some manual data wrangling. 这是我的结果,但确实需要一些手动数据处理。

Step 1 : Get geospatial data. 步骤1 :获取地理空间数据。

library(sp)

# generate a map of France, along with a fortified dataframe version for ease of
# referencing lat / long ranges

mapaFR <- raster::getData("GADM", country="France", level=0)
map.FR <- fortify(mapaFR)

# generate a spatial point version of the same map, defining your own grid size 
# (a smaller size yields a higher resolution heatmap in the final product, but will
# take longer to calculate)
grid.size = 0.01
points.FR <- expand.grid(
  x = seq(min(map.FR$long), max(map.FR$long), by = grid.size),
  y = seq(min(map.FR$lat), max(map.FR$lat), by = grid.size)
)
points.FR <- SpatialPoints(coords = points.FR, proj4string = mapaFR@proj4string)

Step 2 : Generate a voronoi diagram based on store locations, & obtain the corresponding polygons as a SpatialPolygonsDataFrame object. 第2步 :根据商店位置生成一个voronoi图,并获得相应的多边形作为SpatialPolygonsDataFrame对象。

library(deldir)
library(dplyr)

voronoi.tiles <- deldir(mac_do_FR_df$lon, mac_do_FR_df$lat,
                        rw = c(min(map.FR$long), max(map.FR$long),
                               min(map.FR$lat), max(map.FR$lat)))
voronoi.tiles <- tile.list(voronoi.tiles)
voronoi.center <- lapply(voronoi.tiles, 
                         function(l) data.frame(x.center = l$pt[1],
                                                y.center = l$pt[2],
                                                ptNum = l$ptNum)) %>% 
                             data.table::rbindlist()
voronoi.polygons <- lapply(voronoi.tiles,
                           function(l) Polygon(coords = matrix(c(l$x, l$y), 
                                                               ncol = 2), 
                                               hole = FALSE) %>%
                             list() %>%
                             Polygons(ID = l$ptNum)) %>%
  SpatialPolygons(proj4string = mapaFR@proj4string) %>%
  SpatialPolygonsDataFrame(data = voronoi.center,
                           match.ID = "ptNum")

rm(voronoi.tiles, voronoi.center)

Step 3 . 第三步 Check which voronoi polygon each point on the map overlaps with, & calculate its distance to the corresponding nearest store. 检查地图上每个点与哪个voronoi多边形重叠,并计算其与相应最近的商店的距离。

which.voronoi <- over(points.FR, voronoi.polygons)    
points.FR <- cbind(as.data.frame(points.FR), which.voronoi)
rm(which.voronoi)

points.FR <- points.FR %>%
  rowwise() %>%
  mutate(dist = geosphere::distm(x = c(x, y), y = c(x.center, y.center))) %>%
  ungroup() %>%
  mutate(dist = ifelse(is.na(dist), max(dist, na.rm = TRUE), dist)) %>%
  mutate(dist = dist / 1000) # convert from m to km for easier reading

Step 4 . 第四步 Plot, adjusting the fill gradient parameters as needed. 绘制,根据需要调整填充梯度参数。 I felt the result of a square root transformation looks quite good for emphasizing distances close to a store, while a log transformation is rather too exaggerated, but your mileage may vary. 我觉得平方根转换的结果对于强调商店附近的距离看起来相当不错,而对数转换则过于夸张,但是里程可能会有所不同。

ggplot() +

  geom_raster(data = points.FR %>%
                mutate(dist = pmin(dist, 100)),
             aes(x = x, y = y, fill = dist)) +

  # optional. shows outline of France for reference
  geom_polygon(data = map.FR,
               aes(x = long, y = lat, group = group),
               fill = NA, colour = "white") +

  # define colour range, mid point, & transformation (if desired) for fill
  scale_fill_gradient2(low = "yellow", mid = "red", high = "black", 
                       midpoint = 4, trans = "sqrt") +

  labs(x = "longitude", 
       y = "latitude",
       fill = "Distance in km") +

  coord_quickmap()

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

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