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 ↓
# 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.
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.
# 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
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.
# 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.
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.
[Offizielles Beispiel] 0 [Quellcode] 1
Recommended Posts