Bokeh: Mehrere Plots (Glyphs) in einem Graphen (figure) über Schleife

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
UvW
User
Beiträge: 1
Registriert: Mittwoch 1. April 2020, 07:13

Hallo zusammen,

ich versuche, mehrere Scatterglyphen mit Hilfe einer Schleife in einen Plot zu bekommen. Das Ziel ist es, für jede Marke (brand) eine eigene Glyphe zu verwenden und die Werte zu aktualisieren, wenn ein anderer Wert von den Select-Widgets (Wert x-Achse, Wert -Achse) gewählt wird.
Hintergrund ist, dass ich später eine "Interactive Legend" erstellen möchte, bei der man durch klick auf enen Eintrag den Graphen "verstecken" kann.

Das man mehrere Graphen/Glyphen in einen Plot bekommt habe ich ohne Schleife schon hinbekommen, s. auch hier: https://docs.bokeh.org/en/latest/docs/g ... ght=legend
Die Interaktive Legende wird hier beschrieben: https://docs.bokeh.org/en/latest/docs/u ... ght=legend

Die Abbildung zeigt jedoch ein leeres Diagramm, bzw nur den letzten Graphen aus der Schleife. Ich gehe davon aus, dass das Problem die ColumnDataSource und die Aktualisierung in der Funktion "update()" ist. Unten findet Ihr ein ausführbares Beispiel (Ich verwende eigentlich einen Bokeh server, habe hier aber ein Ausführbares Beispiel gepostet, daher kommt die Warnung mit NodeJS und Bokehserver).

Habt Ihr eine Idee? Vielen Dank für Eure Hilfe!

Code: Alles auswählen

from bokeh.layouts import column, row
from bokeh.models import ColumnDataSource, Select, HoverTool
from bokeh.plotting import figure, show

import pandas as pd

brands = ['a', 'b', 'c', 'a', 'b', 'b', 'c']
product = ['v1', 'v2', 'v3', 'v4', 'v5', 'v6', 'v7']
price = [2, 3, 54, 48, 9, 2, 4]
size = [10, 11, 12, 13, 14, 15, 16]
value = [5, 4, 3, 8, 1, 0, 1]
id = [1, 2, 3, 4, 5, 6, 7]
col = ['ID', 'brand', 'product', 'price', 'size', 'value']
label = ['price', 'size', 'value']

df = pd.DataFrame(zip(brands, product, price, size, value, id), columns=col)

# Widgets:
select_x_axis = Select(title="x-Axis:", value=label[0], options=label)
select_y_axis = Select(title="y-Axis:", value=label[1], options=label)

# Set up figure
hover = HoverTool(tooltips=[
    ("index", "@id"),
    ('Brand', '@brand'),
    ('Product', '@product'),
    (select_x_axis.value, '@x'),
    (select_y_axis.value, '@y')
])

# Set up plots:
fig = figure(plot_height=400, plot_width=800, title="xyz",
             # tooltips=TOOLTIPS,
             tools=[hover, 'reset'],
             x_axis_label=select_x_axis.value,
             y_axis_label=select_y_axis.value)
source = {}
plots = {}
for brand in brands:
    # Create Column Data Source that will be used by the plot
    source[brand] = ColumnDataSource(data=dict(x=[], y=[], id=[], product=[], brand=[]))
    plots[brand] = fig.scatter(x='x', y='y', size=5, source=source[brand])


def update():
    x_name = select_x_axis.value
    y_name = select_y_axis.value
    fig.xaxis.axis_label = x_name
    fig.yaxis.axis_label = y_name
    for brand in brands:
        df1 = df.loc[df['brand'] == brand]
        source[brand].data = dict(
            x=df1[x_name],
            y=df1[y_name],
            id=df1['ID'],
            product=df1['product'],
            brand=df1['brand']
        )

# Set up layouts and add to document
controls = [select_x_axis, select_y_axis]
for control in controls:
    control.on_change('value', lambda attr, old, new: update())

inputs = column(select_x_axis, select_y_axis)
update()  # initial load of the data

show(row(inputs, fig, width=1000))
#curdoc().add_root(row(inputs, fig, width=1000))
#curdoc().title = "xyz"
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Du begibst dich mit sowas in die Untiefen der GUI-Programmierung, wenn du das interaktiv und dynamisch machen willst. Und da darf man keine Schleifen haben, die etwas updaten in der GUI, sondern muss Ereignisbasiert arbeiten.

Eine Moeglichkeit ist das hier: https://docs.bokeh.org/en/latest/docs/r ... c_callback

Auf die Warnung achten!
Antworten