The goal is combining the land-use GIS and the metropolitan areas around Chicago in order to compare land use in various towns. This will require manipulating two kinds of GIS in ways we reviewed 18-25 Oct. The large land-use raster should be cropped down, then it must be combined Chicago GIS, requiring identical coordinate systems (the projection).
The raster GIS lcoi_99-00b.tif gives land-use categories across all Illinois. Categories are defined at here. In a raster class, the slot crs shows the projection. You must remember that slots are accessed with the @:
library(raster) LandUse=raster('lcoi_99-00b.tif')
Cropping is most easily down using the raster function drawExtent, then clicking on the map to surround Chicago. Saving the output produces an Extent object with four corners.
plot(LandUse) ## Graph omitted ChiBox=drawExtent()
ChiBox
class : Extent xmin : 380547.6 xmax : 461105.5 ymin : 4588527 ymax : 4706936
ChiLandUse=crop(LandUse,ChiBox)
plot(ChiLandUse) ## Graph omitted
The raster package includes convenient tools for getting at the data. The following steps can be used to convert any raster into a dataframe with columns for coordinates and the land use score.
landcat=getValues(ChiLandUse) ChiLandUseCoord=xyFromCell(ChiLandUse,cell=1:length(landcat)) ChiLandUseDF=data.frame(ChiLandUseCoord,landcat) head(ChiLandUseDF)
x y landcat 1 380557.2 4706932 14 2 380587.2 4706932 14 3 380617.2 4706932 14 4 380647.2 4706932 11 5 380677.2 4706932 12 6 380707.2 4706932 11
Now the municipalities GIS must be aligned into the same projection. I downloaded Chicago GISes from the Chicago Data Portal, and have prj files. What I just learned is that readShapePoly does not capture the prj, while readOGR from the rgdal library does, saving it in the proj4string slot. It has the same information as raster's slot crs. So it is a big advantage getting rgdal working and using readOGR. To learn more about projections, you could look at the Spatial Reference web page or notes from NCEAS (where I first studied this).
library(maptools) library(rgdal) Cities=readShapePoly('Municipalities') CitiesOGR=readOGR('','Municipalities') ## Notice that readOGR takes first a folder then a file as the arguments to read a set of GIS files
Once the projections are known and stored for two different GISes, the transformation works easily. To switch a Spatial Class, such as Shape Polygons (created by readShapePoly and by readOGR, the function is spTransform. Here, CitiesOGR has its projection properly named (slot proj4string), and ChiLandUse has one too (slot crs):
ChiLandUse@crs
CRS arguments: +proj=utm +zone=16 +datum=NAD83 +units=m +no_defs +ellps=GRS80 +towgs84=0,0,0
Cities@proj4string
CRS arguments: NA
CitiesOGR@proj4string
CRS arguments: +proj=tmerc +lat_0=36.66666666666666 +lon_0=-88.33333333333333 +k=0.9999749999999999 +x_0=300000 +y_0=0 +datum=NAD83 +units=us-ft +no_defs +ellps=GRS80 +towgs84=0,0,0
CitiesUTM=spTransform(CitiesOGR,ChiLandUse@crs)
Now you can test by plotting to show the two GISes overlay correctly.
plot(ChiLandUse) plot(CitiesUTM,add=TRUE) ## Graph omitted
To count land use categories in one municipality, it is quickest (and most accurate) to take advantage of features built-in to the Spatial Classes. Emma discovered this last week... This requires converting the raster object to a Spatial Points Class, which starts with the data frame and coordinates created from the raster. It takes just one step, using the maptools function SpatialPointsDataFrame, passing it the table of coordinates, the table of data (having the land use column), and the projection. Once it is converted to this Spatial Class (check its class), it is then just one step to extract all the points within any Spatial Polygons class. You can confirm this by plotting maps. The step of extracting land use points wihin a town is rather slow. I will leave until later procedures that might speed this up.
landusePt=SpatialPointsDataFrame(coords=ChiLandUseCoord,data=ChiLandUseDF,proj4string=ChiLandUse@crs) class(landusePt)
[1] "SpatialPointsDataFrame" attr(,"package") [1] "sp"
lislepoly=subset(CitiesUTM,NAME=='Lisle') landuseLisle=landusePt[lislepoly,] ## This is a very convenient tool: find all points in the landuse Points class that are inside all polygons of one city landcatsLisle=landuseLisle@data$landcat table(landcatsLisle)
landcatsLisle 11 12 14 21 25 31 32 35 41 42 44 51 42 4 2 1771 457 2200 8932 4922 150 38 17 255
sp::plot(lisle) points(y~x,data=landusePt@coords,pch='.',col='red') points(y~x,data=landuseLisle@coords,pch='.',col='blue')