如何在R语言中检查Simple Features几何对象是否连续?
Great question! The issue you're facing comes down to how your current code handles multipart polygons (like countries with islands or enclaves, stored as MULTIPOLYGON in sf/sp objects). Your point.in.polygon check treats the entire country's geometry as a single shape, which causes points meant for islands/enclaves to be filtered out incorrectly.
The Solution: Split Multipolygons into Individual Polygons
The sf package has built-in tools to split multipart polygons into single-part polygons, letting you handle each island/enclave separately. Here's how to adapt your code to fix this:
Modified flag_fill Function
The core change is using st_cast() to break MULTIPOLYGON objects into individual POLYGON entries, then processing each part separately before combining results:
flag_fill <- function(df){ df <- df %>% st_as_sf() %>% # Split multipolygons into individual polygon entries st_cast("POLYGON") %>% # Group by country to keep all parts of a nation together group_by(state) %>% nest() %>% ungroup() # Process each country's split polygons df <- df %>% mutate(processed = map(data, function(sub_df){ # Get bounding boxes for each individual polygon xmin <- map(sub_df$geometry, st_bbox) %>% map_dbl("xmin") xmax <- map(sub_df$geometry, st_bbox) %>% map_dbl("xmax") ymin <- map(sub_df$geometry, st_bbox) %>% map_dbl("ymin") ymax <- map(sub_df$geometry, st_bbox) %>% map_dbl("ymax") # Reuse your alpha check logic alpha_check <- function(flag_image){ if(dim(flag_image)[3] > 3) hasalpha <- TRUE else hasalpha <- FALSE } alph <- map_lgl(sub_df$flag_image, alpha_check) # Create color matrices from flag images NumRow <- map_dbl(sub_df$flag_image, function(x) dim(x)[1]) NumCol <- map_dbl(sub_df$flag_image, function(x) dim(x)[2]) matrixList <- vector("list", nrow(sub_df)) matrixList <- mapply(matrix, matrixList, data = "#00000000", nrow = NumRow, ncol = NumCol, byrow = FALSE) matrixList <- map2(sub_df$flag_image, alph, function(x, y) { rgb(x[,,1], x[,,2], x[,,3], ifelse(y, x[,,4], 1) ) %>% matrix(ncol = dim(x)[2], nrow = dim(x)[1]) }) # Reshape matrix to data frame df_func <- function(DF){ suppressWarnings( DF <- DF %>% set_colnames(value = 1:ncol(.)) %>% mutate(Y = nrow(.):1) %>% gather(X, color, -Y) %>% select(X, Y, color) %>% mutate(X = as.integer(X)) ) return(DF) } matrixList <- map(matrixList, as.data.frame) matrixList <- map(matrixList, df_func) # Resize flag points to match polygon bounds for(m in 1:length(matrixList)){ matrixList[[m]]$X <- rescale(matrixList[[m]]$X, to = c(xmin[[m]], xmax[[m]])) matrixList[[m]]$Y <- rescale(matrixList[[m]]$Y, to = c(ymin[[m]], ymax[[m]])) } # Filter points to only those inside each polygon latlonList <- map(sub_df$geometry, st_coordinates) for(ll in 1:length(latlonList)){ latlonList[[ll]] <- latlonList[[ll]][, 1:2] } poly_check <- function(x, y){ x <- x[point.in.polygon(x$X, x$Y, y[, 1], y[, 2] ) %>% as.logical, ] return(x) } matrixList <- Map(poly_check, matrixList, latlonList) # Return processed data for this country's polygons sub_df %>% mutate(plot_image = matrixList) })) %>% unnest(processed) %>% select(-data) return(df) }
Key Changes Breakdown
st_cast("POLYGON"): Converts anyMULTIPOLYGONinto separatePOLYGONrows—one for each island, enclave, or mainland segment.group_by(state) %>% nest(): Keeps all parts of a single country grouped together during processing.- Per-Polygon Processing: Each individual shape gets its own bounding box, resized flag, and point-in-polygon check, ensuring the flag fills every part of the country correctly.
Test with Portugal
Run your existing plotting code with the updated function:
globe %>% filter(state %in% c("Portugal")) %>% flag_fill() %>% flag_plot()
This will now correctly fill mainland Portugal and the Azores/Madeira islands with the Portuguese flag, no more messy overlapping.
Bonus: Handle Enclaves (Like the Netherlands)
For countries with enclaves (e.g., Netherlands' Caribbean territories), this approach works identically—each enclave is split into its own polygon and processed separately.
Additional Tips
- Use
st_is(df$geometry, "MULTIPOLYGON")to quickly identify countries with multipart shapes. - For better performance with large datasets, replace
point.in.polygon()withsf's nativest_point_in_polygon()function for faster spatial checks.
内容的提问来源于stack exchange,提问作者RobertMyles

