class: center, middle, inverse, title-slide .title[ # Introduction to Geospatial Techniques for Social Scientists in R ] .subtitle[ ## Raster Data ] .author[ ### Stefan Jünger & Anne-Kathrin Stroppe ] .institute[ ###
GESIS Workshop
] .date[ ### April 23, 2024 ] --- layout: true --- ## Now <table class="table" style="color: black; margin-left: auto; margin-right: auto;"> <thead> <tr> <th style="text-align:left;"> Day </th> <th style="text-align:left;"> Time </th> <th style="text-align:left;"> Title </th> </tr> </thead> <tbody> <tr> <td style="text-align:left;color: gray !important;"> April 23 </td> <td style="text-align:left;color: gray !important;"> 10:00-11:30 </td> <td style="text-align:left;font-weight: bold;"> Introduction to GIS </td> </tr> <tr> <td style="text-align:left;color: gray !important;"> April 23 </td> <td style="text-align:left;color: gray !important;"> 11:45-13:00 </td> <td style="text-align:left;font-weight: bold;"> Vector Data </td> </tr> <tr> <td style="text-align:left;color: gray !important;color: gray !important;"> April 23 </td> <td style="text-align:left;color: gray !important;color: gray !important;"> 13:00-14:00 </td> <td style="text-align:left;font-weight: bold;color: gray !important;"> Lunch Break </td> </tr> <tr> <td style="text-align:left;color: gray !important;"> April 23 </td> <td style="text-align:left;color: gray !important;"> 14:00-15:30 </td> <td style="text-align:left;font-weight: bold;"> Mapping </td> </tr> <tr> <td style="text-align:left;color: gray !important;border-bottom: 1px solidbackground-color: yellow !important;"> April 23 </td> <td style="text-align:left;color: gray !important;border-bottom: 1px solidbackground-color: yellow !important;"> 15:45-17:00 </td> <td style="text-align:left;font-weight: bold;border-bottom: 1px solidbackground-color: yellow !important;"> Raster Data </td> </tr> <tr> <td style="text-align:left;color: gray !important;"> April 24 </td> <td style="text-align:left;color: gray !important;"> 09:00-10:30 </td> <td style="text-align:left;font-weight: bold;"> Advanced Data Import & Processing </td> </tr> <tr> <td style="text-align:left;color: gray !important;"> April 24 </td> <td style="text-align:left;color: gray !important;"> 10:45-12:00 </td> <td style="text-align:left;font-weight: bold;"> Applied Data Wrangling & Linking </td> </tr> <tr> <td style="text-align:left;color: gray !important;color: gray !important;"> April 24 </td> <td style="text-align:left;color: gray !important;color: gray !important;"> 12:00-13:00 </td> <td style="text-align:left;font-weight: bold;color: gray !important;"> Lunch Break </td> </tr> <tr> <td style="text-align:left;color: gray !important;"> April 24 </td> <td style="text-align:left;color: gray !important;"> 13:00-14:30 </td> <td style="text-align:left;font-weight: bold;"> Investigating Spatial Autocorrelation </td> </tr> <tr> <td style="text-align:left;color: gray !important;"> April 24 </td> <td style="text-align:left;color: gray !important;"> 14:45-16:00 </td> <td style="text-align:left;font-weight: bold;"> Spatial Econometrics & Outlook </td> </tr> </tbody> </table> --- ## General Difference to Vector Data Data Structure: - Other data format(s), different file extensions - geometries do not differ within one dataset Implications: - Other geospatial operations possible Benefits: - can be way more efficient - straightforward processing of raster values and extraction of zonal statistics - it's like working with simple tabular data --- ## Visual Difference Between Vector and Raster Data <img src="data:image/png;base64,#../img/fig_geometries.png" width="40%" style="display: block; margin: auto;" /> --- ## What Exactly Are Raster Data? - Hold information on (most of the time) evenly shaped grid cells - Basically, a simple data table - each cell represents one observation <img src="data:image/png;base64,#../img/table_to_raster.png" width="5333" style="display: block; margin: auto;" /> --- ## Metadata - Information about geometries is globally stored - they are the same for all observations - their location in space is defined by their cell location in the data table - Without this information, raster data were simple image files --- ## Important Metadata - Raster Dimensions - number of columns, rows, and cells - Extent - Similar to bounding box in vector data - Resolution - the size of each raster cell - Coordinate reference system - defines where on the earth's surface the raster layer lies --- ## All Beginnings Are... Easy! ```r terra::rast() ``` ``` ## class : SpatRaster ## dimensions : 180, 360, 1 (nrow, ncol, nlyr) ## resolution : 1, 1 (x, y) ## extent : -180, 180, -90, 90 (xmin, xmax, ymin, ymax) ## coord. ref. : lon/lat WGS 84 ``` --- ## Feed With Data ```r input_data <- sample(1:100, 16) |> matrix(nrow = 4) raster_layer <- terra::rast(input_data) raster_layer ``` ``` ## class : SpatRaster ## dimensions : 4, 4, 1 (nrow, ncol, nlyr) ## resolution : 1, 1 (x, y) ## extent : 0, 4, 0, 4 (xmin, xmax, ymin, ymax) ## coord. ref. : ## source(s) : memory ## name : lyr.1 ## min value : 10 ## max value : 98 ``` --- ## Plotting ```r terra::plot(raster_layer) ``` <img src="data:image/png;base64,#1_4_Raster_Data_files/figure-html/plot-raster-1.png" width="60%" style="display: block; margin: auto;" /> --- ## File Formats/Extensions - Gtiff/GeoTiff - JPEG2000 - ... - .grd - netCDF - ... - sometimes, raster data come even in a text format, such as CSV **In this course, we will only use `tiff` files as it is pretty common. Just be aware that there a different formats out there.** --- ## Implementations in `R` AFAIK `terra` is the most commonly used package for raster data in `R`. Some other developments, e.g., in the `stars` package, also implement an interface to simple features in `sf`. The `terra` package also helps to use more elaborate zonal statistics. The same holds for the `spatstat` package. --- class: middle ## Basic Raster Operations --- ## Loading Raster Tiffs (Census Data) ```r immigrants_cologne <- terra::rast("./data/immigrants_cologne.tif") inhabitants_cologne <- terra::rast("./data/inhabitants_cologne.tif") immigrants_cologne ``` ``` ## class : SpatRaster ## dimensions : 289, 264, 1 (nrow, ncol, nlyr) ## resolution : 100, 100 (x, y) ## extent : 4094850, 4121250, 3084050, 3112950 (xmin, xmax, ymin, ymax) ## coord. ref. : ETRS89-extended / LAEA Europe (with axis order normalized for visualization) ## source : immigrants_cologne.tif ## name : immigrants_cologne ## min value : 3 ## max value : 639 ``` ```r inhabitants_cologne ``` ``` ## class : SpatRaster ## dimensions : 289, 264, 1 (nrow, ncol, nlyr) ## resolution : 100, 100 (x, y) ## extent : 4094850, 4121250, 3084050, 3112950 (xmin, xmax, ymin, ymax) ## coord. ref. : ETRS89-extended / LAEA Europe (with axis order normalized for visualization) ## source : inhabitants_cologne.tif ## name : inhabitants_cologne ## min value : 3 ## max value : 956 ``` --- ## Compare Layers by Plotting .pull-left[ ```r terra::plot(immigrants_cologne) ``` <img src="data:image/png;base64,#1_4_Raster_Data_files/figure-html/plot-immigrants-1.png" style="display: block; margin: auto;" /> ] .pull-right[ ```r terra::plot(inhabitants_cologne) ``` <img src="data:image/png;base64,#1_4_Raster_Data_files/figure-html/plot-inhabitants-1.png" style="display: block; margin: auto;" /> ] --- ## Btw: We Can Also Use `tmap` .pull-left[ ```r tm_shape(immigrants_cologne) + tm_raster() ``` <img src="data:image/png;base64,#1_4_Raster_Data_files/figure-html/plot-immigrants-tmap-1.png" style="display: block; margin: auto;" /> ] .pull-right[ ```r tm_shape(inhabitants_cologne) + tm_raster() ``` <img src="data:image/png;base64,#1_4_Raster_Data_files/figure-html/plot-inhabitants-tmap-1.png" style="display: block; margin: auto;" /> ] --- ## Preparing for Analysis / Base `R` Functionalities ```r immigrants_cologne[immigrants_cologne == -9] <- NA inhabitants_cologne[inhabitants_cologne == -9] <- NA immigrants_cologne ``` ``` ## class : SpatRaster ## dimensions : 289, 264, 1 (nrow, ncol, nlyr) ## resolution : 100, 100 (x, y) ## extent : 4094850, 4121250, 3084050, 3112950 (xmin, xmax, ymin, ymax) ## coord. ref. : ETRS89-extended / LAEA Europe (with axis order normalized for visualization) ## source(s) : memory ## varname : immigrants_cologne ## name : immigrants_cologne ## min value : 3 ## max value : 639 ``` ```r inhabitants_cologne ``` ``` ## class : SpatRaster ## dimensions : 289, 264, 1 (nrow, ncol, nlyr) ## resolution : 100, 100 (x, y) ## extent : 4094850, 4121250, 3084050, 3112950 (xmin, xmax, ymin, ymax) ## coord. ref. : ETRS89-extended / LAEA Europe (with axis order normalized for visualization) ## source(s) : memory ## varname : inhabitants_cologne ## name : inhabitants_cologne ## min value : 3 ## max value : 956 ``` --- ## Simple Statistics Working with raster data is straightforward - quite speedy - yet not as comfortable as working with `sf` objects For example, to calculate the mean we would use: ```r terra::global(immigrants_cologne, fun = "mean", na.rm = TRUE) ``` ``` ## mean ## immigrants_cologne 15.1337 ``` --- ## Get All Values As a Vector We can also extract the values of a raster directly as a vector: ```r all_raster_values <- terra::values(immigrants_cologne) mean(all_raster_values, na.rm = TRUE) ``` ``` ## [1] 15.1337 ``` Nevertheless, although raster data are simple data tables, working with them is a bit different compared to, e.g., simple features. --- ## Combining Raster Layers to Calculate New Values .pull-left[ ```r immigrant_rate <- immigrants_cologne * 100 / inhabitants_cologne immigrant_rate ``` ``` ## class : SpatRaster ## dimensions : 289, 264, 1 (nrow, ncol, nlyr) ## resolution : 100, 100 (x, y) ## extent : 4094850, 4121250, 3084050, 3112950 (xmin, xmax, ymin, ymax) ## coord. ref. : ETRS89-extended / LAEA Europe (with axis order normalized for visualization) ## source(s) : memory ## varname : immigrants_cologne ## name : immigrants_cologne ## min value : 0.6637168 ## max value : 100.0000000 ``` ] -- .pull-right[ <img src="data:image/png;base64,#1_4_Raster_Data_files/figure-html/combined-raster-plot-1.png" style="display: block; margin: auto;" /> ] --- ## 'Subsetting' Raster Layers We can subset vector data by simply filtering for specific attribute values. For example, to subset Cologne's districts only by the one of Deutz, we can use the `Tidyverse` for `sf` data: .pull-left[ ```r deutz <- sf::st_read("./data/cologne.shp") |> dplyr::filter(NAME == "Deutz") ``` ``` ## Reading layer `cologne' from data source ## `C:\Users\mueller2\a_talks_presentations\gesis-workshop-geospatial-techniques-R-2024\data\cologne.shp' using driver `ESRI Shapefile' ## Simple feature collection with 86 features and 7 fields ## Geometry type: MULTIPOLYGON ## Dimension: XY ## Bounding box: xmin: 4094821 ymin: 3084022 xmax: 4121277 ymax: 3112952 ## Projected CRS: ETRS89-extended / LAEA Europe ``` ] .pull-right[ <img src="data:image/png;base64,#1_4_Raster_Data_files/figure-html/plot-deutz-1.png" style="display: block; margin: auto;" /> ] --- ## Cropping Cropping is a method of cutting out a specific `slice` of a raster layer based on an input dataset or geospatial extent, such as a bounding box. -- .pull-left[ ```r cropped_immigrant_rate <- terra::crop(immigrant_rate, deutz) ``` ] -- .pull-right[ <img src="data:image/png;base64,#1_4_Raster_Data_files/figure-html/crop-raster-map-1.png" style="display: block; margin: auto;" /> ] --- ## Masking Masking is similar to cropping, yet values outside the extent are set to missing values (`NA`). -- .pull-left[ ```r masked_immigrant_rate <- raster::mask(immigrant_rate, terra::vect(deutz)) ``` ] -- .pull-right[ <img src="data:image/png;base64,#1_4_Raster_Data_files/figure-html/mask-raster-map-1.png" style="display: block; margin: auto;" /> ] --- ## Combining Cropping and Masking .pull-left[ ```r cropped_masked_immigrant_rate <- terra::crop(immigrant_rate, deutz) |> raster::mask(terra::vect(deutz)) ``` ] -- .pull-right[ <img src="data:image/png;base64,#1_4_Raster_Data_files/figure-html/crop-mask-raster-map-1.png" style="display: block; margin: auto;" /> ] --- class: middle ## Exercise 1_4_1: Basic Raster Operations [Exercise](https://stefanjuenger.github.io/gesis-workshop-geospatial-techniques-R-2024/exercises/1_4_1_Basic_Raster_Operations.html) [Solution](https://stefanjuenger.github.io/gesis-workshop-geospatial-techniques-R-2024/solutions/1_4_1_Basic_Raster_Operations.html) --- class: middle ## Raster Extraction / Zonal statistics --- ## Sampling of some points .pull-left[ ```r fancy_points <- immigrants_cologne |> terra::spatSample(size = 10, na.rm = TRUE, as.points = TRUE) |> sf::st_as_sf() |> dplyr::select(-1) ``` ] -- .pull-right[ ```r plot(fancy_points) ``` <img src="data:image/png;base64,#1_4_Raster_Data_files/figure-html/plot-fancy-points-1.png" style="display: block; margin: auto;" /> ] --- ## Extract Information From Rasters .pull-left[ Raster data are helpful when we aim to - apply calculations that are the same for all geometries in the dataset - **extract information from raster fast and efficient** ] .pull-right[ ```r tm_shape(immigrant_rate) + tm_raster() + tm_shape(fancy_points) + tm_dots(size = .25) ``` <img src="data:image/png;base64,#1_4_Raster_Data_files/figure-html/plot-raster-extraction-1.png" style="display: block; margin: auto;" /> ] --- ## Raster Extraction To extract the raster values at a specific point by location, we use the following: ```r terra::extract(immigrants_cologne, fancy_points, ID = FALSE) ``` ``` ## immigrants_cologne ## 1 5 ## 2 3 ## 3 4 ## 4 3 ## 5 27 ## 6 9 ## 7 9 ## 8 32 ## 9 27 ## 10 3 ``` --- ## Add Results to Existing Dataset This information can be added to an existing dataset (our points in this example): ```r fancy_points <- fancy_points |> dplyr::mutate( immigrant_rate_value = as.vector( terra::extract(immigrant_rate, fancy_points, ID = FALSE, raw = TRUE) ) ) fancy_points ``` ``` ## Simple feature collection with 10 features and 1 field ## Geometry type: POINT ## Dimension: XY ## Bounding box: xmin: 4102000 ymin: 3089700 xmax: 4120200 ymax: 3110100 ## Projected CRS: ETRS89-extended / LAEA Europe (with axis order normalized for visualization) ## geometry immigrant_rate_value ## 1 POINT (4106300 3102400) 26.315789 ## 2 POINT (4107700 3110100) 2.400000 ## 3 POINT (4120200 3100000) 7.547170 ## 4 POINT (4103300 3099200) 3.125000 ## 5 POINT (4114100 3089900) 20.000000 ## 6 POINT (4102000 3089700) 11.538462 ## 7 POINT (4113200 3097500) 8.108108 ## 8 POINT (4106200 3092300) 21.917808 ## 9 POINT (4103800 3105400) 40.298507 ## 10 POINT (4117700 3102700) 5.882353 ``` --- ## More Elaborated: Spatial Buffers .pull-left[ Sometimes, extracting information 1:1 is not enough - too narrow - missing information about the surroundings of a point ] .pull-right[ ```r tm_shape(immigrants_cologne) + tm_raster() + tm_shape( sf::st_buffer(fancy_points, 500) ) + tm_dots(size = .1) + tm_borders() ``` <img src="data:image/png;base64,#1_4_Raster_Data_files/figure-html/plot-buffer-extraction-1.png" width="75%" style="display: block; margin: auto;" /> ] --- ## A Closer Look <img src="data:image/png;base64,#../img/FIGURE_1.png" width="75%" style="display: block; margin: auto;" /> .footnote[Jünger, 2021] --- ## Buffer Extraction We can use spatial buffers of different sizes to extract information on surroundings: .pull-left[ ```r terra::extract( immigrants_cologne, sf::st_buffer(fancy_points, 500), fun = mean, na.rm = TRUE, ID = FALSE, raw = TRUE ) ``` ``` ## immigrants_cologne ## 1 16.160000 ## 2 14.075000 ## 3 8.090909 ## 4 8.923077 ## 5 17.568627 ## 6 8.150000 ## 7 8.111111 ## 8 17.186047 ## 9 57.326087 ## 10 7.468750 ``` ] .pull-right[ ```r terra::extract( immigrants_cologne, sf::st_buffer(fancy_points, 1000), fun = mean, na.rm = TRUE, ID = FALSE, raw = TRUE ) ``` ``` ## immigrants_cologne ## 1 15.913043 ## 2 14.333333 ## 3 7.065789 ## 4 22.723757 ## 5 18.500000 ## 6 7.982143 ## 7 5.884615 ## 8 14.905109 ## 9 50.307018 ## 10 6.943925 ``` ] --- class: middle ## Exercise 1_4_2: Fancier Raster Operations [Exercise](https://stefanjuenger.github.io/gesis-workshop-geospatial-techniques-R-2024/exercises/1_4_2_Fancier_Raster_Operations.html) [Solution](https://stefanjuenger.github.io/gesis-workshop-geospatial-techniques-R-2024/solutions/1_4_2_Fancier_Raster_Operations.html) --- ## Raster Stacks So far, raster data have been unidimensional: we only had one attribute for each dataset. But they can also be stacked: ```r census_stack <- c(immigrants_cologne, inhabitants_cologne) census_stack ``` ``` ## class : SpatRaster ## dimensions : 289, 264, 2 (nrow, ncol, nlyr) ## resolution : 100, 100 (x, y) ## extent : 4094850, 4121250, 3084050, 3112950 (xmin, xmax, ymin, ymax) ## coord. ref. : ETRS89-extended / LAEA Europe (with axis order normalized for visualization) ## source(s) : memory ## varnames : immigrants_cologne ## inhabitants_cologne ## names : immigrants_cologne, inhabitants_cologne ## min values : 3, 3 ## max values : 639, 956 ``` --- ## Non-Regular Grids In this course, we only use regular grid-based raster data. However, be aware that non-regular grid data also exists. <img src="data:image/png;base64,#../img/nonregular_grid.png" width="70%" style="display: block; margin: auto;" /> .footnote[https://r-spatial.github.io/stars/] --- ## Relevant In This Context: Earth Observation Data Earth observation data have become increasingly popular in social science applications. They can be used, among others, to develop alternative measures for inequality, particularly in the global south. For example, Weidmann & Theunissen (2017) use nighttime light emissions data to construct measures of local inequality. Satellite data or remote sensing data are often not only geographically fine-grained but also temporary. This characteristic makes them attractive for (near) real-time analysis of events. .footnote[Weidmann, N. B., & Theunissen, G. (2021). Estimating Local Inequality from Nighttime Lights. Remote Sensing, 13(22), 4624. https://doi.org/10.3390/rs13224624 ] --- ## Magic of Data Cubes In the `stars` Package <img src="data:image/png;base64,#../img/cube2.png" width="80%" style="display: block; margin: auto;" /> .footnote[https://raw.githubusercontent.com/r-spatial/stars/master/images/cube2.png] --- ## Tomorrow <table class="table" style="color: black; margin-left: auto; margin-right: auto;"> <thead> <tr> <th style="text-align:left;"> Day </th> <th style="text-align:left;"> Time </th> <th style="text-align:left;"> Title </th> </tr> </thead> <tbody> <tr> <td style="text-align:left;color: gray !important;"> April 23 </td> <td style="text-align:left;color: gray !important;"> 10:00-11:30 </td> <td style="text-align:left;font-weight: bold;"> Introduction to GIS </td> </tr> <tr> <td style="text-align:left;color: gray !important;"> April 23 </td> <td style="text-align:left;color: gray !important;"> 11:45-13:00 </td> <td style="text-align:left;font-weight: bold;"> Vector Data </td> </tr> <tr> <td style="text-align:left;color: gray !important;color: gray !important;"> April 23 </td> <td style="text-align:left;color: gray !important;color: gray !important;"> 13:00-14:00 </td> <td style="text-align:left;font-weight: bold;color: gray !important;"> Lunch Break </td> </tr> <tr> <td style="text-align:left;color: gray !important;"> April 23 </td> <td style="text-align:left;color: gray !important;"> 14:00-15:30 </td> <td style="text-align:left;font-weight: bold;"> Mapping </td> </tr> <tr> <td style="text-align:left;color: gray !important;border-bottom: 1px solid"> April 23 </td> <td style="text-align:left;color: gray !important;border-bottom: 1px solid"> 15:45-17:00 </td> <td style="text-align:left;font-weight: bold;border-bottom: 1px solid"> Raster Data </td> </tr> <tr> <td style="text-align:left;color: gray !important;background-color: yellow !important;"> April 24 </td> <td style="text-align:left;color: gray !important;background-color: yellow !important;"> 09:00-10:30 </td> <td style="text-align:left;font-weight: bold;background-color: yellow !important;"> Advanced Data Import & Processing </td> </tr> <tr> <td style="text-align:left;color: gray !important;background-color: yellow !important;"> April 24 </td> <td style="text-align:left;color: gray !important;background-color: yellow !important;"> 10:45-12:00 </td> <td style="text-align:left;font-weight: bold;background-color: yellow !important;"> Applied Data Wrangling & Linking </td> </tr> <tr> <td style="text-align:left;color: gray !important;color: gray !important;background-color: yellow !important;"> April 24 </td> <td style="text-align:left;color: gray !important;color: gray !important;background-color: yellow !important;"> 12:00-13:00 </td> <td style="text-align:left;font-weight: bold;color: gray !important;background-color: yellow !important;"> Lunch Break </td> </tr> <tr> <td style="text-align:left;color: gray !important;background-color: yellow !important;"> April 24 </td> <td style="text-align:left;color: gray !important;background-color: yellow !important;"> 13:00-14:30 </td> <td style="text-align:left;font-weight: bold;background-color: yellow !important;"> Investigating Spatial Autocorrelation </td> </tr> <tr> <td style="text-align:left;color: gray !important;background-color: yellow !important;"> April 24 </td> <td style="text-align:left;color: gray !important;background-color: yellow !important;"> 14:45-16:00 </td> <td style="text-align:left;font-weight: bold;background-color: yellow !important;"> Spatial Econometrics & Outlook </td> </tr> </tbody> </table> --- class: middle ## Add-on Slides: Conversion and possible applications --- ## Raster to Points ```r raster_now_points <- immigrant_rate |> terra::as.points() raster_now_points ``` ``` ## class : SpatVector ## geometry : points ## dimensions : 13867, 1 (geometries, attributes) ## extent : 4094900, 4121200, 3084100, 3112900 (xmin, xmax, ymin, ymax) ## coord. ref. : ETRS89-extended / LAEA Europe (with axis order normalized for visualization) ## names : immigrants_cologne ## type : <num> ## values : 6.509 ## 45.03 ## 33.19 ``` --- ## Points to Raster ```r points_now_raster <- raster_now_points |> terra::rast(vals = raster_now_points$immigrants_cologne, resolution = 100) points_now_raster ``` ``` ## class : SpatRaster ## dimensions : 288, 263, 1 (nrow, ncol, nlyr) ## resolution : 100, 100 (x, y) ## extent : 4094900, 4121200, 3084100, 3112900 (xmin, xmax, ymin, ymax) ## coord. ref. : ETRS89-extended / LAEA Europe (with axis order normalized for visualization) ## source(s) : memory ## name : lyr.1 ## min value : 0.6637168 ## max value : 100.0000000 ``` --- ## Application: Point Pattern Analysis Using Global Kernel Densities (‘Heatmap’) .pull-left[ ```r kernel_densities <- raster_now_points |> sf::st_as_sf() |> dplyr::filter(immigrants_cologne > 25) |> sf::as_Spatial() |> as("ppp") |> spatstat.explore::density.ppp(sigma = 250) |> terra::rast() terra::crs(kernel_densities) <- "epsg:3035" ``` ] .pull-right[ <img src="data:image/png;base64,#1_4_Raster_Data_files/figure-html/plot-densities-1.png" style="display: block; margin: auto;" /> ] --- ## Raster to Polygons .pull-left[ ```r polygon_raster <- immigrant_rate |> terra::as.polygons() |> sf::st_as_sf() ``` ] .pull-right[ <img src="data:image/png;base64,#1_4_Raster_Data_files/figure-html/plot-polygon-raster-1.png" style="display: block; margin: auto;" /> ] --- ## Application: Rotation in Space <img src="data:image/png;base64,#1_4_Raster_Data_files/figure-html/plot-polygon-raster-rotated-1.png" style="display: block; margin: auto;" /> --- ## Focal Statistics Focal statistics are another method of including information near a point in space. However, it's applied to the whole dataset and is independent of arbitrary points we project onto a map. - relates focal cells to surrounding cells - vastly used in image processing - but also applicable in social science research, as we will see --- ## Focal Application: Edge Detection .pull-left[ <img src="data:image/png;base64,#../img/Bikesgray.jpg" width="853" style="display: block; margin: auto;" /> ] .pull-right[ <img src="data:image/png;base64,#../img/Bikesgraysobel.jpg" width="853" style="display: block; margin: auto;" /> ] .tinyisher[Source: https://en.wikipedia.org/wiki/Sobel_operator] --- ## Edges of Immigrant Rates <img src="data:image/png;base64,#../img/legewie_schaeffer_2016.png" width="2797" style="display: block; margin: auto;" /> --- ## We Can Do That As Well Using a Sobel Filter `$$r_x = \begin{bmatrix}1 & 0 & -1 \\2 & 0 & -2 \\1 & 0 & -1\end{bmatrix} \times raster\_file \\r_y = \begin{bmatrix}1 & 2 & 1 \\0 & 0 & 0 \\-1 & -2 & -1\end{bmatrix}\times raster\_file \\r_{xy} = \sqrt{r_{x}^2 + r_{y}^2}$$` --- ## Implementation in R From the [official documentation](http://search.r-project.org/R/library/raster/html/focal.html): ```r sobel <- function(r) { fy <- matrix(c(1, 0, -1, 2, 0, -2, 1, 0, -1), nrow = 3) fx <- matrix(c(-1, -2, -1, 0, 0, 0, 1, 2, 1) , nrow = 3) rx <- terra::focal(r, fx) ry <- terra::focal(r, fy) sqrt(rx^2 + ry^2) } ``` --- ## Data Preparation and Application of Filter ```r old_extent <- terra::ext(immigrant_rate) new_extent <- old_extent + c(10000, -10000, 10000, -10000) smaller_immigrant_rate <- immigrant_rate |> terra::crop(new_extent) smaller_immigrant_rate[smaller_immigrant_rate < 15] <- NA immigrant_edges <- sobel(smaller_immigrant_rate) ``` --- ## Comparison .pull-left[ <img src="data:image/png;base64,#1_4_Raster_Data_files/figure-html/original-image-1.png" style="display: block; margin: auto;" /> ] .pull-right[ <img src="data:image/png;base64,#1_4_Raster_Data_files/figure-html/sobel-image-1.png" style="display: block; margin: auto;" /> ] --- layout: false class: center background-image: url(data:image/png;base64,#../assets/img/the_end.png) background-size: cover .left-column[ </br> <img src="data:image/png;base64,#../img/Stefan.png" width="75%" style="display: block; margin: auto;" /> ] .right-column[ .left[.small[<svg viewBox="0 0 512 512" style="height:1em;position:relative;display:inline-block;top:.1em;" xmlns="http://www.w3.org/2000/svg"> <path d="M464 64H48C21.49 64 0 85.49 0 112v288c0 26.51 21.49 48 48 48h416c26.51 0 48-21.49 48-48V112c0-26.51-21.49-48-48-48zm0 48v40.805c-22.422 18.259-58.168 46.651-134.587 106.49-16.841 13.247-50.201 45.072-73.413 44.701-23.208.375-56.579-31.459-73.413-44.701C106.18 199.465 70.425 171.067 48 152.805V112h416zM48 400V214.398c22.914 18.251 55.409 43.862 104.938 82.646 21.857 17.205 60.134 55.186 103.062 54.955 42.717.231 80.509-37.199 103.053-54.947 49.528-38.783 82.032-64.401 104.947-82.653V400H48z"></path> </svg> [stefan.juenger@gesis.org](mailto:stefan.juenger@gesis.org)] .small[<svg viewBox="0 0 512 512" style="height:1em;position:relative;display:inline-block;top:.1em;" xmlns="http://www.w3.org/2000/svg"> <path d="M459.37 151.716c.325 4.548.325 9.097.325 13.645 0 138.72-105.583 298.558-298.558 298.558-59.452 0-114.68-17.219-161.137-47.106 8.447.974 16.568 1.299 25.34 1.299 49.055 0 94.213-16.568 130.274-44.832-46.132-.975-84.792-31.188-98.112-72.772 6.498.974 12.995 1.624 19.818 1.624 9.421 0 18.843-1.3 27.614-3.573-48.081-9.747-84.143-51.98-84.143-102.985v-1.299c13.969 7.797 30.214 12.67 47.431 13.319-28.264-18.843-46.781-51.005-46.781-87.391 0-19.492 5.197-37.36 14.294-52.954 51.655 63.675 129.3 105.258 216.365 109.807-1.624-7.797-2.599-15.918-2.599-24.04 0-57.828 46.782-104.934 104.934-104.934 30.213 0 57.502 12.67 76.67 33.137 23.715-4.548 46.456-13.32 66.599-25.34-7.798 24.366-24.366 44.833-46.132 57.827 21.117-2.273 41.584-8.122 60.426-16.243-14.292 20.791-32.161 39.308-52.628 54.253z"></path> </svg> [`@StefanJuenger`](https://twitter.com/StefanJuenger)] .small[<svg viewBox="0 0 496 512" style="height:1em;position:relative;display:inline-block;top:.1em;" xmlns="http://www.w3.org/2000/svg"> <path d="M165.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3.3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6zm-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5.3-6.2 2.3zm44.2-1.7c-2.9.7-4.9 2.6-4.6 4.9.3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9zM244.8 8C106.1 8 0 113.3 0 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C428.2 457.8 496 362.9 496 252 496 113.3 383.5 8 244.8 8zM97.2 352.9c-1.3 1-1 3.3.7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1zm-10.8-8.1c-.7 1.3.3 2.9 2.3 3.9 1.6 1 3.6.7 4.3-.7.7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3.7zm32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3.7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1zm-11.4-14.7c-1.6 1-1.6 3.6 0 5.9 1.6 2.3 4.3 3.3 5.6 2.3 1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2z"></path> </svg> [`StefanJuenger`](https://github.com/StefanJuenger)] .small[<svg viewBox="0 0 576 512" style="height:1em;position:relative;display:inline-block;top:.1em;" xmlns="http://www.w3.org/2000/svg"> <path d="M280.37 148.26L96 300.11V464a16 16 0 0 0 16 16l112.06-.29a16 16 0 0 0 15.92-16V368a16 16 0 0 1 16-16h64a16 16 0 0 1 16 16v95.64a16 16 0 0 0 16 16.05L464 480a16 16 0 0 0 16-16V300L295.67 148.26a12.19 12.19 0 0 0-15.3 0zM571.6 251.47L488 182.56V44.05a12 12 0 0 0-12-12h-56a12 12 0 0 0-12 12v72.61L318.47 43a48 48 0 0 0-61 0L4.34 251.47a12 12 0 0 0-1.6 16.9l25.5 31A12 12 0 0 0 45.15 301l235.22-193.74a12.19 12.19 0 0 1 15.3 0L530.9 301a12 12 0 0 0 16.9-1.6l25.5-31a12 12 0 0 0-1.7-16.93z"></path> </svg> [`https://stefanjuenger.github.io`](https://stefanjuenger.github.io)]] ]