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".

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

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

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).

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.

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...