Javascript 自定义JS使用bokeh的独立html文档中的单选组按钮在数据帧之间进行过滤/切换

Javascript 自定义JS使用bokeh的独立html文档中的单选组按钮在数据帧之间进行过滤/切换,javascript,python,callback,pandas-groupby,bokeh,Javascript,Python,Callback,Pandas Groupby,Bokeh,这是我第一次在这里发帖,如果格式不正确,我很抱歉,我对Python也相当陌生,所以仍在学习诀窍 我一直在使用bokeh为我的同事构建可视化工具,我收集数据,运行脚本,然后将html放在服务器上供每个人访问。它一直工作得很好,但我想在bokeh绘图中添加一些标准工具以外的功能 我在bokeh图上方添加了一个单选组按钮,我想使用自定义JS代码来过滤数据帧或在已经过滤的部分数据帧之间切换。我不想使用bokeh服务器,因为我不希望其他人必须这样做,我只希望他们打开一个html 正如你在这里看到的: #

这是我第一次在这里发帖,如果格式不正确,我很抱歉,我对Python也相当陌生,所以仍在学习诀窍

我一直在使用bokeh为我的同事构建可视化工具,我收集数据,运行脚本,然后将html放在服务器上供每个人访问。它一直工作得很好,但我想在bokeh绘图中添加一些标准工具以外的功能

我在bokeh图上方添加了一个单选组按钮,我想使用自定义JS代码来过滤数据帧或在已经过滤的部分数据帧之间切换。我不想使用bokeh服务器,因为我不希望其他人必须这样做,我只希望他们打开一个html

正如你在这里看到的:

# df_final is the main data frame

# this creates 3 data frames which i could switch between:

mask_sector_1 = (df_final['Lap Distance'] < 2000)
df_sector_1 = df_final[mask_sector_1]

mask_sector_2 = (df_final['Lap Distance'] > 2000) & (df_final['Lap Distance'] < 4000)
df_sector_2 = df_final[mask_sector_2]

mask_sector_3 = (df_final['Lap Distance'] > 4000) & (df_final['Lap Distance'] < 6000)
df_sector_3 = df_final[mask_sector_3]

# this adds a new column to the data frame which corresponds to the radio group button active value, to help with filtering:

df_final.loc[(df_final['Lap Distance'] < 2000), 'callback_tag'] = '0'
df_final.loc[(df_final['Lap Distance'] >= 2000) & (df_final['Lap Distance'] < 4000), 'callback_tag'] = '1'
df_final.loc[(df_final['Lap Distance'] >= 4000) & (df_final['Lap Distance'] < lap_distance_min), 'callback_tag'] = '2'
任何帮助或指导都将不胜感激,如果我需要更多或更好的解释,请告诉我

谢谢

更新:我没有通过基本上过滤原始数据帧来让customJS代码正常工作:

from bokeh.plotting import figure, output_file, show
from bokeh.models import BoxAnnotation, Span

from bokeh.layouts import column, row, widgetbox
from bokeh.models import CustomJS, ColumnDataSource, Slider

from bokeh.io import output_notebook # , show
from bokeh.models import LinearAxis, Range1d, Label

from bokeh.palettes import Category10
from bokeh.palettes import Dark2_5 as palette
import itertools

from bokeh.models import CustomJS, ColumnDataSource, RadioButtonGroup

#source = ColumnDataSource(df_final)

group = df_final.groupby(['driver','trace_colour', 'lap_time', 'lap_number'])
source = ColumnDataSource(group)


# adding the interactive tools
tools = ["hover", "reset", "pan", "wheel_zoom", "box_zoom", 'save']

# create a new plot with a title and axis labels
p3 = figure(title = 'Driver_compare - All ' + str(n_fastest_laps) + ' Fastest Laps', x_axis_label='Lap Distance (m)', y_axis_label='variable',plot_width=700, plot_height=500, tools=tools) # x_range=(-810, lap_distance_min+100)
p3.background_fill_color = "whitesmoke"


RA_pow = Label(x = -750, y = -175, text = 'RA Lat Sliding Power', text_font_size = '10pt')
FA_pow = Label(x = -750, y = -100, text = 'FA Lat Sliding Power', text_font_size = '10pt')
CB = Label(x = -750, y = 0, text = 'Car Balance (^ = US)', text_font_size = '10pt')
curv = Label(x = -750, y = 300, text = 'Curvature', text_font_size = '10pt')

p3.add_layout(RA_pow)
p3.add_layout(FA_pow)
p3.add_layout(CB)
p3.add_layout(curv)

# Sector lines
vline = Span(location=2000, dimension='height', line_color='black', line_width=2, line_dash = 'dashed')
vline2 = Span(location=4000, dimension='height', line_color='black', line_width=2, line_dash = 'dashed')

p3.renderers.extend([vline, vline2])
    # p.add_layout(vline)


for [driver_label, trace_colour, lap_time_label, lap_number_label], group_compare in group:

    p3.line(group_compare['x_new'], group_compare['curvature'], legend_label = driver_label + ' Lap - ' + str(lap_number_label) + ' = ' + str(round(lap_time_label, 2)), line_width = 1,line_color = trace_colour) # *2000+300



# make the legend interactive 
#p3.legend.click_policy="hide"

#p3.line('x_new','curvature', source = source)


# add callback to control 

button = RadioButtonGroup(labels=["Sector_1", "Sector_2","Sector_3"], active=0) #, callback = callback

button.callback = CustomJS(args=dict(p=p3, source=source), code="""

            var radio_value = cb_obj.active;
            var data = source.data;  

            x = data['Lap Distance']
            x_new = data['x_new']

            gps_lat = data['GPS latitude']
            gps_lat_filtered = data['gps_lat_filtered']

            x_filter = data['callback_tag']
            y = data['curvature']

            for (i = 0; i < x.length; i++) {
                if(x_filter[i] == radio_value) {
                    x_new[i] = x[i];
                    gps_lat_filtered[i] = gps_lat[i];
                } else {
                    x_new[i] = undefined;
                    gps_lat_filtered[i] = undefined;
                }
            }
        source.change.emit();
        """)
然后它工作得很好,但我希望能够将数据分组并绘制单独的线

任何人都可以帮助我的语法,因为我接近得到我需要的,谢谢

from bokeh.plotting import figure, output_file, show
from bokeh.models import BoxAnnotation, Span

from bokeh.layouts import column, row, widgetbox
from bokeh.models import CustomJS, ColumnDataSource, Slider

from bokeh.io import output_notebook # , show
from bokeh.models import LinearAxis, Range1d, Label

from bokeh.palettes import Category10
from bokeh.palettes import Dark2_5 as palette
import itertools

from bokeh.models import CustomJS, ColumnDataSource, RadioButtonGroup

#source = ColumnDataSource(df_final)

group = df_final.groupby(['driver','trace_colour', 'lap_time', 'lap_number'])
source = ColumnDataSource(group)


# adding the interactive tools
tools = ["hover", "reset", "pan", "wheel_zoom", "box_zoom", 'save']

# create a new plot with a title and axis labels
p3 = figure(title = 'Driver_compare - All ' + str(n_fastest_laps) + ' Fastest Laps', x_axis_label='Lap Distance (m)', y_axis_label='variable',plot_width=700, plot_height=500, tools=tools) # x_range=(-810, lap_distance_min+100)
p3.background_fill_color = "whitesmoke"


RA_pow = Label(x = -750, y = -175, text = 'RA Lat Sliding Power', text_font_size = '10pt')
FA_pow = Label(x = -750, y = -100, text = 'FA Lat Sliding Power', text_font_size = '10pt')
CB = Label(x = -750, y = 0, text = 'Car Balance (^ = US)', text_font_size = '10pt')
curv = Label(x = -750, y = 300, text = 'Curvature', text_font_size = '10pt')

p3.add_layout(RA_pow)
p3.add_layout(FA_pow)
p3.add_layout(CB)
p3.add_layout(curv)

# Sector lines
vline = Span(location=2000, dimension='height', line_color='black', line_width=2, line_dash = 'dashed')
vline2 = Span(location=4000, dimension='height', line_color='black', line_width=2, line_dash = 'dashed')

p3.renderers.extend([vline, vline2])
    # p.add_layout(vline)


for [driver_label, trace_colour, lap_time_label, lap_number_label], group_compare in group:

    p3.line(group_compare['x_new'], group_compare['curvature'], legend_label = driver_label + ' Lap - ' + str(lap_number_label) + ' = ' + str(round(lap_time_label, 2)), line_width = 1,line_color = trace_colour) # *2000+300



# make the legend interactive 
#p3.legend.click_policy="hide"

#p3.line('x_new','curvature', source = source)


# add callback to control 

button = RadioButtonGroup(labels=["Sector_1", "Sector_2","Sector_3"], active=0) #, callback = callback

button.callback = CustomJS(args=dict(p=p3, source=source), code="""

            var radio_value = cb_obj.active;
            var data = source.data;  

            x = data['Lap Distance']
            x_new = data['x_new']

            gps_lat = data['GPS latitude']
            gps_lat_filtered = data['gps_lat_filtered']

            x_filter = data['callback_tag']
            y = data['curvature']

            for (i = 0; i < x.length; i++) {
                if(x_filter[i] == radio_value) {
                    x_new[i] = x[i];
                    gps_lat_filtered[i] = gps_lat[i];
                } else {
                    x_new[i] = undefined;
                    gps_lat_filtered[i] = undefined;
                }
            }
        source.change.emit();
        """)
source = ColumnDataSource(df_final)

p3.line('x_new','curvature', source = source)