import pandas as pd import os import pathlib import numpy as np import sys sys.path.append("..") class TabularSpecies: """ Class holding pandas data frame and helper dicts on all MNP species """ def __init__(self): filepath = pathlib.Path(__file__) # De volledige Species tabel als Pandas dataframe self.df = pd.read_csv( r"https://git.wur.nl/roelo008/benb_utils/-/raw/master/resources/mnp_species.csv", sep=",", comment="#", encoding="cp1252", ) # TODO: soortenlijst N-gevoelige soorten (179 stuks) toevoegen aan mnp_species.csv en labellen als dusdanig # Dictionaries tussen code, lokale naam, wetenschappelijke naam self.code2local = dict(zip(self.df.Species_code, self.df.Local_name)) self.local2code = dict(zip(self.df.Local_name, self.df.Species_code)) self.code2scientific = dict(zip(self.df.Species_code, self.df.Scientific_name)) self.scientific2code = dict(zip(self.df.Scientific_name, self.df.Species_code)) self.local2scientific = dict(zip(self.df.Local_name, self.df.Scientific_name)) self.scientific2local = dict(zip(self.df.Scientific_name, self.df.Local_name)) self.code2taxon = dict(zip(self.df.Species_code, self.df.taxon)) # Dictionaries to self, is usefull sometimes. Trust me... self.local2local = dict(zip(self.df.Local_name, self.df.Local_name)) self.code2code = dict(zip(self.df.Species_code, self.df.Species_code)) self.scientific2scientific = dict( zip(self.df.Scientific_name, self.df.Scientific_name) ) # # Dict between species code and boolean species lists self.code2selall = self.df.set_index('Species_code').assign(selall=True).selall.to_dict() self.code2sel468 = pd.Series( np.where( self.df.has_landscape_density & self.df.has_gvg_response & self.df.has_ndep_response & self.df.has_ph_response & self.df.has_species_traits, True, False, ), index=self.df.Species_code, ).to_dict() self.code2sel281 = pd.Series( np.where( self.df.has_landscape_density & self.df.has_gvg_response & self.df.has_ndep_response & self.df.has_ph_response & self.df.has_species_traits & ~self.df.enp2016_validatie.isin( [ "slecht", "slecht model", "Slecht model", "zeer matig model", "Zeer matig model", "nvt", ] ), True, False, ), index=self.df.Species_code, ).to_dict() self.code2sel146 = pd.Series( np.where( self.df.has_landscape_density & self.df.has_gvg_response & self.df.has_ndep_response & self.df.has_ph_response & self.df.has_species_traits & ~self.df.enp2016_validatie.isin( [ "slecht", "slecht model", "Slecht model", "zeer matig model", "Zeer matig model", "nvt", ] ) & self.df.enp2016_typisch, True, False, ), index=self.df.Species_code, ).to_dict() self.code2selNSensitive = pd.Series( np.where(self.df.mnp2021_n_sensitive, True, False), index=self.df.Species_code, ).to_dict() # Additional data sources. Note that population factors are not defined for all species # TODO: merge deze tabel met self.df ? # self.pop_factors_src = r'W:\PROJECTS\QMAR\MNP-SNL-ParameterSet\Parameters_v05_2021_04_08\07_MNP_versie4_par_population_factors.csv' # self.pop_factors = pd.read_csv(self.pop_factors_src, sep=',') # self.code2local_distance = dict(zip(self.pop_factors.Species_code, self.pop_factors.Local_distance)) # self.code2key_area = dict(zip(self.pop_factors.Species_code, self.pop_factors.Key_area)) class IndividualSpecies: """ Class for holding properties of a single species instance. Hans Roelofsen, WEnR, 12 jan 2022 """ def __init__(self, x, brief=False, verbose=False): """ Initiate for a species. :param x: species code, local name or scientific name """ species_tab = TabularSpecies() species_identifiers_full = ["Species_code", "Local_name", "Scientific_name"] species_identifiers_brief = ["code", "local", "scientific"] try: # Determine if X is a species code, local name, scientific name or not-existing isin = [ x in getattr(species_tab.df, col).values for col in species_identifiers_full ].index(True) typer = species_identifiers_brief[isin] except ValueError: if verbose: print("{} is not a recognized species".format(x)) raise self.code = getattr(species_tab, "{}2code".format(typer))[x] # Species code self.local = getattr(species_tab, "{}2local".format(typer))[ x ] # Species local name self.scientific = getattr(species_tab, "{}2scientific".format(typer))[ x ] # Species Scientific name self.taxondict = {"S02": "V", "S06": "E", "S09": "P"} self.taxon = self.taxondict[self.code[:3]] # try: # self.key_area = species_tab.code2key_area[self.code] # self.local_distance = species_tab.code2local_distance[self.code] # except KeyError: # self.key_area = None # self.local_distance = None # Paths to default files with species response towards abiotic conditions self.gvg_response_src = r"w:\PROJECTS\QMAR\MNP-SNL-ParameterSet\Parameters_v05_2021_04_08\04_MNP_versie4_par_response_GVG.csv" self.ndep_response_src = r"w:\PROJECTS\QMAR\MNP-SNL-ParameterSet\Parameters_v05_2021_04_08\05_MNP_versie4_par_response_Ndep.csv" self.ph_response_src = r"w:\PROJECTS\QMAR\MNP-SNL-ParameterSet\Parameters_v05_2021_04_08\06_MNP_versie4_par_response_PH.csv" if not brief: # Set all relevant attributes self.sel281 = species_tab.code2sel281[ self.code ] # boolean, species is part of 281 selection? self.sel468 = species_tab.code2sel468[self.code] # idem for 468 selection self.sel146 = species_tab.code2sel146[self.code] # idem foo 146 selection self.selNSensitive = species_tab.code2selNSensitive[ self.code ] # idem for N-Sensitive selection self.selall = species_tab.code2selall[self.code] # catch all self.groupinfo = "146:{0} - 281:{1} - 468:{2} - NSensitive: {3}".format( self.sel146, self.sel281, self.sel468, self.selNSensitive ) def abiotic_limits(self, abiotic, of="txt"): """ return response limits for an abiotic factor :param abiotic: {gvg, ndep, ph} :return: dict """ tab = pd.read_csv( getattr(self, "{}_response_src".format(abiotic)), index_col="Species_code" ) try: response = tab.loc[self.code] return { "dict": dict( zip([i[1] for i in response.index.str.split("_")], response) ), "array": response.values, "lst": response.to_list(), "sep": "\t".join([str(i) for i in response.to_list()]), }[of] except KeyError: print("{0} limits for {1} not found".format(abiotic, self.local)) return None def response_to_abiotic(self, abiotic, x): """ return response to a given Abiotic value :param abiotic which abiotic? :param x: the abiotic value :return: response {0, 0.5, 1} _____ 1| | | | | | 0.5| _____| |_____ | | | | | | 0 __|________________|__ L20 L80 H80 H20 """ limits = self.abiotic_limits(abiotic=abiotic, of="array") # limits = np.array(getattr(self, '{}_response_src'.format(abiotic)).loc[self.code]) return [0, 0.5, 1, 0.5, 0][int(np.digitize(x, limits))] def response_to_beheertype(self, beheertype): """ return Landtype Quality (aka draagkracht of self towards a beheertype :param beheertype: :return: land type quality [0-1] """ # TODO (20220323) Vergelijk met ./dkq.Draagkracht.query4species() if __name__ == "__main__": import argparse parser = argparse.ArgumentParser() parser.add_argument("species", help="Species local name, scientific name or code.") parser.add_argument("what", help="any property of the species") args = parser.parse_args() sp = IndividualSpecies(args.species) try: print(getattr(sp, args.what)) except AttributeError: print("{0} does not have a {1}".format(sp.local, args.what)) sys.exit(1)