How to save dataframe geometry to a shapefile in R - r

I want to save route_dhdb_sf in SHP file, it looks like this :
My problem is the geometry column.
The R code :
library(sf)
library(ggplot2)
library(stplanr)
# Read shapefile
nl_rails_sf <- sf::st_read("~/netherlands-railways-shape/railways.shp")
# Data frame with station locations
stations_df <- data.frame(station = c("Den Haag", "Den Bosch"),
lat = c(52.080276, 51.690556),
lon = c(4.325, 5.293611))
# Create sf object
stations_sf <- sf::st_as_sf(stations_df, coords = c("lon", "lat"), crs = 4326)
# Find shortest route
slnetwork <- SpatialLinesNetwork(nl_rails_sf)
find_nodes <- find_network_nodes(sln = slnetwork,
x = stations_df$lon,
y = stations_df$lat,
maxdist = 2e5)
route_dhdb_df <- data.frame(start = find_nodes[1], end = find_nodes[2])
route_dhdb_sf <- sum_network_links(sln = slnetwork, routedata = route_dhdb_df)
How do I save this route_dhdb_sf to a shape file?
#Code of mharinga

Normally you can use:
sf::st_write(route_dhdb_sf,"~/netherlands-railways-shape/route_dhdb_sf.shp")
If you tried it, and if it did not work (you got an error message), you can try to save to other formats e.g. geosjon by editing the suffix like this:
sf::st_write(route_dhdb_sf,"~/netherlands-railways-shape/route_dhdb_sf.geojson")

Related

Export SpatialPolygonsDataFrame as geojson or topojson in R

I am trying to convert a geojson of London local authorities into a hex cartogram where each hexagon represents one local authority. It works in R but when I try to export the generated hexgrid as geojson or topojson I get the following error:
Error in sp::SpatialPolygonsDataFrame(polys, data = input#data) :
row.names of data and Polygons IDs do not match
Here's the code. I am using geogrid to generate the grid and geojsonio to export the generated dataframe to geojson or topojson:
library(geogrid)
library(geojsonio) # version 0.9.0
df <- read_polygons(system.file("extdata", "london_LA.json", package = "geogrid"))
# you can get the json file from here: https://github.com/jbaileyh/geogrid/blob/master/inst/extdata/london_LA.json
# Set arguments for plot
par(mfrow = c(2, 3), mar = c(0, 0, 2, 0))
# Hexagonal grid with 6 seeds
for (i in 1:3) {
grid_hexagon <- calculate_grid(shape = df, learning_rate = 0.05, grid_type = "hexagonal", seed = i)
plot(grid_hexagon, main = paste("Seed", i, sep = " "))
}
# Square grid
for (i in 1:3) {
grid_square <- calculate_grid(shape = df, grid_type = "regular", seed = i)
sp::plot(grid_square, main = paste("Seed", i, sep = " "))
}
# Get a SpatialDataFrame from our desired grid
tmp <- calculate_grid(shape = df, grid_type = "hexagonal", seed = 3)
df_hex <- assign_polygons(df, tmp)
# And export to TopoJSON
topojson_write(df_hex, object_name = "local_authorities", file = "output/london_hex.json")
Any suggestions about how can I solve this issue? Also, I am interested in hearing about other approaches to generate hex cartograms giving a specific input file.
References: https://github.com/jbaileyh/geogrid
You can convert the SpatialPolygonsDataFrame to sf, and then write to GeoJSON file with st_write:
library(sf)
df_hex = st_as_sf(df_hex)
st_write(df_hex, "df_hex.geojson")
Here is the result in QGIS:

How can I build this JSON file in R?

Working in R, I am having difficulty building a JSON file that I would use in an API call.
The required format for the JSON file can be seen here:
https://developer.trimblemaps.com/restful-apis/routing/route-reports/post-route-reports/
The input to the exercise is a dataframe like so:
Shipper_Latitude <- c(1,2,3,4)
Shipper_Longitude <- c(1,2,3,4)
r_combine.NewShipperLat <- c(1,2,3,4)
r_combine.NewShipperLon <- c(1,2,3,4)
r4 <- data.frame(Shipper_Latitude,Shipper_Longitude,r_combine.NewShipperLat,r_combine.NewShipperLon)
My attempt at building the required JSON file is as follows:
# assemble lat and long for starting location:
tempfuna <- function(Lat,Lon) {list(Coords = list(Lat = Lat,Lon = Lon))}
df_jsona <- mapply(FUN = tempfuna,Lat = r4$Shipper_Latitude, Lon = r4$Shipper_Longitude)
df_jsona <- lapply(df_jsona, function(x) {list(Coords = x)})
# assemble lat and long for ending location:
tempfunb <- function(Lat,Lon) {list(Coords = list(Lat = Lat,Lon = Lon))}
df_jsonb <- mapply(FUN = tempfunb,Lat = r4$r_combine.NewShipperLat, Lon = r4$r_combine.NewShipperLon)
df_jsonb <- lapply(df_jsonb, function(x) {list(Coords = x)})
# assemble list of ReportRoutes:
tempfunc <- function(A,B) {list(ReportRoutes = list(Stops = list(A,B)))}
df_jsonc <- mapply(FUN = tempfunc,A = df_jsona, B = df_jsonb)
# create final list:
post_body <- list(ReportRoutes = df_jsonc)
I get an error when I use the resulting file in an API call.
I think the problem is that the list items in the ReportRoutes list are incorrectly named. For example, the first item is named “Coords.ReportRoutes” instead of [[1]]].
How can I rework the above to produce the required JSON file?

How to extract NetCDF data frame by region using a polygon shapefile

I'am trying to extract the variable "swh_ku" from multiple NetCDF files together with their corresponding latitude and longitude values into csv files using a polygon shapefile or it's extent. I'm working with Jason-1 global altimetry swath data but I only need the data for the domain represented by the shapefile. I just need help with some lines of code that would complete the working code bellow so I can extract only the data for the region I'm interested in.
I've tried several software applications such as QGIS, ESA SNAP, Broadview Radar Altimetry Toolbox (BRAT) with no success unfortunately because I couldn't find a way automate the extraction process for the hundreds of NetCDF files. So I resorted to code with which I'm fairly new but managed to get it working after reading other posts. I've tried opening the files as raster or brick to use the #extract or #mask functions because they seem more straightforward but I couldn't manage to work them out.
Link to data: https://drive.google.com/drive/folders/1d_XVYFe__-ynxbJNUwlyl74SPJi8GybR?usp=sharing
library(ncdf4)
library(rgdal)
library(raster)
my_read_function <- function(ncname) {
setwd("D:/Jason-1/cycle_030")
bs_shp=readOGR("D:/Black_Sea.shp")
e<-extent(bs_shp)
ncfname = ncname
names(ncin[['var']])
dname = "swh_ku"
ncin = nc_open(ncfname)
print(ncin)
vars<-(names(ncin[['var']]))
vars
lon <- ncvar_get(ncin, "lon")
nlon <- dim(lon)
head(lon)
lat <- ncvar_get(ncin, "lat", verbose = F)
nlat <- dim(lat)
head(lat)
print(c(nlon, nlat))
sm_array <- ncvar_get(ncin,dname)
dlname <- ncatt_get(ncin,dname,"long_name")
dunits <- ncatt_get(ncin,dname,"units")
fillvalue <- ncatt_get(ncin,dname,"_FillValue")
dim(sm_array)
ls()
sm.slice <- sm_array[]
sm.vec <- as.vector(sm.slice)
length(sm.vec)
lonlat <- expand.grid(lon, lat)
sm.df01 <- data.frame(cbind(lonlat, sm.vec))
names(sm.df01) <- c("lon", "lat", paste(dname, sep = "_"))
head(na.omit(sm.df01), 20)
csvfile <- paste0(ncname,".csv")
write.table(na.omit(sm.df01), csvfile, row.names = FALSE, sep = ",")
}
my_files <- list.files("D:/Jason-1/cycle_030/")
lapply(my_files, my_read_function)
Looks like your data is not gridded.
library(ncdf4)
library(raster)
bs <- shapefile("Black_Sea.shp")
# simplify so that the data will look better later
bs <- as(bs, "SpatialPolygons")
f <- list.files("cycle_022", pattern="nc$", full=TRUE)
Loop would start here
ncfname = f[1]
dname = "swh_ku"
ncin = nc_open(ncfname)
lon <- ncvar_get(ncin, "lon")
lat <- ncvar_get(ncin, "lat", verbose = F)
sm_array <- ncvar_get(ncin, dname)
xyz <- na.omit(cbind(lon, lat, sm_array))
p <- SpatialPoints(xyz[,1:2], proj4string=crs(bs))
p <- SpatialPointsDataFrame(p, data.frame(xyz))
x <- intersect(p, bs)
x has the points that intersect with the Black Sea
plot(bs)
points(x)
head(x#data)

R-Geocoding with Address

I have 32K lines of addresses for which I have to find long/latitude values.
I'm using the code found here. I'm so very thankful for this person to creating it but I have a question:
I'd like to edit it so that if the loop runs into an issue with the current row's address, it simply states NA in the Lat/Long fields and moves to the next one. Does anyone know how that may be accomplished? The code is below:
# Geocoding a csv column of "addresses" in R
#load ggmap
library(ggmap)
# Select the file from the file chooser
fileToLoad <- file.choose(new = TRUE)
# Read in the CSV data and store it in a variable
origAddress <- read.csv(fileToLoad, stringsAsFactors = FALSE)
# Initialize the data frame
geocoded <- data.frame(stringsAsFactors = FALSE)
# Loop through the addresses to get the latitude and longitude of each address and add it to the
# origAddress data frame in new columns lat and lon
for(i in 1:nrow(origAddress))
{
# Print("Working...")
result <- geocode(origAddress$addresses[i], output = "latlona", source = "google")
origAddress$lon[i] <- as.numeric(result[1])
origAddress$lat[i] <- as.numeric(result[2])
origAddress$geoAddress[i] <- as.character(result[3])
}
# Write a CSV file containing origAddress to the working directory
write.csv(origAddress, "geocoded.csv", row.names=FALSE)
You can use tryCatch() to isolate the geocode warning and return a data.frame with the same structure (lon, lat, address) as geocode() would return.
Your code would then be
# Geocoding a csv column of "addresses" in R
# load ggmap
library(ggmap)
# Select the file from the file chooser
fileToLoad <- file.choose(new = TRUE)
# Read in the CSV data and store it in a variable
origAddress <- read.csv(fileToLoad, stringsAsFactors = FALSE)
# Loop through the addresses to get the latitude and longitude of each address and add it to the
# origAddress data frame in new columns lat and lon
for(i in 1:nrow(origAddress)) {
result <- tryCatch(geocode(origAddress$addresses[i], output = "latlona", source = "google"),
warning = function(w) data.frame(lon = NA, lat = NA, address = NA))
origAddress$lon[i] <- as.numeric(result[1])
origAddress$lat[i] <- as.numeric(result[2])
origAddress$geoAddress[i] <- as.character(result[3])
}
# Write a CSV file containing origAddress to the working directory
write.csv(origAddress, "geocoded.csv", row.names=FALSE)
Alternatively, you can do this faster and more cleanly without the loop and error checking. However, without a reproducible example of your data there is no way to know if this will retain all of the information you need.
# Substituted for for loop
result <- geocode(origAddress$addresses, output = "latlona", source = "google")
origAddress <- cbind(origAddress$addresses, result)

How to insert values into variable?

I need to take a basename from a file path and insert it into a variable so I can access a column in a dataframe. I have created some sample data to illustrate what I am trying to accomplish.
Create some sample data:
library(raster)
## Create a matrix with random data & use image()
xy = matrix(rnorm(400),20,20)
image(xy)
# Turn the matrix into a raster
rast = raster(xy)
# Give it lat/lon coords for 36-37°E, 3-2°S
extent(rast) = c(36,37,-3,-2)
# ... and assign a projection
projection(rast) = CRS("+proj=longlat +datum=WGS84")
plot(rast)
# Write to disk:
writeRaster(rast, "C:/temp/12345.tif", format = "tif")
Create a path to raster
path = 'C:/temp/12345.asc
Create a raster object:
r = raster(file)
Sample random locations in raster and report values in a dataframe
df = data.frame(sampleRandom(r, size=1000, cells=TRUE, sp=TRUE))
Now I need to automate the insertion of the basename into a variable so that it looks like:
test = df$X12345
This is my unsuccessful attempt at inserting the basename into the test variable:
require(tools)
name = basename(file_path_sans_ext(path))
test2 = paste('df$', 'X', name, sep = '')
>test2
[1] "df$X12345"
This method seems to create a the correct character "df$X12345", although I cannot access the dataframe by calling test2. How can I construct a series of characters into a functioning variable so that I can access the particular dataframe column?
Maybe you are looking for parse and eval:
df <- data.frame(a = 1, b = 2)
test2 <- "df$b"
eval(parse(text = test2))
# [1] 2
test = df[,paste0('X', name)]
Is this what you're looking for?

Resources