diff options
| -rwxr-xr-x | gis-observation-map | 168 | 
1 files changed, 167 insertions, 1 deletions
diff --git a/gis-observation-map b/gis-observation-map index 4fe06cf..551a8af 100755 --- a/gis-observation-map +++ b/gis-observation-map @@ -322,6 +322,78 @@ artDataBankenHeaders = {      # https://github.com/biodiversitydata-se/SOS/blob/master/Docs/Authentication.md      'Ocp-Apim-Subscription-Key': config['ArtDataBanken']['Subscription-Key']  } + +def getObservations(taxonLists, taxonRedlistCategories, data): +    # https://api-portal.artdatabanken.se/docs/services/sos-api-v1/operations/Exports_DownloadGeoJson +    headers = artDataBankenHeaders.copy() +    headers['Content-Type'] = 'application/json' +    headers['Authorization'] = config['ArtDataBanken']['Authorization'] +    params = { +        'cultureCode': 'sv-SE', +        'flat': 'true', +        'excludeNullValues': 'true', +        'gzip': 'false', +        #'sensitiveObservations': 'true', +        'validateSearchFilter': 'true', +    } +    resp = requests.post( +        artDataBankenURL + '/species-observation-system/v1/Exports/Download/GeoJson', +        headers=headers, +        params=params, +        data=json.dumps(data) +    ) + +    resp.raise_for_status() +    obs = resp.json() + +    # https://www.rfc-editor.org/rfc/rfc7946 +    if obs is None or type(obs) != dict or 'type' not in obs.keys(): +        raise Exception('invalid GeoJSON output') +    if 'crs' not in obs.keys(): +        print('WARN: GeoJSON output lacks CRS', file=sys.stderr) + +    if obs['type'] == 'FeatureCollection' and 'features' in obs.keys() and type(obs['features']) == list: +        for feat in obs['features']: +            if (type(feat) != dict or 'type' not in feat.keys() or feat['type'] != 'Feature' +                    or 'properties' not in feat.keys() or type(feat['properties']) != dict): +                print('WARN: Invalid feature in GeoJSON output', file=sys.stderr) +                continue +            properties = feat['properties'] +            if 'DyntaxaTaxonId' not in properties.keys() or properties['DyntaxaTaxonId'] is None: +                print('WARN: Feature lacks taxon ID', file=sys.stderr) +                continue + +            tid = properties['DyntaxaTaxonId'] +            for k, taxonList in taxonLists.items(): +                v = (tid in taxonList) +                if k in properties.keys() and properties[k] != v: +                    print(f'WARN: #{tid} {k}: {properties[k]} → {v}', file=sys.stderr) +                properties[k] = v + +            if tid in taxonRedlistCategories.keys(): +                k = 'RedlistCategory' +                v = taxonRedlistCategories[tid] +                if k in properties.keys() and properties[k] != v: +                    print(f'WARN: #{tid} {k}: {properties[k]} → {v}', file=sys.stderr) +                properties[k] = v + +    # TODO generate GPKG instead and reproject to EPSG:3006 +    path = projectHome.joinpath('fynd.geojson') +    with path.open(mode='w') as fp: +        json.dump(obs, fp, indent=2, ensure_ascii=False) + +    if projectInstance is not None: +        layer = QgsVectorLayer(path.as_posix() + '''|subset="Kingdom" IN ('Fungi', 'Plantae') AND "IsPositiveObservation" AND "IsNaturalOccurrence" AND "CoordinateUncertaintyInMeters" <= 250''', path.stem, 'ogr') +        if not layer.isValid(): +            raise Exception(f'ERROR: {path}: failed to load in QGIS') +        if 'QGIS' in config.keys() and 'style' in config['QGIS']: +            style = Path(config['QGIS']['style']).expanduser() +            layer.loadNamedStyle(style.as_posix()) +        layer.setReadOnly(True) +        layer.setFlags(QgsMapLayer.Identifiable | QgsMapLayer.Searchable) +        projectInstance.addMapLayer(layer) +        layerTreeRoot.findLayer(layer.id()).setItemVisibilityChecked(True) +  def getTaxonLists():      resp = requests.get(          artDataBankenURL + '/species-observation-system/v1/TaxonLists?cultureCode=en-US', @@ -442,7 +514,101 @@ geograficsFilter = {      'considerDisturbanceRadius': True  }  taxonLists, taxonRedlistCategories = getTaxonLists() -exit() + +# https://github.com/biodiversitydata-se/SOS/blob/master/Docs/SearchFilter.md +searchFilter = { +    'geographics': geograficsFilter, +    'determinationFilter': 'NoFilter', +    'notRecoveredFilter': 'NoFilter', +    'occurrenceStatus': 'BothPresentAndAbsent', +    'verificationStatus': 'BothVerifiedAndNotVerified', +    'output': { +        'fields': [ +            # https://github.com/biodiversitydata-se/SOS/blob/master/Docs/SearchFilter.md#fields +            # https://github.com/biodiversitydata-se/SOS/blob/master/Docs/Observation.md +            'dataProviderId', +            'datasetName', +            #'basisOfRecord', +            'rightsHolder', + +            'modified', +            'sensitive', +            'measurementOrFacts', +            'projects', + +            'occurrence.occurrenceId', +            'occurrence.occurrenceRemarks', +            'occurrence.recordedBy', +            'occurrence.reportedBy', +            'occurrence.reportedDate', +            'occurrence.occurrenceStatus', +            'occurrence.activity', +            'occurrence.behavior', +            'occurrence.biotope', +            'occurrence.biotopeDescription', +            'occurrence.lifeStage', +            'occurrence.reproductiveCondition', +            'occurrence.sex', +            'occurrence.associatedMedia', +            'occurrence.associatedReferences', +            'occurrence.individualCount', +            'occurrence.organismQuantityInt', +            'occurrence.organismQuantityUnit', +            'occurrence.sensitivityCategory', +            'occurrence.isNaturalOccurrence', +            'occurrence.isNeverFoundObservation', +            'occurrence.isNotRediscoveredObservation', +            'occurrence.isPositiveObservation', +            'occurrence.substrate.description', +            'occurrence.substrate.name', +            'occurrence.length', +            'occurrence.weight', +            'occurrence.url', + +            'event.startDate', +            'event.endDate', +            'event.habitat', +            'event.eventRemarks', +            'event.discoveryMethod', +            'event.measurementOrFacts', +            'event.fieldNotes', + +            'identification.verified', +            'identification.uncertainIdentification', +            'identification.verificationStatus', +            'identification.confirmedBy', +            'identification.confirmedDate', +            'identification.identifiedBy', +            'identification.dateIdentified', +            'identification.verifiedBy', +            'identification.determinationMethod', +            'identification.identificationRemarks', + +            'location.locality', +            'location.county', +            'location.municipality', +            'location.coordinateUncertaintyInMeters', + +            'taxon.id', +            'taxon.scientificName', +            'taxon.scientificNameAuthorship', +            'taxon.vernacularName', +            'taxon.genus', +            'taxon.family', +            'taxon.order', +            'taxon.class', +            'taxon.phylum', +            'taxon.kingdom', + +            'taxon.attributes.taxonCategory', +            'taxon.attributes.organismGroup', + +            'taxon.attributes.redlistCategory', +        ] +    } +} + +getObservations(taxonLists, taxonRedlistCategories, searchFilter)  topo_maps = ['Topografi 10', 'Topografi 50', 'Topografi 100']  if projectInstance is not None:  | 
