You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在R语言中检查Simple Features几何对象是否连续?

Fixing Flag Filling for Countries with Islands/Enclaves in R ggplot2

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

  1. st_cast("POLYGON"): Converts any MULTIPOLYGON into separate POLYGON rows—one for each island, enclave, or mainland segment.
  2. group_by(state) %>% nest(): Keeps all parts of a single country grouped together during processing.
  3. 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() with sf's native st_point_in_polygon() function for faster spatial checks.

内容的提问来源于stack exchange,提问作者RobertMyles

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 03:46:19