Skip to article frontmatterSkip to article content

On rappelle la formule de Taylor

fn(x)=i=0nf(i)(0).xii!f_n(x) = \sum_{i=0}^{n}\frac{f^{(i)}(0).x^i}{i!}

un dashboard

le but du jeu dans cette dernière partie du TP est de créer un dashboard qui permet d’afficher un matplotlib interactif du genre de celui capturé sur la figure, c’est-à-dire à la fois

modes disponibles

la solution à cet exercice est relativement différente selon le mode de restitution choisi pour matplotlib; notamment il y a

notre solution utilise ce dernier mode
pour quelques exemples voir https://matplotlib.org/ipympl/examples/full-example.html

%matplotlib ipympl

ce qui change fondamentalement entre le premier mode (inline) et les deux autres, c’est que dans le premier cas, à chaque changement de réglage on repeint toute la figure; c’est plus facile à écrire, mais ça “flashe” du coup à chaque fois; dans les autres modèles au contraire, on a une figure affichée, et lorsqu’on change un paramètre on va seulement modifier un des morceaux de la figure

ici par exemple notre figure c’est principalement deux courbes (la fonction, et son approximation), plus les décorations (axes, titres, etc..)
et au changement de paramètre, on va changer seulement la courbe de l’approximation - et éventuellement le titre si on veut

on utilise le TP #2

pour commencer, on a besoin de la fonction taylor2 qu’on a écrite dans le TP #2 - et la fonction custom aussi d’ailleurs

vous pouvez, au choix:

bref, à vous de faire ce qu’il faut pour définir ces deux symboles

# votre code pour copier ou importer `taylor2` et `custom`
# ! pip install autograd
import autograd.numpy as np
import matplotlib.pyplot as plt

from math import factorial

on importe

la librairie qui nous sert ici est ipywidgets https://ipywidgets.readthedocs.io/

import ipywidgets as widgets

from ipywidgets import AppLayout, Dropdown, IntSlider, FloatSlider, HBox, VBox

plt.ioff();

ipywidgets, comment ça marche ?

on vous montre d’abord pas à pas le code pour faire un tout petit dashboard

les widgets

un widget c’est un morceau d’interface, qui permet de choisir un paramètre; on va vous montrer le FloatSlider qui permet de choisir une valeur flottante, mais il y a aussi le IntSlider, le Dropdown pour choisir parmi un nombre fini de choix, etc...

# ici knob c'est juste un nom de variable Python

knob = FloatSlider(
    min=0, max=10,
    value=3, step=0.05,
    description="un potard",
    # ceci est jsute cosmétique, vous pouvez ignorer en première lecture...
    layout={'margin': '5px', 'width': '100%'},
)

on peut en faire quoi? eh bien si on l’affiche

knob
Loading...

je peux faire bouger la réglette, mais c’est à peu près tout, il ne se passe rien
c’est normal, on ne l’a pas “branché”

les callbacks

pour que ma réglette serve à quelque chose, on va lui attacher une callback
c’est-à-dire une fonction qui sera appelée lorsqu’il y aura un changement

pour commencer j’écris cette callback, c’est une fonction Python,

def knob_has_changed(change):
    print(f"knob vaut maintenant {change.new}, et change name = {change.name}")

so far so good, mais bien sûr il ne se passe toujours rien si on bouge la réglette
sauf que maintenant, on est prêts à “brancher” les deux, comme ceci:

# on dit au slider que lorsque sa valeur change (names='value')
# il doit appeler la callback knob_has_changed

knob.observe(knob_has_changed, names='value')

et maintenant si vous faites bouger la réglette, il va se passer des trucs
bon, pour ne pas polluer tout l’écran, les impressions qu’on fait se retrouvent dans la console de Jupyter Lab, regardez bien le bas de l’écran,

vous ouvrez la console et vous voyez les messages affichés par la callback, qui disent e.g.

knob vaut maintenant 2.85, et change name = value

super, on a déjà un moyen de choisir parmi plusieurs valeurs, et de réagir aux changements

les boites pour construire

la librairie vient aussi avec des moyens d’organiser les widgets en lignes et colonnes, c’est là qu’interviennent les HBox et VBox

VBox([
    # la première ligne est elle-même composite
    HBox([knob, knob]),
    # dans la deuxième ligne on met juste un widget
    knob
])
Loading...

vous remarquez d’ailleurs que les trois réglettes sont synchrones, c’est normal car elles servent à définir une seule valeur !
qui est d’ailleurs en permanence accessible comme

# par contre le résultat de cette cellule ne va pas
# tout seul se rafraichir si vous bougez la réglette...

knob.value
3.0

matplotlib incrémental

il ne nous reste plus qu’à voir comment on peut utiliser matplotlib de manière incrémentale, c’est-à-dire comment on peut modifier une figure après l’avoir affichée

ça se présente comme ceci; imaginons qu’on a créé une figure, qui montre la valeur de knob sur le domaine

X = np.linspace(-2*np.pi, 2*np.pi)

fig = plt.figure(figsize=(4, 2))
ax = plt.axes()

# on va afficher une droite Y=knob
# donc Y sera dans l'intervalle [0, 10]
# plt.ylim(0, 10)
ax.set_ylim(0, 10)

# la clé est de garder une référence vers la courbe

line = ax.plot(
    # une astuce pour que Y soit de la même forme que X
    X, X*0. + knob.value)

fig.show()
Loading...

eh bien, grâce à cette référence vers line, on va pouvoir modifier la figure “après coup” en faisant juste, par exemple

# on change ensuite la hauteur comme on veut

# par exemple Y = 4
# attention à ce line[0], ce n'est pas intuitif !
line[0].set_data(X, X * 0. + 4)

# c'est ceci qui va "flusher" la mise à jour de la figure
# à ne faire qu'une fois que tous les changements sont effectués
fig.canvas.draw()

on assemble avec AppLayout

enfin pour mettre tout ensemble, on dispose d’une classe AppLayout; le tout se présenterait comme ceci

knob = FloatSlider(
    min=0, max=10,
    value=3, step=0.05,
    description="pick Y",
    # ceci est juste cosmétique, vous pouvez ignorer en première lecture...
    layout={'margin': '0px 5px', 'width': '100%'},
)

fig = plt.figure(figsize=(4, 2))
axes = plt.axes()
axes.set_ylim((0, 10))
line = axes.plot(X, 0*X + knob.value)

def update_y(change):
    print("got a change", change)
    line[0].set_data(X, X*0. + change.new)
    fig.canvas.draw()

knob.observe(update_y, names='value')

controls = knob
# on aurait pu mettre artificiellement 2 réglettes
controls = HBox([knob, knob])

AppLayout(
    header=controls,
    center=fig.canvas,
    footer=None,
    pane_heights=[1, 6, 0],
)
Loading...

à vous de vous en inspirer

en vous inspirant du petit exemple, et en explorant la documentation de ipywidgets, tentez de reproduire un dashboard comme décrit dans le screenshot au début de ce notebook