x
Package pyair
Ceci est une présentation de "pyair",
un package écrit en langage python pour la manipulation de données de la qualité de l'air.
Pour l'utiliser, il suffit de l'importer:
In [1]:
import pyair
. . .
x
pyair se compose d'un ensemble de module, chacun affecté à une tache particulière
In [2]:
dir(pyair)
Out[2]:
['__all__', '__author__', '__builtins__', '__doc__', '__email__', '__file__', '__name__', '__package__', '__path__', '__version__', 'date', 'geo', 'plot', 'reg', 'stats', 'utils', 'xair']
. . .
Sans tenir compte des noms commencant par deux underscores '__', pyair se compose de 7 modules, chacun affecté à une tache particulière et détaillé dans la suite du document.
Le premier module a utiliser est "xair". Comme sont nom l'indique, il est utilisé pour se connecter à une base XAIR et récupérer des données. La classe principale de se module se nomme "XAIR".
x
Le module xair
In [3]:
help(pyair.xair.XAIR)
Help on class XAIR in module pyair.xair: class XAIR | Connexion et méthodes de récupération de données depuis une base XAIR. | Usage : | import pyair | xr=pyair.xair.XAIR(user, pwd, adr, port=1521, base='N') | xr.liste_stations() | mes=xr.liste_mesures(reseau='OZONE').MESURES | m=xr.get_mesure(mes=mes, debut="2009-01-01", fin="2009-12-31", freq='H') | m.describe() | | Methods defined here: | | __init__(self, user, pwd, adr, port=1521, base='N') | | detail_df(self, df) | Renvoie les caractéristiques des mesures d'un dataframe. | | Paramètres: | df: dataframe à lister, tel que fournie par get_mesure() | | Retourne: | Les mêmes informations que liste_mesure() | | disconnect(self) | Fermeture de la connexion à la base | | get_SQLTXT(self, format_=1) | retourne les requêtes actuellement lancées sur le serveur | | get_indices(self, res, debut, fin) | Récupération des indices ATMO pour un réseau donné. | | Paramètres: | res : Nom du ou des réseaux à chercher (str, list, pandas.Series) | debut: date de début, format YYYY-MM-JJ (str) | fin: Date de fin, format YYYY-MM-JJ (str) | | get_manuelles(self, site, code_parametre, debut, fin, court=False) | Recupération des mesures manuelles (labo) pour un site | | site: numéro du site (voir fonction liste_sites_prelevement) | code_parametre: code ISO du paramètre à rechercher (C6H6=V4) | debut: date de début du premier prélèvement | fin: date de fin du dernier prélèvement | court: Renvoie un tableau au format court ou long (colonnes) | | get_mesures(self, mes, debut=None, fin=None, freq='H', format=None, dayfirst=False, brut=False) | Récupération des données de mesure. | | Paramètres: | mes: Un nom de mesure ou plusieurs séparées par des virgules, une liste | (list, tuple, pandas.Series) de noms | debut: Chaine de caractère ou objet datetime décrivant la date de début. | Défaut=date du jour | fin: Chaine de caractère ou objet datetime décrivant la date de fin. | Défaut=date de début | freq: fréquence de temps. '15T' | 'H' | 'D' | 'M' | 'A' (15T pour quart-horaire) | format: chaine de caractère décrivant le format des dates (ex:"%Y-%m-%d" | pour debut/fin="2013-01-28"). Appeler pyair.date.strtime_help() pour | obtenir la liste des codes possibles. | Defaut="%Y-%m-%d" | dayfirst: Si aucun format n'est fourni et que les dates sont des chaines | de caractères, aide le décrypteur à transformer la date en objet datetime | en spécifiant que les dates commencent par le jour (ex:11/09/2012 | pourrait être interpreté comme le 09 novembre si dayfirst=False) | brut: si oui ou non renvoyer le dataframe brut, non invalidé, et les | codes d'état des mesures | Defaut=False | | Retourne: | Un dataframe contenant toutes les mesures demandées. | Si brut=True, renvoie le dataframe des mesures brutes non invalidées et | le dataframe des codes d'états. | Le dataframe valide (net) peut être alors recalculé en faisant: | brut, etats = xr.get_mesure(..., brut=True) | invalides = etats_to_invalid(etats) | net = brut.mask(invalides) | | liste_campagnes(self, campagne=None) | Liste des campagnes de mesure et des stations associées | | Paramètres: | campagne: Si définie, liste des stations que pour cette campagne | | liste_mesures(self, reseau=None, station=None, parametre=None, mesure=None) | Décrit les mesures: | - d'un ou des reseaux, | - d'une ou des stations, | - d'un ou des parametres | ou décrit une (des) mesures suivant son (leur) identifiant(s) | Chaque attribut peut être étendu en rajoutant des noms séparés par des | virgules ou en les mettant dans une liste/tuple/pandas.Series. | Ainsi pour avoir la liste des mesures en vitesse et direction de vent: | parametre="VV,DV" ou = ["VV", "DV"] | | Paramètres: | reseau : nom du reseau dans lequel lister les mesures | station: nom de la station où lister les mesures | parametre: Code chimique du parametre à lister | mesure: nom de la mesure à décrire | | liste_parametres(self, parametre=None) | Liste des paramètres | | Paramètres: | parametre: si fourni, retourne l'entrée pour ce parametre uniquement | | liste_reseaux(self) | Liste des sous-réseaux de mesure | | liste_reseaux_indices(self) | Liste des réseaux d'indices ATMO | | liste_sites_prelevement(self) | Liste les sites de prélèvements manuels | | liste_stations(self, station=None, detail=False) | Liste des stations | | Paramètres: | station : un nom de station valide (si vide, liste toutes les stations) | detail : si True, affiche plus de détail sur la (les) station(s). | | reconnect(self)
. . .
Il suffit de l'appeler (l'instancier) pour être connecté à la base. Les paramètres de connexion (utilisateur, mot de passe, adresse et port du serveur, base) doivent être saisie lors de l'appel. Le port et le nom de la base sont déjà mis par défaut sur 1521 et 'N', il n'y a donc pas besoin de les passer en paramètres s'ils sont bons
In [4]:
xr=pyair.xair.XAIR('USER','PASSWORD','172.16.45.33')
XAIR: Connexion établie
. . .
x
Pour se déconnecter, rien de plus simple...
In [5]:
xr.disconnect()
XAIR: Connexion fermée
. . .
x
...et se reconnecter
In [6]:
xr.reconnect()
XAIR: Connexion établie
. . .
Les méthodes de la classe XAIR commencant par 'liste_' sont utiles pour trouver des informations sur une mesure, une station, un réseau de mesure...
Pour obtenir de l'aide sur une méthode, utiliser help (ou xr.liste_mesures? dans une console IPython)
In [7]:
help(xr.liste_mesures)
Help on method liste_mesures in module pyair.xair: liste_mesures(self, reseau=None, station=None, parametre=None, mesure=None) method of pyair.xair.XAIR instance Décrit les mesures: - d'un ou des reseaux, - d'une ou des stations, - d'un ou des parametres ou décrit une (des) mesures suivant son (leur) identifiant(s) Chaque attribut peut être étendu en rajoutant des noms séparés par des virgules ou en les mettant dans une liste/tuple/pandas.Series. Ainsi pour avoir la liste des mesures en vitesse et direction de vent: parametre="VV,DV" ou = ["VV", "DV"] Paramètres: reseau : nom du reseau dans lequel lister les mesures station: nom de la station où lister les mesures parametre: Code chimique du parametre à lister mesure: nom de la mesure à décrire
. . .
x
Ainsi pour obtenir la liste des mesures d'une station de nom 'GARROS':
In [8]:
xr.liste_mesures(station='GARROS')
Out[8]:
<class 'pandas.core.frame.DataFrame'> Int64Index: 14 entries, 0 to 13 Data columns (total 6 columns): MESURE 14 non-null values LIBELLE 14 non-null values UNITE 14 non-null values STATION 14 non-null values CODE_PARAM 14 non-null values PARAMETRE 14 non-null values dtypes: object(6)
. . .
/!\Remarque: le package pyair est hautement dépendant du package "pandas", qui apporte un nombre significatif de facilités dans la manipulation de données (voir http://pandas.pydata.org).
Pour faire simple, pandas fourni 2 grandes classes à python, les Series et les DataFrames. Les Series peuvent être vu comme un tableau d'une seule colonne et plusieurs lignes, les lignes étant nommées (numérotées) dans ce qu'on nomme un index. Un DataFrame est un ensemble de Series qui peut être vu comme une feuille d'un classeur Excel, où toutes les colonnes partagent les mêmes lignes (un seul index).
Dans la sortie ci-dessus, nous obtenons plusieurs informations:
<class 'pandas.core.frame.DataFrame'> : le résultat de la commande passée en entrée est fournie dans un DataFrame,
Int64Index: 14 entries, 0 to 13 : l'index (les noms des lignes) est de type Int64 (des entiers), il y a 14 lignes, numérotées de 0 à 13,
Data columns (total 6 columns) : le DataFrame contient 6 colonnes (6 Series),
MESURE 14 non-null values... : un résumé des colonnes, avec son nom et le nombre de valeurs non nulles dans cette colonne,
dtypes: object(6) : peu d'interêt ici, mais pour info ca donne le type général (de plus haut niveau) du DataFrame.
Bref, le résultat ci-dessus c'est bien, mais nous voulons voir ce qu'il y a écrit dedans. Le plus simple est de dire à pandas qu'il peut utiliser plus d'espace (sur votre affichage) pour faire son rendu. Par défaut les paramètres de pandas sont limitatifs, pour ne pas surcharger l'affichage sur de petits écrans. Ca peut être forcé en lui disant d'utiliser une plus grande largeur sur chaque ligne (par défaut, il se bloque à 80 caractères par ligne):
In [9]:
import pandas
pandas.options.display.line_width=200
. . .
In [10]:
xr.liste_mesures(station='GARROS')
Out[10]:
MESURE | LIBELLE | UNITE | STATION | CODE_PARAM | PARAMETRE | |
---|---|---|---|---|---|---|
0 | DV_GAR | DIREC VENT GARROS | degre | GARROS | DV | Direction du vent |
1 | HUM_GA | HUMIDITE GARROS | % | GARROS | HR | Humidite relative |
2 | NO2_GA | NO2 ROLAND GARROS | microg/m3 | GARROS | NO2 | Dioxyde d'azote |
3 | NOX_GA | NOX ROLAND GARROS | microg/m3 | GARROS | NOX | Oxydes d azote |
4 | NO_GAR | NO ROLAND GARROS | microg/m3 | GARROS | NO | Monoxyde d'azote |
5 | O3_GA | O3 | ug/m3 | GARROS | O3 | Ozone |
6 | O3_GAR | O3 ROLAND GARROS | microg/m3 | GARROS | O3 | Ozone |
7 | PSC_GA | PM10 corrigree GARRO | microg/m3 | GARROS | PM10 | PM10 |
8 | PS_GA | PS ROLAND GARROS | microg/m3 | GARROS | PM10 | PM10 |
9 | SO2GAR | SO2 GARROS | ug/m3 | GARROS | SO2 | Dioxyde de soufre |
10 | SO2_GA | SO2 ROLAND GARROS | microg/m3 | GARROS | SO2 | Dioxyde de soufre |
11 | TEM_GA | TEMPERATURE GARROS | degreC | GARROS | TC | Temperature |
12 | TO3_GAR | Temp Interne 03 | degreC | GARROS | TINT | Temperature interne analyseur |
13 | VV_GAR | VITESSE VENT GARROS | m/s | GARROS | VV | Vitesse du vent |
. . .
C'est beaucoup mieux.
La méthode liste_mesures accepte d'autres paramètres. Nous pouvons par exemple récupérer toutes les informations sur les mesures de vent en utilisant leurs codes paramètres (vitesse du vent=VV, direction=DV)
In [11]:
xr.liste_mesures(parametre="VV,DV")
Out[11]:
<class 'pandas.core.frame.DataFrame'> Int64Index: 84 entries, 0 to 83 Data columns (total 6 columns): MESURE 84 non-null values LIBELLE 84 non-null values UNITE 84 non-null values STATION 84 non-null values CODE_PARAM 84 non-null values PARAMETRE 84 non-null values dtypes: object(6)
. . .
Là, ce n'est plus la largeur des lignes qui nous pose problème, mais le nombre de lignes par défaut que pandas accepte d'imprimer sur l'écran (réglé à 60 par défaut, et on en a 84). Soit on modifie ca dans les options, soit on utilise d'autres subtilités de pandas, comme la possibilité d'afficher les n premières lignes:
In [12]:
xr.liste_mesures(parametre="VV,DV").head(10)
Out[12]:
MESURE | LIBELLE | UNITE | STATION | CODE_PARAM | PARAMETRE | |
---|---|---|---|---|---|---|
0 | DV | DV virtuel labomobil | degre | EUROCO | DV | Direction du vent |
1 | DV-VAL | DIR VENT LABO MOBIL | degre | VALDI5 | DV | Direction du vent |
2 | DVEURO | DIR VENT LABO MOBIL | degre | EUROCO | DV | Direction du vent |
3 | DV_AMBAZ | DIR VENT LABO MOBIL | degre | :00021 | DV | Direction du vent |
4 | DV_BA | DIR VENT LABO MOBIL | degre | BAUDRA | DV | Direction du vent |
5 | DV_BEAUN | DIR VENT LABO MOBIL | degre | :00001 | DV | Direction du vent |
6 | DV_BEAUNES | DIR VENT LABO MOBIL | degre | SYDE2 | DV | Direction du vent |
7 | DV_BON | DIR VENT LABO MOBIL | degre | BONNY | DV | Direction du vent |
8 | DV_C3 | DIR VENT LABO MOBIL | degre | BOUSSA | DV | Direction du vent |
9 | DV_C4 | DIR VENT LABO MOBIL | degre | BOUSS2 | DV | Direction du vent |
. . .
... la méthode "tail" à la place de "head) permet quant à elle de voir les n dernières lignes.
Si nous avons créé un sous-réseau dans XAIR contenant toutes les mesures d'ozone, et nommé 'OZONE' (très original n'est-il pas?), nous pouvons aussi voir la liste des mesures contenues dedans:
In [13]:
xr.liste_mesures(reseau='OZONE')
Out[13]:
MESURE | LIBELLE | UNITE | STATION | CODE_PARAM | PARAMETRE | |
---|---|---|---|---|---|---|
0 | O3_DA | O3 DALTON | microg/m3 | DALTON | O3 | Ozone |
1 | O3_FON | O3 FONTAINE | microg/m3 | FONTAI | O3 | Ozone |
2 | O3_GAR | O3 ROLAND GARROS | microg/m3 | GARROS | O3 | Ozone |
3 | O3_HUG | O3 VICTOR HUGO | microg/m3 | HUGO | O3 | Ozone |
4 | O3_MER | O3 MERA MONTFRANC | microg/m3 | MERA | O3 | Ozone |
5 | O3_NI | O3 NICOLAS | microg/m3 | NICOLA | O3 | Ozone |
6 | O3_PRE | O3 ECOLE PRESIDIAL | microg/m3 | PRESID | O3 | Ozone |
. . .
x
... mais c'est encore mieux si on peut les récupérer pour les manipuler par la suite:
In [14]:
mes=xr.liste_mesures(reseau='OZONE').MESURE
mes
Out[14]:
0 O3_DA 1 O3_FON 2 O3_GAR 3 O3_HUG 4 O3_MER 5 O3_NI 6 O3_PRE Name: MESURE, dtype: object
. . .
Les méthodes "liste_" sont utiles pour récupérer des informations. Les méthodes "get_" quant à elles servent à récupérer des valeurs stockées dans les tables de mesure d'XAIR. La plus importante est get_mesures
In [15]:
help(xr.get_mesures)
Help on method get_mesures in module pyair.xair: get_mesures(self, mes, debut=None, fin=None, freq='H', format=None, dayfirst=False, brut=False) method of pyair.xair.XAIR instance Récupération des données de mesure. Paramètres: mes: Un nom de mesure ou plusieurs séparées par des virgules, une liste (list, tuple, pandas.Series) de noms debut: Chaine de caractère ou objet datetime décrivant la date de début. Défaut=date du jour fin: Chaine de caractère ou objet datetime décrivant la date de fin. Défaut=date de début freq: fréquence de temps. '15T' | 'H' | 'D' | 'M' | 'A' (15T pour quart-horaire) format: chaine de caractère décrivant le format des dates (ex:"%Y-%m-%d" pour debut/fin="2013-01-28"). Appeler pyair.date.strtime_help() pour obtenir la liste des codes possibles. Defaut="%Y-%m-%d" dayfirst: Si aucun format n'est fourni et que les dates sont des chaines de caractères, aide le décrypteur à transformer la date en objet datetime en spécifiant que les dates commencent par le jour (ex:11/09/2012 pourrait être interpreté comme le 09 novembre si dayfirst=False) brut: si oui ou non renvoyer le dataframe brut, non invalidé, et les codes d'état des mesures Defaut=False Retourne: Un dataframe contenant toutes les mesures demandées. Si brut=True, renvoie le dataframe des mesures brutes non invalidées et le dataframe des codes d'états. Le dataframe valide (net) peut être alors recalculé en faisant: brut, etats = xr.get_mesure(..., brut=True) invalides = etats_to_invalid(etats) net = brut.mask(invalides)
. . .
Comme la documentation l'indique, get_mesures renvoie les valeurs des mesures dont les noms sont passées en paramètre dans la variable "mes". Par défaut, elle retourne un DataFrame de valeurs où les données invalides (maintenance, défaut appareil, phase de calibration, ...) sont remplacées par des valeurs nulles (NaN, pour Not a Number) et donc non prises en compte dans les calculs ulterieurs.
La variable mes peut être:
- un nom seul, par ex.: "O3_DA",
- plusieurs noms contenus dans une seule chaine de caractère, chaque nom étant séparé du suivant par une virgule, par ex. "O3_DA,O3_FON",
- plusieurs noms contenus dans un tableau ["O3_DA", "O3_FON", "O3_GAR"],
- plusieurs noms contenus dans une Series, comme celle que nous avons récupérer en faisant mes=xr.liste_mesures(reseau='OZONE').MESURE
Ainsi pour obtenir toutes les mesures du jour en ozone (par défaut get_mesures prend les dates de début et de fin à aujourd'hui, et une fréquence horaire)
In [16]:
xr.get_mesures(mes)
Out[16]:
O3_DA | O3_FON | O3_GAR | O3_HUG | O3_MER | O3_NI | O3_PRE | |
---|---|---|---|---|---|---|---|
2013-07-15 00:00:00 | 70 | 47 | 88 | 50 | 110 | 76 | 59 |
2013-07-15 01:00:00 | 62 | 37 | 77 | 46 | 103 | 72 | 68 |
2013-07-15 02:00:00 | 59 | 38 | 68 | 43 | 102 | 70 | 72 |
2013-07-15 03:00:00 | 51 | 31 | 73 | 29 | 98 | 29 | 61 |
2013-07-15 04:00:00 | 39 | 32 | 69 | 19 | 99 | 37 | 46 |
2013-07-15 05:00:00 | 28 | 28 | 73 | 13 | 92 | 5 | 25 |
2013-07-15 06:00:00 | 22 | 44 | 69 | 19 | 89 | 24 | 50 |
2013-07-15 07:00:00 | 51 | 58 | 81 | 52 | 95 | 61 | 64 |
2013-07-15 08:00:00 | 84 | 79 | 88 | 79 | 97 | 79 | 80 |
2013-07-15 09:00:00 | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
2013-07-15 10:00:00 | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
2013-07-15 11:00:00 | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
2013-07-15 12:00:00 | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
2013-07-15 13:00:00 | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
2013-07-15 14:00:00 | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
2013-07-15 15:00:00 | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
2013-07-15 16:00:00 | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
2013-07-15 17:00:00 | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
2013-07-15 18:00:00 | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
2013-07-15 19:00:00 | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
2013-07-15 20:00:00 | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
2013-07-15 21:00:00 | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
2013-07-15 22:00:00 | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
2013-07-15 23:00:00 | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
. . .
x
... ou pour obtenir l'ensemble des valeurs journalières sur une année complète:
In [17]:
df=xr.get_mesures(mes, debut='2012-01-01', fin='2012-12-31', freq='D')
df
Out[17]:
<class 'pandas.core.frame.DataFrame'> DatetimeIndex: 366 entries, 2012-01-01 00:00:00 to 2012-12-31 00:00:00 Freq: D Data columns (total 7 columns): O3_DA 352 non-null values O3_FON 366 non-null values O3_GAR 362 non-null values O3_HUG 335 non-null values O3_MER 345 non-null values O3_NI 361 non-null values O3_PRE 364 non-null values dtypes: float64(7)
. . .
xr.get_mesures accepte les fréquences suivantes:
15T: pour 15 minutes (quart-horaire)
H: heure
D: jour
M: mois
Y: année
Une astuce: pour afficher les 5 premiers jours d'un dataframe dont l'index (les noms des lignes) est composé de dates (comme retourné par get_mesures):
In [18]:
df.first('5D')
Out[18]:
O3_DA | O3_FON | O3_GAR | O3_HUG | O3_MER | O3_NI | O3_PRE | |
---|---|---|---|---|---|---|---|
2012-01-01 | 31 | 54 | 52 | 44 | 61 | 59 | 36 |
2012-01-02 | 30 | 50 | 49 | 34 | 66 | 63 | 35 |
2012-01-03 | 31 | 47 | 46 | 37 | 66 | 62 | 30 |
2012-01-04 | 32 | 55 | 55 | 38 | 69 | 62 | 39 |
2012-01-05 | 50 | 61 | 64 | 55 | 70 | 68 | 51 |
. . .
x
... ou obtenir des stats de synthèse des mesures:
In [19]:
df.describe()
Out[19]:
O3_DA | O3_FON | O3_GAR | O3_HUG | O3_MER | O3_NI | O3_PRE | |
---|---|---|---|---|---|---|---|
count | 352.000000 | 366.000000 | 362.000000 | 335.000000 | 345.000000 | 361.000000 | 364.000000 |
mean | 41.116477 | 52.057377 | 56.370166 | 43.397015 | 76.002899 | 58.332410 | 42.906593 |
std | 21.309430 | 18.039211 | 17.261425 | 19.908338 | 17.679560 | 19.799278 | 17.912461 |
min | 0.000000 | 9.000000 | 16.000000 | 1.000000 | 34.000000 | 1.000000 | 3.000000 |
25% | 24.750000 | 40.000000 | 44.000000 | 30.000000 | 65.000000 | 46.000000 | 29.000000 |
50% | 43.000000 | 54.000000 | 57.000000 | 47.000000 | 72.000000 | 60.000000 | 44.500000 |
75% | 57.000000 | 65.750000 | 68.000000 | 58.000000 | 89.000000 | 73.000000 | 55.000000 |
max | 90.000000 | 99.000000 | 94.000000 | 89.000000 | 136.000000 | 110.000000 | 97.000000 |
. . .
x
... ou visualiser les mesures dans un diagramme:
In [20]:
df.plot()
Out[20]:
<matplotlib.axes.AxesSubplot at 0x54da7d0>
. . .
Comme c'est un peu fouilli, on peut aggréger les données suivant plusieurs critères. Par exemple, passer des moyennes journalières à des moyennes mensuelles (attention là pour l'exemple, on ne recupère pas les données mensuelles depuis la base XAIR, c'est bien pandas qui va recalculer les valeurs):
In [21]:
df.resample('M', how=mean).plot()
Out[21]:
<matplotlib.axes.AxesSubplot at 0x5a9db90>
. . .
x
Ca marche aussi sur une seule mesure en calculant les moyennes et les max mensuelles (base horaire) sur un seul graphique:
In [22]:
df.O3_GAR.resample('M', how=mean).plot()
df.O3_GAR.resample('M', how=max).plot()
title("comparaison moyennes/maxi mensuelles")
Out[22]:
<matplotlib.text.Text at 0x5d0e410>
. . .
x
Pour faire des calculs de profils (journalier, hebdomadaire, annuel), le module "date" du package pyair est utile
x
Module date
In [23]:
help(pyair.date)
Help on module pyair.date in pyair: NAME pyair.date - **Timeprocessing FILE /home/lionel/Developpement/python/pyair/date.py DESCRIPTION Profils temporels (journalier, hebdomadaire, annuel) Exemple d'utilisation profil_hebdo(df, func='mean') profil_journalier(df, func='max') profil_annuel(df, func=numpy.std) FUNCTIONS profil_annuel(df, func='mean') Calcul du profil annuel Paramètres: df: DataFrame de données dont l'index est une série temporelle (cf module xair par exemple) func: function permettant le calcul. Soit un nom de fonction numpy ('mean', 'max', ...) soit la fonction elle-même (np.mean, np.max, ...) Retourne: Un DataFrame de moyennes par mois profil_hebdo(df, func='mean') Calcul du profil journalier Paramètres: df: DataFrame de données dont l'index est une série temporelle (cf module xair par exemple) func: function permettant le calcul. Soit un nom de fonction numpy ('mean', 'max', ...) soit la fonction elle-même (np.mean, np.max, ...) Retourne: Un DataFrame de moyennes par journée sur la semaine profil_journalier(df, func='mean') Calcul du profil journalier Paramètres: df: DataFrame de données dont l'index est une série temporelle (cf module xair par exemple) func: function permettant le calcul. Soit un nom de fonction numpy ('mean', 'max', ...) soit la fonction elle-même (np.mean, np.max, ...) Retourne: Un DataFrame de moyennes par heure sur une journée strtime_help() Print a help message on the time strptime format
. . .
In [24]:
p_hebdo=pyair.date.profil_hebdo(df)
p_hebdo
Out[24]:
O3_DA | O3_FON | O3_GAR | O3_HUG | O3_MER | O3_NI | O3_PRE | |
---|---|---|---|---|---|---|---|
Monday | 40.686275 | 49.603774 | 54.433962 | 43.653061 | 73.979592 | 57.156863 | 40.962264 |
Tuesday | 38.431373 | 49.846154 | 55.647059 | 40.812500 | 73.717391 | 56.288462 | 40.980769 |
Wednesday | 38.843137 | 50.134615 | 54.780000 | 42.042553 | 75.940000 | 55.865385 | 39.784314 |
Thursday | 40.591837 | 52.326923 | 55.764706 | 42.914894 | 78.938776 | 57.384615 | 41.490196 |
Friday | 38.755102 | 51.115385 | 55.461538 | 40.191489 | 76.980392 | 56.450980 | 40.384615 |
Saturday | 44.380000 | 55.615385 | 59.096154 | 45.812500 | 77.600000 | 62.019608 | 46.692308 |
Sunday | 46.078431 | 55.735849 | 59.301887 | 48.142857 | 74.680000 | 63.173077 | 49.867925 |
. . .
In [25]:
p_hebdo[['O3_DA','O3_GAR']].plot(kind='bar', legend=False)
Out[25]:
<matplotlib.axes.AxesSubplot at 0x5d216d0>
. . .
x
Quant au module "plot", il sert principalement pour les calculs et l'affichage de rose de vent/pollution
x
Module plot
In [26]:
help(pyair.plot.vents)
Help on function vents in module pyair.plot: vents(vv, dv, speed_classes=[0, 1, 2, 3, 4, 5], histo=True, savein=None, suffix='', format='jpg', **kwargs) Trace les graphiques suivants (16 secteurs fixés): - rose des vents - histogramme des vitesses de vent - histogramme des directions de vent Paramètres: vv: vitesses de vent dv: directions du vent speed_classes: classes de vent histo: si oui ou non il faut tracer les histogrammes de direction et vitesse savein: 'repertoire' oé enregistrer les graphiques suffix: suffixe à ajouter au nom du fichier image sauvegardé format: format du fichier image é sauvegarder. Si aucun, 'jpg' est choisi.
. . .
x
Par exemple, sur la station "GARROS", nous avons des données météo:
In [27]:
xr.liste_mesures(station='GARROS')
Out[27]:
MESURE | LIBELLE | UNITE | STATION | CODE_PARAM | PARAMETRE | |
---|---|---|---|---|---|---|
0 | DV_GAR | DIREC VENT GARROS | degre | GARROS | DV | Direction du vent |
1 | HUM_GA | HUMIDITE GARROS | % | GARROS | HR | Humidite relative |
2 | NO2_GA | NO2 ROLAND GARROS | microg/m3 | GARROS | NO2 | Dioxyde d'azote |
3 | NOX_GA | NOX ROLAND GARROS | microg/m3 | GARROS | NOX | Oxydes d azote |
4 | NO_GAR | NO ROLAND GARROS | microg/m3 | GARROS | NO | Monoxyde d'azote |
5 | O3_GA | O3 | ug/m3 | GARROS | O3 | Ozone |
6 | O3_GAR | O3 ROLAND GARROS | microg/m3 | GARROS | O3 | Ozone |
7 | PSC_GA | PM10 corrigree GARRO | microg/m3 | GARROS | PM10 | PM10 |
8 | PS_GA | PS ROLAND GARROS | microg/m3 | GARROS | PM10 | PM10 |
9 | SO2GAR | SO2 GARROS | ug/m3 | GARROS | SO2 | Dioxyde de soufre |
10 | SO2_GA | SO2 ROLAND GARROS | microg/m3 | GARROS | SO2 | Dioxyde de soufre |
11 | TEM_GA | TEMPERATURE GARROS | degreC | GARROS | TC | Temperature |
12 | TO3_GAR | Temp Interne 03 | degreC | GARROS | TINT | Temperature interne analyseur |
13 | VV_GAR | VITESSE VENT GARROS | m/s | GARROS | VV | Vitesse du vent |
. . .
x
On récupère donc les mesures du 01 janvier au 28 février 2012:
In [28]:
df=xr.get_mesures(mes="DV_GAR,VV_GAR", debut="2012-01-01", fin="2012-02-28")
df.head()
Out[28]:
DV_GAR | VV_GAR | |
---|---|---|
2012-01-01 00:00:00 | 194 | 1.87 |
2012-01-01 01:00:00 | 179 | 2.37 |
2012-01-01 02:00:00 | 181 | 2.30 |
2012-01-01 03:00:00 | 185 | 2.24 |
2012-01-01 04:00:00 | 191 | 1.84 |
. . .
x
puis on utilise la fonction vents pour tracer la rose des vents ainsi qu'une mise à plat (histogrammes) des données de vitesse et direction:
In [29]:
pyair.plot.vents(vv=df.VV_GAR, dv=df.DV_GAR, histo=True)
Out[29]:
[<windrose.windrose.WindroseAxes at 0x61bd350>, <matplotlib.axes.Axes at 0x6491b10>, <matplotlib.axes.Axes at 0x67a6450>]
. . .
x
Une autre fonction nommée ventsMF permet de faire la même chose mais depuis des données Météo-France, en tenant compte des données invalidantes (direction à zéro, vitesse < 1m/s).
x
Module reg
x
C'est le module dévolue aux calculs des valeurs réglementaires pour les polluants visés dans la réglementation 2008/50/CE
In [30]:
help(pyair.reg)
Help on module pyair.reg in pyair: NAME pyair.reg - # -*- coding: UTF-8 -*- FILE /home/lionel/Developpement/python/pyair/reg.py CLASSES exceptions.Exception(exceptions.BaseException) FreqException class FreqException(exceptions.Exception) | Method resolution order: | FreqException | exceptions.Exception | exceptions.BaseException | __builtin__.object | | Methods defined here: | | __init__(self, err) | | __str__(self) | | ---------------------------------------------------------------------- | Data descriptors defined here: | | __weakref__ | list of weak references to the object (if defined) | | ---------------------------------------------------------------------- | Data and other attributes inherited from exceptions.Exception: | | __new__ = <built-in method __new__ of type object> | T.__new__(S, ...) -> a new object with type S, a subtype of T | | ---------------------------------------------------------------------- | Methods inherited from exceptions.BaseException: | | __delattr__(...) | x.__delattr__('name') <==> del x.name | | __getattribute__(...) | x.__getattribute__('name') <==> x.name | | __getitem__(...) | x.__getitem__(y) <==> x[y] | | __getslice__(...) | x.__getslice__(i, j) <==> x[i:j] | | Use of negative indices is not supported. | | __reduce__(...) | | __repr__(...) | x.__repr__() <==> repr(x) | | __setattr__(...) | x.__setattr__('name', value) <==> x.name = value | | __setstate__(...) | | __unicode__(...) | | ---------------------------------------------------------------------- | Data descriptors inherited from exceptions.BaseException: | | __dict__ | | args | | message FUNCTIONS aot40_foret(df, nb_an) Calcul de l'AOT40 du 1er avril au 30 septembre *AOT40 : AOT 40 ( exprimé en micro g/m³ par heure ) signifie la somme des différences entre les concentrations horaires supérieures à 40 parties par milliard ( 40 ppb soit 80 micro g/m³ ), durant une période donnée en utilisant uniquement les valeurs sur 1 heure mesurées quotidiennement entre 8 heures et 20 heures (CET) <==> 7h à 19h TU Paramètres: df: DataFrame de mesures sur lequel appliqué le calcul nb_an: (int) Nombre d'années contenu dans le df, et servant à diviser le résultat retourné Retourne: Un DataFrame de résultat de calcul aot40_vegetation(df, nb_an) Calcul de l'AOT40 du 1er mai au 31 juillet *AOT40 : AOT 40 ( exprimé en micro g/m³ par heure ) signifie la somme des différences entre les concentrations horaires supérieures à 40 parties par milliard ( 40 ppb soit 80 micro g/m³ ), durant une période donnée en utilisant uniquement les valeurs sur 1 heure mesurées quotidiennement entre 8 heures (début de la mesure) et 20 heures (pile, fin de la mesure) CET, ce qui correspond à de 8h à 19h TU (donnant bien 12h de mesures, 8h donnant la moyenne horaire de 7h01 à 8h00) Paramètres: df: DataFrame de mesures sur lequel appliqué le calcul nb_an: (int) Nombre d'années contenu dans le df, et servant à diviser le résultat retourné Retourne: Un DataFrame de résultat de calcul arsenic(df) Calculs réglementaires pour l'arsenic Paramètres: df: DataFrame contenant les mesures, avec un index temporel (voir xair.get_mesure) Retourne: Une série de résultats dans un DataFrame : ****** unité (u): ng/m3 (nanogramme par mètre cube) Valeur cible en moyenne A: 6u Les résultats sont donnés en terme d'heure de dépassement bap(df) Calculs réglementaires pour le benzo(a)pyrène Paramètres: df: DataFrame contenant les mesures, avec un index temporel (voir xair.get_mesure) Retourne: Une série de résultats dans un DataFrame : ****** unité (u): ng/m3 (nanogramme par mètre cube) Valeur cible en moyenne A: 1u Les résultats sont donnés en terme d'heure de dépassement c6h6(df) Calculs réglementaires pour le benzène Paramètres: df: DataFrame contenant les mesures, avec un index temporel (voir xair.get_mesure) Retourne: Une série de résultats dans un DataFrame : ****** unité (u): µg/m3 (microgramme par mètre cube) Objectif de qualité en moyenne A: 2u Valeur limite pour la santé humaine en moyenne A: 5u Les résultats sont donnés en terme d'heure de dépassement cadmium(df) Calculs réglementaires pour le cadmium Paramètres: df: DataFrame contenant les mesures, avec un index temporel (voir xair.get_mesure) Retourne: Une série de résultats dans un DataFrame : ****** unité (u): ng/m3 (nanogramme par mètre cube) Valeur cible en moyenne A: 5u Les résultats sont donnés en terme d'heure de dépassement co(df) Calculs réglementaires pour le monoxyde de carbone Paramètres: df: DataFrame contenant les mesures, avec un index temporel (voir xair.get_mesure) Retourne: Une série de résultats dans un DataFrame : ****** unité (u): µg/m3 (microgramme par mètre cube) Valeur limite pour la santé humaine max J 8H glissantes: 10000u Les résultats sont donnés en terme d'heure de dépassement compresse(df) Compresse un DataFrame en supprimant les lignes dont toutes les Valeurs (colonnes) sont vides. Si au moins une valeur est présente sur la ligne, alors elle est conservée. Paramètres: df: DataFrame a présenter Retourne: Un DataFrame réduit à son strict minimum consecutive(df, valeur, sur=3) Calcule si une valeur est dépassée durant une période donnée. Détecte un dépassement de valeur sur X heures/jours/... consécutifs Paramètres: df: DataFrame de mesures sur lequel appliqué le calcul valeur: (float) valeur à chercher le dépassement (strictement supérieur à) sur: (int) Nombre d'observations consécutives où la valeur doit être dépassée Retourne: Un DataFrame de valeurs, de même taille (shape) que le df d'entrée, dont toutes les valeurs sont supprimées, sauf celles supérieures à la valeur de référence et positionnées sur les heures de début de dépassements depassement(df, valeur) Calcule les dépassements d'une valeur. Paramètres: df: DataFrame de mesures sur lequel appliqué le calcul valeur: (float) valeur à chercher le dépassement (strictement supérieur à) Retourne: Un DataFrame de valeurs, de même taille (shape) que le df d'entrée, dont toutes les valeurs sont supprimées, sauf celles supérieures à la valeur de référence excel_synthese(fct, df, excel_file) Enregistre une synthèse des calculs réglementaires en fournissant les valeurs calculées suivant les réglementations définies dans chaque fonction de calcul et un tableau de nombre de dépassement. Les résultats sont enregistrés dans un fichier Excel Paramètres: fct: fonction renvoyant les éléments calculées df: DataFrame de valeurs d'entrée à fournir à la fonction excel_file: Chemin du fichier excel où écrire les valeurs Retourne: Rien moyennes_glissantes(df, sur=8, rep=0.75) Calcule de moyennes glissantes Paramètres: df: DataFrame de mesures sur lequel appliqué le calcul sur: (int, par défaut 8) Nombre d'observations sur lequel s'appuiera le calcul rep: (float, défaut 0.75) Taux de réprésentativité en dessous duquel le calcul renverra NaN Retourne: Un DataFrame des moyennes glissantes calculées nickel(df) Calculs réglementaires pour le nickel Paramètres: df: DataFrame contenant les mesures, avec un index temporel (voir xair.get_mesure) Retourne: Une série de résultats dans un DataFrame : ****** unité (u): ng/m3 (nanogramme par mètre cube) Valeur cible en moyenne A: 20u Les résultats sont donnés en terme d'heure de dépassement no2(df) Calculs réglementaires pour le dioxyde d'azote Paramètres: df: DataFrame contenant les mesures, avec un index temporel (voir xair.get_mesure) Retourne: Une série de résultats dans un DataFrame : ****** unité (u): µg/m3 (microgramme par mètre cube) Seuil de RI en moyenne H: 200u Seuil d'Alerte sur 3H consécutives: 400u Seuil d'Alerte sur 3J consécutifs: 200u Valeur limite pour la santé humaine 18H/A: 200u Valeur limite pour la santé humaine en moyenne A: 40u Objectif de qualité en moyenne A: 40u Protection de la végétation en moyenne A: 30u Les résultats sont donnés en terme d'heure de dépassement nombre_depassement(df, valeur, freq=None) Calcule le nombre de dépassement d'une valeur sur l'intégralité du temps, ou suivant un regroupement temporel. Paramètres: df: DataFrame de mesures sur lequel appliqué le calcul valeur: (float) valeur à chercher le dépassement (strictement supérieur à) freq: (str ou None): Fréquence de temps sur lequel effectué un regroupement. freq peut prendre les valeurs 'H' pour heure, 'D' pour jour, 'W' pour semaine, 'M' pour mois et 'A' pour année, ou None pour ne pas faire de regroupement. Le nombre de dépassement sera alors regroupé suivant cette fréquence de temps. Retourne: Une Series du nombre de dépassement, total suivant la fréquence intrinsèque du DataFrame d'entrée, ou aggloméré suivant la fréquence de temps choisie. o3(df) Calculs réglementaires pour l'ozone Paramètres: df: DataFrame contenant les mesures, avec un index temporel (voir xair.get_mesure) Retourne: Une série de résultats dans un DataFrame : ****** unité (u): µg/m3 (microgramme par mètre cube) Seuil de RI sur 1H: 180u Seuil d'Alerte sur 1H: 240u Seuil d'Alerte sur 3H consécutives: 240u Seuil d'Alerte sur 3H consécutives: 300u Seuil d'Alerte sur 1H: 360u Objectif de qualité pour la santé humaine sur 8H glissantes: 120u Les résultats sont donnés en terme d'heure de dépassement pb(df) Calculs réglementaires pour le plomb Paramètres: df: DataFrame contenant les mesures, avec un index temporel (voir xair.get_mesure) Retourne: Une série de résultats dans un DataFrame : ****** unité (u): µg/m3 (microgramme par mètre cube) Objectif de qualité en moyenne A: 0.25u Valeur limite pour la santé humaine en moyenne A: 0.5u Les résultats sont donnés en terme d'heure de dépassement pm10(df) Calculs réglementaires pour les particules PM10 Paramètres: df: DataFrame contenant les mesures, avec un index temporel (voir xair.get_mesure) Retourne: Une série de résultats dans un DataFrame : ****** unité (u): µg/m3 (microgramme par mètre cube) Seuil de RI en moyenne J: 50u Seuil d'Alerte en moyenne J: 80u Valeur limite pour la santé humaine 35J/A: 50u Valeur limite pour la santé humaine en moyenne A: 40u Objectif de qualité en moyenne A: 30u Les résultats sont donnés en terme d'heure de dépassement print_synthese(fct, df) Présente une synthèse des calculs réglementaires en fournissant les valeurs calculées suivant les réglementations définies dans chaque fonction de calcul et un tableau de nombre de dépassement. Paramètres: fct: fonction renvoyant les éléments calculées df: DataFrame de valeurs d'entrée à fournir à la fonction Retourne: Imprime sur l'écran les valeurs synthétisées so2(df) Calculs réglementaires pour le dioxyde de soufre Paramètres: df: DataFrame contenant les mesures, avec un index temporel (voir xair.get_mesure) Retourne: Une série de résultats dans un DataFrame : ****** unité (u): µg/m3 (microgramme par mètre cube) Seuil de RI en moyenne H: 300u Seuil d'Alerte sur 3H consécutives: 500u Valeur limite pour la santé humaine 24H/A: 350u Valeur limite pour la santé humaine 3J/A: 125u Objectif de qualité en moyenne A: 50u Protection de la végétation en moyenne A: 20u Protection de la végétation du 01/10 au 31/03: 20u Les résultats sont donnés en terme d'heure de dépassement
. . .
x
Par exemple, pour calculer l'AOT40 sur 3 ans de toutes les mesures d'ozone:
In [31]:
mes=xr.liste_mesures(reseau='OZONE').MESURE
df=xr.get_mesures(mes, debut='2010-01-01', fin='2012-12-31', freq='H')
pyair.reg.aot40_vegetation(df, 3)
3312 mesures au totales du 5 au 7 entre 8 et 19
Out[31]:
O3_DA | O3_FON | O3_GAR | O3_HUG | O3_MER | O3_NI | O3_PRE | |
---|---|---|---|---|---|---|---|
brutes | 9097 | 10339 | 9365 | 9159 | 13251 | 8981 | 5621 |
mesures valides | 3234 | 3296 | 3303 | 3178 | 3097 | 3243 | 3295 |
% de rep. | 98 | 100 | 100 | 96 | 94 | 98 | 99 |
nettes | 9316 | 10389 | 9391 | 9545 | 14171 | 9172 | 5650 |
. . .
x
... ou Le calcul des valeurs réglementaires pour le dioxyde d'azote:
In [32]:
mes=xr.liste_mesures(reseau='NO2').MESURE
df=xr.get_mesures(mes, debut='2012-01-01', fin='2012-12-31', freq='H')
pyair.reg.print_synthese(pyair.reg.no2, df)
Pour le polluant: NO2 Valeurs mesurées suivant critères: NO2_AINE NO2_DA NO2_FO NO2_HU NO2_IP NO2_NI NO2_PR Protection de la végétation en moyenne A: 30u 2012-12-31 31 nan nan nan nan nan nan Valeur limite pour la santé humaine en moyenne A: 40u: aucune valeur en dépassement Seuil de RI en moyenne H: 200u: aucune valeur en dépassement Valeur limite pour la santé humaine 18H/A: 200u: aucune valeur en dépassement Seuil d'Alerte sur 3J consécutifs: 200u: aucune valeur en dépassement Objectif de qualité en moyenne A: 40u: aucune valeur en dépassement Seuil d'Alerte sur 3H consécutives: 400u: aucune valeur en dépassement Nombre de dépassements des critères: NO2_AINE NO2_DA NO2_FO NO2_HU NO2_IP NO2_NI NO2_PR Objectif de qualité en moyenne A: 40u 0 0 0 0 0 0 0 Protection de la végétation en moyenne A: 30u 1 0 0 0 0 0 0 Seuil d'Alerte sur 3H consécutives: 400u 0 0 0 0 0 0 0 Seuil d'Alerte sur 3J consécutifs: 200u 0 0 0 0 0 0 0 Seuil de RI en moyenne H: 200u 0 0 0 0 0 0 0 Valeur limite pour la santé humaine 18H/A: 200u 0 0 0 0 0 0 0 Valeur limite pour la santé humaine en moyenne A: 40u 0 0 0 0 0 0 0
. . .
La fonction "print_synthese" est une fonction de convenance, dans le sens où elle n'est là que pour présenter les résultats des "vraies" fonctions de calculs. Ces fonctions peuvent être appelées directement (par exemple pyair.reg.no2(df)), à chacun alors de présenter les résultats comme il l'entend, sachant que chaque fonction de calcul renverra, et le nom du polluant sur lequel s'applique le calcul, et un dictionnaire (au sens python, on ne va pas vous renvoyer un petit Robert...) contenant pour chaque seuil et chaque mesure, les heures où le seuil a été dépassé. Ainsi, "print_synthese" formate ces résultats, en présentant en plus un tableau en fin d'impression montrant le nombre de dépassement par seuil et par mesure. Une fonction similaire, "excel_synthese", permet d'enregistrer toutes ces informations dans un classeur Excel.
x
Module geo
Ce module est utilisé pour le travail sur des données géospatiales. Il comporte un certain nombre de fonctions pratiques pour la gestion des données géométriques (transfert d'un format de fichier vers un autre (ex: shapefile vers MIF/MID), de transformation de projection, etc... et de calculs de distance entre sites de mesures et de pourcentage d'un site sous les vents en provenance d'un autre.
Pour ce faire, la classe "Site" est la plus utile
In [33]:
help(pyair.geo.Site)
Help on class Site in module pyair.geo: class Site(__builtin__.object) | Définition d'un site dans le plan | | Paramètres: | nom: nom du site | x: longitude du site | y: latitude du site | epsg: Système de projection à utiliser en entrée ('epsg:4326' = WGS84) | | Methods defined here: | | __init__(self, nom, x, y, epsg='epsg:4326') | | __str__(self) | | angle_avec(self, origine) | Renvoie l'angle que forme ce site par rapport à un autre point d'origine | et le nord (angle site-origine-nord)) | | Paramètres: | origine: Site instance représentant l'origine de l'angle à calculer, | typiquement l'émetteur (usine) | | distance_avec(self, origine, epsg2='epsg:2154') | Renvoie la distance du site avec le site d'orgine | | Paramètres: | origine: Site instance représentant l'origine, typiquement l'émetteur (usine) | epsg2: système de projection à utiliser pour le calcul des distances | et le format de sortie ('epsg:2154' = Lambert93) | | reprojete(self, epsg2='epsg:2154', inplace=False) | reprojete les coordonnées du site dans un autre système de projection | | Paramètres: | epsg2: Système de projection à utiliser en sortie ('epsg:2154' = Lambert93) | inplace: Si oui, l'objet lui-même sera mis à jour avec les nouvelles | coordonnées et projection, sinon renvoie juste les nouvelles coordonnées | | save_in_KML(self, fname='./site.kml') | Enregistre le site dans un fichier KML | | Paramètres: | fname: Nom du fichier à enregistrer | | show(self) | Affiche le point dans Google Maps | | ---------------------------------------------------------------------- | Data descriptors defined here: | | __dict__ | dictionary for instance variables (if defined) | | __weakref__ | list of weak references to the object (if defined)
. . .
Nous allons créer 4 sites pour l'exercice, représentant 3 jauges OWEN et un incinérateur. Nous avons besoin de leur nom, coordonnées géographiques et du système de projection utilisé pour les coordonnées:
In [34]:
jauge1=pyair.geo.Site(u'Jauge n°1', x=519447, y=2097835, epsg='epsg:27572')
jauge2=pyair.geo.Site(u'Jauge n°2', x=521064, y=2099403, epsg='epsg:27572')
jauge3=pyair.geo.Site(u'Jauge n°3', x=516017, y=2091898, epsg='epsg:27572')
incinerateur=pyair.geo.Site(u'Incinerateur', x=570487, y=6517341, epsg='epsg:2154')
. . .
Toutes les jauges sont définies suivant la projection Lambert 2 étendu (code EPSG 27572), mais l'incinérateur est en Lambert93 (code EPSG 2154). Pour ne pas avoir de surprise par la suite, il est préférable de travailler avec le même système de projection sur tous les sites. Il suffit alors de reprojeter l'incinérateur:
In [35]:
incinerateur.reprojete(epsg2='epsg:27572', inplace=True)
print(incinerateur)
<Site Incinerateur (521994.520919, 2083059.19234)>
. . .
Le paramètre "inplace=True" force la mise à jour sur place du site. Si "inplace=False", l'utilisation de la méthode "reprojete" vous renverra uniquement à l'écran les nouvelles coordonnées X et Y reprojetées, sans modifier celles du site.
Pour connaitre la distance d'un site par rapport à un autre ou l'angle que forme un site par rapport à un autre et le Nord, les méthodes "distance_avec" et "angle_avec" sont utilisées:
In [36]:
jauge1.distance_avec(jauge2)
Out[36]:
2250.3766390788883
. . .
In [37]:
jauge1.angle_avec(jauge2)
Out[37]:
225.88140399658212
. . .
Si un grand nombre de sites sont à comparer à un point origine, les fonctions "pyair.geo.distances_avec" et "pyair.geo.angles_avec" sont mieux adaptées. Il suffit de passer les sites de référence dans une liste (au sens python, pas de courses...) et le point d'origine. "distances_avec" prend aussi un argument facultatif, dans le cas où les sites devraient être reprojetés dans le processus (les sites ne seront là, pas modifiés sur place)
In [38]:
pyair.geo.distances_avec([jauge1,jauge2,jauge3], incinerateur)
Out[38]:
distance | |
---|---|
site | |
Jauge n°1 | 14980.238237 |
Jauge n°2 | 16355.466974 |
Jauge n°3 | 10660.616124 |
. . .
In [39]:
pyair.geo.angles_avec([jauge1,jauge2,jauge3], incinerateur)
Out[39]:
angle | |
---|---|
site | |
Jauge n°1 | 350.217714 |
Jauge n°2 | 356.741431 |
Jauge n°3 | 325.930243 |
. . .
x
Comme les 2 résultats sont des DataFrames de même index, on peut les joindre ensemble pour ne former qu'un seul tableau final:
In [40]:
pyair.geo.distances_avec([jauge1,jauge2,jauge3], incinerateur).join(pyair.geo.angles_avec([jauge1,jauge2,jauge3], incinerateur))
Out[40]:
distance | angle | |
---|---|---|
site | ||
Jauge n°1 | 14980.238237 | 350.217714 |
Jauge n°2 | 16355.466974 | 356.741431 |
Jauge n°3 | 10660.616124 | 325.930243 |
. . .
Si nous connaissons les vitesses et directions de vent d'une station météo (par exemple comme vu précédement), il est possible de faire calculer pour chaque site, son pourcentage de temps sous les vents par rapport à un point d'origine
In [41]:
df=xr.get_mesures("VV_GAR,DV_GAR",debut="2013-01-15", fin="2013-02-14", freq='H')
sites=[jauge1,jauge2,jauge3]
pyair.geo.vents(vv=df.VV_GAR, dv=df.DV_GAR, origine=incinerateur, sites=sites)
Out[41]:
angle | distance | pourcentage | |
---|---|---|---|
site | |||
Jauge n°1 | 350 | 14980 | 12 |
Jauge n°2 | 357 | 16355 | 12 |
Jauge n°3 | 326 | 10661 | 8 |
. . .
x
Les sites peuvent être exportés au format KML pour être visualisable dans un SIG
In [42]:
jauge1.reprojete(epsg2='epsg:4326', inplace=True)
jauge2.reprojete(epsg2='epsg:4326', inplace=True)
jauge3.reprojete(epsg2='epsg:4326', inplace=True)
incinerateur.reprojete(epsg2='epsg:4326', inplace=True)
fichier='/tmp/mes_sites.kml'
pyair.geo.save_in_KML([jauge1,jauge2,jauge3,incinerateur], fichier)
KML enregistré sous /tmp/mes_sites.kml
. . .
De plus, un Site présente l'interface standardisé geo_interface, ce qui fait que les sites peuvent être importés dans d'autres modules comme Shapely ou Descartes pour d'éventuels traitement géographique, mais ceci est une autre histoire...