[PYTHON] Visualisation interactive avec ipywidgets et Bokeh

Pourquoi c'est interactif

Si vous souhaitez générer un graphique avec certains paramètres, les méthodes suivantes peuvent être considérées comme une méthode pour vérifier chaque fois que les paramètres sont modifiés.

  1. Entrez l'argument de la fonction de sortie à chaque fois et sortez le graphique
  2. Sortez tous les graphiques des paramètres que vous souhaitez modifier
  3. Définissez les paramètres et le graphique de sortie de manière interactive

La méthode «1» est un peu lourde à taper. Même si c'est sur la console IPython, exécutez la fonction avec Jupyter notebook et réécrivez l'argument de la fonction exécutée ... Oui, c'est gênant. Et la méthode «2»? Il semble assez pratique de produire deux ou trois graphiques à la fois et de les comparer. Cependant, dans une situation où il existe 100 paramètres de ce type, il semble difficile de vérifier avec l'œil humain. Alors, implémentons la méthode 3.

Installation d'ipywidgets

Il est facile d'utiliser ʻipywidgets pour implémenter une interface utilisateur interactive avec Jupyter notebook`. La méthode d'installation est la suivante.

Pour pip

pip install ipywidgets
jupyter nbextension enable --py widgetsnbextension

Pour conda

conda install -c conda-forge ipywidgets

ipywidgets.interact

Vous pouvez créer une interface utilisateur interactive simplement en décorant ʻipywidgets.interact la fonction souhaitée. Dans l'exemple ci-dessous, le cours de l'action est acquis et la moyenne mobile du cours de clôture pendant n jours est sortie sur le graphique. Si vous donnez une valeur numérique à l'argument de ʻinteract, un curseur sera affiché sur le notebook Jupyter, et l'ajuster changera le paramètre de la moyenne mobile. n = (5, 30) définit la valeur minimale sur "5" et la valeur maximale sur "30". Vous pouvez également définir n = 10, qui est la valeur par défaut sans aucune restriction.

%matplotlib inline

from pandas_datareader.data import DataReader
from ipywidgets import interact

price = DataReader('^GSPC', 'yahoo', start='2016-01-01', end='2016-12-31')


@interact(n=(5, 30))
def plot_rolling_mean(n):
    price['Adj Close'].plot()
    price['Adj Close'].rolling(n).mean().plot()

rolling_mean.gif

De cette manière, il est possible de rechercher visuellement la valeur appropriée du paramètre dans l'interface utilisateur.

Comme autre exemple, changeons le type de graphique. Si vous donnez un tap ou une liste à l'argument de ʻinteract`, un menu déroulant sera affiché. Utilisons ceci pour changer le type de graphique dans l'interface utilisateur.

@interact(kind=['line', 'area'])
def plot_line_or_band(kind):
    price['Adj Close'].plot(kind=kind)

chart_type.gif

En préparant l'interface utilisateur et les options à l'avance de cette manière, il est possible d'encourager intuitivement les opérations même pour ceux qui ne comprennent pas le programme.

En savoir plus sur ipywidgets

Vous pouvez également le trouver dans la documentation (https://ipywidgets.readthedocs.io/en/latest/index.html), mais voir la liste des interfaces utilisateur fournies par ʻipywidgets de ʻipywidgets.widgets.Widget.widget_types Est possible.

import ipywidgets as widgets
widgets.Widget.widget_types

Il n'y a que ça ...

{'Jupyter.Accordion': ipywidgets.widgets.widget_selectioncontainer.Accordion,
 'Jupyter.BoundedFloatText': ipywidgets.widgets.widget_float.BoundedFloatText,
 'Jupyter.BoundedIntText': ipywidgets.widgets.widget_int.BoundedIntText,
 'Jupyter.Box': ipywidgets.widgets.widget_box.Box,
 'Jupyter.Button': ipywidgets.widgets.widget_button.Button,
 'Jupyter.Checkbox': ipywidgets.widgets.widget_bool.Checkbox,
 'Jupyter.ColorPicker': ipywidgets.widgets.widget_color.ColorPicker,
 'Jupyter.Controller': ipywidgets.widgets.widget_controller.Controller,
 'Jupyter.ControllerAxis': ipywidgets.widgets.widget_controller.Axis,
 'Jupyter.ControllerButton': ipywidgets.widgets.widget_controller.Button,
 'Jupyter.Dropdown': ipywidgets.widgets.widget_selection.Dropdown,
 'Jupyter.FlexBox': ipywidgets.widgets.widget_box.FlexBox,
 'Jupyter.FloatProgress': ipywidgets.widgets.widget_float.FloatProgress,
 'Jupyter.FloatRangeSlider': ipywidgets.widgets.widget_float.FloatRangeSlider,
 'Jupyter.FloatSlider': ipywidgets.widgets.widget_float.FloatSlider,
 'Jupyter.FloatText': ipywidgets.widgets.widget_float.FloatText,
 'Jupyter.HTML': ipywidgets.widgets.widget_string.HTML,
 'Jupyter.Image': ipywidgets.widgets.widget_image.Image,
 'Jupyter.IntProgress': ipywidgets.widgets.widget_int.IntProgress,
 'Jupyter.IntRangeSlider': ipywidgets.widgets.widget_int.IntRangeSlider,
 'Jupyter.IntSlider': ipywidgets.widgets.widget_int.IntSlider,
 'Jupyter.IntText': ipywidgets.widgets.widget_int.IntText,
 'Jupyter.Label': ipywidgets.widgets.widget_string.Label,
 'Jupyter.PlaceProxy': ipywidgets.widgets.widget_box.PlaceProxy,
 'Jupyter.Play': ipywidgets.widgets.widget_int.Play,
 'Jupyter.Proxy': ipywidgets.widgets.widget_box.Proxy,
 'Jupyter.RadioButtons': ipywidgets.widgets.widget_selection.RadioButtons,
 'Jupyter.Select': ipywidgets.widgets.widget_selection.Select,
 'Jupyter.SelectMultiple': ipywidgets.widgets.widget_selection.SelectMultiple,
 'Jupyter.SelectionSlider': ipywidgets.widgets.widget_selection.SelectionSlider,
 'Jupyter.Tab': ipywidgets.widgets.widget_selectioncontainer.Tab,
 'Jupyter.Text': ipywidgets.widgets.widget_string.Text,
 'Jupyter.Textarea': ipywidgets.widgets.widget_string.Textarea,
 'Jupyter.ToggleButton': ipywidgets.widgets.widget_bool.ToggleButton,
 'Jupyter.ToggleButtons': ipywidgets.widgets.widget_selection.ToggleButtons,
 'Jupyter.Valid': ipywidgets.widgets.widget_bool.Valid,
 'jupyter.DirectionalLink': ipywidgets.widgets.widget_link.DirectionalLink,
 'jupyter.Link': ipywidgets.widgets.widget_link.Link}

En fait, je n'ai pas la force physique pour expliquer tout cela, donc je vais utiliser ʻipywidgets.widgets.Dropdown` comme exemple.

from IPython.display import display
d = widgets.Dropdown(options=['red', 'green', 'blue'], value='blue')


def on_value_change(change):
    print(change['new'])


d.observe(on_value_change, names='value')

display(d)

La liste déroulante est affichée dans ʻIPython.display.display, et l'événement est géré dans la méthode ʻobserve. L'argument mot-clé names reçoit les propriétés à transmettre à la fonction ʻon_value_change. Utilisez normalement `` valeur ''. Lorsque la valeur de la liste déroulante change, ʻon_value_change est appelé et la valeur de la propriété'value' est affichée.

Essayez de combiner avec push_notebook de Bokeh

Bokeh a une méthode pratique appelée bokeh.io.push_notebook, qui vous permet de gérer les graphiques qui ont déjà été générés et de pousser les modifications à leur contenu. Changeons dynamiquement la couleur de l'objet graphique en utilisant la liste déroulante décrite ci-dessus.

from IPython.display import display
import ipywidgets as widgets
from bokeh.io import output_notebook, push_notebook
from bokeh.plotting import figure, show

d = widgets.Dropdown(options=['red', 'green', 'blue'], value='blue')


def on_value_change(change):
    r.glyph.fill_color = change['new']
    push_notebook(handle=t)


d.observe(on_value_change, names='value')

p = figure(width=250, height=250)
r = p.circle(1, 1, size=20, line_color=None)

output_notebook()

display(d)
t = show(p, notebook_handle=True)

change_color.gif

Les points ici sont les deux points suivants.

De cette façon, Bokeh vous permet d'apporter des modifications à l'objet graphique sur Jupyter notebook. Le matplotlib mentionné ci-dessus a exécuté le processus de redessiner le graphique entier, mais Bokeh vous permet de ne modifier que les parties nécessaires, de sorte que vous pouvez alléger le processus des graphiques dynamiques.

Comparé à matplotlib, Bokeh a une fonction qui est consciente de Jupyter notebook depuis le début car il est un retardataire, et il semble que l'on puisse dire que c'est un outil de visualisation compatible avec Jupyter notebook.

Bonus (histoire principale nommée)

C'était l'introduction. Cet article est le 16e jour du calendrier de l'Avent Jupyter Notebook 2016. Le 15ème jour était Yakiu no Hito, je vais donc continuer à essayer le matériel Yakiu.

Faisons une machine à lancer simple en supposant qu'il existe un lanceur qui peut changer dynamiquement la position du cercle sur le graphique et le lancer dans les parties supérieure, moyenne et inférieure.

from random import randint
from bokeh.io import output_notebook, push_notebook
from bokeh.plotting import figure, show
from IPython.display import display
import ipywidgets as widgets


STRIKE_ZONE_HEIGHT = 750  #Hauteur de la zone de frappe
STRIKE_ZONE_WIDTH = 432  #Largeur de la zone de frappe
STRIKE_ZONE_DIV = 3  #Divisez en 3 et lancez
zone_low = (0, int(STRIKE_ZONE_HEIGHT / STRIKE_ZONE_DIV))  #Bas de gamme
zone_mid = (zone_low[1], zone_low[1] * 2)  #Gamme moyenne
zone_high = (zone_mid[1], STRIKE_ZONE_HEIGHT)  #Gamme supérieure


#Décidez du cours
def get_cause(zone):
    return randint(0, STRIKE_ZONE_WIDTH), randint(*zone)


#Lancer à un cours fixe
def pitch(zone):
    x, y = get_cause(zone)
    r.data_source.data['x'] = [x]
    r.data_source.data['y'] = [y]
    #C'est le point! Pousser jusqu'à la poignée spécifiée
    push_notebook(handle=t)


#Que se passe-t-il lorsque vous cliquez sur le bouton
def on_button_clicked(b):
    cause_dict = {'High': zone_high, 'Mid': zone_mid, 'Low': zone_low}
    pitch(cause_dict[b.description])

#Créer un objet bouton
h = widgets.Button(description="High")
m = widgets.Button(description="Mid")
l = widgets.Button(description="Low")

#Gérer les événements lorsque vous cliquez dessus
h.on_click(on_button_clicked)
m.on_click(on_button_clicked)
l.on_click(on_button_clicked)


output_notebook()


p = figure(
    width=250,
    height=250,
    x_range=(0, STRIKE_ZONE_WIDTH),
    y_range=(0, STRIKE_ZONE_HEIGHT))
#valeur initiale
r = p.circle([STRIKE_ZONE_WIDTH / 2], [STRIKE_ZONE_HEIGHT / 2], size=20)
# notebook_handle=En ajoutant True, vous pouvez l'utiliser plus tard.
t = show(p, notebook_handle=True)
display(h)
display(m)
display(l)

pitch.gif

Pour les boutons, vous pouvez passer le contrôle avec un gestionnaire d'événements appelé ʻon_click`. Consultez la documentation relative aux événements de widget (https://ipywidgets.readthedocs.io/en/latest/examples/Widget%20Events.html) pour plus d'informations. Cette fois, les coordonnées du parcours ont été décidées par des nombres aléatoires, mais si vous insérez les données réelles et ajoutez les informations sur le type de balle et la vitesse de la balle, je pense que vous pouvez mettre en œuvre le bulletin de balle Oleore One qui n'est pas inférieur au site de baseball en direct. Personne précédente a effectué la collecte des données, donc si vous êtes celui qui est le seul, essayez-le.

Résumé

Cela fait un peu plus longtemps, mais voici un résumé de ce que je voulais vous dire cette fois.

ʻIpywidgets et Bokehsont de bons outils pourJupyter notebook`, mais ils sont peu conscients. Je serais reconnaissant si quelqu'un pouvait envisager de profiter de cette opportunité.

Recommended Posts

Visualisation interactive avec ipywidgets et Bokeh
Ajustez le style et la disposition des widgets avec ipywidgets
Implémentez "Data Visualization Design # 3" avec pandas et matplotlib
"Apprentissage de word2vec" et "Visualisation avec Tensorboard" sur Colaboratory
Vue d'ensemble et astuces de Seaborn avec visualisation de données statistiques
Visualisation des données avec les pandas
Avec et sans WSGI
Visualisation de la logistique avec Python
Un simple lecteur de musique interactif fait avec Chuck et OpenPose
Utilisation de MLflow avec Databricks ② --Visualisation des paramètres expérimentaux et des métriques -
Avec moi, cp et sous-processus
Programmation avec Python et Tkinter
Chiffrement et déchiffrement avec Python
Comprendre t-SNE et améliorer la visualisation
Travailler avec le tkinter et la souris
Python et matériel - Utilisation de RS232C avec Python -
Super résolution avec SRGAN et ESRGAN
Group_by avec sqlalchemy et sum
python avec pyenv et venv
Avec moi, NER et Flair
Fonctionne avec Python et R
Utilisation de Bokeh avec IPython Notebook