Quelques bonnes pratiques pour les documents exécutables

Quelques bonnes pratiques pour les documents exécutables

Introduction

Lors de la création d’un document exécutable – tel que le rapport d’analyse de données que nous allons explorer aujourd’hui – le but est de rendre le document aussi lisible que possible, en mettant en évidence ce qui est calculé et en faisant abstraction des détails techniques de comment il est calculé.

Avec les feuilles Jupyter, cela est généralement réalisé en développant une collection d’utilitaires dans des fichiers de code séparés. De la sorte, les détails techniques de ces utilitaires ne polluent pas la lecture du document. Ils n’en restent pas moins immédiatement accessibles pour étude plus approfondie: le lecteur peut à tout moment utiliser l”introspection (en utilisant ? après la fonction, voir les exemples ci-dessous) pour consulter rapidement la documentation et le code des utilitaires.

Des utilitaires pour l’ensemble du cours sont fournis dans le module Python intro_science_donnees préinstallé sur le système. En outre, des utilitaires dédiés au devoir en cours sont fournis dans le module utilities.py présent dans le dossier du devoir.

Certains de ces utilitaires sont incomplets : vous serez invité à les compléter au fur et à mesure de votre progression. Nous ne nous attendons pas à ce que vous soyez dès maintenant en capacité de tous les réécrire vous-même; cependant, vous devriez certainement les consulter et essayer de les comprendre.

Rendre les données disponibles pour l’analyse peut également nécessiter un certain soin. En général, c’est un sujet à part entière; voir par exemple les principes FAIR (Findable, Accessible, Interoperable, Reproducible) de la Science Ouverte. À l’échelle de l’analyse que nous allons mener dans ce cours, la principale préoccupation est de rendre les données facilement accessibles depuis les feuilles Jupyter sans les dupliquer partout - et en particulier dans vos espaces en salle de TP, sur JupyterHub et sur GitLab – pour économiser de l’espace de stockage. Aussi, les jeux de données sont ils préinstallés avec la pile logicielle du cours.

En pratique

Les commandes suivantes configurent Jupyter pour recharger automatiquement les modules comme utilities.py chaque fois qu’ils sont modifiés; ainsi il ne sera pas nécessaire de redémarrer le noyau à tout bout de champ.

%load_ext autoreload
%autoreload 2

Importons les fonctions load_images et image_grid du module intro_science_donnees et toutes les fonctions du module utilities.py :

from intro_science_donnees import *
from utilities import *

Nous pouvons maintenant utiliser l’introspection pour consulter, par exemple, la documentation de load_images:

load_images?

voire pour étudier son code:

load_images??

Les jeux de données pour ce TP (et le projet 1) sont disponibles dans le dossier suivant :

from intro_science_donnees import data
data.dir

La liste des jeux de données disponibles peut s’obtenir ainsi :

!ls {data.dir}

Quelques explications: vous aurez reconnu la commande ls du shell, et ce n’est pas un accident: lorsqu’une cellule commence par un !, la commande est interprétée avec le shell au lieu de Python. Qui plus est, un nom de variable Python apparaissant entre accolade dans la commande shell, comme {data.dir} ci-dessus, est substitué par sa valeur.

Aujourd’hui nous nous intéressons au jeu de données ApplesAndBananasSimple :

import os.path
dataset_dir = os.path.join(data.dir, 'ApplesAndBananasSimple')
dataset_dir

Il consiste en une collection d’images :

! ls {dataset_dir}

Exercice : Chargez toutes ces images dans une variable images et affichez les.
Indication : consultez la documentation de load_images et de image_grid.

### BEGIN SOLUTION
images = load_images(dataset_dir, '*.png')
image_grid(images, titles=images.index)
### END SOLUTION
assert isinstance(images, pd.Series)
assert len(images) == 20
assert images.index[0] == "a01.png"

Rappelez-vous de la documentation : images est une série Pandas indexé par les noms des images :

images.index

Ainsi, vous pouvez récupérer une image individuelle soit par son nom, soit par son numéro :

images['a03.png']
images.iloc[2]

Chargez maintenant dans la variable bimages les images dont le nom commence par b. Affichez-les en utilisant leur nom de fichier comme titre.
Indication : si besoin, relisez les documentations !

### BEGIN SOLUTION
bimages = load_images(dataset_dir, 'b*.png')
image_grid(bimages, titles=bimages.index)
### END SOLUTION
assert isinstance(bimages, pd.Series)
assert len(bimages) == 10
assert bimages.index[0] == "b01.png"

Sections repliables

Lors de la manipulation d’un long document comme un rapport, il devient vite fastidieux de naviguer dans le document en faisant défiler d’avant en arrière. L’extension Jupyter «Collapsible Headings» permet de replier à volonté sections et sous-sections. Cette extension est activée par défaut dans l’environnement du cours : cherchez le triangle gris «» ou «» à gauche des titres de section et essayez de cliquer dessus.

Toutes les cellules ci-dessous (code ou texte) sont contenues dans une section repliable.

print("Hello")

Conclusion

Dans cette feuille, nous avons exploré quelques bonnes pratiques pour la rédaction de documents exécutables. C’est un premier pas vers la reproductibilité et la Science Ouverte!

Mettez à jour votre rapport dans la feuille index.md et déposez votre travail sur GitLab (submit). Passez enssuite à la feuille analyse de données.