[PYTHON] Ich möchte die Grundlagen von Bokeh vollständig verstehen

Um die interaktive Handlung von Bokeh so sorgfältig wie möglich zu verstehen, werde ich versuchen, sie am Beispiel von [Erschwingliches Beispiel] 0 zu entschlüsseln. Ich habe die Spezifikationen erwartungsgemäß aus dem Quellcode geschrieben, aber da ich auch die Dokumentation überprüft habe, sollte es keinen Zweifel geben. Der gesamte Quellcode ist [hier] 1

So ein Typ ↓ bokeh.png

Datengenerierung

# create three normal population samples with different parameters
x1 = np.random.normal(loc=5.0, size=400) * 100
y1 = np.random.normal(loc=10.0, size=400) * 10

x2 = np.random.normal(loc=5.0, size=800) * 50
y2 = np.random.normal(loc=5.0, size=800) * 10

x3 = np.random.normal(loc=55.0, size=200) * 10
y3 = np.random.normal(loc=4.0, size=200) * 10

x = np.concatenate((x1, x2, x3))
y = np.concatenate((y1, y2, y3))

Die Erklärung wird weggelassen, da sie nicht mit Bokeh zusammenhängt.

Punktgruppendiagramm

TOOLS="pan,wheel_zoom,box_select,lasso_select,reset"

# create the scatter plot
p = figure(tools=TOOLS, plot_width=600, plot_height=600, min_border=10, min_border_left=50,
           toolbar_location="above", x_axis_location=None, y_axis_location=None,
           title="Linked Histograms")
p.background_fill_color = "#fafafa"

↑ Geben Sie dem Figurenobjekt den Namen des Werkzeugs, das Sie anzeigen möchten, und legen Sie die Hintergrundfarbe fest. Bis zu diesem Punkt entspricht der Durchfluss einem normalen Diagramm. figure ist eine Funktion von bokeh.models.figure und der Rückgabewert ist bokeh.models.Figure. Ich werde verschiedene Einstellungen vornehmen.

p.select(BoxSelectTool).select_every_mousemove = False
p.select(LassoSelectTool).select_every_mousemove = False

↑ Seien Sie von hier aus vorsichtig. Erstens ist p.select () eine Zahlenmethode, und die wichtigste ist die Vererbungsquelle bokeh.models.Model. Gibt bei Angabe eines Klassenobjekts für den Selektor den entsprechenden Selektortyp zurück, der der Abbildung zugewiesen ist. In der ersten Zeile wird beispielsweise eine Instanz der BoxSelectTool-Klasse abgerufen. Wenn Sie select_every_mousemove auf False setzen, erfolgt die Aktualisierung erst, wenn die Mausauswahl abgeschlossen ist.

Referenz →

select(selector) Query this object and all of its references for objects that match the given selector.

r = p.scatter(x, y, size=3, color="#3A5785", alpha=0.6)

Hier ist eine Darstellung der Punkte! Der Rückgabewert r wird zuletzt verwendet. Der zurückgegebene Rückgabewert wird im Allgemeinen von einer Instanz der GlyphRenderer-Klasse zurückgegeben, die später zum Optimieren des Diagramms verwendet werden kann.

Histogramm

# create the horizontal histogram
hhist, hedges = np.histogram(x, bins=20)
hzeros = np.zeros(len(hedges)-1)
hmax = max(hhist)*1.1

↑ Der Rückgabewert von numpy.histrogram () ist (Höhenliste jedes Histogramms, Grenzwertliste des Histogramms). Bokeh spielt keine Rolle.

LINE_ARGS = dict(color="#3A5785", line_color=None)

ph = figure(toolbar_location=None, plot_width=p.plot_width, plot_height=200, x_range=p.x_range,
            y_range=(-hmax, hmax), min_border=10, min_border_left=50, y_axis_location="right")
ph.xgrid.grid_line_color = None
ph.yaxis.major_label_orientation = np.pi/4
ph.background_fill_color = "#fafafa"

ph.quad(bottom=0, left=hedges[:-1], right=hedges[1:], top=hhist, color="white", line_color="#3A5785")

↑ Horizontales Histogramm. Es gibt viele Einstellungselemente und es ist kompliziert, aber der Grundablauf bleibt der gleiche. Ich bekomme eine Figur mit figure () und zeichne ein Viereck mit seiner quad () -Methode. (Es scheint eine Methode zu sein, die ein Rechteck parallel zu den Koordinaten zeichnet, keine Methode, die dem Histogramm gewidmet ist.) Die Koordinaten der vier Seiten werden durch unten ~ oben angegeben. Jedes Viereck scheint eine Instanz der Klasse bokeh.models.glyphs.Quad zu sein.

Die anderen Argumente, die nützlich erscheinen, sind wie folgt.

toolbar_location=None #Werkzeugleiste verstecken
plot_width=p.plot_width #Teilen Sie die Breite des Diagramms
x_range=p.x_range #x Bereichsfreigabe koordinieren
min_border_left=50 #Minimaler Rand auf der linken Seite des Diagramms
ph.yaxis.major_label_orientation = np.pi/4 #Etikettenrotation koordinieren

Histogramm zum Zeitpunkt der Auswahl

Das Histogramm, das angezeigt wird, wenn Sie eine Punktgruppe auswählen.

hh1 = ph.quad(bottom=0, left=hedges[:-1], right=hedges[1:], top=hzeros, alpha=0.5, **LINE_ARGS)
hh2 = ph.quad(bottom=0, left=hedges[:-1], right=hedges[1:], top=hzeros, alpha=0.1, **LINE_ARGS)

Ich habe es zuerst gezeichnet. Zu diesem Zeitpunkt ist top = hzeros, daher wird die Höhe auf 0 gesetzt und ist nicht sichtbar. Es scheint, dass die Höhe dieser Rückgabewerte hh1 und hh2 bei Auswahl (*) aktualisiert wird.

Vertikales Histogramm

# create the vertical histogram
vhist, vedges = np.histogram(y, bins=20)
vzeros = np.zeros(len(vedges)-1)
vmax = max(vhist)*1.1

pv = figure(toolbar_location=None, plot_width=200, plot_height=p.plot_height, x_range=(-vmax, vmax),
            y_range=p.y_range, min_border=10, y_axis_location="right")
pv.ygrid.grid_line_color = None
pv.xaxis.major_label_orientation = np.pi/4
pv.background_fill_color = "#fafafa"

pv.quad(left=0, bottom=vedges[:-1], top=vedges[1:], right=vhist, color="white", line_color="#3A5785")
vh1 = pv.quad(left=0, bottom=vedges[:-1], top=vedges[1:], right=vzeros, alpha=0.5, **LINE_ARGS)
vh2 = pv.quad(left=0, bottom=vedges[:-1], top=vedges[1:], right=vzeros, alpha=0.1, **LINE_ARGS)

Es wird auf die gleiche Weise wie in horizontaler Richtung eingestellt.

Fertig

Bauen Sie die alten zusammen.

layout = gridplot([[p, pv], [ph, None]], merge_tools=False)

↑ Zunächst werden Figuren mit der Funktion bokeh.layouts.girdplot () zweidimensional angeordnet. Übrigens, wenn Sie nur vertikal oder horizontal anstatt zweidimensional anordnen möchten, verwenden Sie bokeh.layouts.column oder row.

curdoc().add_root(layout)
curdoc().title = "Selection Histogram"

↑ curdoc ist eine Abkürzung für das aktuelle Dokument, das das Standarddokument (eine Klasse, die die Ausgabe von bokeh zusammenfasst) abruft und es mit der Methode add_root () mit dem Raster verknüpft. Dies ist der Punkt, aber es scheint, dass die Spezifikation lautet: "Wenn Änderungen am add_root-Raster vorgenommen werden, wird der in Document mit" on_change "registrierte Rückruf aufgerufen." Aus der Referenz →

add_root(model, setter=None)

Add a model as a root of this Document. Any changes to this model (including to other models referred to by it) will trigger on_change callbacks registered on this document.

Wenn Sie also zuerst die letzte Zeile betrachten,

r.data_source.selected.on_change('indices', update)

Es ist wahr, dass der Rückruf in on_change registriert ist.

R hier ist der Rückgabewert von Scatter Plot () (eine Instanz der GlyphRenderer-Klasse) r.data_source entspricht dem geplotteten Datensatz und seine Auswahl entspricht dem ausgewählten Teil der Daten.

on_chage () ist eine Methode von bokeh.model.Model, die einen Rückruf für dieses Objekt registriert.

def on_change(self, attr, *callbacks):
        ''' Add a callback on this object to trigger when ``attr`` changes.

        Args:
            attr (str) : an attribute name on this object
            *callbacks (callable) : callback functions to register

Das erste Argument attr ist schwer zu verstehen, aber hier beschreiben wir "welche Änderungen, um den Rückruf aufzurufen". Da es sich diesmal um einen Auswahlbereich handelt (= Datenindex = Auswahlindizes), werden "Indizes" angegeben.

Wenn Sie einen Rückruf an ein bestimmtes Ereignis (Tastendruck, Schiebereglerbewegung usw.) binden möchten, anstatt ihn zu ändern

on_event(event, callback)

verwenden.

(Abgesehen von den folgenden) Hier werden Python-Funktionen registriert, aber wenn Sie in Javascript geschriebene Funktionen registrieren möchten (eine Instanz von bokeh.models.CustomJS)

m.js_on_change(attr, callback)

Sollte benutzt werden. Dieser Bereich wird in [Kapitel 6 des offiziellen Tutorials] 1 beschrieben. Es scheint, dass Sie dies verwenden müssen, wenn Sie eine einzelne HTML-Ausgabe wünschen. Warnung zur Laufzeit →

WARNING:bokeh.embed.util:
You are generating standalone HTML/JS output, but trying to use real Python
callbacks (i.e. with on_change or on_event). This combination cannot work.

Only JavaScript callbacks may be used with standalone output. For more
information on JavaScript callbacks with Bokeh, see:

    https://docs.bokeh.org/en/latest/docs/user_guide/interaction/callbacks.html

Alternatively, to use real Python callbacks, a Bokeh server application may
be used. For more information on building and running Bokeh applications, see:

    https://docs.bokeh.org/en/latest/docs/user_guide/server.html

(Abgesehen von hier)

Zum Schluss über den Inhalt der Rückruffunktion update ()

def update(attr, old, new):
    inds = new
    if len(inds) == 0 or len(inds) == len(x):
        hhist1, hhist2 = hzeros, hzeros
        vhist1, vhist2 = vzeros, vzeros
    else:
        neg_inds = np.ones_like(x, dtype=np.bool)
        neg_inds[inds] = False
        hhist1, _ = np.histogram(x[inds], bins=hedges)
        vhist1, _ = np.histogram(y[inds], bins=vedges)
        hhist2, _ = np.histogram(x[neg_inds], bins=hedges)
        vhist2, _ = np.histogram(y[neg_inds], bins=vedges)

    hh1.data_source.data["top"]   =  hhist1
    hh2.data_source.data["top"]   = -hhist2
    vh1.data_source.data["right"] =  vhist1
    vh2.data_source.data["right"] = -vhist2

Es scheint, dass das durch on_change angegebene attr und die alten und neuen Werte vor und nach der Änderung des Attributs als Argumente angegeben werden. Neu ist hier der Index der neu ausgewählten Punktgruppe. Wie durch (*) vorhergesagt, wird der Spitzenwert des horizontalen Histogramms gemäß dem ausgewählten Index aktualisiert. Die Referenzbeziehung ist ein wenig weit, aber

Originaldatensatz ↑ Streudiagramm (= Datenquelle mit horizontalem Histogramm teilen) ↑ selection ↑ Rückruf on_change

Es ist ersichtlich, dass der Index, der dem Argument von on_change gegeben wird, mit dem Index des ersten Datensatzes identisch ist, da er wie folgt verbunden ist.

Verweise

[Offizielles Beispiel] 0 [Quellcode] 1

Recommended Posts

Ich möchte die Grundlagen von Bokeh vollständig verstehen
Ich möchte das Erscheinungsbild von zabbix anpassen
Selbst Anfänger möchten sagen "Ich verstehe Python voll und ganz"
Ich möchte das Ausführungsergebnis von strace erfassen
Ich möchte die Sicherheit der SSH-Verbindung erhöhen
Ich möchte systemd grob verstehen
Ich möchte nur die SudachiPy-Normalisierungsverarbeitung verwenden
Ich möchte die Authentizität eines Elements eines numpy-Arrays bestimmen
Ich möchte die Natur von Python und Pip kennenlernen
Keras Ich möchte die Ausgabe einer beliebigen Ebene erhalten !!
Ich möchte die Legende der IT-Technologiewelt kennenlernen
Ich möchte Spyder an die Taskleiste anheften
Ich möchte den Namen der ausgeführten Funktion / Methode erhalten
Ich möchte kühl auf die Konsole ausgeben
[Pytorch] Ich möchte die Trainingsparameter des Modells manuell zuweisen
[Python3] Verstehe die Grundlagen von Beautiful Soup
Ich möchte mit dem Reim Teil1 umgehen
Ich möchte die HTML-Version der OpenCV 3.1-Version "OpenCV-Python Tutorials" lesen
Ich möchte mit dem Reim part3 umgehen
Ich kannte die Grundlagen von Python nicht
Ich möchte den Fortschrittsbalken anzeigen
Ich möchte die Position meines Gesichts mit OpenCV überprüfen!
Ich möchte die Bevölkerung jedes Landes der Welt kennenlernen.
Ich möchte mit dem Reim part2 umgehen
Ich möchte mit dem Reim part5 umgehen
Ich möchte mit dem Reim part4 umgehen
[Python3] Grundlegendes zu Dateivorgängen
Ich möchte es nicht zugeben ... Die dynamische Systemdarstellung von Neural Network
Ich möchte die abstrakte Klasse (ABCmeta) von Python im Detail erklären
Ich möchte eine Liste in der Reihenfolge anderer Listen sortieren
Ich möchte meine Gefühle mit den Texten von Mr. Children ausdrücken
Ich möchte die Gefühle von Menschen analysieren, die sich treffen und zittern wollen
Ich möchte den Erfolg von NBA-Spielern mit dem Qore SDK vorhersagen
Ich möchte einen beliebigen Befehl im Befehlsverlauf von Shell belassen
Ich möchte das automatische Löschen des tmp-Bereichs in RHEL7 stoppen
Python: Ich möchte die Verarbeitungszeit einer Funktion genau messen
Ich möchte mit dem Reim part7 (BOW) umgehen
Ich möchte die Daten von League of Legends ③ erhalten
Ich möchte die Daten von League of Legends ② erhalten
Ich möchte League of Legends-Daten erhalten ①
Ich möchte die Aktivierungsfunktion Mish verwenden
Ich möchte den Fortschritt in Python anzeigen!
Ich habe versucht, die Texte von Hinatazaka 46 zu vektorisieren!
Ich möchte den Pfad des Verzeichnisses abrufen, in dem die laufende Datei gespeichert ist.
Ich möchte den Transferstatus der 2020 J League visualisieren. Was soll ich tun?
Die Geschichte der IPv6-Adresse, die ich auf ein Minimum beschränken möchte
Ich möchte Python in der Umgebung von pyenv + pipenv unter Windows 10 verwenden
Ich möchte PyTorch verwenden, um so etwas wie den Text von Japari Park zu generieren
Ich möchte einen Lebenszyklus in der Aufgabendefinition von ECS festlegen
Ich möchte dem Anfang einer WAV-Datei 1 Sekunde lang Stille hinzufügen
Ich möchte eine Liste der WebDAV-Dateien im Modul Anfragen anzeigen
Ich möchte das Bild entlang der Kontur anstelle des Rechtecks zuschneiden [Python OpenCV]
Ich möchte die Ergebnisse von% time, %% time usw. in einem Objekt (Variable) speichern.
Ich habe die Größenänderung von TensorFlow nicht verstanden und sie daher visuell zusammengefasst.
Ich möchte den Dateinamen von DataLoader sehen
Ich möchte UMAP (Engineering) stärker verstehen als t-SNE
Ich möchte Bilder von Katzen von Instagram erkennen