Пользовательский JS для фильтрации / переключения между фреймами данных с помощью радиогрупповой кнопки в отдельном документе html от bokeh - PullRequest
1 голос
/ 08 апреля 2020

Это первый раз, когда я опубликовал здесь, извините, если формат не правильный, я также довольно новичок в Python, поэтому все еще изучаю веревки.

Я использовал bokeh для построения визуализации Инструменты для моих коллег по работе, я собираю данные, запускаю сценарий и затем помещаю html на сервер, чтобы все могли получить к нему доступ. Это отлично работает, но я хочу добавить немного больше функциональности к графику боке, чем стандартные инструменты.

Я добавил кнопку Radio Group над графиком боке, и я хотел бы использовать Custom 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'

Как видно из приведенного ниже кода, я понятия не имею, как сконструировать код JS, несмотря на то, что, рассмотрев немало примеров, я не могу найти что-то подобное.

Другая проблема, с которой я столкнулся, заключается в том, что я использую .groupby для упрощения построения графиков, но я не уверен, как и где реализовать переменные x, y и source = source при использовании источника данных столбца. Я пытался сделать это, но каждый раз это не удавалось.

from bokeh.plotting import figure, output_file, show
from bokeh.models import BoxAnnotation, Span, CustomJS, ColumnDataSource, Slider, LinearAxis, Range1d, Label, RadioButtonGroup
from bokeh.layouts import column, row, widgetbox
from bokeh.io import output_notebook # , show
from bokeh.palettes import Category10
from bokeh.palettes import Dark2_5 as palette
import itertools

# turn data frames into ColumnDataSource
source = ColumnataSource(df_final)
source1 = ColumnDataSource(df_sector_1)
source2 = ColumnDataSource(df_sector_2)
source3 = ColumnDataSource(df_sector_3)


# output to static HTML file
output_file("Mutli_driver.html")

# 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=1400, plot_height=650, tools=tools,x_range=(-810, lap_distance_min+100))
p3.background_fill_color = "whitesmoke"

# plot labels
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 df_final.groupby(['driver','trace_colour', 'lap_time', 'lap_number']):


    CB_raw = group_compare['Car Balance']
    CB_smoothed = gaussian_filter1d(CB_raw, sigma=5)

    FA_pow_raw = group_compare['FA Lat Tyre Power']
    FA_pow_smoothed = gaussian_filter1d(FA_pow_raw, sigma=5)

    RA_pow_raw = group_compare['RA Lat Tyre Power']
    RA_pow_smoothed = gaussian_filter1d(RA_pow_raw, sigma=5)

    # not sure here where how to add x and y of the Column data source, and source = source
    p3.line(group_compare['Lap Distance'], group_compare['curvature']*2000+300, legend_label = driver_label + ' Lap - ' + str(lap_number_label) + ' = ' + str(round(lap_time_label, 2)), line_width = 1,line_color = trace_colour)



p3.legend.click_policy="hide"


codes = """

var f = cb_obj.active;

var sdata = source.data;
var data1 = source1.data;
var data2 = source2.data;

console.log(data2);

for (key in data1) {console.log(key);}

if (f == "0") {

# either use df_sector_1 or filter df_final for all values of df['callback_tag'] == 0


source.trigger("change");
"""

# add callback to control 
callback = CustomJS(args=dict(p=p3, source=source,source1=source1,source2=source2), code=codes)

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

p3 = column(widgetbox(button), p3)

show(p3)

любая помощь или руководство будет высоко ценится, или дайте мне знать, если мне нужно объяснить больше или лучше

спасибо

ОБНОВЛЕНИЕ: я не получил пользовательский JS код работает, в основном, фильтруя исходный фрейм данных:

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();
        """)

, но если я попробую и l oop по группам, чтобы я мог иметь отдельные строки, то пользовательский JS обратный вызов больше не будет работает так, как я должен удалить строку source = source из p.line ():

, когда я назначаю df только columndatasource и затем использую это:

source = ColumnDataSource(df_final)

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

, тогда это работает отлично, но я хочу иметь возможность группировать данные и строить отдельные строки

Может кто-нибудь, пожалуйста, помогите мне с синтаксисом, поскольку я близок к получению того, что мне нужно, спасибо

...