Ferroao
Ferroao

Reputation: 3043

how to plot rivers efficiently?

I came up with a way to plot rivers using geom_path. I do not know if there is a better way. I had to split the dataframe into hundreds of "rivers". So it is very slow. Any ideas?

world_map <- map_data('world') 
system("wget https://sites.google.com/site/joabelb/Home/PrincRiosBrazil.zip")
system("unzip -o PrincRiosBrazil.zip")
library(rgdal)
shapeHid <- readOGR(dsn = ".", layer = "PrincipaisRiosDoBrasil") 
shapeHid@data$id = rownames(shapeHid@data)
library(ggplot2)
shapeHid.points = fortify(shapeHid, region="id")#
shapeHid.df = merge(shapeHid.points, shapeHid@data, by="id", all=F)

listofrivers<-split(shapeHid.df, shapeHid.df$id)

myMap3 <- ggplot() +
  lapply(listofrivers, function(x) geom_path(data=x, aes(x=long, y=lat), color="gray70", linetype=1)) +
  geom_map(data = world_map, map = world_map, aes(map_id = region),
           color = 'black', fill = NA, linetype=2) +
  theme(panel.border = element_rect(fill = NA, colour = "black"))+
  theme(axis.title=element_blank())+
  scale_y_continuous(limits=c(-15,6),expand=c(0,0))+
  scale_x_continuous(limits=c(-76,-55),expand=c(0,0))
myMap3

enter image description here

Upvotes: 0

Views: 2440

Answers (2)

Carlos Eduardo Lagosta
Carlos Eduardo Lagosta

Reputation: 1001

If you routinely work with shapefiles, geom_path and geom_polygon gives everything you need. In recent versions, ggplot deals directly with spatial objects, so there's no need to use fortify and merge (probably the step taking more time in your code). Here's an example using the shapefile of federative units of Brazil from IBGE as base map:

shapeUFs <- readOGR('.', 'BRUFE250GC_SIR')
shapeHid <- readOGR('.', 'PrincipaisRiosDoBrasil') 

ggplot(shapeUFs, aes(long, lat, group = group)) +
  geom_polygon(fill = 'gray90', color = 'black') +
  geom_path(data = shapeHid, color = 'steelblue2') +
  coord_map() + theme_void()

enter image description here

Performance will be affected by the size of your shapes (determined by number of features and level of details) more than the geometry you're using in ggplot. You can use rgeos::gSimplify to reduce the number of vertices in a spatial polygon/lines object. You can also plot points directly over the map:

# Simplifying the geometry of the federative units
shapeUFs.s <- rgeos::gSimplify(shapeUFs, .05, TRUE)

# Storing map in an object
riversMap <- ggplot(shapeUFs.s, aes(long, lat)) +
  geom_polygon(aes(group = group), fill = 'gray90', color = 'black') +
  geom_path(data = shapeHid, aes(group = group), color = 'steelblue2') +
  coord_map() + theme_void()

# Sampling 20 cities in Brazil
brMunics <- read.csv('https://raw.githubusercontent.com/kelvins/Municipios-Brasileiros/master/Municipios_Brasileiros.csv')
Munics <- brMunics[sample(nrow(brMunics), 20), ]

# Plotting points over the map
riversMap + geom_point(data = Munics, aes(Longitude, Latitude), color = 'red')

# If your data already have the coordinates named 'lat' and 'long',
# you can skip aes(Longitude, Latitude):
names(Munics)[6:7] <- c('lat','long')
riversMap + geom_point(data = Munics, color = 'red')

enter image description here

Upvotes: 1

AndS.
AndS.

Reputation: 8110

I would do the following:

library(sf)
library(ggplot2)

world_map <- map_data('world')
sdf <- read_sf("PrincipaisRiosDoBrasil.shp")

myMap3 <- ggplot() +
    geom_map(data = world_map, map = world_map, aes(map_id = region), color = 'black', fill = NA, linetype=2) +
    geom_sf(data = sdf)+
    theme(panel.border = element_rect(fill = NA, colour = "black"))+
    theme(axis.title=element_blank())+
    scale_y_continuous(limits=c(-15,6),expand=c(0,0))+
    scale_x_continuous(limits=c(-76,-55),expand=c(0,0))
myMap3

enter image description here

You'll need to update ggplot2 to 3.0.0 for geom_sf.

Upvotes: 1

Related Questions