diff --git a/5_GEONATURE/MIGRATION/RNGL/serena.py b/5_GEONATURE/MIGRATION/RNGL/serena.py new file mode 100644 index 0000000..750b920 --- /dev/null +++ b/5_GEONATURE/MIGRATION/RNGL/serena.py @@ -0,0 +1,208 @@ +from pycen import con_sicen, update_to_sql +from sqlalchemy import create_engine # pour lecture de la bd Géonature +from sqlalchemy.engine import URL +from shapely.geometry import Polygon +import geopandas as gpd +import pandas as pd +import json +import matplotlib.pyplot as plt + +PATH = '/home/colas/Documents/9_PROJETS/6_GEONATURE/MIGRATION/RNGL/DUMP/' +FILE = 'export_rnngl.txt' + +usr = 'postgres' +pdw = 'postgres' +bdd = 'serenadb' +host = '172.17.0.2' + +eng = URL.create('postgresql+psycopg2',username=usr,password=pdw,host=host,database=bdd) +conn = create_engine(eng) + +tax = pd.read_sql_table('rnf_taxo',con=conn,schema='serenarefe') +obs = pd.read_sql_table('rnf_obse',con=conn,schema='serenabase') +sit = pd.read_sql_table('rnf_site',con=conn,schema='serenabase') +exp = pd.read_table(PATH+FILE,sep='\t',encoding='Windows-1252',dtype={'OBSE_NOMBRE':str,'OBSE_ABOND_CHOI':str,'OBSE_DATE':str}) +exp.columns = exp.columns.str.lower() +exp[['obse_lat','obse_lon','obse_nombre','oglat','oglon']] = exp[['obse_lat','obse_lon','obse_nombre','oglat','oglon']].replace(',','.',regex=True) +cols_coord = exp.columns[exp.columns.str.endswith('lat|lon')] +year_only = exp.obse_date.str.len() == 4 +month_only = exp.obse_date.str.len() == 6 +exp.loc[year_only,'obse_date'] = exp.loc[year_only,'obse_date'] + '0101' +exp.loc[month_only,'obse_date'] = exp.loc[month_only,'obse_date'] + '01' +exp = (gpd.GeoDataFrame( + exp,crs=4326, + geometry=gpd.points_from_xy(exp.oglon,exp.oglat)) + .to_crs(2154)) +exp['obse_date'] = pd.to_datetime(exp.obse_date) + +# Re-création des géométries des sites +sit['poly'] = (sit + .site_poly.str[9:] + .str.split(',')) + +sit.loc[sit.poly.notna(),'geom'] = (sit.loc[sit.poly.notna(),'poly'] + .apply(lambda x: [xx.split(' ') for xx in x if xx]) + .apply(lambda x: [[float(xxx) for xxx in xx] for xx in x ]) + .apply(lambda x: Polygon(x))) + +sit = (sit + .set_geometry('geom',crs=4326) + .to_crs(2154)) + +# Création des géométries à partir des coordonnées +geom_na = obs.geom_obse.isna() +idx = obs[geom_na].obse_id.tolist() + +# Test des données de l'export +exp[exp.obse_id.isin(idx)] + + +# Mise à jour des observations-sites +obs_sit = (obs[geom_na] + .merge(sit[['site_id','geom']],how='left',left_on='obse_site_id',right_on='site_id') + .set_geometry('geom',crs=2154)) +update_to_sql( + obs_sit[['obse_id','geom']].rename_geometry('geom_site'), + conn,'rnf_obse','serenabase','obse_id') + +#### IDENTIFICATION SERENA-GLEMPS ON SICEN #### + + +#### IDENTIFICATION SERENA-GLEMPS ON SICEN #### +obs = pd.read_sql_table('rnf_obse',con=conn,schema='serenabase') +sic = pd.read_sql_table('saisie_observation',con=con_sicen,schema='saisie') +vsi = pd.read_sql_table('v_saisie_observation',con=con_sicen,schema='saisie') +# vmsi = pd.read_sql_table('vm_synthese_observations',con=con_sicen,schema='saisie') +vmsi = gpd.read_postgis('SELECT * FROM saisie.vm_synthese_observations',con_sicen,crs=2154) +vmsi['date_obs'] = pd.to_datetime(vmsi.date_obs) +test_obsEXP = exp.obsv_libel.str.contains('BIRON|JUTON|MARRON',na=False) +exp[test_obsEXP] + +id_obsGL = obs.obse_id.astype(str).tolist() +t1_obsVM = ~vmsi.observateurs_v2.str.contains('BIRON',na=False) +t2_obsVM = vmsi.rmq_localisation.str.contains('GRAND-LEMPS|GRAND LEMPS',na=False,case=False) +t3_obsVM = ~vmsi.id_origine.isin(exp[test_obsEXP].obse_id.astype(str)) +t4_obsVM = vmsi.date_obs <= '2019-01-01' +t5_obsVM = vmsi.etude != 'Import données Pro Faune Isère' +t6_obsVM = vmsi.id_origine.isin(id_obsGL) + +GL = vmsi[t2_obsVM&t1_obsVM].copy() +GL['lat'] = GL.to_crs(4326).geometry.y.round(10).astype(str) +GL['lon'] = GL.to_crs(4326).geometry.x.round(10).astype(str) + +while (GL.lat.str.len()==13).all() == False: + GL.loc[GL.lat.str.len()<13,'lat'] = GL[GL.lat.str.len()<13].lat + '0' + +while (GL.lon.str.len()==12).all() == False: + GL.loc[GL.lon.str.len()<12,'lon'] = GL[GL.lon.str.len()<12].lon + '0' + +test = GL[['lat','lon']].eq(exp[['oglat','oglon']]) +test = GL.intersects(exp.unary_union) +GL[test] +# 18819 Données dans Sicen Qui concerne le Grand-Lemps +data_gl = vmsi[t6_obsVM] +t7 = ~vmsi.id_obs.isin(data_gl.id_obs) +GL = vmsi[t1_obsVM&t2_obsVM&t4_obsVM&t5_obsVM&t7].copy() +4259862565 +45.4259862565 + +id_obs = obs.obse_id.astype(str).tolist() +vsi[vsi.id_origine.isin(id_obs)].astype({'id_origine':int}).sort_values('id_origine') +vsi[vsi.id_origine.isin(id_obs)].date_obs.max() + +loc_glps = vsi.localisation.str.contains('ETANG DU GRAND-LEMPS',na=False) +vsi[loc_glps].observateur.unique() +loc_glps = vmsi.rmq_localisation.str.contains('ETANG DU GRAND-LEMPS',na=False) +loc_avenir = vmsi.observateurs_v2.str.contains('BIRON|JUTON|MARRON',na=False) +vmsi[loc_glps&~loc_avenir].observateurs_v2.unique() +(vsi[loc_glps].observateur + .astype(list)) + + +## By OBSV_LIBEL + DATE +rnn = exp.copy() +rnn.obsv_libel = (rnn.obsv_libel + .replace(r'\(.*?\)','',regex=True) + .str.strip() + .replace({' - ':' '},regex=True) + .replace({' ':' '},regex=True) + .replace({' et ':' & '},regex=True) + .replace({'&':','},regex=True) + .replace({' , ':', '},regex=True) + .replace({' , ':', '},regex=True) + .apply(lambda x: ', '.join(sorted(x.split(', '))))) + +sieg = vmsi.copy() +sieg.observateurs_v2 = (sieg.observateurs_v2 + .replace(r'\(.*?\)','',regex=True) + .str.strip() + .replace({' ':' '},regex=True) + .replace({' ,':', '},regex=True) + .replace({' ,':', '},regex=True) + .apply(lambda x: ', '.join(sorted(x.split(', '))))) + +sit.set_index('site_id',inplace=True) + +lst_etude_serena = [ + 'Protocole de suivi AVENIR', + 'Veille écologique AVENIR', + 'Anciennes BD AVENIR', + 'BIBLIOGRAPHIE', + 'Échange de données - CORA Rhône', + 'Veille écologique', + 'Échange de données - CBNA', + 'Echange de données - GRPLS', + # 'Echange de données (partenaires)' +] +t1 = sieg.observateurs_v2.isin(rnn.obsv_libel) +t2 = sieg.date_obs.isin(rnn.obse_date) +t3 = sieg.intersects(sit.iloc[2].geom.buffer(0)) +t4 = sieg.etude.isin(lst_etude_serena) +t4 = sieg.etude=='Échange de données - CORA Rhône' +sieg[t1&t2&t3&t4] # Données à écarter. 15212 données dans Sicen qui concerne le Grand-Lemps +# 10404 dans le Grand-Lemps avant le 01-01-2018 + +date_max = sieg[t1&t2&t3&t4].date_obs.max() +rnn[rnn.obse_date <= date_max] +t5 = sieg.date_obs==date_max +sieg[t1&t2&t3&t4&(~t5)] +dat_max2 = sieg[t1&t2&t3&t4&(~t5)].date_obs.max() +t6 = sieg.date_obs==dat_max2 +sieg[t1&t2&t3&t4&(~t5)&(~t6)] +sieg[t1&t2&t3&t4&t6] + +dict_col = { + 'observateurs_v2':'obsv_libel', + 'date_obs':'obse_date', + # 'lot_donnee':'lot_donnee', + 'etude':'relv_nom', + 'nom_complet':'taxo_latin_c', + # 'geom':'geometry', +} +fusion = pd.concat( + [sieg[t1&t2&t3&t4].rename(columns=dict_col)[[*dict_col.values()]], + rnn[[*dict_col.values()]]], +) + + +#### Test equivalence [obse_lat - oglat, obse_lon - oglon] +# Columns : + # obsv_libel : Observateur + # obse_date : date d'Observation + +test = exp[exp.obse_lat.notna()] +tlat = test.obse_lat.eq(test.oglat) +tlon = test.obse_lon.eq(test.oglon) +test[~tlat].index.equals(test[~tlon].index) +test[~tlat] +test[~tlon] + +lst_tax = tax.taxo_id.tolist() +test = obs[~obs.obse_taxo_id.isin(lst_tax)] + +# ERREUR: une instruction insert ou update sur la table « rnf_obse » viole la contrainte de clé +# étrangère « rnf_obse_rnf_user_fk » +# Détail : La clé (obse_obsv_id)=(6052) n'est pas présente dans la table « rnf_user ». +test = ~vmsi.observateurs_v2.str.contains('Isère|Personnel',na=False,case=False) +vmsi[test] +vmsi[test].observateurs_v2