mercredi 26 février 2020

Bokeh plot not updating with checkboxgroup.on_change()

I am plotting a name frequency figure with Bokeh and all of my code works perfectly apart from one issue with checkboxgroup. The current issue is that the new plot is not updating when updating my checkboxgroup. I have simplified the code below to only include the checkbox part. My code is split into two parts: 1) A main function and 2) callbacks. I have been looking around and seen that this is an ongoing issue, but to me it seems that I am doing as people are suggesting. I am deploying the figure on a local host.

To me it seems that it would be enough to only update the data source, but I have also made a new plotting callback, but still nothing happens and no error is returned. The main file is ran only once, which is the very first time and then the callbacks are used to update the data and plot. The callbacks are basically a copy of what is happening in the main file.

I would really appreciate some help for this one. I hope that everything is clear.

I am using python 3.7 and bokeh 4.0.

Main

from bokeh.palettes import d3
from bokeh.layouts import layout, gridplot, column, row
from bokeh.plotting import figure
from bokeh.document import Document
from bokeh.models.widgets import inputs, Div, CheckboxGroup
from bokeh.models import ColumnDataSource, Column, Button, CDSView, GroupFilter, Select, Range1d, Legend

import pytz
import pandas as pd
import datetime as dt
import numpy as np
from functools import partial

from utils.server import run_server
from utils.functions import load_names, get_name_freq, make_plot
from utils.callbacks import *


names = ['VEvaa', 'Drugnas', 'Polace', 'WERTB']

def document(doc: Document):

    timezone = pytz.utc
    sd = dt.datetime(2015,1,1, tzinfo=timezone)
    ed = dt.datetime(2020,4,1, tzinfo=timezone)

    # check_box_group
    selection = CheckboxGroup(labels = names, active = [2,3])

    # get data
    names = load_names(start_date=sd, end_date=ed)
    names = names[names['Name'].isin(selection.labels)]

    values.names_PQ = get_name_freq(names)
    source_DA = ColumnDataSource(data = values.names_PQ)


    # Plot
    plot_name_freq = figure(plot_width = 1200, 
                           plot_height = 400, 
                           x_range = Range1d(sd, ed), 
                           y_range = Range1d(0, 5.2),
                           y_axis_label = 'Day Ahead Price Volatility',
                           x_axis_type = 'datetime')

    for c in [selection.labels[i] for i in selection.active]:
        view_DA = CDSView(source = source_DA, filters = [GroupFilter(column_name = 'Name', group = c)])

        plot_name_freq.line(source = source_DA, 
                           x = 'TradeGasDay', 
                           y = 'Volatility', 
                           view = view_DA,
                           line_color = mypalette[selection.labels.index(c)], 
                           line_width = 2,
                           legend_label = c)

    # import callbacks
    all_arguments = dict(doc = doc, names_PQ = source_DA, selection = selection)

    selection.on_change('active', update_checkbox_callback(**all_arguments))


    # arrange elements in page
    menu = Column(app_header, selection)

    doc.add_root(layout(row(menu, plot_name_freq)))

if __name__ == "__main__":
    run_server(document, ioloop = None, port = 8055)

Callbacks

import datetime as dt  # type: ignore
import pandas as pd  # type: ignore
from bokeh.models import ColumnDataSource, CDSView, GroupFilter, Range1d, Column
from utils.functions import load_names, get_name_freq, make_plot
from bokeh.models.widgets import inputs
from bokeh.palettes import d3
import pytz
from bokeh.plotting import figure
from bokeh.layouts import layout

class App_Values():
    def __init__(self):
        self.prices = pd.DataFrame()


values = App_Values()

def update_checkbox_callback(**kwargs):
    def update_checkbox(attr, old, new):

        timezone = pytz.utc
        sd = dt.datetime(2015,1,1, tzinfo=timezone)
        ed = dt.datetime(2020,4,1, tzinfo=timezone)

        # Get the list of carriers for the graph
        labels = [kwargs['selection'].labels[i] for i in kwargs['selection'].active] 

        names = load_names(start_date = sd, end_date = ed)
        names = names[names['Name'].isin(labels)]

        names_PQ = get_name_freq(names)
        values.names_PQ = names_PQ

        kwargs['doc'].add_next_tick_callback(update_plot(**kwargs))

    return update_checkbox

def update_plot(**kwargs):

    def callback():

        new_src_DA = ColumnDataSource(data = values.names_PQ, id = 'names_PQ')

        kwargs['names_PQ'].data.update(new_src_DA.data)

        timezone = pytz.utc
        sd = dt.datetime(2015,1,1, tzinfo=timezone)
        ed = dt.datetime(2020,4,1, tzinfo=timezone)

        mypalette = d3['Category20'][13]

        plot_name_freq = figure(plot_width = 1200, 
                               plot_height = 400, 
                               x_range = Range1d(sd, ed), 
                               y_range = Range1d(0, 5.2),
                               y_axis_label = 'Day Ahead Price Volatility')


        selection = [kwargs['selection'].labels[i] for i in kwargs['selection'].active]

        for c in selection:
            print('looping')
            view_DA = CDSView(source = kwargs['names_PQ'], filters = [GroupFilter(column_name = 'Name', group = c)])
            print(view_DA.to_json_string(True))
            plot_name_freq.line(source = kwargs['names_PQ'], 
                               x = 'TradeGasDay', 
                               y = 'Volatility', 
                               view = view_DA,
                               line_color = mypalette[kwargs['selection'].labels.index(c)], 
                               line_width = 2,
                               legend_label = c)

    return callback



Aucun commentaire:

Enregistrer un commentaire