Commit aeea3700 authored by Roelofsen, Hans's avatar Roelofsen, Hans
Browse files

method 4 man overwrite EUNIS and add metadata

parent 025726c6
# doren_2019
# DOREN 2019
Code and data for DOREN project; relation between vegetation growth and nitrogen deposition. By Hans Roelofsen, Wieger Wamelink, WEnR, team Biodiversiteit & Beleid. September 2019.
\ No newline at end of file
Dit repository bevat python code voor selectie van Vegetatieopnames uit de EVA database en ruimtelijke-koppeling met diverse GIS bestanden. Deze code is onderdeel van het DOREN project van Wageningen Environenmental Research (WEnR).
Code door: Hans Roelofsen, Wageningen Environmental Research
Project leider: Wieger Wamelink, Wageningen Environmental Research
Datum: begonnen september 2019.
###Brongegevens
* Export van de EVA vegetetieopname database uit, bestaande uit:
* kopgegevens (headers) met opnameID, datum, latitude, longitude en andere metadata per plot
* inventarisgegevens met soortnaam, soortnummer en bedekking voor alle soorten in elke opname
* Shapefile met landsgrenzen (met wijdere begrenzing op zee om opnames langs de kustlijn mee te kunnen nemen).
* Geospatial raster met bodemtypes
* Geospatial rasters met gemiddelde dagelijkse neerslagsom per jaar
* *idem* voor jaarlijkse gemiddelde temperatuur
* *\*.csv* files met N-depositie gegevens per opname (rijen) per jaar (kolommen)
* Excel file met daarin soortnamen waarvoor output gemaakt moet worden
* Excel file met doorvertaling van EUNIS *vegetatietypen* naar *structuurtypen* en *ruwheidsfactorcategorieen*.
### Methode
De DOREN class is gedefinieerd als klasse om
1. vegetatieopnames te lezen vanuit een file-bestand en intern op te slaan als [Pandas](https://pandas.pydata.org/) dataframe.
2. selectiecriteria toe te passen op de vegetatieopnames, bijvoorbeeld op jaartal.
3. aanvullende gegevens toe te voegen aan de opnames via GIS spatial joins
4. aanvullende gegevens toe te voegen aan de opnames op basis van de plotIDs en jaartallen
5. diverse tabellen en rapportages te genereren
6. een Excel file inlezen met een lijst van plantensoorten waarvoor output gemaakt moet worden (*requested species*)
7. voor een plantensoort een tabel te genereren waarin:
1. per opname is aangegeven of de soort daarin aanwezig is ('positieve' opname)
2. de bedekking van de soort in elke positieve opname
3. de afstand van elke negatieve opname tot dichstbijzijnde positieve opname
4. de afstand van elke negatieve opname tot dichstbijzijnde positieve opname *van een bepaalde structuurtype*
In `create_doren.py` worden de gewenste selecties op de EVA opnames toegepast en de resterende opnamen gekoppeld aan landsnaam, temperatuur, neerslag, N-depositie. Tevens worden de EUNIS vegetatietypes van elke opname doorvertaald naar een *structuurtype* en een *ruwheidsfactorcategorie*. Het DOREN class object genereert een rapportage waarin alle stappen worden vastgelegd en wordt daarna opgeslagen als [`pickle`](https://docs.python.org/3/library/pickle.html) object.
De `pickle` wordt vervolgens gekopieerd naar de WUR [Anunna High Performance Computer](https://wiki.anunna.wur.nl/index.php/Main_Page). Hier wordt voor elke gewenste soort een soort-file gegenereerd middels het `run_species.py` script. Dit gebeurt gedistribueerd over meerdere HPC nodes, zodat de totale doorlooptijd beperkt blijft. Dit process wordt aangestuurd via `doren_batch.sh`.
### requirements
* [python 3.5.6](https://www.python.org/)
* [geopandas 0.6.3](https://geopandas.org/install.html)
* [numpy 1.15.2](https://numpy.org/)
* [pandas 0.23.34](https://pandas.pydata.org/)
* [rasterio 0.36.0](https://rasterio.readthedocs.io/en/latest/)
* [rasterstats 0.14.0](https://pythonhosted.org/rasterstats/)
* [xlrd 1.2.0](https://xlrd.readthedocs.io/en/latest/)
### Meer informatie
Neem contact op met [Hans Roelofsen](https://www.wur.nl/en/Persons/Hans-dr.-HD-Hans-Roelofsen.htm).
### Copyright
Deze repository is onderdeel van Wamelink *et al* (2021) *Responsecurven van habitattypen voor stikstofdepositie*.
Copyright 2021 Wageningen Environmental Research (instituut binnen de rechtspersoon Stichting Wageningen Research), Postbus 47, 6700 AA Wageningen, T 0317 48 07 00, [Wageningen Environmental Research](www.wur.nl/environmental-research). Wageningen Environmental Research is onderdeel van Wageningen University & Research.
* Overname, verveelvoudiging of openbaarmaking van deze uitgave is toegestaan mits met duidelijke bronvermelding.
* Overname, verveelvoudiging of openbaarmaking is niet toegestaan voor commerciële doeleinden en/of geldelijk gewin.
* Overname, verveelvoudiging of openbaarmaking is niet toegestaan voor die gedeelten van deze uitgave waarvan duidelijk is dat de auteursrechten liggen bij derden en/of zijn voorbehouden.
\ No newline at end of file
......@@ -31,26 +31,31 @@ doren = dc.Doren(header_src=param_header_src, sp_src=param_sp_src)
doren.initiate(sample=testing)
doren.apply_requirements('req1', 'req2', 'req3', 'req4', 'req8', 'req9', 'req10',
aoi_src=None if testing else param_aoi_src, dem_src=param_dem_src)
doren.overwrite_eunis(source_file=r'W:\PROJECTS\Doren19\a_brondata\EVA\delivery_20210112\Calluna_Avenula.csv',
col='PlotObservationID', target_eunis='S42')
doren.overwrite_eunis(source_file=r'W:\PROJECTS\Doren19\a_brondata\EVA\delivery_20210112\Calluna_Molinea.csv',
col='PlotObservationID', target_eunis='S42')
doren.overwrite_eunis(source_file=r'W:\PROJECTS\Doren19\a_brondata\EVA\delivery_20210112\Empetrum_Avenula.csv',
col='PlotObservationID', target_eunis='S42')
doren.overwrite_eunis(source_file=r'W:\PROJECTS\Doren19\a_brondata\EVA\delivery_20210112\Empetrum_Molinea.csv',
col='PlotObservationID', target_eunis='S42')
doren.overwrite_eunis(source_file=r'W:\PROJECTS\Doren19\a_brondata\EVA\delivery_20210112\Erica_Avenula.csv',
col='PlotObservationID', target_eunis='S41')
doren.overwrite_eunis(source_file=r'W:\PROJECTS\Doren19\a_brondata\EVA\delivery_20210112\Erica_Molinea.csv',
col='PlotObservationID', target_eunis='S41')
doren.get_requested_species(xls=sp_req_src, sheet=sp_req_sheet, col=column, skip=skip, simplify_names=True)
doren.add_covar(covar_dir=cv_cntr_dir, covar_src=cv_cntr_src, covar_name='country', raster=False, column='SOV_A3')
doren.add_covar(covar_dir=cv_soil_dir, covar_src=cv_soil_src, covar_name='soil_type', nominal=True)
doren.add_yearly_covar(covar_dir=cv_precp_dir, covar_src_basename=cv_precp_src, covar_name='five_yearly_precip')
doren.add_yearly_covar(covar_dir=cv_temp_dir, covar_src_basename=cv_temp_src, covar_name='five_yearly_temp')
doren.add_eunis()
doren.eunis2structuur()
doren.add_posch_single(posch_src_dir=param_posch_single)
doren.add_posch_differentiated(posch_src_dir=param_posch_diff)
doren.test()
'''
sp = 'Holcus lanatus'
doren.select_plts_w_species(species_name=sp)
for structuurtype in doren.structuurtypes:
doren.nearest_positive_queryd(col='structuurtype', val=structuurtype)
doren.get_bedekking_selected_sp()
doren.write_stuff('plot_covars_file')
doren.write_stuff('species_single_file')
'''
doren.write_stuff('plot_covars_file')
doren.write_stuff('report')
......
......@@ -20,4 +20,4 @@ echo $SLURM_ARRAY_TASK_ID
# Run
cd /home/WUR/roelo008/projs/doren_2019
python run_species.py $SLURM_ARRAY_TASK_ID 50 doren_20201209.pkl
\ No newline at end of file
python run_species.py $SLURM_ARRAY_TASK_ID 50 doren_20210113.pkl
\ No newline at end of file
......@@ -18,7 +18,7 @@ n_batches = int(args.n_batches)
# Recover the Pickled doren object
pkl_src = os.path.join('./pkl_src/', args.pkl)
# pkl_src = r'c:\Users\roelo008\OneDrive - WageningenUR\a_projects\DOREN\b_compiled_data\a_pkl\doren_20201201.pkl'
# pkl_src = r'c:\Users\roelo008\OneDrive - WageningenUR\a_projects\DOREN\b_compiled_data\a_pkl\doren_20201209.pkl'
with open(pkl_src, 'rb') as handle:
doren = pickle.load(handle)
......
"""
Helper functions for the DOREN project
Helper functions for the DOREN project.
"""
......
......@@ -320,6 +320,12 @@ class Doren:
def add_posch_single(self, posch_src_dir):
"""
Add NDep data from Max Posch from *.csv file where rows are PlotIDs and Columns are years. This function
is tailored towards the Posch data that are not differentiated between ruwheidsfactor
:param posch_src_dir: directory containing the source data
:return: additional columns to self.eva
"""
# posch_src_dir = r'\\wur\dfs-root\PROJECTS\Doren19\a_brondata\POSCH_dep\20200401delivery'
try:
......@@ -533,12 +539,12 @@ class Doren:
def add_yearly_covar(self, covar_dir, covar_src_basename, covar_name, nominal=False):
"""
Add a covariable column to self.eva that is differentiated per year
:param covar_dir:
Add a covariable column to self.eva that is differentiated per year based on yearly geospatial rasters
:param covar_dir: directory containing the geospatial rasters
:param covar_src_basename: basename of yearly rasters. Assumed: <covar_src_basename><year>.tif
:param covar_name:
:param nominal:
:return:
:param covar_name: name of the covariable as to appear in self.eva columns
:param nominal: boolean, is the covariable nominal?
:return: additional column covar_name to self.eva
"""
# get all years present in the EVA header dataframe
......@@ -559,7 +565,7 @@ class Doren:
self.report += 'Added Covariable {0} from {1} with {2} plots remaining.\n'.format(covar_name, covar_dir,
self.status['n_plots'])
def add_eunis(self):
def eunis2structuur(self):
"""
Add doorvertaling van EUNIS type to self.eva, based on vertalingstabellen in Teams
EUNIS --> Structuurtype
......@@ -656,7 +662,7 @@ class Doren:
def get_bedekking_selected_sp(self):
"""
Create Series of bedekking of self.sel_species in all positive plots
:return:
:return: pandas Series as new attribute self.sel_sp_coverage
"""
extract = self.spec.loc[self.spec.species_name_hdr == self.sel_species, ['plot_obs_id', 'cover_perc']]
# Pivot table to accomodate plots where self.sel_species occurs > 1. You can never know...
......@@ -673,6 +679,7 @@ class Doren:
def filter_by_buffer_around_positive_plots(self, buffer_size):
"""
Filter plots by buffering X meter around self.positive plots
: param buffer_size: buffer size in meters.
:returns self.buffer_gdf: geodataframe with polygon geometry of all buffers *buffer_size* around
self.positive_plots
self.nearby_plots: plots w/o self.sel_species but within buffer
......@@ -765,6 +772,24 @@ class Doren:
self.eva.loc[query, 'nearest_+_{}_id'.format(colname)] = self.eva.loc[query, 'plot_obs_id']
self.eva.loc[other, 'nearest_+_{}_id'.format(colname)] = np.nan
def overwrite_eunis(self, target_eunis, source_file, col):
"""
Manually overwrite assigned EUNIS type of selected plot_ids to a new EUNIS type
:param target_eunis: new EUNIs type
:param source_file: source file containing plot IDs
:param col: column in source_file
:return: updated self.eva and self.report
"""
df = pd.read_csv(source_file, sep='\t')
plot_ids = df[col]
sel_plot_ids = set(plot_ids).intersection(self.eva.index)
self.eva.loc[sel_plot_ids, 'EUNIS_New'] = target_eunis
msg = 'Manual overwrite EUNIS type for {0} plots to {1} based on {2}\n' \
.format(len(sel_plot_ids), target_eunis, source_file)
self.report += msg
def write_stuff(self, what, covars=False):
"""
Write contents to file. This should prob be organised as: self.generate_report(X) and then self.write_report(x)
......
"""
Class containing several output methods for DOREN objects
"""
import doren_classes as dc
\ No newline at end of file
"""
Verify that EUNIS types are translated 1:1 to structuurtypen
HDR 30/11/2020
"""
import pandas as pd
eunis_new = pd.read_excel(
r'c:\Users\roelo008\Wageningen University & Research\DOREN - General\EUNIS\EUNIS-classification.xlsx',
sheet_name='eindlijst opgeschoond')
eunis_old = pd.read_excel(
r'c:\Users\roelo008\Wageningen University & Research\DOREN - General\EUNIS\Selectie_oude_EUNIS_typecodes.xlsx',
sheet_name='eindlijst opgeschoond')
# NO NAs
assert eunis_new.drop('tweede type', axis=1).isna().sum(axis=0).sum() == 0
assert eunis_old.drop('tweede type', axis=1).isna().sum(axis=0).sum() == 0
# NEW EUNIS code to Structuurtype
piv = pd.pivot_table(data=eunis_new, index='eunis_code', columns='type', values='hoog_laag', aggfunc='count')
piv['stype_count'] = piv.notna().sum(axis=1)
assert piv.drop(piv.loc[piv.stype_count == 1].index).empty
# OLD EUNIS code to Structuurtype
piv = pd.pivot_table(data=eunis_old, index='EUNIS_OLD', columns='type', values='hoog_laag', aggfunc='count')
piv['stype_count'] = piv.notna().sum(axis=1)
assert piv.drop(piv.loc[piv.stype_count == 1].index).empty
# test from clas
eunis_new.fillna(value='?', inplace=True)
eunis_old.fillna(value='?', inplace=True)
# mappings from old/new eunis types to Wieger Wamelink categories. Also include "?" as key
eunis_new2structuur = {**dict(zip(eunis_new.eunis_code, eunis_new.type)), **{'?': '?'}}
eunis_new2bos = {**dict(zip(eunis_new.eunis_code, eunis_new.hoog_laag)), **{'?': '?'}}
eunis_old2structuur = {**dict(zip(eunis_old.EUNIS_OLD, eunis_old.type)), **{'?': '?'}}
eunis_old2bos = {**dict(zip(eunis_old.EUNIS_OLD, eunis_old.hoog_laag)), **{'?': '?'}}
\ No newline at end of file
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment