I would like to make a map in R that colours in the FAO Fishing Areas according to a data set (in my case, length data of shark species).
I would prefer to do a choropleth map in ggplot but other types of maps are also fine. Worst case scenario a base map of FAO areas that I can add bubbles to. Even just an existing base map of FAO areas would be great. Any suggestions welcome!
I went to this page and clicked through to find this link to retrieve a GeoJSON file:
download.file("http://www.fao.org/fishery/geoserver/fifao/ows?service=WFS&request=GetFeature&version=1.0.0&typeName=fifao:FAO_AREAS_CWP&outputFormat=json", dest="FAO.json")
From here on, I was following this example from the R graph gallery, with a little help from this SO question and these notes:
library(geojsonio)
library(sp)
library(broom)
library(ggplot2)
library(dplyr) ## for joining values to map
spdf <- geojson_read("FAO.json", what = "sp")
At this point, plot(spdf) will bring up a plain (base-R) plot of the regions.
spdf_fortified <- tidy(spdf)
## make up some data to go with ...
fake_fish <- data.frame(id = as.character(1:324), value = rnorm(324))
spdf2 <- spdf_fortified %>% left_join(fake_fish, by = "id")
ggplot() +
geom_polygon(data = spdf2, aes( x = long, y = lat, group = group,
fill = value), color="grey") +
scale_fill_viridis_c() +
theme_void() +
theme(plot.background = element_rect(fill = 'lightgray', colour = NA)) +
coord_map() +
coord_sf(crs = "+proj=cea +lon_0=0 +lat_ts=45") ## Gall projection
ggsave("FAO.png")
notes
some of the steps are slow, it might be worth looking up how to coarsen/lower resolution of a spatial polygons object (if you just want to show the picture, the level of resolution might be overkill)
to be honest the default sequential colour scheme might be better but all the cool kids seem to like "viridis" these days so ...
There are probably better ways to do a lot of these pieces (e.g. set map projection, fill in background colour for land masses, ... ?)
Related
despite having some experience with R, I am much less experienced using R for GIS-like tasks.
I have a shapefile of all communities within Germany and created a new object that only shows the borders of the 16 states of Germany.
gem <- readOGR(path/to/shapefile.shp) # reading shapefile
gemsf <- st_read(path/to/shapefile.shp) # reading shapefile as sf object
f00 <- gUnaryUnion(gem, id = gem#data$SN_L) # SN_L is the column of the various states - this line creates a new sp object with only the states instead of all communities
f002 <- sf::st_as_sf(f00, coords = c("x","y")) # turning the object into an sf object, so graphing with ggplot is easier
To check my work so far I plotted the base data (communities) using
gemsf %>%
ggplot(data = .,) + geom_sf( aes(fill = SN_L)) # fill by state
as well as plot(f002) which creates a plot of the 16 states, while the ggplot-code provides a nice map of Germany by community, with each state filled in a different color.
Now I'd like to overlay this with a second layer that indicates the borders of the states (so if you e.g. plot population density you can still distinguish states easily).
My attempt to do so, I used "standard procedure" and added another layer
ggplot() +
geom_sf(data = gemsf, aes(fill = SN_L)) + # fill by state
geom_sf(data = f002) # since the f002 data frame/sf object ONLY has a geometry column, there is no aes()
results in the following output: https://i.ibb.co/qk9zWRY/ggplot-map-layer.png
So how do I get to add a second layer that only provides the borders and does not cover the actual layer of interest below? In QGIS or ArcGIS, this is common procedure and not a problem, and I'd like to be able to recreate this in R, too.
Thank you very much for your help!
I found a solution which I want to share with everyone.
ggplot() +
geom_sf(data = gemsf_data, aes(fill = log(je_km2))) + # fill by state
geom_sf(data = f002, alpha = 0, color = "black") + # since the f002 data frame/sf object ONLY has a geometry column, there is no aes()
theme_minimal()
The trick was adding "alpha" not in the aes() part, but rather just as shown above.
I want to create a zipcode map for Dallas.
I have this shapefile which should include all postal codes within it (Street files)
I've been using this as a resource
below is an example of what I would like to create, and color the zipcode map in as well for certain regions I'm discussing at the time
The data isn't ideal for making something exactly like what you've linked to, but you can still get close.
After unzipping the downloaded data:
library(tidyverse)
library(sf)
dallas_streets <- sf_read('unzipped_folder/')
ggplot(sample_frac(dallas_streets, .05)) + #large file, 5% used for example
geom_sf(aes(color = POSTAL_R)) +
theme(legend.position = 'none')
Should get you here:
Color palette needs to be adjusted, labels could be added, and geometries joined (or unioned) to get closer.
If you're really looking for a zip code map of Dallas, you should try to find a shapefile meant for that purpose.
A little closer:
dallas_streets %>%
sample_frac(.3) %>%
group_by(POSTAL_L) %>%
summarize(geometry = st_convex_hull(st_union(geometry))) %>%
ggplot() +
geom_sf(aes(fill = as.numeric(POSTAL_L))) +
geom_sf_text(aes(label = POSTAL_L)) +
scale_fill_viridis_c(option = "C")
group_by, then summarize for a new geometry based on unioned convex hulls gets close to the actual zip code boundaries with only 30% of the data.
I'm trying to apply a shapefile to a ggmaps map, but it's giving me really weird results. The shapefile in question is the "Statistical Local Area" (groups similar to postcode) shapefile from the Australian Bureau of Statistics available here.
Normally I might think that it's a problem of cut off edge points, but I'm hitting it even at zoom level 1 (in fact it looks even worse):
Here's some code I used to produce the charts above:
library(tidyverse)
library(ggmap)
library(rgdal)
slas <- readOGR(dsn="SLA",layer="SLA11aAust")
aus4 <- get_map("Australia",zoom=4)
ggmap(aus4)
ggmap(aus4)+
geom_polygon(data=slas, aes(x=long,y=lat))
aus1 <- get_map("Australia",zoom=1)
ggmap(aus1)
ggmap(aus1)+
geom_polygon(data=slas, aes(x=long,y=lat))
Am I doing something wrong, or is the shapefile incorrectly configured somehow?
I think you just need to (optionally) fortify the variable slas, don't forget to group and make the boundaries visible with a color:
slas <- fortify(slas, region = "SLA_CODE11")
ggmap(aus4) +
geom_polygon(data = slas2, color = "white", aes(x = long, y = lat, group = group))
I have a data set of ~25,000 people that have complete postal codes. I'm trying to create a map of Canada at the FSA level but always seem to get bizarre results. I would appreciate if someone could point out where my mistakes are happening or what I'm missing.
library(rgeos)
library(maptools)
library(ggplot2)
fsas = readShapeSpatial('./Resources/FSA/gfsa000a11a_e.shp')
data = fortify(fsas, region = 'CFSAUID')
data$fsa = factor(data$id)
data$id = NULL
df$fsa = substr(df$Postal, 1, 3)
prvdr_cts = data.frame(table(df$fsa)) ; names(prvdr_cts) = c('fsa', 'ct')
plot.data = merge(data, prvdr_cts, by = 'fsa')
ggplot(plot.data, aes(x = long, y = lat, group = group, fill = ct)) +
geom_polygon() +
coord_equal()
This is my resulting plot
I got my map file from http://www12.statcan.gc.ca/census-recensement/2011/geo/bound-limit/bound-limit-2011-eng.cfm under 'Forward sortation areas'. df has two columns Person ID and FSA.
I've seen similar problems before when I forgot group = group (as #r.bot points out), but as you have that I wonder if it's because the shapefile you're using is highly detailed.
I suggest trying the sf package to load shapefiles which has superseded using readShapePoly. This has the advantages of being faster and you don't need to fortify(). I've also simplified the shapefile somewhat to make plotting faster. Finally, you need to development version of ggplot2 to use the new geom_sf() (ATOW):
install.packages(c("rmapshaper", "sf", "devtools"))
devtools::install_github("tidyverse/ggplot2")
library("ggplot2")
fsas = sf::read_sf("gfsa000a11a_e.shp")
fsas = rmapshaper::ms_simplify(fsas, keep = 0.05)
ggplot(fsas) + geom_sf()
perhaps you have an idea and could help me. I have following data:
lon.x <- c(11.581981, 13.404954, 9.993682, 7.842104 , 11.741185)
lat.x <- c(48.135125, 52.520007, 53.551085, 47.999008, 48.402880)
lon.y <- c(8.801694, 7.842104 , 11.581981, 13.404954, 7.842104 )
lat.y <- c(53.079296,47.999008, 48.135125, 52.520007, 47.999008)
pred <- c(1,2,3,4,5)
data <- data.frame(cbind(lon.x, lat.x, lon.y, lat.y, pred))
where "lon.x" and "lat.x" are longitude-latitude points of a city and "lon.y" and "lat.y" of another city. So there are pairs of cities.
Now, I would like to make a map in R, with
(1) the direct distances between the x and y coordinates as a line
(2) which will receive a different color based on the variable "pred", this could be red for higher values and blue for lower, or thicker lines with higher values of "pred".
The result should be a simple map, with lines between the cities, that are shaped based on the variable "pred". For instance, the line between the first pair of cities would be thinner, while the last one would be thicker. Is that possible?
I have currently only made to receive a (very complicated) google map of Germany:
library(mapproj)
map <- get_map(location = 'Germany', zoom = 6.2)
ggmap(map)
But I am not sure how to plot points and especially relations between the points that differ based on "pred". Also a very simple map (not so detailed google map) would be best! Any idea? THANKS!
You can use ggplot2 to add lines onto the plot.
library(ggplot2)
library(ggmap)
map <- get_map(location = 'Germany', zoom = 6)
ggmap(map) +
geom_segment(data=data, aes(x=lon.x, xend=lon.y, y=lat.x, yend=lat.y, color=pred), size=2) +
scale_color_continuous(high="red", low="blue")
As for the simpler map, you can download shape files (just the outlines of countries) from www.gadm.org. Level 0 maps are just the country, level 1 have state boundaries, etc. To use one of these, download the file from the website and use this code:
load("DEU_adm0.RData")
gadm <- fortify(gadm)
ggplot(gadm) +
geom_path(aes(x=long, y=lat, group=group)) +
geom_segment(data=data, aes(x=lon.x, xend=lon.y, y=lat.x, yend=lat.y, color=pred), size=2) +
scale_color_continuous(high="red", low="blue")