Goal of lab exercise: Make multi-layer maps
yem_map_2.png
Violence and terrain in Afghanistan (we’ll make this)
Violence and ethnicity in Afghanistan (this too)
Violence and ethnicity in Yemen (you’ll make this)
You can make these plots in QGIS or in R. Instructions for both are below.
Map 1 in R
Map 2 in R
PS02 in R
We will put multiple types of data on same map:
Category | Type | Format | Data source |
---|---|---|---|
Elevation (meters) | Raster | .tif |
ETOPO |
Province borders | Vector (polygon) | .shp |
GADM |
Roads | Vector (polyline) | .shp |
DCW |
Violence (1989-2016) | Vector (point) | .csv |
xSub/UCDP |
Ethnic settlement patterns | Vector (polygon) | .shp |
GeoEPR |
These are all in the PS02.zip
file posted on Canvas.
Let’s open QGIS…
Save your progress!
Go to Project
\(\to\) Save As...
Load elevation data: Layer
\(\to\) Add Layer
\(\to\) Add Raster Layer...
Press the ...
button to select the file
Navigate to ETOPO1_downsampled.tif
file in Data/Elevation/
folder, click Open
Click Add
on next screen and go back to main window.
You should now see a global elevation raster
Load Afghanistan borders: Layer
\(\to\) Add Layer
\(\to\) Add Vector Layer...
Click ...
in dialog box to select the file.
Navigate to gadm36_AFG_1.geojson
in Data/Borders/
folder.
Click Open
, then Add
Afghanistan’s borders should appear on the map. But they are hard to see
Right click on gadm36_AFG_1
in the layer menu. Click Zoom to Layer
Now we can see Afghanistan, but the elevation layer is hidden behind it
Make polygons transparent: Right-click on gadm36_AFG_1
in layer menu, click on Properties
. Highlight Simple fill
in the symbology menu.
Select Fill style: No Brush
Click OK
The polygons should now be transparent, with provincial borders still visible.
Let’s drop the rest of the raster, keeping only the overlap with Afghanistan.
Clip raster: Raster
\(\to\) Extraction
\(\to\) Clip Raster by Extent...
Set the Input layer
as ETOPO1_downsampled
.
Click Clipping extent
\(\to\) Calculate from Layer
\(\to\) gadm36_AFG_1
Click Run
Check log to make sure there were no errors.
The output is a temporary raster dataset, clipped to extent of Afghanistan.
Rename the new layer to “Elevation”. Right click Clipped
\(\to\) Rename Layer
Change the name to Elevation
Let’s do the same for gadm36_AFG_1
Change its name to Borders
.
Also, un-check the box next to ETOPO1_downsampled
to hide the big raster
Change plot order. Drag Borders
above Elevation
in Layer menu.
Borders should now be (faintly) visible above elevation layer.
Change raster color. Right click Elevation
\(\to\) Properties
.
Click on the menu next to Render type
Select Render type
: Singleband pseudocolor
Click menu button next to Color ramp
\(\to\) Create New Color Ramp...
Select Catalog: cpt-city
as color ramp type
This will open a window with a lot of color themes.
Select Topography
\(\to\) elevation
. Click OK
Click Classify
button, then OK
The elevation layer should now appear in blue-green-brown
Add roads layer. Same Add Layer
procedure as for borders. Open AFG_roads.geojson
from Data/Roads/
folder
You should see the AFG_roads
layer on the map
Change layer’s name from AFG_roads
to Roads
Change color to blue. Right click
on Roads
\(\to\) Properties
.
Highlight Simple line
in Symbology menu
Click menu button next to Color
. Select blue from Standard colors
list
Click Apply
or OK
The roads should appear in blue
Add violence data. Layer
\(\to\) Add Layer
\(\to\) Add Delimited Text Layer...
Click ...
button next to File name
dialog
Navigate to xSub_GED_AFG_event.csv
in Data/Violence/
menu.
Click Open
Under Geometry Definition
, set X field
\(=\) LONG
and Y field
\(=\) LAT
.
Click Add
You should now see about 30,000 violent events on the map
Change layer’s name to Violence
Change layer’s color. Right click
\(\to\) Properties
. Click on dot white
(\(\circ\))
Make points smaller and translucent. Set Opacity
\(=\) 50%
and Size
\(=\) 2.0
The rendered points should look something like this.
Export the map to image. Project
\(\to\) New Print Layout
.
Place map on layout, with Add Item
\(\to\) Add Map
Add legend with Add Item
\(\to\) Add Legend
.
The legend includes an item we need to remove (ETOPO1_downsampled
)
To remove this item, highlight the legend, go to Item Properties
. Un-check the Auto update
box under Legend Items
. Highlight ETOPO1_downsampled
and click on the red “\(-\)” button to remove it
The ETOPO1_downsampled
item should now disappear from the legend.
Edit layers’ names in legend. Highlight Elevation
and click on the Edit
button (pencil and paper icon). Change text to “Elevation (m)”
Let’s also remove the band information from the legend. Highlight Band 1: ETOPO1_Bed...
, click the “–” button to remove it.
Change legend Title
to “Violence in Afghanistan” in Item Properties
The legend should now look something like this
Add scale bar. Change Scalebar units
to Miles
Export to file. Layout
menu \(\to\) Export as Image...
. Name it afg_map_1.png
The output file should look like this.
Load ethnicity data. Add (as vector layer) GeoEPR_AFG.geojson
from Data/Ethnicity/
folder
This will add a new polygon layer to the map.
Change its name from GeoEPR_AFG
to Ethnicity
Open the layer’s Properties
. Click on Single symbol
in Symbology menu
Change symbol type from Single symbol
to Categorized
Make polygon boundaries transparent. Click on menu button next to Stroke color
\(\to\) check Transparent Stroke
box
Select Value
\(=\) group
Click on Classify
button, then Apply
or OK
Each ethnic group’s polygon should appear as a different color
Create a new map layout and export it as afg_map_2.png
. You can do it
Problem Set 2
Your assignment (if using QGIS):
GeoEPR_YEM.geojson
xSub_GED_YEM_event.csv
gadm36_YEM_1.geojson
yem_map_2.png
Can you make this map?
Loading R packages
To implement these steps in R, we will be using two packages:
sf
(“simple features”, to handle spatial vector data)terra
(to handle raster data, like Elevation)library(sf)
library(terra) # NEW!
NOTE: The code to produce Map 1 and Map 2 in R is in ps02_demo.R
on RStudio Cloud, and in PS02.zip
(posted on Canvas).
Loading spatial data
Let’s load the elevation raster into R, using the rast()
command from terra
:
elevation_global = terra::rast("Data/Elevation/ETOPO1_downsampled.tif")
plot(elevation_global)
Let’s load the provincial boundaries and roads into R, using sf::read_sf()
:
borders = sf::read_sf("Data/Borders/gadm36_AFG_1.geojson")
roads = sf::read_sf("Data/Roads/AFG_roads.geojson")
plot(borders["geometry"])
plot(roads["geometry"])
Let’s load the violence data into R, using read.csv()
:
violence = read.csv("Data/Violence/xSub_GED_AFG_event.csv")
To convert this table into a spatial object, we will use the sf::st_as_sf()
command, specifying columns corresponding to geographic coordinates (LONG, LAT
), and copying the CRS from the borders
object:
violence = sf::st_as_sf(violence, coords=c("LONG","LAT"))
sf::st_crs(violence) = sf::st_crs(borders)
plot(violence["geometry"])
Clipping the raster to Afghanistan’s extent
R’s equivalent of QGIS’s Clip Raster by Extent...
command is the following:
borders
sf::st_bbox()
finds the spatial extent of a layersf::st_as_sfc()
converts the extent object into a polygonextent_afg = sf::st_as_sfc(sf::st_bbox(borders))
terra::crop()
elevation = terra::crop(elevation_global, extent_afg)
plot(elevation, col=terra::map.pal("elevation"));
plot(borders["geometry"], add=TRUE)
Plotting Map 1
To create the map, we will execute the following commands in sequence:
par()
plot()
(note different syntax for rasters vs. vectors)legend()
(specify x and y coordinates for top-left corner of legend)par(mar=c(2,2,.5,.5))
plot(elevation, col=terra::map.pal("elevation"))
plot(violence["geometry"],
plot(roads["geometry"],add=T,col="black",lwd=1.618)
plot(roads["geometry"],add=T,col="pink",lwd=.62)
plot(borders["geometry"],add=T,lwd=2)
legend(x=70.5,y=31.5,legend=c("Violence","Borders","Roads"),
pch=c(1,NA,NA),lwd=c(NA,2,1),title="Violence in Afghanistan",
bg="white",col=c("black","black","pink4"))
Here’s what the plot should look like:
Exporting Map 1 to image file
To save the map, we will use the png()
and dev.off()
commands, as in PS01:
png("Output/afg_map_1_r.png",width = 8,height = 6,
units = "in",res = 300)
par(mar=c(2,2,.5,.5))
plot(elevation, col=terra::map.pal("elevation"))
plot(violence["geometry"],
plot(roads["geometry"],add=T,col="black",lwd=1.618)
plot(roads["geometry"],add=T,col="pink",lwd=.62)
plot(borders["geometry"],add=T,lwd=2)
legend(x=70.5,y=31.5,legend=c("Violence","Borders","Roads"),
pch=c(1,NA,NA),lwd=c(NA,2,1),title="Violence in Afghanistan",
bg="white",col=c("black","black","pink4"))
dev.off()
The output file should look like this.
Loading ethnicity data
Let’s load the ethnic settlements data into R, using sf::read_sf()
:
ethnicity = sf::read_sf("Data/Ethnicity/GeoEPR_AFG.geojson")
plot(ethnicity["geometry"])
Plotting Map 2
Let’s begin by creating a vector of colors, corresponding to the group
column:
groups = as.factor(ethnicity$group)
n = length(unique(groups))
cols = hcl.colors(n,palette="Pastel 1")[groups]
plot(ethnicity["group"],col=cols,border="white")
To see what other color palettes are available in hcl.colors()
, see hcl.pals()
:
hcl.pals()
## [1] "Pastel 1" "Dark 2" "Dark 3" "Set 2"
## [5] "Set 3" "Warm" "Cold" "Harmonic"
## [9] "Dynamic" "Grays" "Light Grays" "Blues 2"
## [13] "Blues 3" "Purples 2" "Purples 3" "Reds 2"
## [17] "Reds 3" "Greens 2" "Greens 3" "Oslo"
## [21] "Purple-Blue" "Red-Purple" "Red-Blue" "Purple-Orange"
## [25] "Purple-Yellow" "Blue-Yellow" "Green-Yellow" "Red-Yellow"
## [29] "Heat" "Heat 2" "Terrain" "Terrain 2"
## [33] "Viridis" "Plasma" "Inferno" "Rocket"
## [37] "Mako" "Dark Mint" "Mint" "BluGrn"
## [41] "Teal" "TealGrn" "Emrld" "BluYl"
## [45] "ag_GrnYl" "Peach" "PinkYl" "Burg"
## [49] "BurgYl" "RedOr" "OrYel" "Purp"
## [53] "PurpOr" "Sunset" "Magenta" "SunsetDark"
## [57] "ag_Sunset" "BrwnYl" "YlOrRd" "YlOrBr"
## [61] "OrRd" "Oranges" "YlGn" "YlGnBu"
## [65] "Reds" "RdPu" "PuRd" "Purples"
## [69] "PuBuGn" "PuBu" "Greens" "BuGn"
## [73] "GnBu" "BuPu" "Blues" "Lajolla"
## [77] "Turku" "Hawaii" "Batlow" "Blue-Red"
## [81] "Blue-Red 2" "Blue-Red 3" "Red-Green" "Purple-Green"
## [85] "Purple-Brown" "Green-Brown" "Blue-Yellow 2" "Blue-Yellow 3"
## [89] "Green-Orange" "Cyan-Magenta" "Tropic" "Broc"
## [93] "Cork" "Vik" "Berlin" "Lisbon"
## [97] "Tofino" "ArmyRose" "Earth" "Fall"
## [101] "Geyser" "TealRose" "Temps" "PuOr"
## [105] "RdBu" "RdGy" "PiYG" "PRGn"
## [109] "BrBG" "RdYlBu" "RdYlGn" "Spectral"
## [113] "Zissou 1" "Cividis" "Roma"
To create the map, we will use the same commands as above, with some differences:
reset=FALSE
when plotting the ethnicity
layerlegend()
(including the vector of group colors)par(mar=c(0,0,0,0))
plot(ethnicity["group"],col=cols,border=NA,reset=FALSE,main="")
plot(borders["geometry"],add=T,lwd=2)
# Add violence (white points + black outlines)
plot(violence["geometry"],col=rgb(1,1,1,alpha = .25),pch=16,add=T)
plot(violence["geometry"],col=rgb(0,0,0,alpha = .25),pch=1,add=T)
# Add legend
legend("bottomright",bty="n",ncol=2,
legend=c("Violence","Borders",as.character(groups)),
col=c("black","black",cols),pch=c(1,0,rep(15,length(cols))),
cex=.8,title="Ethnicity and violence\n in Afghanistan"
)
Here’s what the plot should look like:
Exporting Map 2 to image file
Using the png()
and dev.off()
commands as bookends:
png("Output/afg_map_2_r.png",width = 8,height = 6,
units = "in",res = 300)
par(mar=c(0,0,0,0))
plot(ethnicity["group"],col=cols,border=NA,reset=FALSE,main="")
plot(borders["geometry"],add=T,lwd=2)
# Add violence (white points + black outlines)
plot(violence["geometry"],col=rgb(1,1,1,alpha = .25),pch=16,add=T)
plot(violence["geometry"],col=rgb(0,0,0,alpha = .25),pch=1,add=T)
# Add legend
legend("bottomright",bty="n",ncol=2,
legend=c("Violence","Borders",as.character(groups)),
col=c("black","black",cols),pch=c(1,0,rep(15,length(cols))),
cex=.8,title="Ethnicity and violence\n in Afghanistan")
dev.off()
The output file should look like this.
Problem Set 2
Your assignment (if using R):
GeoEPR_YEM.geojson
xSub_GED_YEM_event.csv
gadm36_YEM_1.geojson
yem_map_2_r.png
Can you make this map?