💻 Vektor Data I/O#

Open In Colab

Et av de første trinnene i mange analysearbeidsflyter er å lese data fra en fil, et av de siste trinnene skriver ofte data til en fil. Til skrekk og gru for mange geoinformatikkforskere, finnes det mange filformater for GIS-data: den gamle og forhatte, men også elskede og etablerte ESRI Shapefile, den universelle Geopackage (GPKG), og den web-optimaliserte GeoJSON er bare noen av de mer kjente eksemplene.

De fleste av dagens Python GIS-pakker er avhengige av GDAL/OGR-bibliotekene, som det finnes moderne grensesnitt for i form av Python-pakkene fiona og rasterio.

I dag skal vi konsentrere oss om vektordata, så la oss først ta en nærmere titt på fionas egenskaper, og deretter importere og eksportere data ved hjelp av geopandas, som bruker fiona.


Definere en konstant for datamappen

For å gjøre det lettere å håndtere stiene til inngangs- og utgangsdatafiler, er det en god vane å definere en konstant som peker på datamappen øverst i en notatbok:

import pathlib 
NOTEBOOK_PATH = pathlib.Path().resolve()
DATA_MAPPE = NOTEBOOK_PATH / "data"

Filformater#

Fiona kan lese (nesten) alle geospatiale filformater, og skrive mange av dem. For å finne ut nøyaktig hvilke (det kan avhenge av den lokale installasjonen og versjonen), kan vi skrive ut listen over dens filformatdrivere:

import fiona
fiona.supported_drivers
---------------------------------------------------------------------------
ModuleNotFoundError                       Traceback (most recent call last)
Cell In[2], line 1
----> 1 import fiona
      2 fiona.supported_drivers

ModuleNotFoundError: No module named 'fiona'

Hint

I denne listen markerer r filformater som Fiona kan lese, og w formater det kan skrive. En a markerer formater som Fiona kan appendere (legge til) nye data til eksisterende filer.

Merk at hver av de listede ‘formatene’ faktisk er navnet på driverimplementasjonen, og mange av driverne kan åpne flere relaterte filformater.

Mange flere ‘eksotiske’ filformater kan kanskje ikke vises i denne listen over din lokale installasjon, fordi du må installere ekstra biblioteker. Du kan finne en fullstendig liste over filformater som støttes av GDAL/OGR (og Fiona) på nettsiden: gdal.org/drivers/vector/.

Lesing og skriving av romlige data#

Fiona gir tilgang til geodatafiler på et lavt nivå. Dette er noen ganger nødvendig, men i typiske analysearbeidsflyter er det mer praktisk å bruke et høyere-nivå bibliotek. Den mest brukte for geospatiale/romlige vektordata er geopandas. Som nevnt ovenfor, bruker den Fiona for lesing og skriving av filer, og støtter dermed de samme filformatene.

For å lese data fra en GeoPackage -fil til en geopandas.GeoDataFrame (en romlig versjon av en pandas.DataFrame), bruk geopandas.read_file():

import geopandas
kommuner = geopandas.read_file(
    DATA_MAPPE / "kommuner" / "kommuner.gpkg"
)
kommuner.head()
gml_id lokalId navnerom versjonId oppdateringsdato gyldigFra datauttaksdato navn språk kommunenummer kommunenavn samiskForvaltningsområde geometry
0 kommune.1 0466e7c3-6a23-4b70-97d4-cf81f949490b https://data.geonorge.no/sosi/inndelinger/innd... 3 2023-11-28T17:47:39 2024-01-01 2024-03-04T12:27:57 Ibestad nor 5514 Ibestad False MULTIPOLYGON (((589669.263 7630312.979, 589669...
1 kommune.2 0f821a2d-a307-41ec-9b64-f01c80e39357 https://data.geonorge.no/sosi/inndelinger/innd... 4 2023-11-07T23:33:28 2023-11-07 2024-03-04T12:27:57 Rendalen nor 3424 Rendalen False MULTIPOLYGON (((327391.890 6869419.570, 327363...
2 kommune.3 251a3fdd-ac96-4ef2-badb-a9b75e6ab2e6 https://data.geonorge.no/sosi/inndelinger/innd... 3 2023-11-28T15:42:05 2024-01-01 2024-03-04T12:27:57 Rakkestad nor 3120 Rakkestad False MULTIPOLYGON (((284560.990 6591094.550, 284575...
3 kommune.4 2758a7b8-edba-4d6a-936e-4754ce03ca8f https://data.geonorge.no/sosi/inndelinger/innd... 3 2023-11-28T15:56:10 2024-01-01 2024-03-04T12:27:57 Nordre Follo nor 3207 Nordre Follo False MULTIPOLYGON (((269615.270 6638265.470, 269615...
4 kommune.5 340fff7f-b153-4a87-814d-12ca4f2d1682 https://data.geonorge.no/sosi/inndelinger/innd... 4 2023-11-07T23:33:28 2023-11-07 2024-03-04T12:27:57 Overhalla nor 5047 Overhalla False MULTIPOLYGON (((359415.100 7152572.930, 359412...

Å lese en lokal GPKG-fil er mest sannsynlig den enkleste oppgaven for en GIS-pakke. Imidlertid kan geopandas også lese Shapefiles innenfor en ZIP-arkiv, og/eller direkte fra en Internett-URL. For eksempel, nedlasting, utpakking og åpning av et datasett av NUTS-regioner fra European Union’s GISCO/eurostat download page er en linje med kode:

nuts_regions = geopandas.read_file("https://gisco-services.ec.europa.eu/distribution/v2/nuts/shp/NUTS_RG_60M_2021_3035.shp.zip")
nuts_regions.head()
NUTS_ID LEVL_CODE CNTR_CODE NAME_LATN NUTS_NAME MOUNT_TYPE URBN_TYPE COAST_TYPE geometry
0 DE149 3 DE Sigmaringen Sigmaringen 4.0 3 3 POLYGON ((4272515.778 2791989.118, 4291502.208...
1 DE211 3 DE Ingolstadt, Kreisfreie Stadt Ingolstadt, Kreisfreie Stadt 4.0 2 3 POLYGON ((4430560.572 2849070.969, 4426522.606...
2 DE212 3 DE b'4dfc6e6368656e2c204b726569736672656965205374... b'4dfc6e6368656e2c204b726569736672656965205374... 4.0 1 3 POLYGON ((4426190.454 2780289.957, 4425325.775...
3 DE213 3 DE Rosenheim, Kreisfreie Stadt Rosenheim, Kreisfreie Stadt 4.0 2 3 POLYGON ((4470814.937 2743662.905, 4477767.129...
4 DE214 3 DE b'416c74f67474696e67' b'416c74f67474696e67' 4.0 2 3 POLYGON ((4539906.565 2792493.475, 4525936.167...

Skrive romlige data til en fil#

Å skrive data til en fil er like enkelt: bruk bare to_file() metoden til en GeoDataFrame.

Hvis vi vil beholde en lokal kopi av NUTS-region datasettet vi nettopp åpnet ‘on-the-fly’ fra en internettadress kan vi lagre dataene til en GeoJSON-fil (filformatet blir gjettet fra filnavnet). Før vi gjør det må vi sikre oss at datatypene er riktig formatert (ofte når data komprimeres, sånn som med NUTS-dataene, blir formateringen forenklet). Først kan vi sjekke hva slags datatype de ulike kolonnene har:

print(nuts_regions.dtypes)
NUTS_ID         object
LEVL_CODE        int64
CNTR_CODE       object
NAME_LATN       object
NUTS_NAME       object
MOUNT_TYPE     float64
URBN_TYPE        int64
COAST_TYPE       int64
geometry      geometry
dtype: object

Her ser vi at vi har mange kolonner av typen object, noe som bør endres. I dette tilfellet inneholder alle de gjeldende kolonnene tekststrenger, så vi kan endre de til str før vi lagrer:

nuts_regions = nuts_regions.astype({col: 'str' for col in nuts_regions.select_dtypes(include='object').columns})
nuts_regions.to_file(DATA_MAPPE / "europe_nuts_regions.geojson")
NUTS_ID         object
LEVL_CODE        int64
CNTR_CODE       object
NAME_LATN       object
NUTS_NAME       object
MOUNT_TYPE     float64
URBN_TYPE        int64
COAST_TYPE       int64
geometry      geometry
dtype: object

Note

Lesing og skriving av romlige data fra eller til en fil er nesten identisk for alle filformater som støttes av geopandas, fiona, og GDAL. Sjekk ut geopandas’ dokumentasjon for tips om hvordan du kan finjustere lesing eller skriving av en fil, og hvordan du kan bruke forskjellige filtre.

Lesing og skriving fra og til databaser (RDBMS)#

Geopandas har innebygd støtte for lese/skrive-tilgang til PostgreSQL/PostGIS-databaser, ved hjelp av dens geopandas.read_postgis() funksjon og GeoDataFrame.to_postgis() metode. For databasetilkoblingen kan du bruke, for eksempel, sqlalchemy-pakken.

# Siden dette ikke er en ekte database, må informasjonen endres hvis den skal kjøre
'''
import sqlalchemy
DB_CONNECTION_URL = "postgresql://myusername:mypassword@myhost:5432/mydatabase";
db_engine = sqlalchemy.create_engine(DB_CONNECTION_URL)

countries = geopandas.read_postgis(
    "SELECT name, geometry FROM countries",
    db_engine
)
countries.to_postgis(
    "new_table", 
    db_engine
)
'''
'\nimport sqlalchemy\nDB_CONNECTION_URL = "postgresql://myusername:mypassword@myhost:5432/mydatabase";\ndb_engine = sqlalchemy.create_engine(DB_CONNECTION_URL)\n\ncountries = geopandas.read_postgis(\n    "SELECT name, geometry FROM countries",\n    db_engine\n)\ncountries.to_postgis(\n    "new_table", \n    db_engine\n)\n'

Lesing av data direkte fra en WFS (Web feature service) endepunkt#

Geopandas kan også lese data direkte fra en WFS-endepunkt, som for eksempel geodata-APIene til Kartverket. Å konstruere en gyldig WFS-URI (adresse) er ikke en del av dette kurset (men sjekk, for eksempel, egenskapene til et lag lagt til QGIS).

Følgende kode laster et administrative enheter for Norge. Parameterne kodet inn i WFS-adressen spesifiserer lagets navn og det forespurte referansesystemet.

administrative_enheter = geopandas.read_file(
    "https://wfs.geonorge.no/skwms1/wfs.administrative_enheter?"
    "service=WFS"
    "&version=2.0.0"
    "&request=GetFeature"
    "&srsname=EPSG:25833"
    "&restrictToRequestBBOX=258331"
    "&typename=app:Kommune"
)
administrative_enheter.head()
gml_id lokalId navnerom versjonId oppdateringsdato gyldigFra datauttaksdato navn språk kommunenummer kommunenavn samiskForvaltningsområde geometry
0 kommune.1 0466e7c3-6a23-4b70-97d4-cf81f949490b https://data.geonorge.no/sosi/inndelinger/innd... 3 2023-11-28T17:47:39 2024-01-01 2024-03-04T12:27:57 [Ibestad] [nor] 5514 Ibestad False MULTIPOLYGON (((589669.263 7630312.979, 589669...
1 kommune.2 0f821a2d-a307-41ec-9b64-f01c80e39357 https://data.geonorge.no/sosi/inndelinger/innd... 4 2023-11-07T23:33:28 2023-11-07 2024-03-04T12:27:57 [Rendalen] [nor] 3424 Rendalen False MULTIPOLYGON (((327391.890 6869419.570, 327363...
2 kommune.3 251a3fdd-ac96-4ef2-badb-a9b75e6ab2e6 https://data.geonorge.no/sosi/inndelinger/innd... 3 2023-11-28T15:42:05 2024-01-01 2024-03-04T12:27:57 [Rakkestad] [nor] 3120 Rakkestad False MULTIPOLYGON (((284560.990 6591094.550, 284575...
3 kommune.4 2758a7b8-edba-4d6a-936e-4754ce03ca8f https://data.geonorge.no/sosi/inndelinger/innd... 3 2023-11-28T15:56:10 2024-01-01 2024-03-04T12:27:57 [Nordre Follo] [nor] 3207 Nordre Follo False MULTIPOLYGON (((269615.270 6638265.470, 269615...
4 kommune.5 340fff7f-b153-4a87-814d-12ca4f2d1682 https://data.geonorge.no/sosi/inndelinger/innd... 4 2023-11-07T23:33:28 2023-11-07 2024-03-04T12:27:57 [Overhalla] [nor] 5047 Overhalla False MULTIPOLYGON (((359415.100 7152572.930, 359412...
administrative_enheter.plot()
<Axes: >
../../_images/02f85f96288487a49d02a2cd1a6e38353eda823623f826ebcb285b9d3285c787.png