Search code examples
rggplot2dplyrr-sfgeom

Trying to create continent map for South America but geom_polygon produces zigzag fill


I try to do this ggplot:

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

continents.f.xy <- st_zm(continents.f)
continents_map_SA <- continents.f.xy%>%
  dplyr::bind_rows() %>% #bind the list into a data.frame
  sf::st_cast(to = "POINT") %>% #convert polygon to a list of points
  dplyr::mutate(
    long =  sf::st_coordinates(geometry)[,1], #retrieve X coord
    lat =  sf::st_coordinates(geometry)[,2],  #retrieve Y coord
    group = rep(1, nrow(.)) #create a group column  
  ) %>%
  sf::st_drop_geometry() #drop the geometry column
continents_map_SA <- continents_map_SA%>%select(long,lat,group)
continents_map_SA  <- fortify(continents_map_SA , region = "South America")


plotactual.high<-ggplot() +
  geom_raster(data = ras.actual.df, aes(x = longitude, y = latitude, fill = hpds)) + 
  scale_fill_gradientn(name="hpds",colours = c("white","red"))+
  #scale_y_continuous(breaks=seq(-50, 50, by = 10)) +
  #scale_x_continuous(breaks=seq(-100, 0, by = 10)) +
  xlab("longitude") + ylab("latitude") +
  geom_polygon(data = continents_map_SA, aes(x=long, y = lat, group = group), fill = NA, color = "black") +
  annotate(geom="text", x=-45, y=-45, label="Potential area = 9,338.380 km2", color="black", family = c("serif"), size=4.5) +
  coord_quickmap() +
  theme_bw() + 
  theme(panel.border = element_blank(), plot.margin = margin(r = 1, l = 1), panel.grid.major = element_blank(),
panel.grid.minor = element_blank(), axis.line = element_line(colour = "black"),
text=element_text(size=16,  family="serif"),legend.position="none")
plotactual.high

and I have as a result:

test

I also use fortify and group inside aes in geom_polygon and arrange.


Solution

  • Your problem occurs because you need to account for the fact that you are actually creating a multipolygon.

    In order to do that, you need to use something like summarise() in conjunction with st_combine(). To ensure multipolygons are created correctly, a grouping function defining each individual polygon (ring) within a multipolygon is also required. Otherwise, they will all be joined as a single polygon. By example, you need something like:

    summarise(geometry = combine(geometry), .by = c(country, sub_country))
    

    where country is the main multipolygon group, and sub_country defines each individual polygon within country. How this is executed will depend on the structure of your data. For instance, the map_data() world dataset that comes with ggplot2 has "region" and "group" columns for this purpose.

    In your use case it is better to create geospatial objects. In other words, if you want a continent for a map, create a polygon or multipolygon sf. Then you can simply use ggplot2::geom_sf() to plot your data.

    Here is a method to create a South America multipolygon sf using data from the rnaturalearth package. As it is already a multipolygon dataset, it skips the requirement to manipulate raw coordinate values. I have used scale = large to return the most detailed option. This can be changed to medium or small if it does not suit. You may be prompted to install another rnaturalearth package for the most detailed data.

    library(sf)
    library(dplyr)
    library(rnaturalearth)
    library(ggplot2)
    
    sa_countries <- c("Brazil", "Peru", "Venezuela", "Chile", "Ecuador", 
                      "Bolivia", "Paraguay", "Uruguay", "Guyana", "Suriname", 
                      "French Guiana", "Falkland Islands", "Colombia", "Argentina")
    
    continents_map_SA <- ne_countries(scale = "large") %>%
      filter(admin %in% sa_countries) %>%
      st_union()
    
    ggplot() +
      geom_sf(data = continents_map_SA)
    

    result