I am used to reading in shapefiles in Python with the following simple code:
import geopandas
url='https://opendata.arcgis.com/datasets/01fd6b2d7600446d8af768005992f76a_3.geojson'
gdf = geopandas.read_file(url)
I am trying to do it in R so that people do not have to download the shapefiles, but I am struggling.
I have tried this, but getting 'cannot open data source' error:
sp <- readOGR(dsn="https://opendata.arcgis.com/datasets/01fd6b2d7600446d8af768005992f76a_3.geojson", layer="OGRGeoJSON")
If I download the shapefile, my code looks like this:
#load shape file
shape_file_name<- "D:/Users/XXX/Documents/R/NUTS_Level_2_January_2018_Generalised_Clipped_Boundaries_in_the_United_Kingdom.shp"
#import the shape file
shape_file <- readOGR(shape_file_name, stringsAsFactors = F)
#fortify shapefile
shp <- fortify(shape_file)
#creates the NUTS map
NUTS_map <- ggplot() +
geom_polygon(data = shp,
aes(x = long, y = lat, group = group),
color = 'lightsteelblue', fill = 'lightcyan', size = .9) +coord_fixed(1.7)+ theme_void()
I just want to replace the following lines:
shape_file_name<- "D:/Users/XXX/Documents/R/NUTS_Level_2_January_2018_Generalised_Clipped_Boundaries_in_the_United_Kingdom.shp"
shape_file <- readOGR(shape_file_name, stringsAsFactors = F)
With a call to the API found at the following webpage:
https://geoportal.statistics.gov.uk/datasets/nuts-level-2-january-2018-names-and-codes-in-the-united-kingdom
Many thanks
st_read from the sf-package works fine for me.
#load library
library(sf)
#load geojson from url
data <- st_read('https://opendata.arcgis.com/datasets/01fd6b2d7600446d8af768005992f76a_3.geojson')
#quick view to see what we're dealing with
mapview::mapview(data)
Related
I am using similar to code to other scripts with different shape files from Statistics Canada. However, I can't get a simple script to work with a provincial map. I think the problem is simple but I can't see it.
setwd("D:\\OneDrive\\lfs_stuff")
project_folder<-getwd()
data_folder<-project_folder
library(tidyverse)
#now start the map
library(rgeos)
library(rgdal)
library(maptools)
library(sp)
library(mapproj)
library(ggplot2)
#get test data
mydata<-read_csv("map_data.csv",col_types=list(col_character(),col_double()))
print(mydata)
# shape file came from this link for a digital shape file
# http://www12.statcan.gc.ca/census-recensement/2011/geo/bound-limit/files-fichiers/2016/lpr_000a16a_e.zip
target_url<-"http://www12.statcan.gc.ca/census-recensement/2011/geo/bound-limit/files-fichiers/2016/lpr_000a16a_e.zip"
url_file<-"lpr_000a16a_e.zip"
download_target<-paste0(project_folder,"/",url_file)
download.file(target_url,download_target,mode="wb",quiet=FALSE)
unzip(download_target,overwrite=TRUE,exdir=data_folder)
provincial_shape_file<-gsub(".zip",".shp",download_target)
provincial_shp<-readOGR(dsn=provincial_shape_file,layer="lpr_000a16a_e")
#convert it to the reqired data structure. the id vbl will contain the provincial codes
prov_base_map<-fortify(provincial_shp,region="PRUID")
map_data_1<-merge(prov_base_map,as_data_frame(mydata),by="id")
map1<-ggplot()+
geom_map(data=map_data_1,map=map_data_1,stat="identity",
aes(map_id=id,x=long,y=lat,fill=(pch),group=group),
colour="black",size=0.3)+
coord_map()
print(map1)
The download for the shape file is in the script. The mydata file is shown below
"id","pch"
"10",0.667259786476859
"11",5.63186813186813
"12",2.12053571428572
"13",-0.563697857948142
"24",0.150669774230772
"35",1.15309092428315
"46",0.479282622139765
"47",1.70242950877815
"48",1.84482533036765
"59",1.96197656978394
Here's one way with sf (though I think the ultimate issue is not having the id being identified correctly):
library(sf)
library(httr)
library(tidyverse)
read.csv(text='"id","pch"
"10",0.667259786476859
"11",5.63186813186813
"12",2.12053571428572
"13",-0.563697857948142
"24",0.150669774230772
"35",1.15309092428315
"46",0.479282622139765
"47",1.70242950877815
"48",1.84482533036765
"59",1.96197656978394',
stringsAsFactors=FALSE,
colClasses = c("character", "double")) -> xdf
# cross-platform-friendly d/l with caching built-in
try(httr::GET(
url = "http://www12.statcan.gc.ca/census-recensement/2011/geo/bound-limit/files-fichiers/2016/lpr_000a16a_e.zip",
httr::write_disk("~/Data/lpr_00a16a_e.zip"),
httr::progress()
)) -> res
fils <- unzip("~/Data/lpr_00a16a_e.zip", exdir = "~/Data/lpr")
ca_map <- st_read(grep("shp$", fils, value=TRUE), stringsAsFactors = FALSE)
ca_map <- st_simplify(ca_map, TRUE, 10) # you don't need the coastlines to be that detailed
ca_map <- left_join(ca_map, xdf, by=c("PRUID"="id"))
ggplot(ca_map) +
geom_sf(aes(fill = pch)) +
viridis::scale_fill_viridis(direction=-1, option="magma") +
coord_sf()
As an aside, even though I simplified the shapefile (for faster plotting) I'd hunt around for a light[er]-weight GeoJSON version of the provinces since the one you grabbed has super fine-grained coastlines and you absolutely don't need that for a choropleth.
I am having trouble merging shapefiles in R. Here is my code thus far:
library(rgdal)
library(maptools)
library(gridExtra)
setwd("/Users/Cornelius/Dropbox/Cornelius_Sharedfolder")
#Load a geodatabase
fgdb = "/Users/Cornelius/Dropbox/Cornelius_Sharedfolder/RwandaGDB.gdb"
subset(ogrDrivers(), grepl("GDB", name))
fc_list = ogrListLayers(fgdb)
print(fc_list)
#Get the shapefiles from the geodatabase:
Residence=readOGR(dsn=fgdb, layer="RĂ©sidence")
Territoire = readOGR(dsn=fgdb,layer="Territoire")
Chefferie=readOGR(ds=fgdb, layer="Chefferie")
Sous_Chefferie=readOGR(ds=fgdb, layer="Sous_Chefferie")
RwandaPre2002=readOGR(ds=fgdb, layer="RwandaPre2002")
Country_Boundary2012=readOGR(ds=fgdb, layer="Country_Boundary2012")
Province_Boundary2012=readOGR(ds=fgdb, layer="Province_Boundary2012")
Sector_Boundary2012=readOGR(ds=fgdb, layer="Sector_Boundary2012")
District_Boundary2012=readOGR(ds=fgdb, layer="District_Boundary2012")
Cell_Boundary2012=readOGR(ds=fgdb, layer="Cell_Boundary2012")
x = list(Residence, Territoire, Sous_Chefferie, RwandaPre2002, Country_Boundary2012, Province_Boundary2012, Sector_Boundary2012, District_Boundary2012, Cell_Boundary2012)}
This all goes fine. However, when I try to merge two shapefiles - for example, Residence and Territoire, and use the following code, it gives me an error:
test_bind <-spRbind(Territoire, Residence)
The error says: "non-unique polygon IDs."
I'm not sure what this means. Could you please help?
Is it possible to style a TopoJSON file from its features for a choropleth using R/leaflet? Tried a few things, and I'm not sure if this is impossible with the leaflet package or if I just don't have the syntax right, especially accessing the properties to enter in the pal() function. Here's what I have:
pal<-colorNumeric(palette ="YlOrRd",domain = USAdata$GINI) #USAdata data frame I merged with the spdf before converting it to shp/topojson
map<-leaflet() %>%
addTiles(options=tileOptions(minZoom = 3)) %>%
setMaxBounds(-167.276413,5.499550,-52.233040, 83.162102) %>%
setView(93.85,37.45,zoom =3) %>%
#addGeoJSON(geojson = jso5)
addTopoJSON(topojson=jso, fillColor = ~pal("GINI"))
#addPolygons(data=poly)
this throws up an error:
"Error in UseMethod("doResolveFormula") :
no applicable method for 'doResolveFormula' applied to an object of class "NULL""
I also tried converting it to an R object the topojson with fromJSON() and adding style elements, but this won't load after I try send it back with toJSON().
Not sure if relevant, but the topojson was created from a shapefile made following the instructions here:
with cl:
topojson -o 'USApuma.json' --shapefile-encoding utf8 --id-property=+GEOID10 -p GINI,+STATEFP10,+GEOID10 -- 'usaetest.shp'
then read in with readLines().
Eventually trying to throw this into a shiny app. Here's some examples I've been following.
Do you need to use TopoJSON? If not consider using the tigris package (disclosure: I created and maintain the package). It'll get you access to just about any Census geographic dataset you need, and plays nicely with leaflet. Here's a brief example in line with what you are doing. For example, you can get all PUMAs in the continental US with the following code:
library(readr)
library(tigris)
library(leaflet)
us_states <- unique(fips_codes$state)[1:51]
continental_states <- us_states[!us_states %in% c("AK", "HI")]
pumas_list <- lapply(continental_states, function(x) {
pumas(state = x, cb = TRUE)
})
us_pumas <- rbind_tigris(pumas_list)
I've generated a sample dataset that measures PUMA median household income for this example; the geo_join function from the tigris package can merge the dataset to the spatial data frame us_pumas:
puma_income <- read_csv('http://personal.tcu.edu/kylewalker/data/puma_income.csv')
joined_pumas <- geo_join(us_pumas, puma_income, 'GEOID10', 'GEOID')
We can then plot with Leaflet:
pal <- colorQuantile(palette = 'YlOrRd', domain = joined_pumas$hhincome, n = 7)
leaflet(joined_pumas) %>%
addProviderTiles('CartoDB.Positron') %>%
addPolygons(weight = 0.5, fillColor = ~pal(hhincome),
color = 'lightgrey', fillOpacity = 0.75,
smoothFactor = 0.2) %>%
addLegend(pal = pal,
values = joined_pumas$hhincome)
If you are planning to build a Shiny app, I'd recommend saving out the PUMAs you obtain from tigris first as a .rda file and reading it in with your Shiny script so you don't have to rbind_tigris every time.
I am a total newbie to R and I would like to draw a line (possibly weighted, e.g., by the number of trips made) between two countries. Currently, I use longitude and latitude for each capital to draw a line, but I would like to do it using the package ggmap. I was looking around, but did not find any solution so far. I would appreciate a quick help.
require(ggmap)
require (rworldmap)
all_content = readLines("ext_lt_intratrd_1_Data.csv")
skip_second = all_content[-2]
dat = read.csv(textConnection(skip_second), header = TRUE, stringsAsFactors =F)
dat[5,2]<- c("Germany") # using a data where the first line is
header, but second line must be skipped as it is EU 27
and not a single country
europe <- read.csv("eulonglat.csv", header = TRUE) # using world capitals to
generate points
myfulldata <- merge(dat, europe)
map <- get_map(location = 'Europe', zoom = 4)
mapPoints <- ggmap(map) + geom_point(aes(x = UNc_longitude, y = UNc_latitude, size
= log(myfulldata$Value)), data = myfulldata, col = "red", alpha= 0.5) # this can
be plotted
# i would continue with drawing line and i searched for references
# i found arrows(42.66,23.34,50.82,4.47) - which did not work
# i tried to look for a reference work more, but could not find
# instead i found it using with the package rworldmap the following
lines(c(4.47, 23.32), c(50.82, 42.66))
# this does not work on ggmap
History: Extracted raster data from the static Google map png, loaded it on the R device through ggimage.
library (png)
library (ggmap)
rasterArray <- readPNG ("My.png")
x = c (40.702147,40.718217,40.711614)
y = c (-74.012318,-74.015794,-73.998284)
myData <- data.frame (x, y)
print (ggimage (rasterArray, fullpage = TRUE, coord_equal = FALSE)
+ geom_point (aes (x = x, y = y), data = myData, colour = I("green"),
size = I(5), fill = NA))
I did run dput on the rasterArray but the output is of 20 MBs, can't post here.
BTW, this is the URL of that static map:
Question: For plotting "GPS coordinates" on the R device containing the map in pixels, do I need to scale the data.frame?
I saw this page: http://www-personal.umich.edu/~varel/rdatasets/Langren1644.html
Do I need to do scaling the way they have shown here?
If yes, then what else other than the man page of scale function do I need to understand to get this done?
Am I barking at the wrong tree?
I think your mistake was the following:
Trying to plot geographic data on an image, where that image doesn't have any awareness of the map coordinates
Possibly transposing your latitude and longitudes in the data frame
Here is how you should do it instead, in two steps:
Get the map with get_map() and save it to disk using save()
Plot the data with ggmap()
First, get the map.
library (ggmap)
# Read map from google maps and save data to file
mapImageData <- get_googlemap(
c(lon=-74.0087986666667, lat=40.7106593333333),
zoom=15
)
save(mapImageData, file="savedMap.rda")
Then, in a new session:
# Start a new session (well, clear the workspace, to be honest)
rm(list=ls())
# Load the saved file
load(file="savedMap.rda")
# Set up some data
myData <- data.frame(
lat = c (40.702147, 40.718217, 40.711614),
lon = c (-74.012318, -74.015794, -73.998284)
)
# Plot
ggmap(mapImageData) +
geom_point(aes(x=lon, y=lat), data=myData, colour="red", size=5)