# -*- coding: utf-8 -*-
"""
Created on Tue Sep 17 16:58:10 2024
@author: Alexandre Kenshilik Coche
@contact: alexandre.co@hotmail.fr
download.py est un ensemble de fonctions permettant le téléchargement
automatique de données françaises nécessaires à la modélisation
hydrologique des socio-écosystèmes.
Cet outil a notamment vocation à regrouper les données classiques nécessaires
au modèle CWatM utilisé dans le cadre de la
méthodologie Eau et Territoire (https://eau-et-territoire.org ).
"""
#%% IMPORTATIONS
import os
import re
import requests
import datetime
from io import (BytesIO, StringIO)
import gzip
import numpy as np
import pandas as pd
import geopandas as gpd
from shapely.geometry import Point
import xarray as xr
xr.set_options(keep_attrs = True)
from geop4th import (
geobricks as geo,
utils,
)
from geop4th.download.download_sim2 import download_sim2 # redirected to new module
#%% LIST ALL FUNCTIONALITIES
def download_available():
excluded_funcs = {
'valid_request',
'valid_single_request',
}
utils.available(__name__,
ignore = excluded_funcs,
)
#%% Utilitaries to check if a request is valid
[docs]
def valid_request(response,
file_format = 'geojson',
prev_frame = None):
"""
Utilitary to check if a request is valid.
Parameters
----------
response : request.response
`request` object that contains a server's response to an HTTP request.
This ``response`` variable can be obtained with ``requests.get(<url>)``
file_format : {'csv', 'json', 'geojson'}, default 'geojson'
File format in which the data will be retrieved.
prev_frame : pandas.DataFrame or geopandas.GeoDataFrame, optional
Frame used for recurrence run (when request results are on several pages)
Returns
-------
isvalid : bool
Flag indicating if the request has succeeded.
frame : pandas.DataFrame of geopandas.GeoDataFrame
Frame contaning the downloaded values.
If ``file_format`` is 'geojson', returns a geopandas.GeoDataFrame, otherwise
return a pandas.DataFrame (non-geospatialized data).
"""
isvalid = False
frame = prev_frame
if (response.status_code == 200): # all correct, one single page
_, frame = valid_single_request(response, file_format)
elif (response.status_code == 206): # correct but results are on several pages
isvalid, frame = valid_single_request(response, file_format)
# Safeguard preventing technical limitations of BNPE API (max request size)
# BNPE API can not handle more than 20000 results in one request
if 'last' in response.links:
page_pattern = re.compile("page=(\d*)")
n_page = page_pattern.findall(response.links['last']['url'])
if len(n_page) > 0:
n_results = int(n_page[0]) * frame.shape[0]
if n_results > 20000:
print(f"\nErr: Up to {n_results} results were asked but BNPE API cannot retrieve more than 20000 results in one request. If you passed a `masks` argument, please provide smaller masks.")
return False, None
if prev_frame is not None:
frame = pd.concat([prev_frame, frame], axis = 0, ignore_index = True)
for col in ['codes_points_prelevements', 'uri_bdlisa']:
if col in frame.columns:
frame[col] = frame[col].apply(
lambda v: tuple(v.tolist()) if isinstance(v, np.ndarray) else (tuple(v) if isinstance(v, list) else v)
)
frame = frame.drop_duplicates()
if 'next' in response.links:
response = requests.get(response.links['next']['url'])
_, frame = valid_request(response, file_format,
prev_frame = frame)
elif (response.status_code == 400):
print("Err: Incorrect request")
elif (response.status_code == 401):
print("Err: Unauthorized")
elif (response.status_code == 403):
print("Err: Forbidden")
elif (response.status_code == 404):
print("Err: Not Found")
elif (response.status_code == 500):
print("Err: Server internal error")
# if frame is not None
if isinstance(frame, pd.DataFrame):
isvalid = True
return isvalid, frame
def valid_single_request(response,
file_format = 'geojson'):
"""
Utilitary to check if a request is valid.
Parameters
----------
response : request.response
`request` object that contains a server's response to an HTTP request.
This ``response`` variable can be obtained with ``requests.get(<url>)``
file_format : {'csv', 'json', 'geojson'}, default 'geojson'
File format in which the data will be retrieved.
Returns
-------
isvalid : bool
Flag indicating if the request has succeeded.
frame : pandas.DataFrame of geopandas.GeoDataFrame
Frame contaning the downloaded values.
If ``file_format`` is 'geojson', returns a geopandas.GeoDataFrame, otherwise
return a pandas.DataFrame (non-geospatialized data).
"""
# ---- Determine validity of downloaded data
isvalid = False
if file_format == 'csv':
if response.text != '': # not empty
isvalid = True
elif file_format in ['json', 'geojson']:
if response.json()['count'] != 0: # not empty
isvalid = True
if isvalid:
# ---- Retrieve results as a dataframe
# Save data content into a DataFrame (or a GeoDataFrame)
if file_format == 'csv':
frame = pd.read_csv(BytesIO(response.content), sep=";")
elif file_format == 'geojson':
# For some datasets, the 'GeoJSON' format option is not available,
# only classic JSON is retrieved
# In these cases, if the user requires a GeoJSON, the JSON dict
# needs to be converted to GeoJSON before export :
if 'type' in response.json():
if response.json()['type'] == 'FeatureCollection':
# Response content is truly a GeoJSON
json_to_geojson = False
else:
json_to_geojson = True
else:
json_to_geojson = True
if json_to_geojson:
# Additional step of georefencing are necessary
json_df = pd.DataFrame.from_dict(response.json()['data'])
geometry = [Point(xy) for xy in zip(json_df.longitude,
json_df.latitude)]
frame = gpd.GeoDataFrame(
json_df,
crs = 4326,
geometry = geometry)
else:
frame = gpd.read_file(response.text, driver='GeoJSON')
elif file_format == 'json':
# =============== useless =====================================================
# data_stations = pd.DataFrame.from_dict(
# {i: response.json()['data'][i] for i in range(len(response.json()['data']))},
# orient = 'index')
# =============================================================================
frame = pd.DataFrame.from_dict(response.json()['data'])
else:
frame = None
return isvalid, frame
#%% BNPE (Données de prélèvements)
[docs]
def download_bnpe(*, dst_folder,
start_year = None,
end_year = None,
masks = None,
departments = None,
communes = None,
file_formats = 'geojson'):
"""
Function to facilitate the downloading of French water withdrawal data from BNPE API.
Parameters
----------
dst_folder : str or pathlib.Path
Destination folder in which the downloaded data will be stored.
start_year : int, optional
Year from which the data will be retrieved.
end_year : int, optional
Year until which the data will be retrieved.
masks : list of-, or single element among str, pathlib.Path, xarray.Dataset, xarray.DataArray or geopandas.GeoDataFrame, optional
Mask on which the data will be retrieved.
At least one parameter among ``masks``, ``departments`` or ``communes``
should be passed.
departments : int or list of int, optional
INSEE code(s) of department(s) for which data will be retrieved.
At least one parameter among ``masks``, ``departments`` or ``communes``
should be passed.
communes : int or list of int, optional
INSEE code(s) of commune(s) for which data will be retrieved.
At least one parameter among ``masks``, ``departments`` or ``communes``
should be passed.
file_formats : str or list of str, {'csv', 'json', 'geojson'}, default 'geojson'
File format in which the data will be retrieved.
Returns
-------
None. Downloaded data is stored in ``dst_folder``
"""
# ---- Argument retrieving
# Safeguard
if (departments is None) & (communes is None) & (masks is None):
print("Err: It is required to specify at least one area with the arguments `departments` or `communes` or `masks`")
return
if start_year is None:
start_year = 2008
if end_year is None:
end_year = datetime.datetime.today().year
if isinstance(start_year, (str, float)):
start_year = int(start_year)
if end_year is None: # and start_year is not None, see previous case
years = [start_year]
else:
if isinstance(end_year, (str, float)):
end_year = int(end_year)
years = list(range(start_year, end_year + 1))
if masks is not None:
if isinstance(masks, tuple):
masks = list(masks)
elif not isinstance(masks, list):
masks = [masks]
if departments is not None:
if isinstance(departments, (str, float)):
departments = [int(departments)]
elif isinstance(departments, int):
departments = [departments]
elif isinstance(departments, tuple):
departments = list(departments)
if communes is not None:
if isinstance(communes, (str, float)):
communes = [int(communes)]
elif isinstance(communes, int):
communes = [communes]
elif isinstance(communes, tuple):
communes = list(communes)
if isinstance(file_formats, str):
file_formats = [file_formats]
for i in range(0, len(file_formats)):
# file_formats = file_formats.replace('.', '')
if file_formats[i][0] == '.': file_formats[i] = file_formats[i][1:]
file_formats = [ff.casefold() for ff in file_formats] # convert to lowcase
outdir = os.path.join(dst_folder, "originaux")
if not os.path.exists(outdir): os.makedirs(outdir)
outdir_ouvrages = os.path.join(dst_folder, "originaux", "ouvrages")
if not os.path.exists(outdir_ouvrages): os.makedirs(outdir_ouvrages)
# ---- Requests
print("\nDownloading...")
for y in years:
y = int(y)
print(f"\n . {y}")
if departments is not None:
for d in departments:
d = f"{d:02.0f}" # format '00'
for f in file_formats:
if f == 'csv':
url = rf"https://hubeau.eaufrance.fr/api/v1/prelevements/chroniques.csv?annee={y}&code_departement={d}&size=5000"
outpath = os.path.join(outdir, f"dpmt{d}_{y}.csv")
elif f == 'geojson':
url = rf"https://hubeau.eaufrance.fr/api/v1/prelevements/chroniques?annee={y}&code_departement={d}&format=geojson&size=5000"
outpath = os.path.join(outdir, f"dpmt{d}_{y}.json")
elif f == 'json':
url = rf"https://hubeau.eaufrance.fr/api/v1/prelevements/chroniques?annee={y}&code_departement={d}&size=5000"
outpath = os.path.join(outdir, f"dpmt{d}_{y}.json")
response = requests.get(url)
isvalid, frame = valid_request(response, f)
if isvalid:
# Export
if f == 'csv':
geo.export(frame, outpath, sep = ';', encoding = 'utf-8', index = False)
else:
geo.export(frame, outpath)
if communes is not None:
for c in communes:
c = f"{c:<05.0f}" # format '000000'
for f in file_formats:
if f == 'csv':
url = rf"https://hubeau.eaufrance.fr/api/v1/prelevements/chroniques.csv?annee={y}&code_commune_insee={c}&size=5000"
outpath = os.path.join(outdir, f"cmne{c}_{y}.csv")
elif f == 'geojson':
url = rf"https://hubeau.eaufrance.fr/api/v1/prelevements/chroniques?annee={y}&code_commune_insee={c}&format=geojson&size=5000"
outpath = os.path.join(outdir, f"cmne{c}_{y}.json")
elif f == 'json':
url = rf"https://hubeau.eaufrance.fr/api/v1/prelevements/chroniques?annee={y}&code_commune_insee={c}&size=5000"
outpath = os.path.join(outdir, f"cmne{c}_{y}.json")
response = requests.get(url)
isvalid, frame = valid_request(response, f)
if isvalid:
# Export
if f == 'csv':
geo.export(frame, outpath, sep = ';', encoding = 'utf-8', index = False)
else:
geo.export(frame, outpath)
if masks is not None:
i_mask = 0
for m in masks:
i_mask += 1
mask_ds = geo.load(m)
mask_ds = geo.reproject(mask_ds, dst_crs = 4326)
for f in file_formats:
if f == 'csv':
url = rf"https://hubeau.eaufrance.fr/api/v1/prelevements/chroniques.csv?annee={y}&bbox={mask_ds.total_bounds[0]}&bbox={mask_ds.total_bounds[1]}&bbox={mask_ds.total_bounds[2]}&bbox={mask_ds.total_bounds[3]}&size=5000"
outpath = os.path.join(outdir, f"mask{i_mask}_{y}.csv")
elif f == 'geojson':
url = rf"https://hubeau.eaufrance.fr/api/v1/prelevements/chroniques?annee={y}&bbox={mask_ds.total_bounds[0]}&bbox={mask_ds.total_bounds[1]}&bbox={mask_ds.total_bounds[2]}&bbox={mask_ds.total_bounds[3]}&format=geojson&size=5000"
outpath = os.path.join(outdir, f"mask{i_mask}_{y}.json")
elif f == 'json':
url = rf"https://hubeau.eaufrance.fr/api/v1/prelevements/chroniques?annee={y}&bbox={mask_ds.total_bounds[0]}&bbox={mask_ds.total_bounds[1]}&bbox={mask_ds.total_bounds[2]}&bbox={mask_ds.total_bounds[3]}&size=5000"
outpath = os.path.join(outdir, f"mask{i_mask}_{y}.json")
response = requests.get(url)
isvalid, frame = valid_request(response, f)
# ======= {draft} to automatically handle too large requests ==================
# isvalid, frame, exceeds = valid_request(response, f)
#
# if exceeds:
# masks = [*masks[0:i_mask-1], split(masks[i_mask-1]), *masks[i_mask:]]
# bnpe(dst_folder = dst_folder, start_year = start_year,
# end_year = end_year, masks = masks,
# departments = departments, communes = communes,
# file_formats = file_formats)
# return
# =============================================================================
if isvalid:
# In the `mask` case, the data is clipped to the mask
if isinstance(frame, gpd.GeoDataFrame):
frame = geo.reproject(frame, mask = m)
else: # frame is only a pd.DataFrame
# first frame is converted to a GeoDataFrame
geometry = [Point(xy) for xy in zip(frame.longitude,
frame.latitude)]
gdf = gpd.GeoDataFrame(
frame,
crs = 4326,
geometry = geometry)
# Then it is clipped
gdf = geo.reproject(gdf, mask = m)
# Finally it is converted back to a DataFrame
frame = pd.DataFrame(gdf.drop(columns = 'geometry'))
# Export
if f == 'csv':
geo.export(frame, outpath, sep = ';', encoding = 'utf-8', index = False)
else:
geo.export(frame, outpath)
# Infos sur ouvrage
if departments is not None:
for d in departments:
d = f"{d:02.0f}" # format '00'
for f in file_formats:
if f == 'csv':
url = rf"https://hubeau.eaufrance.fr/api/v1/prelevements/referentiel/ouvrages.csv?code_departement={d}&size=5000"
outpath = os.path.join(outdir_ouvrages, f"dpmt{d}_ouvrages.csv")
elif f == 'geojson':
url = rf"https://hubeau.eaufrance.fr/api/v1/prelevements/referentiel/ouvrages?code_departement={d}&format=geojson&size=5000"
outpath = os.path.join(outdir_ouvrages, f"dpmt{d}_ouvrages.json")
elif f == 'json':
url = rf"https://hubeau.eaufrance.fr/api/v1/prelevements/referentiel/ouvrages?code_departement={d}&size=5000"
outpath = os.path.join(outdir_ouvrages, f"dpmt{d}_ouvrages.json")
response = requests.get(url)
isvalid, frame = valid_request(response, f)
if isvalid:
# Export
if f == 'csv':
geo.export(frame, outpath, sep = ';', encoding = 'utf-8', index = False)
else:
geo.export(frame, outpath)
if communes is not None:
for c in communes:
c = f"{c:<05.0f}" # format '000000'
for f in file_formats:
if f == 'csv':
url = rf"https://hubeau.eaufrance.fr/api/v1/prelevements/referentiel/ouvrages.csv?code_commune_insee={c}&size=5000"
outpath = os.path.join(outdir_ouvrages, f"cmne{c}_ouvrages.csv")
elif f == 'geojson':
url = rf"https://hubeau.eaufrance.fr/api/v1/prelevements/referentiel/ouvrages?code_commune_insee={c}&format=geojson&size=5000"
outpath = os.path.join(outdir_ouvrages, f"cmne{c}_ouvrages.json")
elif f == 'json':
url = rf"https://hubeau.eaufrance.fr/api/v1/prelevements/referentiel/ouvrages?code_commune_insee={c}&size=5000"
outpath = os.path.join(outdir_ouvrages, f"cmne{c}_ouvrages.json")
response = requests.get(url)
isvalid, frame = valid_request(response, f)
if isvalid:
# Export
if f == 'csv':
geo.export(frame, outpath, sep = ';', encoding = 'utf-8', index = False)
else:
geo.export(frame, outpath)
if masks is not None:
i_mask = 0
for m in masks:
i_mask += 1
mask_ds = geo.load(m)
mask_ds = geo.reproject(mask_ds, dst_crs = 4326)
for f in file_formats:
if f == 'csv':
url = rf"https://hubeau.eaufrance.fr/api/v1/prelevements/referentiel/ouvrages.csv?bbox={mask_ds.total_bounds[0]}&bbox={mask_ds.total_bounds[1]}&bbox={mask_ds.total_bounds[2]}&bbox={mask_ds.total_bounds[3]}&size=5000"
outpath = os.path.join(outdir_ouvrages, f"mask{i_mask}_ouvrages.csv")
elif f == 'geojson':
url = rf"https://hubeau.eaufrance.fr/api/v1/prelevements/referentiel/ouvrages?bbox={mask_ds.total_bounds[0]}&bbox={mask_ds.total_bounds[1]}&bbox={mask_ds.total_bounds[2]}&bbox={mask_ds.total_bounds[3]}&format=geojson&size=5000"
outpath = os.path.join(outdir_ouvrages, f"mask{i_mask}_ouvrages.json")
elif f == 'json':
url = rf"https://hubeau.eaufrance.fr/api/v1/prelevements/referentiel/ouvrages?bbox={mask_ds.total_bounds[0]}&bbox={mask_ds.total_bounds[1]}&bbox={mask_ds.total_bounds[2]}&bbox={mask_ds.total_bounds[3]}&size=5000"
outpath = os.path.join(outdir_ouvrages, f"mask{i_mask}_ouvrages.json")
response = requests.get(url)
isvalid, frame = valid_request(response, f)
if isvalid:
# In the `mask` case, the data is clipped to the mask
if isinstance(frame, gpd.GeoDataFrame):
frame = geo.reproject(frame, mask = m)
else: # frame is only a pd.DataFrame
# first frame is converted to a GeoDataFrame
geometry = [Point(xy) for xy in zip(frame.longitude,
frame.latitude)]
gdf = gpd.GeoDataFrame(
frame,
crs = 4326,
geometry = geometry)
# Then it is clipped
gdf = geo.reproject(gdf, mask = m)
# Finally it is converted back to a DataFrame
frame = pd.DataFrame(gdf.drop(columns = 'geometry'))
# Export
if f == 'csv':
geo.export(frame, outpath, sep = ';', encoding = 'utf-8', index = False)
else:
geo.export(frame, outpath)
#%% Hydrometry (Mesures de débits)
[docs]
def download_eaufrance(*, dst_folder,
masks,
start_year,
end_year = None,
quantities = 'QmnJ',
file_formats = 'geojson'):
"""
Function to facilitate the downloading of French hydrometry data from EauFrance API.
Parameters
----------
dst_folder : str or pathlib.Path
Destination folder in which the downloaded data will be stored.
masks : list of-, or single element among str, pathlib.Path, xarray.Dataset, xarray.DataArray or geopandas.GeoDataFrame, optional
Mask on which the data will be retrieved.
start_year : int, optional
Year from which the data will be retrieved.
end_year : int, optional
Year until which the data will be retrieved.
quantities : str or list of str, default 'QmnJ'
- 'QmnJ': average daily discharge
- 'QmM': average monthly discharge
- 'HIXM': maximum instant height per month
- 'HIXnJ': maximum instant height per day
- 'QINM': minimum instant discharge per month
- 'QINnJ': minimum instant discharge per day
- 'QixM': maximum instant discharge per month
- 'QIXnJ': maximum instant discharge per day
file_formats : str or list of str, {'csv', 'json', 'geojson'}, default 'geojson'
File format in which the data will be retrieved.
Returns
-------
None. Downloaded data is stored in ``dst_folder``
"""
# ---- Argument retrieving
if isinstance(start_year, (str, float)):
start_year = int(start_year)
if end_year is None:
years = [start_year]
else:
if isinstance(end_year, (str, float)):
end_year = int(end_year)
years = list(range(start_year, end_year + 1))
if masks is not None:
if isinstance(masks, tuple):
masks = list(masks)
elif not isinstance(masks, list):
masks = [masks]
if isinstance(file_formats, str):
file_formats = [file_formats]
for i in range(0, len(file_formats)):
# file_formats = file_formats.replace('.', '')
if file_formats[i][0] == '.': file_formats[i] = file_formats[i][1:]
if isinstance(quantities, str):
quantities = [quantities]
outdir = os.path.join(dst_folder, "originaux")
if not os.path.exists(outdir): os.makedirs(outdir)
outdir_stations = os.path.join(dst_folder, "originaux", "stations")
if not os.path.exists(outdir_stations): os.makedirs(outdir_stations)
# ---- Requests
print("\nDownloading...")
i_mask = 0
for m in masks:
i_mask += 1
mask_ds = geo.load(m)
mask_ds = geo.reproject(mask_ds, dst_crs = 4326)
# List of stations
for f in file_formats:
if f == 'csv':
url = rf"https://hubeau.eaufrance.fr/api/v2/hydrometrie/referentiel/stations.csv?bbox={mask_ds.total_bounds[0]}&bbox={mask_ds.total_bounds[1]}&bbox={mask_ds.total_bounds[2]}&bbox={mask_ds.total_bounds[3]}&size=10000"
outpath = os.path.join(outdir_stations, f"mask{i_mask}_stations.csv")
elif f == 'geojson':
url = url = rf"https://hubeau.eaufrance.fr/api/v2/hydrometrie/referentiel/stations?bbox={mask_ds.total_bounds[0]}&bbox={mask_ds.total_bounds[1]}&bbox={mask_ds.total_bounds[2]}&bbox={mask_ds.total_bounds[3]}&format=geojson&size=10000"
outpath = os.path.join(outdir_stations, f"mask{i_mask}_stations.json")
elif f == 'json':
url = url = rf"https://hubeau.eaufrance.fr/api/v2/hydrometrie/referentiel/stations?bbox={mask_ds.total_bounds[0]}&bbox={mask_ds.total_bounds[1]}&bbox={mask_ds.total_bounds[2]}&bbox={mask_ds.total_bounds[3]}&size=10000"
outpath = os.path.join(outdir_stations, f"mask{i_mask}_stations.json")
response = requests.get(url)
isvalid, data_stations = valid_request(response, f)
if isvalid:
# Data is clipped to the mask
if isinstance(data_stations, gpd.GeoDataFrame):
data_stations = geo.reproject(data_stations, mask = m)
else: # frame is only a pd.DataFrame
# first frame is converted to a GeoDataFrame
data_stations.loc[:, ['longitude', 'latitude']] = data_stations['coordLatLon'].str.split(',', expand = True).rename(columns = {0: 'latitude', 1: 'longitude'}).astype(float)
geometry = [Point(xy) for xy in zip(data_stations.longitude,
data_stations.latitude)]
gdf = gpd.GeoDataFrame(
data_stations,
crs = 4326,
geometry = geometry)
# Then it is clipped
gdf = geo.reproject(gdf, mask = m)
# Finally it is converted back to a DataFrame
data_stations = pd.DataFrame(gdf.drop(columns = ['geometry', 'latitude', 'longitude']))
# Export
if f == 'csv':
geo.export(data_stations, outpath, sep = ';', encoding = 'utf-8', index = False)
else:
geo.export(data_stations, outpath)
# Discharge data
for y in years:
y = int(y)
print(f" . {y}")
for station_id in data_stations['code_station']:
for f in file_formats:
for q in quantities:
if f == 'csv':
url = rf"https://hubeau.eaufrance.fr/api/v2/hydrometrie/obs_elab.csv?code_entite={station_id}&bbox={mask_ds.total_bounds[0]}&bbox={mask_ds.total_bounds[1]}&bbox={mask_ds.total_bounds[2]}&bbox={mask_ds.total_bounds[3]}&date_debut_obs_elab={y}-01-01&date_fin_obs_elab={y}-12-31&grandeur_hydro_elab={q}&size=20000"
outpath = os.path.join(outdir, f"{q}_{station_id}_mask{i_mask}_{y}.csv")
# ============ apparently format option is not available ======================
# elif f == 'geojson':
# url = rf"https://hubeau.eaufrance.fr/api/v2/hydrometrie/obs_elab?code_entite={station_id}&bbox={mask_ds.total_bounds[0]}&bbox={mask_ds.total_bounds[1]}&bbox={mask_ds.total_bounds[2]}&bbox={mask_ds.total_bounds[3]}&date_debut_obs_elab={y}-01-01&date_fin_obs_elab={y}-12-31&grandeur_hydro_elab={q}&format=geojson&size=20000"
# outpath = os.path.join(outdir, f"{q}_{station_id}_mask{i_mask}_{y}.json")
# =============================================================================
elif f in ['geojson', 'json']:
url = rf"https://hubeau.eaufrance.fr/api/v2/hydrometrie/obs_elab?code_entite={station_id}&bbox={mask_ds.total_bounds[0]}&bbox={mask_ds.total_bounds[1]}&bbox={mask_ds.total_bounds[2]}&bbox={mask_ds.total_bounds[3]}&date_debut_obs_elab={y}-01-01&date_fin_obs_elab={y}-12-31&grandeur_hydro_elab={q}&size=20000"
outpath = os.path.join(outdir, f"{q}_{station_id}_mask{i_mask}_{y}.json")
response = requests.get(url)
isvalid, frame = valid_request(response, f)
if isvalid:
# Data is clipped to the mask
if isinstance(frame, gpd.GeoDataFrame):
frame = geo.reproject(frame, mask = m)
else: # frame is only a pd.DataFrame
# first frame is converted to a GeoDataFrame
geometry = [Point(xy) for xy in zip(frame.longitude,
frame.latitude)]
gdf = gpd.GeoDataFrame(
frame,
crs = 4326,
geometry = geometry)
# Then it is clipped
gdf = geo.reproject(gdf, mask = m)
# Finally it is converted back to a DataFrame
frame = pd.DataFrame(gdf.drop(columns = 'geometry'))
# Export
if f == 'csv':
geo.export(frame, outpath, sep = ';', encoding = 'utf-8', index = False)
else:
geo.export(frame, outpath)
# SIM2 download has been moved to geop4th.download.download_sim2
# The import at the top of this file ensures backward compatibility:
# from geop4th.download.download_sim2 import download_sim2