0

I need a world map in R that can be transformed into polygons of land to be able to calculate distances through sea from one point to another and going around land/polygons. These polygons need to be in a dataframe format to be able to rasterize the world map. And from this raster file, I need a transition object.

I've tried map_data("world") from the ggplot2 package, but when I try to turn this dataframe into spatialpolygons with the df_to_SpatialPolygons() function and plot this, some weird horizontal lines appear on the world map (plot(wrld_simpl)). I need to have a world map where I can turn the land to 999 and sea to 1. Just a distinction between land and water. As you can see in the code below. But when I plot the 'tr' or 'worldras', you can clearly see that the lines have a big effect on the distinction between land and sea, and the world map becomes almost not recognisable.unrecognisable world map

wrld_simpl <- map_data("world") # comes from ggplot2
  wrld_simpl <- df_to_SpatialPolygons(df = wrld_simpl,
                                      keys = "region",
                                      coords = c("long", "lat"),
                                      proj = CRS("+proj=longlat +ellps=sphere"))
  plot(wrld_simpl)
  # Generate a scaffold for the raster file
  world_crs <- crs(land_polygons)
  worldshp <- spTransform(land_polygons, world_crs)
  ras <- raster(nrow=1200, ncol=1200)
  
  # Generate a raster file
  worldmask <- rasterize(worldshp, ras)
  worldras <- is.na(worldmask) # inverse water and land, so ocean becomes 1 and land 0
  worldras[worldras==0] <- 999 # set land to 999
  
  # Create a Transition object from the raster
  tr <- transition(worldras, function(x) 1/mean(x), 16)
  tr = geoCorrection(tr, scl=FALSE)

I also tried using the rnaturalearth package in the code below, but this wasn't working either. The world_df doesn't have any data in it.

library(rnaturalearth)

# Step 2: Download High-Quality World Map Data
world <- ne_countries(scale = "medium", returnclass = "sf")

# Plot the high-quality world map
plot(world)
# Dissolve polygons into a single polygon representing the entire world
world_union <- st_union(world)
world_df <- st_sf(geometry = world_union)

Lastly I've tried the code block below. When plotting the land_df and sea_df I get the figure that is the best world map I had until now. But if I try to put the land_polygons variable into the first block of code, it still doesn't work and gives me this error:

worldshp <- spTransform(land_polygons, world_crs) Error in (function (classes, fdef, mtable) : unable to find an inherited method for function ‘spTransform’ for signature ‘"sf", "character"’

Best world map black and white

library(rnaturalearth)
library(sf)

# Step 1: Download World Map Data
world <- ne_countries(scale = "medium", returnclass = "sf")

# Create a rectangle covering the entire world
world_bbox <- st_bbox(world)
world_rectangle <- st_as_sfc(world_bbox)

# Remove land area from the rectangle to obtain sea/ocean areas
sea_mask <- st_difference(world_rectangle, world)

# Plot the map with land in black and sea in white
plot(st_geometry(sea_mask), col = "white", border = NA)
plot(world, col = "black", border = NA, add = TRUE)

# Convert land and sea masks to dataframes
land_df <- as.data.frame(world)
sea_df <- as.data.frame(st_sf(geometry = sea_mask))

# Convert the dataframe land_df to a spatial polygon object
land_polygons <- st_as_sf(land_df)

# Display information about the resulting spatial polygon object
print(land_polygons)

1

1 Answer 1

0

You got close, but there was one thing you needed to factor in. As ne_countries() is an S2 object with full global extent, you either have to st_transform() it to planar coordinates, or turn off sf_as_s2() to return your desired outcome. Also, map_data("world") is optimised for geom_poly() so it takes a few extra steps to convert it to an sf object. Comment below if you want to know how, otherwise let's keep it simple and stick with ne_countries().

It's not clear what analysis you will apply to the result so I have maintained as much of your original workflow as practicable. That way you should be able to easily modify the code in order to output an sf or df object. I've also kept the output as multipolygon geometries. If you want individual polygons, comment below and I'll update the answer.

library(rnaturalearth)
library(sf)
library(dplyr)
library(ggplot2)

# Turn off S2
sf_use_s2(FALSE)

# Create world
world <- ne_countries(scale = "medium")

# Create a rectangle covering the entire world
world_bbox <- st_bbox(world)
world_rectangle <- st_as_sfc(world_bbox)

# Remove land area from the rectangle to obtain sea/ocean areas, convert to df
sea_mask <- st_difference(world_rectangle, st_union(world)) %>%
  st_as_sf() %>%
  mutate(id = 1) %>%
  data.frame()

# Create df of world sf object
world_df <- world %>%
  st_union() %>%
  st_as_sf() %>%
  mutate(id = 999) %>%
  data.frame()

# Join world_df and sea_mask and convert to sf
result <- rbind(sea_mask, world_df) %>%
  st_as_sf() # Omit previous %>% and this line to return df

ggplot() +
  geom_sf(data = result, aes(fill = factor(id))) +
  scale_fill_manual(values = c("#b6dbff", "#F0E442"),
                    name = "Type",
                    labels = c("Sea", "Land")) +
  coord_sf(expand = FALSE)

result

If you're still wanting to create a transition() object:

library(rnaturalearth)
library(sf)
library(terra)
library(raster)
library(gdistance)

# Create world sf
world <- ne_countries(scale = "medium")

# Create base SpatRaster (low-res for this example, increase at 1:2 ratio for actual data)
r <- rast(nrow = 180, ncol = 360)

# Convert world sf to SpatRaster
r <- rasterize(world, r)

# Assign values to sea and land
r <- ifel(is.na(r), 1, 999)

# Convert to RasterLayer for transition()
r1 <- raster(r)

# Create a transition() object from the raster
tr <- transition(r1, function(x) 1/mean(x), 16)
tr <- geoCorrection(tr, scl = FALSE)

Not the answer you're looking for? Browse other questions tagged or ask your own question.