import requests
import pandas as pd
pd.options.mode.chained_assignment = None # default='warn'
import geopandas as gpd
from tqdm import tqdm
import shapely.geometry
class telechargement_geo_spatial():
"""Méthode de télécharment des observations d'une observedProperties par intersection spatiale et filtre temporel
Attributes:
url_service (string): url du service sensorthing
geom (geometry): geometry pour réaliser l'intersection
obsP (string): observedProperty ciblée
date_start (string): date de début d'observation
date_end (string): date de fin d'observation
"""
def __init__(self, url_service, geom, obsP, date_start, date_end):
self.url_service = url_service
self.geom = geom
self.obsP = obsP
self.date_start = date_start
self.date_end = date_end
if self.geom.geom_type == 'MultiPolygon':
print("MultipolygonE, conversion en polygone")
self.geom =self.geom.geoms[0]
def get_data(self,url_requete):
"""Télécharge les données d'une requête sensorthing avec itération dans les pages
Args:
url_requete (str): url à télécharger
Returns:
dataframe: dataframe (pandas) des données téléchargées
"""
r=requests.get(url=url_requete)
if r.status_code not in [200, 201, 202]:
print(r.status_code)
if r.status_code == 414:
print("url trop grande = la géometrie en entrée est trop complexe \n \
tentative d'intersection par la bounding box")
self.geom=shapely.geometry.box(*self.geom.bounds, ccw=True)
url_requete=self.inter_geo_temporelle()
print(url_requete)
r=requests.get(url=url_requete)
data=r.json()
df_all=pd.DataFrame(data['value'])
while '@iot.nextLink' in data:
r=requests.get(url=data['@iot.nextLink'])
data=r.json()
df_all=pd.concat([df_all,pd.DataFrame(data['value'])])
return df_all
def inter_geo_temporelle(self):
"""Façonne l'url de requête selon les différents arguments de la classe
Returns:
string: url avec les filtres
"""
objet='Datastreams'
rqt=f"$filter=geo.intersects(Thing/Locations/location, geography'{self.geom}') \
and ObservedProperty/name eq'{self.obsP}'\
&$select=name,description,unitOfMeasurement,Observations,phenomenonTime\
&$expand=Thing/Locations($select=name,@iot.id,location)"
url_rqt=f"{self.url_service}{objet}?{rqt}"
print("Requête générée:\n")
#print(url_rqt)
return url_rqt
def get_all(self,df):
"""Télécharge les observations des datastreams
Args:
df (dataframe): dataframe des datastreams avec une colonne contenant les lien vers les observations
Returns:
dataframe: dataframe des données téléchargées pour tous les datastreams avec les coordonnées géographiques de chaque observations
"""
df_data=pd.DataFrame()
print("\nTéléchargement en cours : \n")
for idx,row in tqdm(df.iterrows(), total=df.shape[0]):
#print(row['Observations@iot.navigationLink'])
rqt=row['Observations@iot.navigationLink']
rqt+=f"?$select=result,phenomenonTime&$filter=phenomenonTime ge {self.date_start} and phenomenonTime le {self.date_end}"
df_inter=pd.DataFrame(self.get_data(rqt))
df_inter['name']=row['name']
df_inter['x']=row['Thing']['Locations'][0]['location']['geometry']['coordinates'][0]
df_inter['y']=row['Thing']['Locations'][0]['location']['geometry']['coordinates'][1]
df_data=pd.concat([df_data,df_inter])
df_data=df_data.reset_index(drop=True)
self.unite = row['unitOfMeasurement']['name']
self.symbol = row['unitOfMeasurement']['symbol']
return df_data
def telechargement(self):
"""Fonction qui automatise la classe
Returns:
dataframe: dataframe des données téléchargées pour tous les datastreams avec les coordonnées géographiques de chaque observations
"""
print(f"Recherche des Datastreams par l'ObservedProperty : {self.obsP} par intersection spatial sur la période : {self.date_start} {self.date_end}")
url_rqt = self.inter_geo_temporelle()
df_rqt = self.get_data(url_rqt)
if len(df_rqt) == 0:
print("\nIl n'y a pas d'objet dans la zone d'intersection, veuillez changer de zone")
return 0
else:
print(f"\nNombre d'objet à téléchargerger :{len(df_rqt)}")
#faire un retour si pas d'objet
#refaire la requete si erreur 414 par bounding box
df = self.get_all(df_rqt)
df=df.rename(columns={'result':self.obsP})
return df
zone=gpd.read_file('/home/tloree/bosco/bv_cible.geojson')
print(zone.crs)
zone=zone.to_crs('EPSG:4326')
print(zone.crs)
zone.plot()
url_service='https://frost.geosas.fr/bosco/v1.1/'
geom=zone.geometry[0]
obsP="Soil moisture"
date_start, date_end = '2017-01-01T00:00:00Z','2021-01-01T00:00:00Z'
instance = telechargement_geo_spatial(url_service, geom, obsP, date_start, date_end)
df = instance.telechargement()
unite = instance.unite
symbol = instance.symbol
display(df)