rshapefile

How to draw a shapefile with ggpolar


I want to use ggpolar to plot a polar projection map of raster data, but the outermost pixels tend to obscure the land boundaries. Therefore, I want to add a local shapefile, but I failed to draw it using geom_sf in ggpolar. Even after converting the shapefile to the appropriate projection, it still couldn't be plotted. Could you please suggest a way to solve this problem? Below is my code:

continent <- st_read('F:/data/vector/seven_continent/continents/continent_30_90.shp')
ggpolar(pole = "N", max.lat = 90, min.lat = 30, 
    land.fill.colour = "#D9D9D9", land.outline.colour = "#343434", 
    plt.lat.labels = FALSE,size = 0.8) +
ggtitle("A") +
theme(plot.title = element_text(hjust = 0, family = "Arial", size = 18,face = "bold")) 
+
geom_tile(data = change_ratio_df, aes(x = lon, y = lat, fill = change_ratio)) + 
geom_point(data = selected_points, aes(x = lon, y = lat), color = "#343434", size =0.5) +
scale_fill_stepsn(colors = custom_colors,
                breaks = break_points, 
                labels = c("-5", "-4", "-3", "-2", "-1", "0", "1", "2", "3", "4", "5"),
                #labels = c("-0.005", "-0.004", "-0.003", "-0.002", "-0.001", "0", "0.001", "0.002", "0.003", "0.004", "0.005"),
                limits = c(-6, 6),
                #limits = c(-0.006, 0.006),
                name = expression(AE~('%'~ decade^{-1})),
                #name = NULL,
                na.value = "transparent", 
                guide = guide_colorbar(barwidth = 0.8, barheight = unit(10, "cm"), direction = "vertical",
                                       title.position = "right", title.hjust=0.5, label.position = "right", 
                                       title.theme = element_text(family = "Arial", size = 16, angle = 90),
                                       label.theme = element_text(family = "Arial", size = 12)))+
geom_sf(data = continent, fill = NA, color = "#343434") +
coord_sf(crs = sf::st_crs("ESRI:102016"))+
theme(
plot.background = element_rect(fill = NA, color = NA),  
panel.background = element_rect(fill = NA, color = NA), 
legend.position = "none",
legend.key.width = unit(2, "line"),
legend.key.height = unit(0.5, "line"),
legend.title = element_text(family = "Arial", size = 12),
legend.text = element_text(size = 12),
axis.title = element_blank(),
axis.text = element_text(family = "Arial", size = 12),
#panel.grid.major = element_line(size=0.25,linetype='dashed',colour="black"),
axis.ticks = element_blank()
)

Here's my shapefile: https://drive.google.com/drive/folders/1tuxes8oPd_F2OmWYfPyqPjuITE0bbBBp?usp=drive_link

The following figure is without added native shapefile: enter image description here

The following figure is drawn by the untransformed projection of the shapefile: Code Error:Coordinate system already present. Adding new coordinate system, which will replace the existing one. enter image description here

The following figure is plotted after the shapefile transforms the projection: Code Error:Coordinate system already present. Adding new coordinate enter image description here


Solution

  • I think the easiest way to handle this issue is to convert your continent sf object to a dataframe and use ggplot2::geom_path() to plot it.

    First, load required packages, create some example raster data, and load shapefile. You can safely ignore the warning that this code produces in this use case.

    # remotes::install_github("EarthSystemDiagnostics/grfxtools")
    
    library(geodata)
    library(terra)
    library(sf)
    library(ggplot2)
    library(grfxtools)
    
    # Sample SpatRaster
    r <- worldclim_global("tavg", 10, ".")
    r <- r[[1]]
    r <- crop(r, ext(-180, 180, 30, 90))
    
    # Convert r to df
    r_df <- as.data.frame(r, xy = TRUE)
    
    # Load continent shapefile (assumed to be WGS84/EPSG:4326), and
    # convert to multilinestring
    continent <- st_read("F:/data/vector/seven_continent/continents/continent_30_90.shp") |>
      st_cast("MULTILINESTRING")
    
    # Convert to continent sf to df
    line_df <- as.data.frame(st_coordinates(st_cast(continent, "LINESTRING")))
    

    Plot:

    ggpolar(pole = "N",
            min.lat = 30, 
            max.lat = 90,
            land.fill.colour = "#D9D9D9",
            land.outline.colour = NA, 
            plt.lat.labels = FALSE,
            size = 0.8) +
      geom_tile(data = r_df,
                aes(x, y, fill = wc2.1_10m_tavg_01)) +
      geom_path(data = line_df,
                aes(X, Y, group = L1),
                colour = "#343434") +
      theme(
        plot.background = element_rect(fill = NA, color = NA),  
        panel.background = element_rect(fill = NA, color = NA), 
        legend.position = "none",
        legend.key.width = unit(2, "line"),
        legend.key.height = unit(0.5, "line"),
        legend.title = element_text(family = "Arial", size = 12),
        legend.text = element_text(size = 12),
        axis.title = element_blank(),
        axis.text = element_text(family = "Arial", size = 12),
        axis.ticks = element_blank()
      )
    

    1

    In the event that the linked data in the question are deleted, to make this answer a reprex here is an equivalent option using rnaturalearth data:

    library(rnaturalearth) # You may be prompted to install rnaturalearthdata
    library(dplyr)
    
    # Sample sf
    sf_use_s2(FALSE)
    
    poly_sf <- ne_countries(scale = 50) |>
      summarise(geometry = st_union(geometry))
    
    # Ensure polygon sf cropped to intended plot extent, convert to MULTILINESTRING
    line_sf <- poly_sf |>
      st_crop(ext(-180, 180, 30, 90)) |>
      st_cast("MULTILINESTRING")
    
    sf_use_s2(TRUE)
    
    # Convert line_sf to df
    line_df <- as.data.frame(st_coordinates(st_cast(continent, "LINESTRING")))