繁体   English   中英

如何使用 JavaScript 回调和散景滑块更改 bin 宽度

[英]How to change bin widths using JavaScript callback and Bokeh slider

任何人都可以提供有关如何使用 Bokeh 滑块对象更改 Bokeh 直方图的 bin 宽度的帮助。 我知道如何使用 Python 回调来做到这一点,但想知道如何使用 JavaScript 回调——使用CustomJS函数来做到这一点。

import pandas as pd
import numpy as np
from bokeh.plotting import figure
from bokeh.models.widgets import Slider
from bokeh.models import ColumnDataSource, CustomJS

# generate random data
x = np.random.choice(a = 20, size = 100, replace = True)

# generate histogram
hist, edges = np.histogram(x, bins = 10)

# create dataframe of histogram
hist_df = pd.DataFrame({'count': hist, 'left':edges[:-1], 'right':edges[1:]})

# generate bokeh data source
bokeh_data = ColumnDataSource(hist_df)

# generate bokeh plot
plot = figure()
plot.quad(source = bokeh_data, bottom = 0, top = 'counts', left = 'left', right = 'right') 

# generate slider object to change bin widths interactively
bin_slider = Slider(start = 10,  end = 100, step = 5, value = 10)
bin_slider.js_on_change('value', callback)

# javascript callback function to change bin widths goes here...
callback = CustomJS ....

任何帮助是极大的赞赏。

谢谢

我对此的解决方案是使用原始数据(在您的情况下为 x)来重新计算 customjs 中的直方图。 我对 javascript 真的很陌生,所以可能有更优雅的方式来实现这一点。 但无论如何,代码对我有用,所以你可以试一试。

import pandas as pd
import numpy as np
from bokeh.plotting import figure
from bokeh.models.widgets import Slider, RangeSlider
from bokeh.models import ColumnDataSource, CustomJS

# generate random data
x = np.random.normal(10, 1, 1000)

# generate histogram
hist, edges = np.histogram(x, bins = 10)

# create dataframe of histogram
hist_df = pd.DataFrame({'count': hist, 'left':edges[:-1], 'right':edges[1:]})

# generate bokeh data source for initial histogram
bokeh_data = ColumnDataSource(hist_df)

# generate bokeh data source for new histogram calculation
x_df=pd.DataFrame(x,columns={'value'})

x_src=ColumnDataSource(x_df)


# generate bokeh plot
plot = figure()
plot.quad(source = bokeh_data, bottom = 0, top = 'count', left = 'left', right = 'right') 

callback = CustomJS(args=dict(source1=x_src,source2=bokeh_data), code="""
    var data = source1.data;
    var val = data['value'];
    var length = val.length;
    var size  = bin_size.value;
    var min = data_range.value[0];
    var max = data_range.value[1];

    // Decide number of bins needed
    var bins = Math.floor((max - min) / size); 

    // Put left edge point in an array
    var left_edge = new Array(bins);
    for (var i = 0; i < bins; i++){
        left_edge[i] = min+i*size;
    }

    // Put right edge point in an array
    var right_edge = new Array(bins);
    for (var i = 0; i < bins; i++){
        right_edge[i] = min+(i+1)*size;
    }

    // Initialize frequency
    var frequency = new Array(bins);
    for (var i = 0; i < bins; i++) frequency[i] = 0;

    // Calculate frequency for each bin
    for (var i = 0; i < length; i++) {
        if (val[i]==min) frequency[0]++;
        else if (val[i]==max) frequency[bins-1]++;
        else frequency[Math.floor((val[i] - min) / size)]++;

    }

    // Oupdate data source with new bins and frequency
    var bokeh_data_new={};
    bokeh_data_new.count=frequency;
    bokeh_data_new.left=left_edge;
    bokeh_data_new.right=right_edge;

    source2.data=bokeh_data_new;
""")

# generate slider object to change bin widths interactively
binwidth_slider = Slider(start = 0,  end = 1, step = 0.02, value = 0.5 , callback=callback)
callback.args["bin_size"] = binwidth_slider

# generate range slider object to change min and max of the data points to be shown interactively
range_slider = RangeSlider(start = 0, end = 20,  step = 1, value = (0, 20), callback=callback)
callback.args["data_range"] = range_slider

widgets = WidgetBox(binwidth_slider, range_slider)

output_notebook()

show(row(plot, widgets))

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM