2
votes

I am trying to work on a POC model in which I can add some interactivity (like selection of the student based on which the vbar plot will change). I am using a basic student data with their marks.

The data is as follows:

Column 1
Name
Ayan
Deepa
Sayan
Shobhit

Column 2
Marks
98
96
92
94

What I am able to achieve with the below code:

I am able to create the functions and able to get the output in Bokeh Server output. I am also able to create a on_change call back which re creates the dataset based on user input in the dropdown selection.

Where I need help:

I am unable to update the source in my my plots. I tried various ways from various online sites but I am unable to do so.

Some issues faced are:

  1. When I create the ColumnDataSource with the dataframe the output plot is coming blank
  2. If I am using dataframe instead of ColumnDataSource the update function is showing it cant change a df or list

Code:

## Packages

from bokeh.core.properties import value
from bokeh.io import curdoc
from bokeh.plotting import figure
from bokeh.layouts import layout, column, gridplot, Row, widgetbox, row
from bokeh.models import TapTool, HoverTool, ColumnDataSource, Range1d, BoxSelectTool, LinearAxis, Range1d
from bokeh.models.widgets import Button, RadioButtonGroup, Select, Slider, CheckboxGroup, Panel, Tabs
from bokeh.models.annotations import LabelSet


_tools_to_show = 'box_zoom,pan,save,hover,resize,reset,tap,wheel_zoom'  




import pandas as pd
import numpy as np
from datetime import datetime, timedelta
import datetime

## Creating Dataset

def make_dataset(Input):

    global Piv_INCS2_CD_Plot3old
    global Piv_INCS2_CD_Plot3
    global Week_List
    global P2_Major
    global Total_Incidents_Created
    global Resolution_SLO_Miss_Percent
    global new_src
    global Piv_INCS2_CD_Plot3_List
    global Old
    global Old_Filter
    global Old_CDS
    global Name
    global Marks
    global Names2
    global Old_CDS_Name
    global Old_CDS_Marks

    print("select 2 =", select.value )
    print("Input 2 =", Input)

    Old = pd.read_csv('Check_Data.csv', encoding='ISO-8859-1')
    Old_Filter = pd.DataFrame(Old[Old.Name == Input])
    Old_Filter.to_csv('Old_Filter.csv')


    Name = [Input]
    print("Name = ", Name)
    Names2 = Old_Filter["Name"].tolist()
    Marks = Old_Filter["Marks"].tolist()
    print("Names = ", Name )
    print("Marks = ", Marks )



    Old_CDS = ColumnDataSource(data = Old_Filter)
    print("OLD_CDS = ", Old_CDS)

    Old_CDS_Name = ColumnDataSource(data = {'Name':Name})
    Old_CDS_Marks = ColumnDataSource(data = {'Marks': Marks})


    return Old_CDS



##  Creating Plot


def plot(Old_CDS):


    global p3

    p3 = figure(plot_height=630, plot_width=1000, title="Marks Trend",
                   toolbar_location=None, tools="")
    p3.vbar(x = "Name", top = "Marks", width = 0.9, source=Old_CDS)

    p3.xgrid.grid_line_color = None
    p3.y_range.start = 0


    return p3 # returns the plot

## On Change Function

def update(attr, old, new):

    global Piv_INCS2_CD_Plot3_New
    global Week_List_New
    global Old_CDS_1
    global p3
    global lay
    global Old_CDS_Name_2


    Old_CDS_1 = make_dataset(select.value)
    Old_CDS.data.update(Old_CDS_1.data)

## Selection Option   

options=[("Ayan","Ayan"),("Deepa","Deepa")]
select=Select(title="Name",options=options)
print("select=", select.value )

## Changing value based on user input

select.on_change("value",update)

## Defining intial user selection

Initial_Input = "Ayan"

Old_CDS_2 = make_dataset(Initial_Input)

## Defining Layout

p3 = plot(Old_CDS_2)
lay = row(p3, select)

curdoc().add_root(lay)

Expected result: I should be able to view the vbar chart in the page and when I change the user from dropdown the plot changes

1
I'd like to help but there is a huge amount of irrelevant/unrelated code above, which makes it harder and more time consuming to examine. Please pare things down to a minimal self-contained example that just deals deals with creating/updating a plot, and shows what you have tried for that. - bigreddot
Alternatively, there are lots of examples that plot data and update it based on widgets that you can study and compare to in the official project examples: github.com/bokeh/bokeh/tree/master/examples/app - bigreddot
@bigreddot I have uploaded a csv which have some raw data for 2 students Ayan and Deepa. I am looking to create a vbar chart in bokeh so that I can show the vbar chart based on the user input of name (Ayan/Deepa). I have converted the csv into columndatasource and also calling the callback functions on change of user input. That is working fine. But I am stuck inside the callback function when I try to update the data source in the vbar its not getting executed. - Ayan Som
The callback function is as follows: def update(attr, old, new): Old_CDS_1 = make_dataset(select.value) # OLD_CDS_1 - The ColumnDataSource that will return from dataset creation func) Old_CDS.data.update(Old_CDS_1.data) # I am updating the new datasource in the plot function. The plot function code is given below - Ayan Som
You can (and should) edit the question itself. Unformatted code in comments is not readable. - bigreddot

1 Answers

0
votes

Here is your working code (for Bokeh v1.0.4). Changes:

x_range = Old_CDS.data['Name'] added

global Old_CDS_2

Old_CDS_2.data['Marks'] = Old_CDS_1.data['Marks'] You were updating Old_CDS instead of Old_CDS_2 which you passed to the vbars

from bokeh.core.properties import value
from bokeh.io import curdoc
from bokeh.plotting import figure
from bokeh.layouts import layout, column, gridplot, Row, widgetbox, row
from bokeh.models import TapTool, HoverTool, ColumnDataSource, Range1d, BoxSelectTool, LinearAxis, Range1d
from bokeh.models.widgets import Button, RadioButtonGroup, Select, Slider, CheckboxGroup, Panel, Tabs
from bokeh.models.annotations import LabelSet

_tools_to_show = 'box_zoom,pan,save,hover,resize,reset,tap,wheel_zoom'

import pandas as pd
import numpy as np
from datetime import datetime, timedelta
import datetime
import os

# # Creating Dataset
def make_dataset(Input):

    global Piv_INCS2_CD_Plot3old
    global Piv_INCS2_CD_Plot3
    global Week_List
    global P2_Major
    global Total_Incidents_Created
    global Resolution_SLO_Miss_Percent
    global new_src
    global Piv_INCS2_CD_Plot3_List
    global Old
    global Old_Filter
    global Old_CDS
    global Name
    global Marks
    global Names2
    global Old_CDS_Name
    global Old_CDS_Marks

    print("select 2 =", select.value)
    print("Input 2 =", Input)

    Old = pd.read_csv(os.path.join(os.path.dirname(__file__), 'Check_Data.csv'), encoding = 'ISO-8859-1')
    Old_Filter = pd.DataFrame(Old[Old.Name == Input])
    Old_Filter.to_csv(os.path.join(os.path.dirname(__file__), 'Old_Filter.csv'), index = False)

    select.options = [(name, name) for name in Old['Name'].values]
    print options

    Name = [Input]
    print("Name = ", Name)
    Names2 = Old_Filter["Name"].tolist()

    Marks = Old_Filter["Marks"].tolist()
    print("Names = ", Name)
    print("Marks = ", Marks)

    Old_CDS = ColumnDataSource(data = Old_Filter)
    print("OLD_CDS = ", Old_CDS)

    Old_CDS_Name = ColumnDataSource(data = {'Name': Name})
    Old_CDS_Marks = ColumnDataSource(data = {'Marks': Marks})

    return Old_CDS

# #  Creating Plot
def plot(Old_CDS):

    global p3

    print Old_CDS.data
    p3 = figure(plot_height = 630, plot_width = 1000, title = "Marks Trend", x_range = Old_CDS.data['Name'],
                   toolbar_location = None, tools = "")
    p3.vbar(x = "Name", top = "Marks", width = 0.9, source = Old_CDS)

    p3.xgrid.grid_line_color = None
    p3.y_range.start = 0

    return p3  # returns the plot

# # On Change Function
def update(attr, old, new):

    global Piv_INCS2_CD_Plot3_New
    global Week_List_New
    global Old_CDS_1
    global p3
    global lay
    global Old_CDS_Name_2
    global Old_CDS_2

    Old_CDS_1 = make_dataset(select.value)
    Old_CDS_2.data['Marks'] = Old_CDS_1.data['Marks']

# # Selection Option
options = [("Ayan", "Ayan"), ("Deepa", "Deepa")]
select = Select(title = "Name", options = options)
print("select=", select.value)

# # Changing value based on user input
select.on_change("value", update)

# # Defining intial user selection
Initial_Input = "Ayan"

Old_CDS_2 = make_dataset(Initial_Input)

# # Defining Layout
p3 = plot(Old_CDS_2)
lay = row(p3, select)
curdoc().add_root(lay)

Result:

enter image description here