R: Convert sf polygon defined using lat/long to UTM - r

I have the following polygon, defined using degrees latitude/longitude:
## Define latitude/longitude
lats <- c(64.25086, 64.24937, 63.24105, 63.22868)
lons <- c(-140.9985, -136.9171, -137.0050, -141.0260)
df <- data.frame(lon = lons, lat = lats)
polygon <- df %>%
## EPSG 3578; Yukon Albers projection
st_as_sf(coords = c('lon', 'lat'), crs = 3578) %>%
summarise(geometry = st_combine(geometry)) %>%
st_cast('POLYGON')
When I plot it on a map using Tmap, it appears in the Pacific Ocean off the coast of British Columbia, rather than in the middle of the Yukon:
library(sf)
library(sp)
library(tmap)
library(dplyr)
library(magrittr)
library(leaflet)
m <- tm_shape(data$study_boundary) + tm_borders(col = 'black',
lwd = 5,
zindex = 1000)
m
I am guessing that the problem is in using lat/long rather than UTMs because I have other polygons defined using UTMs that do appear where they (and the polygon defined above) are supposed to be. I found several other posts going the other way (UTM to lat/long) using spTransform, but I haven't been able to go lat/long to UTM with spTransform. I tried the code below:
poly_utm <- st_transform(polygon, crs = "+proj=utm+7")
But that didn't work either.
Thanks!

This (which I've improved by removing the pipe):
st_as_sf(df, coords = c('lon', 'lat'), crs = 3578)
creates a spatial points data frame using the numbers in the data frame for the coordinates, and the crs code of 3578 as the label for what those numbers represent. It does not change the numbers.
It looks like those numbers are actually lat-long coordinates, which means they are probable crs code 4326, the lat-long system used for GPS, also known as WGS 84. But it might not be. But probably is. Do check. So anyway, you should do:
df_unprojected = st_as_sf(df, coords = c('lon', 'lat'), crs = 4326)
df_projected = st_transform(df_unprojected, 3578)
The st_transform function does the actual change of the coordinate numbers and assigns the new CRS code to the spatial data metadata. That should give you a set of points you can then plot and check they are in the right place before you throw it into summarise and st_cast.

Related

Test whether lat/lon pairs exist within a shapefile in R

I've read through many forums regarding this topic but I can't seem to adapt anything I've read to my particular question. Basically, I have a data frame of lat/lon values and all I want to do is test whether these coordinates exist within California.
Here is some example data:
library(tidyverse)
library(sf)
coords <- tribble(
~city, ~lon, ~lat,
LA, -118.2437, 34.0522,
SF, -122.4194, 37.7749,
SAC, -121.4944, 38.5816,
CHI, -87.6298, 41.8781,
NY, -74.0060, 40.7128
)
And here is a link to the shape files from the state website: CA Shape Files.
I think I'm close...
# read in shape data
cali <- read_sf("CA_State_TIGER2016.shp")
# convert coordinates to spatial point compatible data
coords_sf <- st_as_sf(coords, coords = c("lon", "lat"), crs = st_crs(cali))
From there, I assume I use st_contains to test whether my cali object contains the coordinates found in coords_sf but I can't get it to work.
Any advice?
Thanks for your help!
In your code, there is a confusion between the original coordinate reference system of your point dataset coords and the crs you want to apply to it.
Note that your dataset named coords is not a spatial dataset. You need to make it a spatial dataset with st_as_sf(). The crs of the coordinates you entered in this dataframe is "geographical coordinates".
Once this is a dataset, you can then transform it to the target crs.
In your code, you tried to do both at the same time.
Hence the answer you are looking for is:
library(tidyverse)
library(sf)
coords <- tribble(
~city, ~lon, ~lat,
"LA", -118.2437, 34.0522,
"SF", -122.4194, 37.7749,
"SAC", -121.4944, 38.5816,
"CHI", -87.6298, 41.8781,
"NY", -74.0060, 40.7128
)
file <- tempfile(fileext = ".zip")
download.file("https://data.ca.gov/dataset/e212e397-1277-4df3-8c22-40721b095f33/resource/3db1e426-fb51-44f5-82d5-a54d7c6e188b/download/ca-state-boundary.zip", destfile = file)
unzip(zipfile = file)
# read in shape data
cali <- read_sf("CA_State_TIGER2016.shp")
# Your data are originally geographical coordinates which has EPSG=4326
coords_sf <- st_as_sf(coords, coords = c("lon", "lat"), crs = 4326)
# Then you can transform them to the system you want
coords_cali <- coords_sf %>% st_transform(crs = st_crs(cali))
cali %>% st_contains(coords_cali)
If you want to add the information of the cali shapefile in your point dataset you can:
Keep entire point dataset and put NA
coords_cali %>%
st_join(cali)
Keep only points that are inside the cali polygon
coords_cali %>%
st_intersection(cali)

Is there an R function to convert numerical values into coordinates?

I am working with a dataset that features chemical analyses from different locations within a cave, with each analysis ordered by a site number and that sites latitude and longitude. This first image is what I had done originally simply using ggplot.
Map of site data, colored by N concentration
But what I want to do is use the shapefile of the cave system from which the data is sourced from and do something similar by plotting the points over the system and then coloring them by concentration. This below is the shapefile that I uploaded Cave system shapefile
Cave system shapefile
So basically I want to be able to map the chemical data from my dataset used to map the first figure, but on the map of the shapefile. Initially it kept on saying that it could not plot on top of it. So I figured I had to convert the latitude and longitude into spatial coordinates that could then be mapped on the shapefile.
Master_Cave_data <- Master_cave_data %>%
st_as_sf(MastMaster_cave_data, agr = "identity", coord = Lat_DD)
This was what I had thought to use in order to convert the numerical Latitude cooridnates into spatial data.
I assume your coordinates are in WSG84 projection system (crs code 4326). You can create your sf object the following way:
Master_Cave_data <- st_as_sf(MastMaster_cave_data, coords = c('lon', 'lat'), crs = 4326)
Change lon and lat columns to relevent names. To plot your points with your shapefile, you need them both in the same projection system so reproject if needed:
Master_Cave_data <- Master_cave_data %>% st_transform(st_crs(shapefile))
Example
Borrowed from there
df <- data.frame(place = "London",
lat = 51.5074, lon = 0.1278,
population = 8500000) # just to add some value that is plotable
crs <- 4326
df <- st_as_sf(x = df,
coords = c("lon", "lat"),
crs = crs)
And you can have a look at the map:
library(tmap)
data("World")
tm_shape(World[World$iso_a3 == "GBR", ]) + tm_polygons("pop_est") +
tm_shape(df) + tm_bubbles("population")

Creating a map based on address or xy coordinates - convert to lat and long?

I have a probably very simple question (I'm rather new to R), but after searching for a while I didn't manage to find what I was looking for.
I need to create a map in R. Preferably with the Leaflet packages, but I'm absolutely open to other suggestions.
My data is what causes issues. I have addresses and x y coordinates for all the points, but most map-making packages need latitude and longitude data.
Is there any way to convert either the addresses or the x y coordinates rather easily?
I've read that the geocode function should do that, but Google requires API to function for this, and I must admit I get lost at that point.
The data contains around 50 points, so it would be nice with a method to mass-convert to lat and long.
Thank you very much in advance.
Example of x,y coordinates
Name x y
Point_1 556305 6306381
something like this?
looked up crs using: https://epsg.io/?q=denmark
sample data
df <- data.frame( city = "Trinbak", lon = 556305, lat = 6306381 )
code
library(sf)
library(leaflet)
df.sf <- st_as_sf( df, coords = c("lon", "lat") ) %>%
st_set_crs( 2198 ) %>% #set coordinate system used
st_transform( 4326 ) #transform coordinates to WGS84 coordinates
leaflet() %>% addTiles() %>% addMarkers( data = df.sf )
output
update
perhaps
df.sf <- st_as_sf( df,
coords = c("lon", "lat") ) %>%
st_set_crs( 23032 ) %>%
st_transform( 4326 )
is more accurate?

Distance between a set of points and a polygon with sf in R

I have a dataframe of points on map and an area of interest described as a polygon of points. I want to calculate the distance between each of the points to the polygon, ideally using the sf package.
library("tidyverse")
library("sf")
# area of interest
area <-
"POLYGON ((121863.900623145 486546.136633659, 121830.369032584 486624.24942906, 121742.202408334 486680.476675484, 121626.493982203 486692.384434804, 121415.359596921 486693.816446951, 121116.219703244 486773.748535465, 120965.69439283 486674.642759986, 121168.798757601 486495.217550029, 121542.879304342 486414.780364836, 121870.487595417 486512.71203006, 121863.900623145 486546.136633659))"
# convert to sf and project on a projected coord system
area <- st_as_sfc(area, crs = 7415L)
# points with long/lat coords
pnts <-
data.frame(
id = 1:3,
long = c(4.85558, 4.89904, 4.91073),
lat = c(52.39707, 52.36612, 52.36255)
)
# convert to sf with the same crs
pnts_sf <- st_as_sf(pnts, crs = 7415L, coords = c("long", "lat"))
# check if crs are equal
all.equal(st_crs(pnts_sf),st_crs(area))
I am wondering why the following approaches do not give me the correct answer.
1.Simply using the st_distance fun-doesn't work, wrong answer
st_distance(pnts_sf, area)
2.In a mutate call - all wrong answers
pnts_sf %>%
mutate(
distance = st_distance(area, by_element = TRUE),
distance2 = st_distance(area, by_element = FALSE),
distance3 = st_distance(geometry, area, by_element = TRUE)
)
However this approach seems to work and gives correct distances.
3.map over the long/lat - works correctly
pnts_geoms <-
map2(
pnts$long,
pnts$lat,
~ st_sfc(st_point(c(.x, .y)) , crs = 4326L)
) %>%
map(st_transform, crs = 7415L)
map_dbl(pnts_geoms, st_distance, y = area)
I'm new to spatial data and I'm trying to learn the sf package so I'm wondering what is going wrong here. As far as i can tell, the first 2 approaches somehow end up considering the points "as a whole" (one of the points is inside the area polygon so i guess that's why one of the wrong answers is 0). The third approach is considering a point at a time which is my intention.
Any ideas how can i get the mutate call to work as well?
I'm on R 3.4.1 with
> packageVersion("dplyr")
[1] ‘0.7.3’
> packageVersion("sf")
[1] ‘0.5.5’
So it turns out that the whole confusion was caused by a small silly oversight on my part. Here's the breakdown:
The points dataframe comes from a different source (!) than the area polygon.
Overseeing this I kept trying to set them to crs 7415 which is a legal but incorrect move and led eventually to the wrong answers.
The right approach is to convert them to sf objects in the crs they originate from, transform them to the one the area object is in and then proceed to compute the distances.
Putting it all together:
# this part was wrong, crs was supposed to be the one they were
# originally coded in
pnts_sf <- st_as_sf(pnts, crs = 4326L, coords = c("long", "lat"))
# then apply the transformation to another crs
pnts_sf <- st_transform(pnts_sf, crs = 7415L)
st_distance(pnts_sf, area)
--------------------------
Units: m
[,1]
[1,] 3998.5701
[2,] 0.0000
[3,] 751.8097

How to calculate centroid of polygon using sf::st_centroid?

I am trying to manipulate some Brazilian Census data in R using the new "sf" package. I am able to import the data, but I get an error when I try to create the centroids of the original polygons
library(sf)
#Donwload data
filepath <- 'ftp://geoftp.ibge.gov.br/organizacao_do_territorio/malhas_territoriais/malhas_de_setores_censitarios__divisoes_intramunicipais/censo_2010/setores_censitarios_shp/ac/ac_setores_censitarios.zip'
download.file(filepath,'ac_setores_censitarios.zip')
unzip('ac_setores_censitarios.zip')
d <- st_read('12SEE250GC_SIR.shp',stringsAsFactors = F)
Now I try to create a new geometry column containing the centroid of column "geometry", but get an error:
d$centroid <- st_centroid(d$geometry)
Warning message:
In st_centroid.sfc(d$geometry) :
st_centroid does not give correct centroids for longitude/latitude data
How can I solve this?
All the GEOS functions underlying sf need projected coordinates to work properly, so you should run st_centroid on appropriately projected data. I don't know much about Brazil's available CRS's, but EPSG:29101 appears to work fine:
library(tidyverse)
d$centroids <- st_transform(d, 29101) %>%
st_centroid() %>%
# this is the crs from d, which has no EPSG code:
st_transform(., '+proj=longlat +ellps=GRS80 +no_defs') %>%
# since you want the centroids in a second geometry col:
st_geometry()
# check with
plot(st_geometry(d))
plot(d[, 'centroids'], add = T, col = 'red', pch = 19)

Resources