Добавьте несколько глифов рассеяния на один график (рисунок) - Python, Bokeh - PullRequest
0 голосов
/ 31 марта 2020

Я пытаюсь нанести несколько глифов рассеяния на одну фигуру, используя al oop. Цель состоит в том, чтобы использовать собственный глиф для каждого бренда и обновлять значения, если виджеты Select выбирают другое значение.

Но на рисунке показан пустой график. Я предполагаю, что проблема в ColumnDataSource и обновлении в функции "update ()". Это исполняемый пример. У вас есть идеи?

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"

повторный сюжет

Ответы [ 2 ]

0 голосов
/ 01 апреля 2020

@ jsgounot Спасибо за вашу помощь. Я понял кое-что, что в данный момент работает хорошо:

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

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']

colors = d3["Category20c"][len(brands)]
markers = ['circle', 'square', 'triangle', 'asterisk', 'circle_x', 'square_x', 'inverted_triangle', 'x', 'circle_cross', 'square_cross', 'diamond', 'cross']

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

default_xcol = "price"
default_ycol = "size"

df["xvalues"] = df[default_xcol]
df["yvalues"] = df[default_ycol]

# 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, '@xvalues'),
    (select_y_axis.value, '@yvalues')
])

# 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)

df_brand = []
sources = []
plots = {}
for index, brand in enumerate(df.brand.unique()):
    df_brand.append(df.loc[df['brand'] == brand])
    sources.append(ColumnDataSource(df_brand[index]))
    plots[brand] = fig.scatter(x='xvalues', y='yvalues', source=sources[index],
                               legend_label=brand,
                               marker=markers[index],
                               color=colors[index])
fig.legend.click_policy="hide"

callback_x = CustomJS(args={'sources': sources, 'axis': fig.xaxis[0], 'brands': df.brand.unique()}, code="""
    for (var i = 0; i <= 2; i++){
        var source = sources[i]
        source.data['xvalues'] = source.data[cb_obj.value];
        source.change.emit();
    }
    axis.axis_label = cb_obj.value;
    """)
callback_y = CustomJS(args={'sources': sources, 'axis': fig.yaxis[0], 'hov': fig.hover, 'brands': df.brand.unique()}, code="""
    for (var i = 0; i <= 2; i++){
        var source = sources[i]
        source.data['yvalues'] = source.data[cb_obj.value];
        source.change.emit();
    }
    axis.axis_label = cb_obj.value;
    """)


select_x_axis.js_on_change('value', callback_x)
select_y_axis.js_on_change('value', callback_y)

show(row(
        column(select_x_axis, select_y_axis),
        fig, width=1000))
0 голосов
/ 31 марта 2020

Что-то в этом роде?

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

import pandas as pd

def make_data() :
    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]
    ident = [1, 2, 3, 4, 5, 6, 7]
    col = ['ID', 'brand', 'product', 'price', 'size', 'value']
    label = ['price', 'size', 'value']
    return pd.DataFrame(zip(brands, product, price, size, value, ident), columns=col)

if __name__ == "__main__" :
    df = make_data()

    default_xcol = "price"
    default_ycol = "size"

    df["xvalues"] = df[default_xcol]
    df["yvalues"] = df[default_ycol]

    # Scatter plot
    hover = HoverTool(tooltips=[(name, "@" + name) for name in df.columns])
    figure = figure(tools=[hover, 'reset'])

    # Source    
    source = ColumnDataSource(df)
    figure.scatter("xvalues", "yvalues", source=source)

    # Selects 
    options = ["product", "price", "size", "value"]
    select_x_axis = Select(title="x-Axis:", value=default_xcol, options=options)
    select_y_axis = Select(title="y-Axis:", value=default_ycol, options=options)

    # callback
    callback = CustomJS(args={"source":source, "axis":figure.xaxis[0]}, code="""
        source.data['xvalues'] = source.data[cb_obj.value];
        source.change.emit();
        axis.axis_label = cb_obj.value;
        """)

    select_x_axis.js_on_change("value", callback)

    callback = CustomJS(args={"source":source, "axis":figure.yaxis[0]}, code="""
        source.data['yvalues'] = source.data[cb_obj.value];
        source.change.emit();
        axis.axis_label = cb_obj.value;
        """)   

    select_y_axis.js_on_change("value", callback)

    show(row(
        column(select_x_axis, select_y_axis), 
        figure, width=1000))
...