Hvordan lage kart i R - en oppdatering

Hvordan lager en kart med R på en effektiv måte i 2023?


Author

Affiliation

Eivind Hageberg

 

Published

Dec. 2, 2023

DOI


Jeg lærte meg i utgangspunktet R for mange år siden, fordi jeg skulle lage kart over fordelinga av griser i Danmark, melkekuer i Sverige og ammekuer i Østerrike. Alle elsker et godt kart! Det var ingen enkel oppgave - både fordi det krevde at jeg lærte meg databehandling og litt halv-avansert figurlaging i R fra bunnen av, og fordi GIS-området var ganske komplekst i R: Det var krevende å finne datafiler med vektor-data om grensene til de ulike landene og de administrative områdene, og når en først hadde funnet dem måtte en håndtere en rekke ulike pakker og avhengigheter.

Slik har jeg hatt inntrykk av at det har vært siden da. Jeg har med jevne mellomrom laget nye kart på nye områder, og når jeg har kommet tilbake til kartlaginga og prøvd å bruke gammel kode, har den vært utdatert, og de siste tutorials en kan finne på nettet benytter litt andre pakker, med litt anna syntax.

Slik var det også sist, men slik jeg tolker CRAN Task Viewet om analyse av romlige data, er de siste endringene kaaaanskje litt mer robuste? At den anbefalte pakka sf er vedlikehold og i tråd med en ekstern standard for åpen formidling av “simple features” lover i hvert fall noe. At Kartverket og mange andre tilbyr en haug med kart som åpne data på Geonorge gjør også datatilgangen langt enklere.

Noe av utfordringa her er at innføringer og tutorials en finner, tar utgangspunkt i å forklare hvordan et spesifikt verktøy fungerer. Dermed blir en veldig sårbar for endringer i verktøyet, og innføringa av nye verktøy. En verktøy-agnostisk tilnærming er som vanlig best - men vil også være med tidkrevende. Det er mye enklere å få et par linjer kode som funker i dag, enn å måtte lære seg hvordan koordinatsystemer egentlig fungerer.

Hvilke pakker trengs nå da?

Svaret er for meg så langt kort og greit: sf, med vignetter her. SF benytter fire viktige bakenforliggende biblioteker utenfor R: GDAL (i/o til en rekke typer geodata), PROJ (for CRS-transformasjon), GEOS (for planetær geometri) og S2 (sfærisk geometri).

Dette er for vektor-data. terra er anbefalt for raster-data. Det finnes også en haug med pakker med diverse geografiske data - se Task Viewet over for lenker. spData er en slik pakke.

#biblioteker
library(sf)
library(spData)
library(tidyverse)
library(tmap)

Det følgende er basert på Lovelace m.fl. sin eminente online-versjon av Geocomputation with R, og div. pakke-vignetter for de brukte pakkene sf og tmap.

Hva er vektorer i denne sammenhengen?

Vektor-data representerer verden med punkter, linjer eller polygoner.

Hvordan ser det ut i praksis?

data(world)

plot(world)

Hvorfor sf?

sf-objektene er data.frames med en spesiell geometri-variabel. Geometri-variabelen er “sticky”, og blir med rundt selv om du manipulerer den.

norway = filter(world, name_long == "Norway") |> 
  select(lifeExp)

summary(norway)
    lifeExp               geom  
 Min.   : NA   MULTIPOLYGON :1  
 1st Qu.: NA   epsg:4326    :0  
 Median : NA   +proj=long...:0  
 Mean   :NaN                    
 3rd Qu.: NA                    
 Max.   : NA                    
 NA's   :1                      
ggplot(data = norway) +
  geom_sf()

Fordelen med sf-objektene er lette å se for meg som så vidt husker å ha brukt andre pakker tidligere: De kan behandles som data.frames, og kan benyttes i en tidyverse-arbeidsflyt.

Sf støtter punkter, linjer, polygoner og en 15 andre geometri-typer. Med sfheaders-pakken kan en konvertere mellom sf-objekter og data.frame-objekter, f.eks. slik:

temp = sfheaders::sf_to_df(norway, fill = TRUE)

head(temp)
  lifeExp sfg_id multipolygon_id polygon_id linestring_id        x
1      NA      1               1          1             1 15.14282
2      NA      1               1          1             1 13.71852
3      NA      1               1          1             1 13.17077
4      NA      1               1          1             1 10.44453
5      NA      1               1          1             1 11.22231
6      NA      1               1          1             1 13.17060
         y
1 79.67431
2 79.66039
3 80.01046
4 79.65239
5 78.86930
6 78.02493

En får da ut x og y-koordinatene til alle punktene, sammen med ID-variabler, for det som i sf-objektet er ett multipolygon:

head(norway)
Simple feature collection with 1 feature and 1 field
Geometry type: MULTIPOLYGON
Dimension:     XY
Bounding box:  xmin: 4.992078 ymin: 58.07888 xmax: 31.29342 ymax: 80.65714
Geodetic CRS:  WGS 84
# A tibble: 1 × 2
  lifeExp                                                         geom
    <dbl>                                           <MULTIPOLYGON [°]>
1      NA (((15.14282 79.67431, 13.71852 79.66039, 13.17077 80.01046,…

Jeg vil bare ha et pent bilde!

Jeg har vist base og ggplot2 så langt. GGPLOT2 kan som vanlig stilles langt bedre inn, med mer kode:

ggplot(data = norway) +
  geom_sf() +
  coord_sf(xlim = c(-2, 32), ylim = c(54, 72), expand = FALSE) +  
  theme_void()

Geometrien her er i utgangspunktet svært grov - alle fjords er borte, her er det internasjonale linjer med kystgrense som gjelder. Det er også en rekke andre pakker som kan brukes til å plotte dette, som tmap (også kalt tm - men det er en anna pakke):

tm_shape(norway) +
  tm_polygons() +
  tm_layout(frame = FALSE)