Поскольку у меня нет данных, я сгенерировал их, используя следующий скрипт.Я предполагаю, что ваши данные имеют 3 столбца - Date
, ExtendedPrice
, CompanyNo
.Сначала я сгенерировал случайные данные из 10К строк, а затем суммировал их на уровне CompanyNo
, day
, month
, year
.
import pandas as pd
import random
CopmanyList = ['00', '01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12', '13', '14', '15']
df = pd.DataFrame({'base' : ["2017-01-01" for t in range(10000)],
'Date' : [random.randint(0, 1035) for t in range(10000)],
'ExtendedPrice' : [random.random() for t in range(10000)],
'CompanyNo' : [CopmanyList[random.randint(0, 15)] for t in range(10000)]})
df['base'] = pd.to_datetime(df['base'])
df["Date2"] = df.apply(lambda x: x["base"] + timedelta(days=x['Date']), axis=1)
df.drop(['base', 'Date'], axis=1, inplace=True)
df.set_index('Date2', inplace=True)
df['month'] = df.index.month
df['year'] = df.index.year
df['day'] = df.index.day
source1=df.groupby(['year','month','day', 'CompanyNo'], as_index = False)['ExtendedPrice'].sum()
source =source1[source1['year']== dt.now().year]
sourcex = source[source['month'] ==1]
sourcex = sourcex[sourcex['CompanyNo'].isin(['01'])]
sourcex.sort_values(by='day', inplace=True)
Теперь вы хотите, чтобыучитывая день и набор названий компаний, вам нужно опубликовать гистограмму с агрегацией некоторого типа ExtendedPrice
, то есть, скажем, есть 2 строки для компании '01' и '02' (которые выбраны) и для месяца2 (который также выбирается ползунком) для текущего года, значение ExtendedPrice для этих двух значений, скажем, 100 и 200. В случае, если мы хотим показать сумму, необходимо отобразить 300 в виде диаграммы.Это резюме нужно вычислять динамически.
Есть два способа выполнить это.
1.Bokeh Callbacks
Это будет использовать собственные функции Python, но вам нужно запустить его с bokeh serve
, например, bokeh serve --show <filename.py>
.См. Приведенный ниже код: встроенная функция Python compsel
фильтрует кадр данных pandas, суммирует его и заменяет данные бэкэнда диаграммы на вновь созданные данные -
from datetime import timedelta
from datetime import datetime as dt
from bokeh.models.widgets import MultiSelect, Slider
from bokeh.layouts import widgetbox, column
from bokeh.models.ranges import FactorRange
from bokeh.plotting import figure, curdoc
from bokeh.models import ColumnDataSource, HoverTool, CustomJS
Overall= ColumnDataSource(source)
Curr= ColumnDataSource(sourcex[['day', 'ExtendedPrice']])
Curr.remove('index')
hover3 = HoverTool(tooltips = [('day', '@day'),('Sales','@{ExtendedPrice}{0,0.00}')],
formatters = {'day': 'datetime','Sales': 'numeral'})
p = figure(title='YEARLY SALES', plot_width=600, plot_height=400, min_border=3,
tools = [hover3,'box_zoom','wheel_zoom', 'pan','reset'],
toolbar_location="above")
r = p.vbar(x='day', top='ExtendedPrice', width=0.2, color='#e8bc76', source=Curr)
p.xaxis.axis_label = 'Day'
p.xaxis.axis_label_text_font_style = 'normal'
p.xaxis.axis_label_text_font_size = '12pt'
def compsel(attr, old, new):
vcomp = multi_select.value
vmonth = slider.value
sourcex = source[source['month'] ==vmonth]
sourcex = sourcex[sourcex['CompanyNo'].isin(vcomp)]
sourcex = sourcex.groupby(['day'], as_index = False)['ExtendedPrice'].sum()
Currnew= ColumnDataSource(sourcex[['day', 'ExtendedPrice']])
Currnew.remove('index')
r.data_source.data=Currnew.data
companies=source['CompanyNo'].unique().tolist()
companies.sort()
multi_select = MultiSelect(title="Select:", value=['01'], options=companies, height=200, width=100)
slider = Slider(start=1, end=12, value=1, step=1, title="Month")
slider.on_change("value", compsel)
multi_select.on_change("value", compsel)
layout = column(multi_select, slider, p)
curdoc().add_root(layout)
Существуют и другие варианты размещения этого приложения.Посмотрите другой вариант, набрав bokeh serve --help
в терминале
2.Обратные вызовы JavaScript
Это создаст функцию javascript для взаимодействия с диаграммой, которая не требует сервера bokeh и работает непосредственно в браузере.Это потребует очень простой код в JavaScript.В примере, решенном здесь, я суммирую ExtendedPrice
как сумму, но код потребует небольших изменений для вычисления других характеристик, например среднего.Функция обратного вызова js здесь делает то же самое, что и функция обратного вызова bokeh, она читает большие наборы данных и фильтрует их на основе значений select и слайдера -
source =source1[source1['year']== dt.now().year]
sourcex = source[source['month'] ==1]
sourcex = sourcex[sourcex['CompanyNo'].isin(['01'])]
sourcex.sort_values(by='day', inplace=True)
Overall= ColumnDataSource(source)
Curr= ColumnDataSource(sourcex[['day', 'ExtendedPrice']])
Curr.remove('index')
hover3 = HoverTool(tooltips = [('day', '@day'),('Sales','@{ExtendedPrice}{0,0.00}')],
formatters = {'day': 'datetime','Sales': 'numeral'})
p = figure(title='YEARLY SALES', plot_width=600, plot_height=400, min_border=3,
tools = [hover3,'box_zoom','wheel_zoom', 'pan','reset'],
toolbar_location="above")
r = p.vbar(x='day', top='ExtendedPrice', width=0.2, color='#e8bc76', source=Curr)
p.xaxis.axis_label = 'Day'
p.xaxis.axis_label_text_font_style = 'normal'
p.xaxis.axis_label_text_font_size = '12pt'
callms = CustomJS(args=dict(source=Overall, sc=Curr), code="""
var comp=msel.attributes.value;
var f = slider.value;
sc.data['ExtendedPrice'] = [];
sc.data['day'] = [];
for (var i = 0; i <= source.get_length(); i++){
if (source.data['month'][i] == f){
if (comp.indexOf(source.data['CompanyNo'][i]) >=0){
var d1 = source.data['day'][i]
if(typeof sc.data['day'][d1-1]=="undefined"){
sc.data['day'][d1-1] = d1
sc.data['ExtendedPrice'][d1-1] = source.data['ExtendedPrice'][i]
}
else{
sc.data['ExtendedPrice'][d1-1] = sc.data['ExtendedPrice'][d1-1] + source.data['ExtendedPrice'][i]
}
}
}
}
sc.change.emit();
""")
companies=source['CompanyNo'].unique().tolist()
companies.sort()
multi_select = MultiSelect(title="Select:", value=['01'], options=companies, height=200, width=100, callback=callms)
slider = Slider(start=1, end=12, value=1, step=1, title="Month", callback=callms)
callms.args["msel"] = multi_select
callms.args["slider"] = slider
layout = column(multi_select, slider, p)
output_file("Filterdata.html")
show(layout)