fortify behaving strangely on adm0 SpatialPolygonsDataFrame - r

I'm trying to do some plots in ggplot, which I'm much more comfortable working with than R's built in plotting function. However, with one of the file's I'm using (a SpatialPolygonsDataFrame containing a map of Kenya), when I try to call fortify on the SPDF to convert it to a data.frame, plotting the result yields odd behavior in a particularly jagged region of the border, while plot manages to work fine. Anyone have any ideas as to what's going on?
library(sp)
library(ggplot2)
riso <- "KEN"
query <- paste0("http://biogeo.ucdavis.edu/data/gadm2/R/", riso, "_adm0.RData")
destination <- "myfile.RData"
download.file(query, destination)
load(destination)
plot(gadm)
map <- fortify(gadm)
g <- ggplot() + geom_path(data = map, aes(x = long, y = lat))
g

Just add group = group to the aes() mappings. Wish I could explain why this works.
g <- ggplot() + geom_path(data = map, aes(x = long, y = lat, group = group))
g

Related

ggplot maps - unwanted horizontal lines when using coord_map

I've problem with projecting properly map of Europe when I use coord_map in ggplot package. The code below gives me a weird and unwanted horizontal lines in random places. Does anyone know how to overcome this problem?
I don't want to use coord_quickmap nor coord_cartesian because I want to preserve straight lines of countries.
library(ggplot2)
map.world <- map_data("world")
ggplot(map.world, aes(x = long, y = lat)) +
geom_polygon(mapping = aes(x = long, y = lat, group = group), fill = "#B3B1B5", color = "#D9D8DA",size = 0.4) +
theme_minimal() +
theme(axis.text = element_blank(), text = element_blank(), panel.grid = element_blank()) +
coord_map(xlim = c(-27,36), ylim = c(34,67))
There are two ways to work around your problem:
The straightforward way
This way just needs a little tweaking of your code (note that I use magrittr's forward pipes):
library(maps)
library(magrittr)
library(maptools)
library(broom)
library(ggplot2)
europe <- maps::map("world", fill=TRUE, plot=FALSE) %>%
maptools::pruneMap(xlim = c(-27,36), ylim = c(34,67))
ggplot(data= broom::tidy(europe)) +
geom_polygon(mapping = aes(x = long, y = lat, group = group),
fill = "#B3B1B5", color = "#D9D8DA",size = 0.4) +
theme_void() +
coord_map()
The "owin/extent" approach
Another way to work around your problem can be done by using owin objects. This kind of objects will allow you to create a spatial window. Then you can represent only the intersection of such window over the world map.
Using this approach your code will be something as follows (also using magrittr's forward pipes and setting up a general CRS)
library(maps)
library(magrittr)
library(spatstat)
library(maptools)
library(raster)
library(broom)
library(ggplot2)
#Defining a general EPSG so there won't be any superposition problems
epsg <- "+proj=longlat +datum=WGS84 +no_defs"
#Using the original maps package, then converting map into SpatialPolygons object
map.world <- maps::map("world", fill=TRUE) %$%
maptools::map2SpatialPolygons(., IDs=names,proj4string=CRS(epsg))
#In order to keep the names of the countries we create the following data.frame
country.labs <- sapply(slot(map.world, "polygons"), function(x) slot(x, "ID")) %>%
data.frame( ID=1:length(map.world), name=., row.names = .)
#We convert object map.world into a SpatialPolygonsDataFrame object
map.world.SPDF <- sp::SpatialPolygonsDataFrame(map.world, country.labs)
#Creating owin object using your zooming coordinates
#This step always requires to load packages 'spatstat' and 'maptools'
zoom <- as(spatstat::as.owin(c(-27,36,34,67)), "SpatialPolygons")
raster::projection(zoom)=epsg
#Storing intersection between 'zoom' and 'world.map'
europe <- raster::intersect(map.world.SPDF, zoom)
#*country names of object europe can be accessed via europe#data
#Representing object 'europe' using broom::tidy to create a data.frame object
ggplot() +
geom_polygon(data = broom::tidy(europe, region="name"),
mapping = aes(x = long, y = lat, group = group),
fill = "#B3B1B5", color = "#D9D8DA",size = 0.4) +
theme_void() +
coord_map()
#*country names after tidying 'europe' this way are in a new column called 'id'
Depending on what you are doing, you may want to use
zoom <- as(raster::extent(c(-27,36,34,67)), "SpatialPolygons")
To create an extent object instead of an owin object (The result here is going to be the same)
The result obtained with any method is displayed below
In case you need to do different zooms you can easily wrap any of the alternatives up in a function.
I hope it helps
BONUS BALL: It might be interesting for you to check out the tmap package

ggplot2 issue with plotting points and polygons

I am trying to create a simple map using ggplot2 to display a series of river basins and data points.
The data points are stored in a .csv file and look like this:
I've projected the points and created a SpatialPointDataFrame and then stored them in a dataframe:
points <- read.csv(c(paste0("./Points/", "points.csv")), header = T, sep = ",")
coordinates(points) <- ~Lat + Lon
cord <- "+init=epsg:2163"
proj4string(points) <- CRS(cord)
points_df <- as.data.frame(points, region = "id")
The basin files are all stored in the same directory and have been read into a single spatialpolygonsdataframe which looks like this:
then are converted to a dataframe using this:
basins_TX$id <- rownames(basins#data)
basins_TX_df <- tidy(basins, region = "id")
Then I try to create a map using this code:
ggplot() +
geom_polygon(data = basins_df,
aes(x = long, y = lat, group = group),
fill = "white", color = "black") +
geom_point(data = points_df,
aes(x = Lon, y = Lat),
color = "red")
this creates a map with polygons and one point at 0,0:
This happens no matter what subsection of the data I am looking at. I want to accurately display the points and the polygons.
The issue was in fact related to the projection of my data. I had defined the projection of the points file rather than projecting it, so it was incorrect. I was able to correct this by redefining it correctly and the projecting the points file using spTransform
leaving this up in case other run into similar issues, although the error was not in the ggplot2 script.

Plotting a SpatialLine in R using ggplot2

I've done a lot of searching on this topic and have yet to find anything that seems to solve my problem. I am working on plotting a road segment and overlaying some radar data that I have. Below is an example of what I am working on.
I've generated the above plot with the following ...
map <- get_map(
location = c(-86.34, 39.94),
source = "google", zoom = 13, maptype = "roadmap"
)
lon <- c(-86.355750256169358, -86.357100144855735, -86.359359890246708)
lat <- c(39.949089789262416, 39.950209921850444, 39.952050262109935)
roadDf <- data.frame(lon, lat)
ggmap(map) + geom_tile(data = mrms_sub, aes(x = longitude, y = latitude, fill = palmer)) +
geom_point(data = mrms_sub, aes(x = longitude, y = latitude)) +
geom_point(data = roadDf, col = "red")
I currently have my road segment showing as the three points from my WKT LINESTRING as a means of visualizing it but ultimately I want to show it as a line segment on the map. I've tried using rgeos readWKT function which makes a "Formal class SpatialLine". If I plot it using,
plot(roadSegment)
it works but I can't make it work with my ggplot. I've tried using geom_lines and geom_segments but it throws the following errors.
geom_segment(roadSegment, aes(x=longitude, y=latitude))
#Error: ggplot2 doesn't know how to deal with data of class uneval
geom_line(line, aes(x=longitude, y=latitude))
#Error: Mapping must be created by `aes()` or `aes_()`
My linestring is the following is read in like so ...
#define roads
road1 <-("LINESTRING(-86.355750256169358 39.949089789262416, -86.357100144855735 39.950209921850444, -86.359359890246708 39.952050262109935)")
roadSegment <- rgeos::readWKT(road1)
Any help would be greatly appreciated!

Unwanted Horizontal Lines in Map Projection in R

A few lines of code to expose my problem. When I work with a map of
the world and I introduce a projection, I always end up with some
weird looking horizontal lines.
Please have a look at
https://www.rdocumentation.org/packages/ggplot2/versions/1.0.0/topics/coord_map
from where I take the example for New Zeland
library(ggplot2)
nz <- map_data("nz")
# Prepare a map of NZ
nzmap <- ggplot(nz, aes(x = long, y = lat, group = group)) +
geom_polygon(fill = "white", colour = "black")
# Plot it in cartesian coordinates
nzmap
# With correct mercator projection
nzmap + coord_map()
which works beautifully. Now let us do the same with the world
world <- map_data("world")
# Prepare a map of the world
worldmap <- ggplot(world, aes(x = long, y = lat, group = group)) +
geom_polygon(fill = "white", colour = "black")
# Plot it in cartesian coordinates
worldmap
##but the following is a disaster!
# With correct mercator projection
worldmap + coord_map()
I see this issue of the horizontal lines with a projection has been
going on for quite a while, but I was able to find only seasoned posts
and I had assumed this was fixed long ago.
Please find below my sessionInfo.
Is there any solution to this? Is it still an open bug?
This is a pretty common problem in ggplot, but happily it is easily fixed:
worldmap + coord_map(xlim=c(-180,180))
produces
solution from: Why does coord_map produce a weird output?

Combine coord_proj and geom_raster

I am looking for a means of plotting raster data (using ggplot and geom_raster) on a small scale map. I would like to use ggalt and coord_proj to 'zoom-in' on particular regions of the shapefile, but I run into the error geom_raster only works with Cartesian coordinates
ggplot() +
geom_polygon(data = land_df, aes(long, lat, group = group), fill = 'grey25')+
geom_raster(data = df, aes(lon_bin, lat_bin, fill = sum_hours)) +
coord_proj(xlim = c(-67, -63),ylim = c(0, 9))
Is there another simple means of generating zoomed in raster maps using coord_proj and avoiding this restriction that geom_raster only works with Cartesian coordinates?
The other options I can think of is to generate individual shapefiles for each 'zoomed-in' region, but I am plotting many of these rasters and would rather not have to generate individual shapefiles for each and instead use coord_proj to programmatically specify raster map limits.
Thanks
I think you need to use geom_tile() instead of geom_raster(). geom_raster() internally uses a rasterGrob, which is a bitmap that can only be scaled linearly. Hence the limitation to Cartesian coordinate systems. geom_tile() draws individual rectangles which can be transformed into any coordinate system.
I don't have your dataset, but I can show a very simple example:
df <- data.frame(x = 1:100) # a very simple dataset
p_raster <- ggplot(df, aes(x, fill = x, y = 0)) +
geom_raster() +
scale_fill_distiller()
p_raster
p_raster + coord_polar()
## Error: geom_raster only works with Cartesian coordinates
Now with geom_tile():
# for geom_tile(), map both fill and color to avoid drawing artifacts
p_tile <- ggplot(df, aes(x, color = x, fill = x, y = 0)) +
geom_tile() +
scale_fill_distiller() +
scale_color_distiller()
p_tile
p_tile + coord_polar()

Resources