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.
Related
Using ggplot I want to add points to a sf map. Take this code:
ggplot(data = shapefile) +
geom_sf()+
geom_point(x = -70.67,y =-33.45, size = 10, colour = "red")
This code works fine for one of my shapefiles but not for another, and I'm not sure why. Here's the code's output with my first shapefile:
And here's the code's output with the second shapefile:
Potential reasons for why the second call is not recognizing the coordinates? The only difference I'm seeing between the two plots is that in the first, longitude and latitude are annotated numerically, and in the second, after their north/south and east/west orientation.
The inconsistent behavior is due to different projections for each shapefile. You typically need to supply the point locations that match the units of the projection you are using. You could either convert the points to your shapefile's projection, or, if you don't care if the data are in a geographic coordinate system, you can convert to 4326 which is lat/long on WGS84 datum.
Method 1: Maintaining your shapefile's projection. This method will convert your point(s) to a spatial sf data type, so you can just plot with geom_sf.
pts <- st_point(c(-70.67, -33.45)) %>% st_sfc() %>% st_as_sf(crs=st_crs(4326))
ggplot(data = shapefile) +
geom_sf() +
geom_sf(data = pts, size = 10, colour = "red")
Method 2: Converting the shapefile to EPSG 4326.
ggplot(data = shapefile %>% st_transform(st_crs(4326))) +
geom_sf() +
geom_point(x = -70.67,y =-33.45, size = 10, colour = "red")
I've imported a shapefile of the world's oceans from Natural Earth to R via readOGR. When I try to render it in ggplot, it fills in land over N. & S. America. The behaviour is inconsistent with QGIS & ArcMap, both of which render & fill the shapefile just fine. Any ideas?
download.file("https://www.naturalearthdata.com/http//www.naturalearthdata.com/download/50m/physical/ne_50m_ocean.zip" , destfile="./ne_50m_ocean.zip")
system("unzip ./ne_50m_ocean.zip")
wrld <- readOGR(dsn=getwd(),layer="ne_50m_ocean")
wrld <- tidy(wrld)
ggplot() + geom_polygon(data = wrld, aes(x = long, y = lat, group = group), colour = "black", fill = "blue")
screenshot of RStudio render
screenshot of QGIS render
I was able to resolve this using read_sf() instead of readOGR(), then tweaking the ggplot code to accommodate. Also worked for the next bit of my workflow which involved rasterizing the sf object using fasterize() for a mask ocean layer (simplified demo code included in case useful to others):
#get data
download.file("https://www.naturalearthdata.com/http//www.naturalearthdata.com/download/50m/physical/ne_50m_ocean.zip" , destfile="./ne_50m_ocean.zip")
system("unzip ./ne_50m_ocean.zip")
wrld <- read_sf(dsn=getwd(),layer="ne_50m_ocean")
#plot sf object
ggplot() + geom_sf(data=wrld, colour = "black", fill = "blue")
#rasterize sf object
r <- raster(ncol=720, nrow=360)
extent(r) <- extent(wrld)
rp <- fasterize(wrld, r)
ocean <- as.data.frame(rasterToPoints(rp))
#plot raster object
ggplot() + geom_tile(data=ocean,aes(x=x,y=y),fill="white")
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!
I have created an elevation map from a raster object (elevation data from worldclim) of my study sites in China, using ggplot code (simplified version of the code). The relevant raster objects have been downloaded from worldclim.org and converted to a data.frame using the raster package. Here is a link to the data used for this plot.
# load library
library("tidyverse")
load(file = "gongga.RData")
ggplot() +
geom_raster(data = gongga, aes(x=x, y=y, fill = elev)) +
coord_equal() +
scale_fill_gradient(name = "Elevation", low = "grey0", high = "grey100") +
scale_x_continuous(expand = c(0,0)) +
scale_y_continuous(expand = c(0,0)) +
theme(aspect.ratio=1/1, text = element_text(size=15))
For clarity I would like to add roads to the map. I came across the osmar package that extracts roads from Openstreetmap.
Using code from here, I extract the roads for the right section, but I don't know how to plot them to my existing ggplot.
# EXTRACT ROADS FROM OPENSTREETMAP AND PLOT THEM WITH RANDOM POINTS
# Load libraries
library('osmar')
library('geosphere')
# Define the spatial extend of the OSM data we want to retrieve
moxi.box <- center_bbox(center_lon = 102.025, center_lat = 29.875,
width = 10000, height = 10000)
# Download all osm data inside this area
api <- osmsource_api()
moxi <- get_osm(moxi.box, source = api)
# Find highways
ways <- find(moxi, way(tags(k == "highway")))
ways <- find_down(moxi, way(ways))
ways <- subset(moxi, ids = ways)
# SpatialLinesDataFrame object
hw_lines <- as_sp(ways, "lines")
# Plot points
plot(hw_lines, xlab = "Lon", ylab = "Lat")
box()
Does the object need any transformation to plot it in ggplot?
Or is there a better solution than osmar package for my purpose?
You can fortify the SpatialLinesDataFrame and then plot that with ggplot
fortify(hw_lines) %>%
ggplot(aes(x = long, y = lat, group = group)) +
geom_path()
The group aesthetic stops ggplot from joining all the roads together into one long line.
I am attempting to plot several shapefiles on top of a map generated through ggmap. This is working well, however I want to constrain the view area to the shapefile (and not rely on the zoom argument in ggmaps). I've done this by getting the bounding box and passing it as an argument in ggplot's coord_cartesian While this works, I am getting some tearing issues on the edges of the map - most specifically on the western portion. I've tried adjusting the x-y coordinates manually but it seems to only severely distort the picture.
My thoughts are to zoom out slightly to allow the entire shapefile to be plotted in the area, but I can't seem to figure it out. It's also possible I am going about this entirely in the wrong way.
Here's the code I used to generate the map. The shapefile can be downloaded here
library(dplyr)
library(ggmap)
library(rgdal)
library(broom)
# Read in shapefile, project into long-lat
# Create 'tbox' which is a minimum bounding box around the shapefile
tracts <- readOGR(dsn = ".", layer = "CensusTracts2010") %>%
spTransform("+proj=longlat +ellps=WGS84")
tbox <- bbox(tracts)
# Plot data
tract_plot <- tidy(tracts)
DetroitMap <- qmap("Detroit", zoom = 11)
DetroitMap + geom_polygon(data = tract_plot, aes(x = long, y = lat, group = id), color = "black", fill = NA) +
coord_cartesian(xlim = c(tbox[1,1], tbox[1,2]),
ylim = c(tbox[2,1], tbox[2,2]))
I followed your workflow, which resulted in the same problem as you mentioned above. Then I changed the zoom on the qmap option from 11 to 10 and it resulted in a much better picture, although you do lose some of the place names but you can add those in manually yourself with annotate:
DetroitMap <- qmap("Detroit", zoom = 10)
DetroitMap + geom_polygon(data = tract_plot, aes(x = long, y = lat, group = id), color = "black", fill = NA) +
coord_cartesian(xlim = c(tbox[1,1], tbox[1,2]),
ylim = c(tbox[2,1], tbox[2,2]))