将GeoJSON转换为SF格式用于Leaflet分级统计图的技术咨询
Hey there! Let's fix this up so you can get those country polygons loaded into Leaflet and linked with your population data. Here's a step-by-step breakdown:
1. Get the actual GeoJSON data (not just datapackage metadata)
The link you used (https://datahub.io/core/geo-countries/datapackage.json) only returns metadata about the dataset, not the polygon data itself. Instead, we can use the sf package (your go-to for spatial data) to directly read the GeoJSON file from its web URL—this skips the messy metadata parsing step entirely:
library(sf) library(leaflet) library(dplyr) # Read country polygons directly from the GeoJSON source countries_sf <- st_read("https://datahub.io/core/geo-countries/r/countries.geojson") # Check the available fields (you'll see NAME/ADMIN for country names) head(countries_sf)
2. Reshape your population data for joining
Your current Countries data is in wide format, which won't play nicely with the spatial data. Let's convert it to long format and fix name mismatches (like "UnitedStates" vs. the full name in the GeoJSON):
# Your original population data Countries <- structure(list(Canada = 37590000, UnitedStates = 328200000, Mexico = 127600000), row.names = c(NA, -1L), class = c("tbl_df", "tbl", "data.frame")) # Convert to long format and align country names with the GeoJSON population_long <- Countries %>% tidyr::pivot_longer(cols = everything(), names_to = "Country", values_to = "Population") %>% mutate(Country = case_when( Country == "UnitedStates" ~ "United States of America", TRUE ~ Country ))
3. Join spatial data with population numbers
Use left_join to link your population data to the polygon shapes. Make sure the matching fields (country names) are exactly the same:
# Join using the NAME field from the spatial data (confirm with head(countries_sf)) countries_with_pop <- countries_sf %>% left_join(population_long, by = c("NAME" = "Country"))
4. Plot in Leaflet with addPolygons()
Now you're ready to build your map! Here's a quick example with popups showing country names and population:
leaflet(countries_with_pop) %>% addTiles() %>% # Add default base map tiles addPolygons( fillColor = "lightblue", color = "white", weight = 1, popup = ~paste0("<strong>", NAME, "</strong><br>Population: ", format(Population, big.mark = ",")) )
Why your original code failed
When you used jsonlite::fromJSON() on the datapackage URL, you pulled down dataset metadata—not the actual GeoJSON polygon content. That's why geojson_sf() threw an error: it was trying to parse metadata as valid GeoJSON, which it isn't. Using sf::st_read() directly on the GeoJSON URL avoids this confusion.
Bonus: Fixing shinyapps.io map issues
For your shinyapps.io problem, switching to web-hosted GeoJSON (like we did here) eliminates the need to upload local shapefiles entirely—this should work seamlessly on the platform. If you ever need to use local files later, just make sure they're in your app's root directory and use relative paths in your code.
内容的提问来源于stack exchange,提问作者k3r0

