Plotting Latitude and Longitude over a map - r

I'm currently using ggmaps to display a map of the location I'm trying to display points over but when I use the points function to try to add the points over the map it says that my list of latitudes and longitudes cannot be used for the arguments in x and y. Is there any better way to plot the points other than having to go one by one and individually code them onto my map?
Edit: Here's the data I'm working with right now and the first few lines of code that aren't working-
-A table of 2 variables "lat" and "lon" that show all the points geocoded
-A list of the addresses where the geo coordinates came from
mapTampa <- get_map(location = 'Tampa', zoom = 10)
points(lon, lat, col = "red", cex = 0.5)
The first line works and gives me the map but when I tried to add points thats when it gave me the x y error so I tried:
finalMap<-mapTampa+geom_point(aes(x=lon, y=lat, data=Filtered_Data))
Where latlong is my table with both latitudes and longitudes but that doesn't work either. I'm fairly new to R and this is my first project working with it but it seems like I've read everything about ggplot and ggmap and nothing is helping me.

Related

How can I plot a map using ggplot2 that includes the latitude and longitude of the data?

I have data that includes the longitude and latitude of certain locations in Arizona however its over 9000 observations and ggplot2 keeps giving me "Error in st_as_sf.data.frame(data, coords = c(x, y), remove = FALSE, crs = crs) : missing values in coordinates not allowed". This data also has missing longitudes and latitudes that may be affecting the code. I need help plotting geolocations for over 9000 observations located in an excel file, excluding missing data.
I tried using ggplot2 but it kept giving me error codes and I tried mapview but I think that it may only work for smaller data observations. I still have to merge this data with 2 other 9000 observations. I think it may be because I need a bigger data visualization program but I don't know. I was expecting all the observations to be displayed on a map by themselves and then all together (layered). Any assistance would be greatly appreciated.
Would ggmap package be helpful?
You may use it to download a map of Arizona and plot the data points according to their longitude and latitude on the map.
For example,
AZmap = get_stamenmap(bbox=c(left = -115.63, bottom = 31.25, right =
-108.84, top = 37.18),zoom = 2)
ggmap(AZmap)+ geom_point(aes(x = your longitude,
y = your latitude,
data = your data,
alpha = 0.1, size = 1, color = 'red')
I tried get_map or get_googlemap before but they required API key. get_stamenmap works best for me.

How to add location points onto a shapefile imported into R from QGIS using ggplot2

I'm working on a project which involves GPS coordinates from offshore locations. I'm looking to measure the distance from shore for each of my points. I have created a shapefile of the shoreline in question in QGIS and I have successfully imported it into R using the st_read() function (named "biminishore" in this example).
With the following code, I'm able to plot my shapefile in ggplot2:
bplot = ggplot() +
geom_sf(data = biminishore, size = 0.1, color = "black", fill = "green1") +
ggtitle("Bimini, The Bahamas") +
coord_sf() +
theme_classic()
plot(bplot)
Now, I would like to add the location coordinates (imported into R as a .csv with separate columns for Lat and Lon) as a layer over the imported shapefile. Can anyone suggest how to go about doing this in a way that will allow me to calculate the distance between each point and the nearest shoreline point?
My currents attempts are giving the error: Error in st_transform.sfc(st_geometry(x), crs, ...) : cannot transform sfc object with missing crs
I assume this means my coordinate systems are incompatible but haven't found a way around this yet. So far, I have tried combining my point columns using SpatialPoints(). I've also tried using multiple forms of st_set_crs() and st_transform() but I haven't had any luck yet. Any help is greatly appreciated! Thanks!
Read your points file as a csv & then transform it to an sf object:
library(tidyverse)
library(sf)
points <- read_csv('path_to_points.csv')
#make it an sf object, change Long and Lat to the correct column name
points_sf <- st_as_sf(points, coords = c("Long", "Lat"))
# set crs of points_sf to same as biminishore object
points_sf <- st_set_crs(points_sf, st_crs(biminishore))
Then you should be able to plot them together by adding:
+ geom_sf(data = points_sf)
to your ggplot2 call.
Finding the nearest feature between the two can be done with sf::st_nearest_feature(points_sf, biminishore).
A good post on nearest features & distances: https://gis.stackexchange.com/questions/349955/getting-a-new-column-with-distance-to-the-nearest-feature-in-r

Incorrect NA return when converting Lat/Long Coordinates to location in R

I am trying to use a modified version of the R code found in the following link:
Latitude Longitude Coordinates to State Code in R
To test the code, I created the following formal arguments:
mapping = "state"
pointsDF = data.frame(x = c(-88.04607, -83.03579), y = c(42.06907, 42.32983))
latlong2state(pointsDF, mapping)
The code returned the following:
[1] "Illinois" NA
The first coordinate set returns a correct answer, i.e. "Illinois". However, when I input the 2nd coordinate set (i.e. -83.03579, 42.32983) into an online converter, I get the following:
Downtown, Detroit, MI, USA
(http://www.latlong.net/Show-Latitude-Longitude.html)
Running the code again but changing the second coordinate from 42.32983 to 43.33 puts the point in the state of Michigan.
When using the "world" map as my formal argument for the "mapping" variable, the code returns "USA". I have been struggling for days to figure this out and have had no luck. I have played around with SpatialPointDataFrames, various projections, and looked into the state polygon objects themselves. I am using R version 3.3.1 on a Windows 7 system. I think the data point in question may be falling on a border line. In which case, I think an "NA" would be expected. The code I used is below.
Code Used:
library(sp)
library(maps)
library(maptools)
library(rgdal)
latlong2state = function(pointsDF, mapping) {
local.map = map(database = mapping, fill = TRUE, col = "transparent", plot = FALSE)
IDs = sapply(strsplit(local.map$names, ":"), function(x) x[1])
maps_sp = map2SpatialPolygons(map = local.map, ID = IDs,
proj4string = CRS("+proj=longlat +datum=WGS84"))
pointsSP = SpatialPoints(pointsDF,
proj4string = CRS("+proj=longlat +datum=WGS84"))
indices = over(x = pointsSP, y = maps_sp)
mapNames = sapply(maps_sp#polygons, function(x) {x#ID})
mapNames[indices]
}
I am only two months in to learning R and love the language thus far. This has been the first time I could not find an answer. I would really appreciate an help provided on the matter!!!
Firstly, the issue is not due to the point lying on a border. In fact, over() would not return NA for a point on a border, but rather "if a point falls in multiple polygons, the last polygon is recorded."
NA denotes a point that does not fall in a polygon. We can zoom in on your map to see this is the case
plot(local.map, xlim = c(-83.2, -82.8), ylim=c(42.2,42.6), type="l")
polygon(local.map, col="grey60")
points(local.map)
points(pointsDF[2,], col="red")
The point falls outside the contiguous USA in Canada, according to the polygons provided by maps::map(). Why would this be the case when other maps, as you say, locate this point on the USA side of the border? I do not think this is a projection issue, because we are using the same WGS84 geographic coordinates for the polygons and the points. It seems, therefore, that the polygons themselves that are provided by maps::map() may be wrong.
We can check this by comparing to polygons from another source. I downloaded the US census departments highest resolution state boundaries from http://www2.census.gov/geo/tiger/GENZ2015/shp/cb_2015_us_state_500k.zip. Then,
shp.path <- "C:/Users/xxx/Downloads/cb_2015_us_state_500k/cb_2015_us_state_500k.shp"
states <- readOGR(path.expand(shp.path), "cb_2015_us_state_500k")
plot(states, xlim = c(-83.2, -82.8), ylim=c(42.2,42.6))
points(pointsDF[2,], col="red")
gets us this map in which we see that the point is inside the US boundary:
The solution I recommend therefore, is to use these better resolution, more reliable boundary polygons, particularly if you are interested to accurately resolve points close to borders.

Obtaining maps that contain location with 2+ US states (cities, etc.) with get_map (location as a vector)

Concept of ggmap seems clear to me:
Use get_map to obtain a map at a certain location at a certain spatial zoom.
Use ggmap() + ggplot() to combine map image with ggplot graphics.
The challenge at the moment lies in step 1 and, precisely, location parameter. Besides a longitude/latitude pair get_map accepts a character string, but no vector. It seems that there is no easy way to obtain a map that includes two or more states, or two or more cities.
Thus, to have a function that draws arbitrary number of (presumably adjacent) US states there is no shortcut but to go through elaborate process of geocoding each state and calculating optimal location and zoom (also not sure how).
as you can find out here - http://journal.r-project.org/archive/2013-1/kahle-wickham.pdf - there is the way to put shapefile into ggmap.
All you need to do is:
# read data into R (for example - your states)
shapefile <- readShapeSpatial(’tr48_d00.shp’,proj4string = CRS("+proj=longlat +datum=WGS84"))
# convert to a data.frame using fortify function
data <- fortify(shapefile)
#and plot your data using qmap or ggmap
qmap(’texas’, zoom = 6, maptype = ’satellite’) + geom_polygon(aes(x = long, y = lat, group = group), data = data,colour = ’white’, fill = ’black’, alpha = .4, size = .3)

How to plot contours on a map with ggplot2 when data is on an irregular grid?

Sorry for the wall of text, but I explain the question, include the data, and provide some code :)
QUESTION:
I have some climate data that I want to plot using R. I am working with data that is on an irregular, 277x349 grid, where (x=longitude, y=latitude, z=observation). Say z is a measure of pressure (500 hPa height (m)). I tried to plot contours (or isobars) on top of a map using the package ggplot2, but I am having some trouble due to the structure of the data.
The data comes from a regular, evenly spaced out 277x349 grid on a Lambert conformal projection, and for each grid point we have the actual longitude, latitude, and pressure measurement. It is a regular grid on the projection, but if I plot the data as points on a map using the actual longitude and latitude where the observations were recorded, I get the following:
I can make it look a little nicer by translating the rightmost piece to the left (maybe this can be done with some function, but I did this manually) or by ignoring the rightmost piece. Here is the plot with the right piece translated to the left:
(An aside) Just for fun, I tried my best to re-apply the original projection. I have some of the parameters for applying the projection from the data source, but I do not know what these parameters mean. Also, I do not know how R handles projections (I did read the help files...), so this plot was produced through some trial and error:
I tried to add the contour lines using the geom_contour function in ggplot2, but it froze my R. After trying it on a very small subset of the data, I found that out after some googling that ggplot was complaining because the data was on an irregular grid. I also found out that that is the reason geom_tile was not working. I am guessing that I have to make my grid of points evenly spaced out - probably by projecting it back into the original projection (?), or by evenly spacing out my data by either sampling a regular grid (?) or by extrapolating between points (?).
My questions are:
How can I draw contours on top of the map (preferably using ggplot2) for my data?
Bonus questions:
How do I transform my data back to a regular grid on the Lambert conformal projection? The parameters of the projection according to the data file include (mpLambertParallel1F=50, mpLambertParallel2F=50, mpLambertMeridianF=253, corners, La1=1, Lo1=214.5, Lov=253). I have no idea what these are.
How do I center my maps so that one side is not clipped (like in the first map)?
How do I make the projected plot of the map look nice (without the unnecessary parts of the map hanging around)? I tried adjusting the xlim and ylim, but it seems to apply the axes limits before projecting.
DATA:
I uploaded the data as rds files on Google drive. You can read in the files using the readRDS function in R.
lat2d: The actual latitude for the observations on the 2d grid
lon2d: The actual longitude for the observations on the 2d grid
z500: The observed height (m) where pressure is 500 millibars
dat: The data arranged in a nice data frame (for ggplot2)
I am told that the data is from the North American Regional Reanalysis data base.
MY CODE (THUS FAR):
library(ggplot2)
library(ggmap)
library(maps)
library(mapdata)
library(maptools)
gpclibPermit()
library(mapproj)
lat2d <- readRDS('lat2d.rds')
lon2d <- readRDS('lon2d.rds')
z500 <- readRDS('z500.rds')
dat <- readRDS('dat.rds')
# Get the map outlines
outlines <- as.data.frame(map("world", plot = FALSE,
xlim = c(min(lon2d), max(lon2d)),
ylim = c(min(lat2d), max(lat2d)))[c("x","y")])
worldmap <-geom_path(aes(x, y), inherit.aes = FALSE,
data = outlines, alpha = 0.8, show_guide = FALSE)
# The layer for the observed variable
z500map <- geom_point(aes(x=lon, y=lat, colour=z500), data=dat)
# Plot the first map
ggplot() + z500map + worldmap
# Fix the wrapping issue
dat2 <- dat
dat2$lon <- ifelse(dat2$lon>0, dat2$lon-max(dat2$lon)+min(dat2$lon), dat2$lon)
# Remake the outlines
outlines2 <- as.data.frame(map("world", plot = FALSE,
xlim = c(max(min(dat2$lon)), max(dat2$lon)),
ylim = c(min(dat2$lat), max(dat2$lat)))[c("x","y")])
worldmap2 <- geom_path(aes(x, y), inherit.aes = FALSE,
data = outlines2, alpha = 0.8, show_guide = FALSE)
# Remake the variable layer
ggp <- ggplot(aes(x=lon, y=lat), data=dat2)
z500map2 <- geom_point(aes(colour=z500), shape=15)
# Try a projection
projection <- coord_map(projection="lambert", lat0=30, lat1=60,
orientation=c(87.5,0,255))
# Plot
# Without projection
ggp + z500map2 + worldmap2
# With projection
ggp + z500map + worldmap + projection
Thanks!
UPDATE 1
Thanks to Spacedman's suggestions, I think I have made some progress. Using the raster package, I can directly read from an netcdf file and plot the contours:
library(raster)
# Note: ncdf4 may be a pain to install on windows.
# Try installing package 'ncdf' if this doesn't work
library(ncdf4)
# band=13 corresponds to the layer of interest, the 500 millibar height (m)
r <- raster(filename, band=13)
plot(r)
contour(r, add=TRUE)
Now all I need to do is get the map outlines to show under the contours! It sounds easy, but I'm guessing that the parameters for the projection need to be inputted correctly to do things properly.
The file in netcdf format, for those that are interested.
UPDATE 2
After much sleuthing, I made some more progress. I think I have the proper PROJ4 parameters now. I also found the proper values for the bounding box (I think). At the very least, I am able to roughly plot the same area as I did in ggplot.
# From running proj +proj=lcc +lat_1=50.0 +lat_2=50.0 +units=km +lon_0=-107
# in the command line and inputting the lat/lon corners of the grid
x2 <- c(-5628.21, -5648.71, 5680.72, 5660.14)
y2 <- c( 1481.40, 10430.58,10430.62, 1481.52)
plot(x2,y2)
# Read in the data as a raster
p4 <- "+proj=lcc +lat_1=50.0 +lat_2=50.0 +units=km +lon_0=-107 +lat_0=1.0"
r <- raster(nc.file.list[1], band=13, crs=CRS(p4))
r
# For some reason the coordinate system is not set properly
projection(r) <- CRS(p4)
extent(r) <- c(range(x2), range(y2))
r
# The contour map on the original Lambert grid
plot(r)
# Project to the lon/lat
p <- projectRaster(r, crs=CRS("+proj=longlat"))
p
extent(p)
str(p)
plot(p)
contour(p, add=TRUE)
Thanks to Spacedman for his help. I will probably start a new question about overlaying shapefiles if I can't figure things out!
Ditch the maps and ggplot packages for now.
Use package:raster and package:sp. Work in the projected coordinate system where everything is nicely on a grid. Use the standard contouring functions.
For map background, get a shapefile and read into a SpatialPolygonsDataFrame.
The names of the parameters for the projection don't match up with any standard names, and I can only find them in NCL code such as this
whereas the standard projection library, PROJ.4, wants these
So I think:
p4 = "+proj=lcc +lat_1=50 +lat_2=50 +lat_0=0 +lon_0=253 +x_0=0 +y_0=0"
is a good stab at a PROJ4 string for your data.
Now if I use that string to reproject your coordinates back (using rgdal:spTransform) I get a pretty regular grid, but not quite regular enough to transform to a SpatialPixelsDataFrame. Without knowing the original regular grid or the exact parameters that NCL uses we're a bit stuck for absolute precision here. But we can blunder on a bit with a good guess - basically just take the transformed bounding box and assume a regular grid in that:
coordinates(dat)=~lon+lat
proj4string(dat)=CRS("+init=epsg:4326")
dat2=spTransform(dat,CRS(p4))
bb=bbox(dat2)
lonx=seq(bb[1,1], bb[1,2],len=277)
laty=seq(bb[2,1], bb[2,2],len=349)
r=raster(list(x=laty,y=lonx,z=md))
plot(r)
contour(r,add=TRUE)
Now if you get a shapefile of your area you can transform it to this CRS to do a country overlay... But I would definitely try and get the original coordinates first.

Resources