R - Cloropleth:在多边形内的数据点中,具有特定列值的百分比是多少?

时间:2017-08-26 21:19:57

标签: r ggplot2 gis choropleth sf

此主题的扩展名:Create choropleth map from coordinate points。 (我不想为了与尽可能多的人相关而将两个线程结合起来。)

我有一个由许多观测组成的数据框,每个观测都有地理坐标(纬度 - 经度)和布尔值(是 - 否)。我想生成一个世界的等值区域图,其中每个区域/多边形用其中相关布尔值等于true的点的百分比着色。

这是一个可重复性最低的示例,现在只根据多边形中的点数进行着色。 “like”数据列是我的布尔值。

# Load package
library(tidyverse)
library(ggmap)
library(maps)
library(maptools)
library(sf)

data <- data.frame(class = c("Private", "Private", "Private", "Private", "Private", "Private", "Not Private", "Not Private", "Private", "Private", "Not Private", "Private", "Not Private", "Private", "Private", "Not Private", "Not Private", "Private", "Private", "Not Private"),
                   lat = c(33.663944, 41.117936, 28.049601, 39.994684, 36.786042, 12.797659, 52.923318, 33.385555, 9.295242, 32.678207, 41.833585, -28.762956, 39.284713, 36.060964, 36.052239, 36.841764, 33.714237, 33.552863, 32.678207, -38.132401),
                   lon = c(-83.98686, -77.60468, -81.97271, -82.98577, -119.78246, 121.82814, -1.16057, -86.76009, 123.27758,   -83.17387, -87.73201, 32.05737, -76.62048, -115.13517, -79.39961, -76.35592, -85.85172, -112.12468, -83.17387, 144.36946))

# Convert to simple feature object
point_sf <- st_as_sf(data, coords = c("lon", "lat"), crs = 4326)

# Get world map data
worldmap <- maps::map("world", fill = TRUE, plot = FALSE)

# Convert world to sp class
IDs <- sapply(strsplit(worldmap$names, ":"), "[", 1L)
world_sp <- map2SpatialPolygons(worldmap, IDs = IDs, 
                                proj4string = CRS("+proj=longlat +datum=WGS84"))

# Convert world_sp to simple feature object
world_sf <- st_as_sf(world_sp)

# Add country ID
world_sf <- world_sf %>%
  mutate(region = map_chr(1:length(world_sp@polygons), function(i){
    world_sp@polygons[[i]]@ID
  }))

# Use st_within
result <- st_within(point_sf, world_sf, sparse = FALSE)

# Calculate the total count of each polygon
# Store the result as a new column "Count" in world_sf
world_sf <- world_sf %>%
  mutate(Count = apply(result, 2, sum))

# Convert world_sf to a data frame world_df 
world_df <- world_sf
st_geometry(world_df) <- NULL

# Get world data frame
world_data <- map_data("world")

# Merge world_data and world_df
world_data2 <- world_data %>%
  left_join(world_df, by = c("region"))

ggplot() + 
  geom_polygon(data = world_data2, aes(x = long, y = lat, group = group, fill = Count)) +
  coord_fixed(1.3)

特别感谢https://stackoverflow.com/users/7669809/ycw到目前为止的帮助。

1 个答案:

答案 0 :(得分:2)

我们可以先计算多边形中的点数,过滤Private列中标记为class的记录的数据集,然后再计算多边形中的点数。我们稍后可以使用Private计数除以所有计数并乘以100%来计算百分比。

关于sf对象的一个​​很好的特性是它也是一个数据框。因此,管理数据框的操作(例如filter包中的dplyr)也适用于sf对象。因此,我们可以使用point_private_sf <- point_sf %>% filter(class %in% "Private")之类的命令轻松过滤点。

# Load package
library(tidyverse)
library(maps)
library(maptools)
library(sf)

### Data Preparation

data <- data.frame(class = c("Private", "Private", "Private", "Private", "Private", "Private", "Not Private", "Not Private", "Private", "Private", "Not Private", "Private", "Not Private", "Private", "Private", "Not Private", "Not Private", "Private", "Private", "Not Private"),
                   lat = c(33.663944, 41.117936, 28.049601, 39.994684, 36.786042, 12.797659, 52.923318, 33.385555, 9.295242, 32.678207, 41.833585, -28.762956, 39.284713, 36.060964, 36.052239, 36.841764, 33.714237, 33.552863, 32.678207, -38.132401),
                   lon = c(-83.98686, -77.60468, -81.97271, -82.98577, -119.78246, 121.82814, -1.16057, -86.76009, 123.27758,   -83.17387, -87.73201, 32.05737, -76.62048, -115.13517, -79.39961, -76.35592, -85.85172, -112.12468, -83.17387, 144.36946))

# Convert to simple feature object
point_sf <- st_as_sf(data, coords = c("lon", "lat"), crs = 4326)

# Get world map data
worldmap <- maps::map("world", fill = TRUE, plot = FALSE)

# Convert world to sp class
IDs <- sapply(strsplit(worldmap$names, ":"), "[", 1L)
world_sp <- map2SpatialPolygons(worldmap, IDs = IDs, 
                                proj4string = CRS("+proj=longlat +datum=WGS84"))

# Convert world_sp to simple feature object
world_sf <- st_as_sf(world_sp)

# Add country ID
world_sf <- world_sf %>%
  mutate(region = map_chr(1:length(world_sp@polygons), function(i){
    world_sp@polygons[[i]]@ID
  }))

### Use st_within for the analysis

# Use st_within for all points
result_all <- st_within(point_sf, world_sf, sparse = FALSE)

# Filter the points by "Private" in the class column
point_private_sf <- point_sf %>% filter(class %in% "Private")

# Use st_within for private points
result_private <- st_within(point_private_sf, world_sf, sparse = FALSE)

### Calculate the total count of each polygon
# Store the result as ew columns "Count_all" and "Count_private" in world_sf
world_sf <- world_sf %>%
  mutate(Count_all = apply(result_all, 2, sum),
         Count_private = apply(result_private, 2, sum)) %>%
  # Calculate the percentage
  mutate(Percent = ifelse(Count_all == 0, Count_all, Count_private/Count_all * 100))

### Plot the data

# Convert world_sf to a data frame world_df 
world_df <- world_sf
st_geometry(world_df) <- NULL

# Get world data frame
world_data <- map_data("world")

# Merge world_data and world_df
world_data2 <- world_data %>%
  left_join(world_df, by = c("region"))

ggplot() + 
  geom_polygon(data = world_data2, aes(x = long, y = lat, group = group, fill = Percent)) +
  coord_fixed(1.3)