Commit 5f39f099 authored by Matthieu Boileau's avatar Matthieu Boileau
Browse files

Up 05

parent 451989f8
%% Cell type:markdown id: tags:
# Microprojet
![](fig/python-logo.png)
- Utiliser les modules de la bibliothèque standard pour récupérer des données via un service web.
- Manipuler les dictionnaires et les chaînes de caractères
- Utiliser la bibliothèque de tracés graphiques matplotlib
- Utiliser un IDE (Spyder)
- Exécuter un fichier script en gérant les arguments de la ligne de commande
%% Cell type:markdown id: tags:
## Exercice
Exploiter les données du site <https://www.prevision-meteo.ch> pour tracer l'évolution horaire de la température à Strasbourg aujourd'hui.
![](fig/icon.png)
%% Cell type:markdown id: tags:
### Ouverture du fichier de prévisions
Le site <https://www.prevision-meteo.ch> fournit des prévisions sous forme de fichier au format [json](https://fr.wikipedia.org/wiki/JavaScript_Object_Notation). On veut récupérer les données relatives à Strasbourg avec la méthode `urlopen()` du module `urllib.request`.
%% Cell type:code id: tags:
``` python
%config InlineBackend.figure_format = 'retina'
%matplotlib inline
from urllib.request import urlopen
jsonfile_url = "https://www.prevision-meteo.ch/services/json/Strasbourg"
try:
f = urlopen(jsonfile_url, timeout=10) # open url
except Exception:
print("Le téléchargement a échoué : on lit une version locale.")
f = open("exos/Strasbourg.json")
```
%% Cell type:markdown id: tags:
### Chargement du fichier json ouvert
%% Cell type:markdown id: tags:
La méthode `json.loads()` permet de charger un fichier json comme un dictionnaire python :
%% Cell type:code id: tags:
``` python
import json
jsondict = json.loads(f.read()) # Read JSON file
```
%% Cell type:markdown id: tags:
### Exploration des données
On commence naïvement par afficher le contenu du fichier :
%% Cell type:code id: tags:
``` python
print(type(jsondict))
print(jsondict)
```
%% Cell type:markdown id: tags:
On essaie de faire mieux en affichant uniquement les clés du dictionnaire :
%% Cell type:code id: tags:
``` python
for k in jsondict:
print(repr(k))
```
%% Cell type:markdown id: tags:
On est intéressé par le temps d'aujourd'hui :
%% Cell type:code id: tags:
``` python
day = jsondict['fcst_day_0']
print(day)
```
%% Cell type:markdown id: tags:
Là aussi, on cherche les clés :
%% Cell type:code id: tags:
``` python
for k in day:
print(repr(k))
```
%% Cell type:markdown id: tags:
Vérifions qu'il s'agit d'aujourd'hui :
%% Cell type:code id: tags:
``` python
print(day['day_long'], day['date'])
```
%% Cell type:markdown id: tags:
C'est bon !
Maintenant, une entrée particulière nous intéresse :
%% Cell type:code id: tags:
``` python
day_hd = day['hourly_data']
for k in day_hd:
print(repr(k))
```
%% Cell type:markdown id: tags:
Regardons ce que contient une `hourly_data` :
%% Cell type:code id: tags:
``` python
for k in day_hd['8H00']:
print(repr(k))
```
%% Cell type:markdown id: tags:
La clé qui nous intéresse est la chaîne `'TMP2m'` qui correspond à la température à 2m du sol.
%% Cell type:code id: tags:
``` python
hour = '12H00'
print(f"Aujourd'hui à {hour}, il fera : {day_hd[hour]['TMP2m']} deg. C.")
```
%% Cell type:markdown id: tags:
Sauver ces lignes de commandes dans le fichier `today_stras.py` en allant de l'exécution 1 au compteur d'exécution courant indiqué dans la cellule de code ci-dessus `In [XX]`. Dans le cas présent :
%% Cell type:code id: tags:
``` python
# Décommenter la ligne ci-dessous
%save today_stras.py 1-10
#%save today_stras.py 1-10
```
%% Cell type:markdown id: tags:
### Tracé de la température
1. Ouvrir le fichier `today_stras.py` dans Spyder et nettoyer les `print` inutiles.
2. Exécutez le code dans Spyder et utilisez la fenêtre "Variable explorer" en haut à droite pour parcourir les données de votre dictionnaire.
3. Extraire la liste des couples `(hour, temperature)` où :
- `hour` est un entier
- `temperature` est un flottant
4. ordonner la liste selon les heures croissantes
5. convertir la liste en un *numpy array* `t` avec la méthode `numpy.array()`
6. Transposer `t` pour obtenir le tableau `[[array of hours], [array of temperatures]]`
7. réaliser un tracé matplotlib en suivant [ce tutoriel](https://matplotlib.org/stable/tutorials/introductory/pyplot.html) ou en intégrant les lignes de code suivantes :
%% Cell type:code id: tags:
``` python
import matplotlib.pyplot as plt # To be placed at the top of python file
# [Your previous code...]
# Plot T = T(hour)
# Décommentez les lignes ci-dessous
#
# fig = plt.figure() # initialise figure
# title = f"{day_of_the_week} {date_of_today}"
# fig.suptitle(title, fontsize=14, fontweight='bold')
#
# ax = fig.add_subplot(111) # initialise a plot area
# fig.subplots_adjust(top=0.85)
# ax.set_title('Day temperature')
# ax.set_xlabel('Time [h]')
# ax.set_ylabel('Temperature [deg. C]')
#
# ax.plot(t[0], t[1]) # plot t[1] (tempe) as a function of t[0] (hour)
```
%% Cell type:markdown id: tags:
> **Option :** intégrer l'icone de la météo du jour en utilisant le module `matplotlib.image`.
%% Cell type:markdown id: tags:
Pas si vite ! Êtes-vous sûr ? Vraiment ?
Alors rendez-vous dans [exos/correction/meteo_json.py](exos/correction/meteo_json.py)
%% Cell type:markdown id: tags:
## Exercice sur les fonctions
À partir de [`exos/correction/meteo_json.py`](exos/correction/meteo_json.py), écrivez le programme `meteo_json_func.py` qui contient une fonction `plot_day_tempe()` admettant deux arguments :
- `day_key` : un entier représentant le jour visé (`0`: aujourd'hui, `1`: demain, `2`: après-demain...)
- `city_name`: une chaîne de caractère de la ville recherchée
%% Cell type:code id: tags:
``` python
# Pour tester votre script dans cette cellule, décommenter les lignes suivantes
# et redémarrer le noyau avant chaque modification:
#from meteo_json_func import plot_day_tempe
#plot_day_tempe(2, city_name='Marseille')
```
%% Cell type:markdown id: tags:
Pas si vite ! Êtes-vous sûr ? Vraiment ?
Alors allez voir une proposition de solution dans [exos/correction/meteo_json_func.py](exos/correction/meteo_json_func.py)
%% Cell type:code id: tags:
``` python
from exos.correction.meteo_json_func import plot_day_tempe
plot_day_tempe(2, city_name='Marseille')
```
%% Cell type:markdown id: tags:
## Exécution avec les widgets ipython
[Jupyter ipywidgets](https://ipywidgets.readthedocs.io/en/latest/index.html) permet de créer très facilement des menus interactifs pour faciliter l'exécution de code dans les notebooks.
%% Cell type:markdown id: tags:
Un exemple avec notre courbe de température :
%% Cell type:code id: tags:
``` python
import exos.correction.meteo_json_func as meteo
from ipywidgets import interact
interact(meteo.plot_day_tempe,
day_key=list(range(5)),
city_name=["Marseille", "Paris", "Toulouse", "Strasbourg"]
);
```
%% Cell type:markdown id: tags:
## Exécution en script
### Utilisation de `if __name__ == '__main__':`
Dans un fichier python `test_module.py`, on souhaite généralement différencier :
- le code exécuté lors de l'import du fichier **comme un module** depuis un autre programme python ou depuis un notebook Jupyter avec :
```python
import test_module
```
Dans ce cas, la variable interne `__name__` vaut le nom du module (ici `test_module`).
- le code éxécuté lorsque le fichier est appelé directement **comme un script** depuis le terminal système :
```bash
python test_module.py
````
Dans ce cas, la variable interne `__name__` vaut la chaîne de caractère `__main__`.
%% Cell type:markdown id: tags:
Prenons comme exemple la cellule suivante que l'on sauvegarde dans le fichier `test_module.py`.
%% Cell type:code id: tags:
``` python
%%writefile test_module.py
def main():
print(f'je suis dans {__name__}')
if __name__ == '__main__':
print("Je suis appelé comme programme principal")
main()
else:
# En mode module importé, on ne fait rien de plus
pass
```
%% Cell type:markdown id: tags:
Appelons le fichier `test_module.py` comme un script python directement depuis le système :
%% Cell type:code id: tags:
``` python
%run test_module.py
```
%% Cell type:markdown id: tags:
La variable `__name__` vaut `__main__`.
%% Cell type:markdown id: tags:
Importons maintenant le fichier comme un module.
%% Cell type:code id: tags:
``` python
import test_module
```
%% Cell type:markdown id: tags:
Le bloc qui appelle la fonction `main()` n'est pas exécuté. En revanche cette fonction est accessible à la demande :
%% Cell type:code id: tags:
``` python
test_module.main()
```
%% Cell type:markdown id: tags:
Cette fois-ci, la variable `__name__` vaut `test_module`, c'est-à-dire le nom du module importé.
> Plus d'information sur `__name__` dans la [doc officielle](https://docs.python.org/fr/3/library/__main__.html).
%% Cell type:markdown id: tags:
### Gestion des arguments de la ligne de commande
Afin de positionner les paramètres d'un script à exécuter (noms de fichier, taille du problème, etc.), on a le choix entre :
- éditer le script là où les variables sont définies : si c'est envisageable pour des tests ou dans le contexte d'un notebook, ça ne l'est pas pour un programme destiné à être exécuté plusieur fois avec des paramètres variables
- positionner des variables d'environnement qui peuvent être lues avec la fonction [`os.getenv()`](https://docs.python.org/fr/3/library/os.html#os.getenv) : le risque est de dissocier la définition des paramètres de l'exécution du programme.
- lire un fichier d'entrée, par exemple avec [`configparser`](https://docs.python.org/3/library/configparser.html). C'est particulièrement utile lorsque les paramètres sont nombreux et variés et que l'on souhaite faciliter la reproductibilité des exécutions mais ça demande d'éditer le fichier d'entrée à chaque changement de paramètre.
- interpréter les arguments de la ligne de commande : c'est la façon la plus souple d'exécuter un script avec des paramètres variables.
%% Cell type:markdown id: tags:
Une façon très simple et très rapide créer une interface de ligne de commande (CLI en anglais) est d'utiliser la bibliothèque [`fire`](https://github.com/google/python-fire) développée par Google.
C'est une biblithèque externe : commençons par l'installer avec pip.
%% Cell type:code id: tags:
``` python
%pip install fire
```
%% Cell type:markdown id: tags:
À titre d'exemple, le fichier [`exos/correction/meteo_json_func.py`](exos/correction/meteo_json_func.py) appelle `fire` dans son bloc final :
```python
if __name__ == '__main__':
import fire
fire.Fire(plot_day_tempe)
```
%% Cell type:markdown id: tags:
`fire` utilise la signature et la docstring de la fonction `plot_day_tempe()` :
%% Cell type:code id: tags:
``` python
from exos.correction.meteo_json_func import plot_day_tempe
help(plot_day_tempe)
```
%% Cell type:markdown id: tags:
pour créer la CLI suivante :
%% Cell type:code id: tags:
``` python
%run exos/correction/meteo_json_func.py -h
```
%% Cell type:markdown id: tags:
De sorte qu'on peut tracer la température à Marseille dans 3 jours en tapant :
%% Cell type:code id: tags:
``` python
%run exos/correction/meteo_json_func.py --day_key=3 --city_name=Marseille
```
%% Cell type:markdown id: tags:
Ou avec les valeurs par défaut :
%% Cell type:code id: tags:
``` python
%run exos/correction/meteo_json_func.py
```
%% Cell type:markdown id: tags:
> Si on se limite ici à la présentation de `fire`, il faut mentionner l'existence du module [`argparse`](https://docs.python.org/3/library/argparse.html) qui fait partie de la bibliothèque standard.
Moins immédiate mais aussi plus souple, l'utilisation d'`argparse` est décrite dans ce [tutoriel](https://docs.python.org/3/howto/argparse.html#argparse-tutorial).
%% Cell type:markdown id: tags:
## Utilisation avancée de Spyder
- explorer le système de [debugging](https://docs.spyder-ide.org/5/panes/debugging.html)
- explorer le [profiler](https://docs.spyder-ide.org/5/panes/profiler.html)
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment