боке, как динамически менять цвет в глифе на основе базовых данных - PullRequest
0 голосов
/ 15 января 2019

Я сделал следующую панель в боке. При нажатии кнопки «Обновить данные» желтые данные гистограммы изменяются. Я хотел бы изменить цвет на желтую гистограмму, если среднее значение больше или меньше среднего значения серой гистограммы.

enter image description here

Это код:

from bokeh.plotting import figure
import numpy as np
import pandas as pd
from bokeh.io import curdoc
from bokeh.layouts import column


from bokeh.models import Button
from bokeh.layouts import widgetbox


from bokeh.plotting import ColumnDataSource

button = Button(label='Update Data')

def generate_time_differences(n=1000, skew_p=0.1, mean=0, std=1, skew_mean=1, skew_std=6):
    normal_dist = np.random.normal(loc=mean, scale=std, size=int(n * (1 - skew_p)))
    skewed_dist = np.random.normal(loc=skew_mean, scale=skew_std, size=int(n * skew_p))

    return np.append(normal_dist, skewed_dist)


def generate_plot_data(data, density=True, bins=50):
    hist, edges = np.histogram(data, density=density, bins=bins)

    df = pd.DataFrame({'top': hist,
                         'left': edges[:-1],
                         'right': edges[1:]}

                      )
    df['mean'] = [np.mean(data) for i in range(len(df))]
    df['std'] = [np.std(data) for i in range(len(df))]
    df['n'] = [len(data) for i in range(len(df))]

    return ColumnDataSource(df)


def create_histogram(plot_data_control, plot_data_observed, title, x_axis_label='Milliseconds',
                     y_axis_label='Frequency'):

    mean_control = np.mean(plot_data_control.data['mean'])
    mean_observed = np.mean(plot_data_observed.data['mean'])

    color_observed = 'yellow' if mean_observed > mean_control else 'green'


    p = figure(plot_height=150, plot_width=600,
               title=title,
               x_axis_label=x_axis_label,
               y_axis_label=y_axis_label)

    # Add a quad glyph for plot_data
    p.quad(source=plot_data_control, bottom=0, top='top', left='left', right='right',
           fill_color='gray', line_color='gray', fill_alpha=0.5, line_alpha=0.5, legend='Control')
    # Add another quad glyph for plot_data2
    p.quad(source=plot_data_observed, bottom=0, top='top', left='left', right='right',
           fill_color=color_observed, line_color=color_observed, fill_alpha=0.5, line_alpha=0.5, legend='Observed')
    return p

def update():

    mean = np.random.randint(500,1500)
    std = 100
    skew_mean =  2000
    skew_std = 500

    new_plot_data = generate_time_differences(n=100, skew_p=0.1, mean=mean, std=std, skew_mean=skew_mean, skew_std=skew_std)

    plot_data2.data =  generate_plot_data(new_plot_data).data


data = generate_time_differences(n=1000, skew_p=0.1, mean=1000, std=100, skew_mean=2000, skew_std=500)
data2 = generate_time_differences(n=100, skew_p=0.1, mean=1050, std=100, skew_mean=2100, skew_std=500)


plot_data = generate_plot_data(data)
plot_data2 = generate_plot_data(data2)


p1 = create_histogram(plot_data, plot_data2, 'Status1 to Status2')

button.on_click(update)

layout = column(widgetbox(button), p1)

curdoc().add_root(layout)

1 Ответ

0 голосов
/ 15 января 2019

Вы можете добавить цвет к источнику columndatasource и изменить его при вызове функции обратного вызова и, если условие истинно. Добавил несколько комментариев к коду, чтобы объяснить, что я изменил.

from bokeh.plotting import figure
import numpy as np
import pandas as pd
from bokeh.io import curdoc
from bokeh.layouts import column


from bokeh.models import Button
from bokeh.layouts import widgetbox


from bokeh.plotting import ColumnDataSource

button = Button(label='Update Data')

def generate_time_differences(n=1000, skew_p=0.1, mean=0, std=1, skew_mean=1, skew_std=6):
    normal_dist = np.random.normal(loc=mean, scale=std, size=int(n * (1 - skew_p)))
    skewed_dist = np.random.normal(loc=skew_mean, scale=skew_std, size=int(n * skew_p))

    return np.append(normal_dist, skewed_dist)


def generate_plot_data(data, density=True, bins=50):
    hist, edges = np.histogram(data, density=density, bins=bins)

    df = pd.DataFrame({'top': hist,
                         'left': edges[:-1],
                         'right': edges[1:]}

                      )
    df['mean'] = [np.mean(data) for i in range(len(df))]
    df['std'] = [np.std(data) for i in range(len(df))]
    df['n'] = [len(data) for i in range(len(df))]

    return ColumnDataSource(df)


def create_histogram(plot_data_control, plot_data_observed, title, x_axis_label='Milliseconds',
                     y_axis_label='Frequency'):

    mean_control = np.mean(plot_data_control.data['mean'])
    mean_observed = np.mean(plot_data_observed.data['mean'])
    #Change color if mean_observed > mean_control
    if mean_observed > mean_control:
        color_observed = 'yellow'
    else:
        color_observed = 'green'
    #Generate a list with the right color
    colorlst = []
    for i in range(len(plot_data_observed.data['top'])):
        colorlst.append(color_observed)
    #Add color list to sourcedata
    plot_data_observed.data['color'] = colorlst

    p = figure(plot_height=150, plot_width=600,
               title=title,
               x_axis_label=x_axis_label,
               y_axis_label=y_axis_label)

    # Add a quad glyph for plot_data
    p.quad(source=plot_data_control, bottom=0, top='top', left='left', right='right',
           fill_color='gray', line_color='gray', fill_alpha=0.5, line_alpha=0.5, legend='Control')
    # Add another quad glyph for plot_data2
    #Get color from source
    p.quad(source=plot_data_observed, bottom=0, top='top', left='left', right='right',
           fill_color='color', line_color='color', fill_alpha=0.5, line_alpha=0.5, legend='Observed')
    p.legend.click_policy="hide"
    return p

def update():
    mean = np.random.randint(500,1500)
    std = 100
    skew_mean =  2000
    skew_std = 500
    new_plot_data = generate_time_differences(n=100, skew_p=0.1, mean=mean, std=std, skew_mean=skew_mean, skew_std=skew_std)
    obs_data = generate_plot_data(new_plot_data).data
    #Get means
    mean_control = plot_data.data['mean'][0]
    mean_observed = obs_data['mean'][0]
    #Change color if mean_observed > mean_control
    if mean_observed > mean_control:
        color_observed = 'yellow'
    else:
        color_observed = 'green'
    #Generate a list with the right color
    colorlst = []
    for i in range(len(obs_data['top'])):
        colorlst.append(color_observed)
    #Add list to dictionary
    obs_data['color'] = colorlst
    #Set dictionary as sourcedata
    plot_data2.data =  obs_data


data = generate_time_differences(n=1000, skew_p=0.1, mean=1000, std=100, skew_mean=2000, skew_std=500)
data2 = generate_time_differences(n=100, skew_p=0.1, mean=1050, std=100, skew_mean=2100, skew_std=500)


plot_data = generate_plot_data(data)
plot_data2 = generate_plot_data(data2)


p1 = create_histogram(plot_data, plot_data2, 'Status1 to Status2')

button.on_click(update)

layout = column(widgetbox(button), p1)

curdoc().add_root(layout)
...