From 06dc49bc98e988cfa13c9ce66655fb10813db09f Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Wed, 27 Sep 2023 14:29:31 +0200 Subject: Get taxon lists. --- gis-observation-map | 99 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) diff --git a/gis-observation-map b/gis-observation-map index 7e97fb9..9c478c7 100755 --- a/gis-observation-map +++ b/gis-observation-map @@ -21,6 +21,10 @@ import argparse import sys import json +import requests +import configparser +from requests.exceptions import HTTPError +from xdg import xdg_config_home from pathlib import Path from osgeo import gdal, ogr, osr gdal.UseExceptions() @@ -46,8 +50,10 @@ target_srs.SetAxisMappingStrategy(osr.OAMS_TRADITIONAL_GIS_ORDER) gpkg_drv = ogr.GetDriverByName('GPKG') geojson_drv = ogr.GetDriverByName('GeoJSON') +programName = 'gis-observation-map' parser = argparse.ArgumentParser( description='Create a QGIS project with observations from Artdatabanken.', + prog = programName, usage='''%(prog)s --project-home=DIR --project-name=NAME {--geometry=FILE|--point=X,Y} ... %(prog)s {--geometry=FILE|--point=X,Y} ...''' ) @@ -60,6 +66,9 @@ parser.add_argument('--point', nargs='*', default=[], help=f'Coordinates of inte args = parser.parse_args() +config = configparser.ConfigParser() +config.read(Path(xdg_config_home()).joinpath(programName).joinpath('config')) + if args.project_home is not None and args.project_name is not None: QgsApplication.setPrefixPath('/usr/bin/qgis', True) qgs = QgsApplication([], False) @@ -305,6 +314,96 @@ def geometricFilter(geometries): return myGeometries +artDataBankenURL = 'https://api.artdatabanken.se' +artDataBankenHeaders = { + 'X-Api-Version': '1.5', + 'X-Requesting-System': '', + # https://github.com/biodiversitydata-se/SOS/blob/master/Docs/Authentication.md + 'Ocp-Apim-Subscription-Key': config['ArtDataBanken']['Subscription-Key'] +} +def getTaxonLists(): + resp = requests.get( + artDataBankenURL + '/species-observation-system/v1/TaxonLists?cultureCode=en-US', + headers=artDataBankenHeaders + ) + resp.raise_for_status() + taxonLists = resp.json() + #print(json.dumps(taxonLists, indent=2)) + taxonLists2 = {} + + # https://github.com/biodiversitydata-se/SOS/blob/master/Src/SOS.lib/Resources/TaxonLists.json + # https://artfakta.se/artinformation/taxa + getTaxonList(taxonLists, taxonLists2, 'ProtectedByLaw', 'Protected by law species') + getTaxonList(taxonLists, taxonLists2, 'TaxonIsSignalSpecie', 'Signal species') + + getTaxonList(taxonLists, taxonLists2, 'TaxonIsInvasive', 'Invasive species') + getTaxonList(taxonLists, taxonLists2, 'TaxonIsInvasiveInSweden', 'Invasive species in Sweden') + getTaxonList(taxonLists, taxonLists2, 'TaxonIsInvasiveEuRegulation', 'EU regulation 1143/2014') + + getTaxonList(taxonLists, taxonLists2, 'Natura2000HabitatsDirective', 'Habitats directive species') + getTaxonList(taxonLists, taxonLists2, 'Natura2000HabitatsDirectiveArticle2', 'Habitats directive Annex 2') + getTaxonList(taxonLists, taxonLists2, 'Natura2000HabitatsDirectiveArticle2PrioritySpecie', 'Habitats directive Annex 2, priority species') + getTaxonList(taxonLists, taxonLists2, 'Natura2000HabitatsDirectiveArticle4', 'Habitats directive Annex 4') + getTaxonList(taxonLists, taxonLists2, 'Natura2000HabitatsDirectiveArticle5', 'Habitats directive Annex 5') + + # sanity check + directives = [ + 'Natura2000HabitatsDirectiveArticle2', + 'Natura2000HabitatsDirectiveArticle2PrioritySpecie', + 'Natura2000HabitatsDirectiveArticle4', + 'Natura2000HabitatsDirectiveArticle5' + ] + d0 = 'Natura2000HabitatsDirective' + for i in taxonLists2[d0]: + if not any(map(lambda d: i in taxonLists2[d], directives)): + raise Exception(f'missing taxon #{i} (in {d0}) from directives {",".join(directives)}') + for d in directives: + for i in taxonLists2[d]: + if not i in taxonLists2[d0]: + raise Exception(f'missing taxon #{i} (in {d}) from {d0}') + for i in taxonLists2['Natura2000HabitatsDirectiveArticle2PrioritySpecie']: + if not i in taxonLists2['Natura2000HabitatsDirectiveArticle2']: + raise Exception(f'missing taxon #{i} (in Natura2000HabitatsDirectiveArticle2PrioritySpecie) from Natura2000HabitatsDirectiveArticle2') + + getTaxonList(taxonLists, taxonLists2, 'BirdDirective', 'Birds Directive') + getTaxonList(taxonLists, taxonLists2, 'BirdDirectiveArticle1', 'Birds directive - Annex 1') + getTaxonList(taxonLists, taxonLists2, 'BirdDirectiveArticle2', 'Birds directive - Annex 2') + getTaxonList(taxonLists, taxonLists2, 'TaxonIsPriorityBird', 'Priority birds') + + directives = ['BirdDirectiveArticle1', 'BirdDirectiveArticle2'] + d0 = 'BirdDirective' + #for i in taxonLists2[d0]: + # if not any(map(lambda d: i in taxonLists2[d], directives)): + # raise Exception(f'missing taxon #{i} (in {d0}) from directives {",".join(directives)}') + for d in directives: + for i in taxonLists2[d]: + if not i in taxonLists2[d0]: + raise Exception(f'missing taxon #{i} (in {d}) from {d0}') + + return taxonLists2 + +def getTaxonList(taxonLists, taxonLists2, key, name): + i = None + for t in taxonLists: + if t['name'] == name: + if i is not None: + raise Exception(f'multiple results found for taxon list "{name}"') + i = t['id'] + if i is None: + raise Exception(f'no found for taxon list "{name}"') + + resp = requests.get( + artDataBankenURL + f'/species-observation-system/v1/TaxonLists/{i}/Taxa', + headers=artDataBankenHeaders + ) + resp.raise_for_status() + resp = resp.json() + if type(resp) != list: + raise Exception(f'expected list, got {type(resp)}') + taxonLists2[key] = {r['id'] for r in resp} + +taxonLists = getTaxonLists() + geograficsFilter = { 'geometries': geometricFilter(geometries), #'maxAccuracy': 5000, -- cgit v1.2.3