How to plot visualization with Interactive Feature Selection in Bokeh, Python

The task is to automate the Visualization. The CSV file contains large nos of features (column names e:g. 32 nos it may increase in future). The task is to plot Interactive Visualization. All the examples I found are hardcoded for the dynamic features selection.

But the requirement is to make the stuff dynamic. How to make it dynamic? Please guide.

I have successfully plotted the graph dynamically, but could not connect the interactive part. The code is as follows:


import pandas as pd
from bokeh.plotting import figure
from bokeh.io import show
from bokeh.models import CustomJS,HoverTool,ColumnDataSource,Select
from bokeh.models.widgets import CheckboxGroup
from bokeh.models.annotations import Title, Legend
import itertools
from bokeh.palettes import inferno
from bokeh.layouts import row

def creat_plot(dataframe):
    data=dataframe
    #Converting the timestamp Column to Timestamp datatype so that it can be used for Plotting on X-axis
    data['timestamp'] = pd.to_datetime(data['timestamp'])
  
    #Segregating Date and Time from timestamp column. It will be used in Hover Tool
    date = lambda x: str(x)[:10]
    data['date'] = data[['timestamp']].applymap(date)
    time= lambda x: str(x)[11:]
    data['time'] = data[['timestamp']].applymap(time)
    
    #Converting whole dataframe ColumnDatasource for easy usage in hover tool
    source = ColumnDataSource(data)
    
    # List all the tools that you want in your plot separated by comas, all in one string.
    TOOLS="crosshair,pan,wheel_zoom,box_zoom,reset,hover"
    
    # New figure
    t = figure(x_axis_type = "datetime", width=1500, height=600,tools=TOOLS,title="Plot for Interactive Features")
    
    #X-axis Legend Formatter
    t.xaxis.formatter.days = '%d/%m/%Y'
    
    #Axis Labels
    t.yaxis.axis_label = 'Count'
    t.xaxis.axis_label = 'Date and Time Span'
    
    #Grid Line Formatter
    t.ygrid.minor_grid_line_color = 'navy'
    t.ygrid.minor_grid_line_alpha = 0.1
    t.xgrid.visible = True
    t.ygrid.visible= True
    
    #Hover Tool Usage
    t.select_one(HoverTool).tooltips = [('Date', '@date'),('Time', '@time')]
    
    #A color iterator creation
    colors = itertools.cycle(inferno(len(data.columns)))
    
    #A Line type iterator creation
    line_types= ['solid','dashed','dotted','dotdash','dashdot']
    lines= itertools.cycle(line_types)
    
    column_name=[]
    #Looping over the columns to plot the Data
    for m in data.columns[2:len(data.columns)-2]:
        column_name.append(m)
        a=t.line(data.columns[0], m ,color=next(colors),source=source,line_dash=next(lines), alpha= 1)
     
    #Adding Label Selection Check Box List
    column_name= list(column_name)
    checkboxes = CheckboxGroup(labels = column_name, active= [0,1,2])
    
    
    show(row(t,checkboxes))


**The above code is executed on the following requirements:

  1. Bokeh version: 2.2.3
  2. Panda Version: 1.1.3

I need to plot the graph based on the value selected with the checkbox(s) .
Figure attached.
For example: If the User will select Feature 1 Feature 2 and Feature 15 then the plot should showcase only the selected feature.

I stuck on this feature filteration. Please guide to accomplish this filtration of features.

Hi @kirtiswagat please edit your post to use code formatting so that the code is intelligible (either with the </> icon on the editing toolbar, or triple backtick ``` fences around the code blocks)

Also you need to explain in detail what you want to accomplish or have happen. “could not connect the interactive part” and the “code needs to be dynamic” does not say anything about what the actual requirements are.

@Bryan Hi , As advised I have edited the post. I need help with the filtration of the features with checkboxes. The Features that will be selected, only be plotted.

@kirtiswagat

Based on inference of what you want to accomplish, namely having the active checkboxes control which lines are plotted, you will need to use the callback mechanism common to bokeh widgets to do this.

See the Adding Widgets documentation in the bokeh Users Guid for more detail here.

The CheckboxGroup widget has example JavaScript code of printing which entries are active when clicked; you could change this to suit your needs. There’s also callbacks that get invoked on-change to a widget. And there are both JavaScript and Python versions with the JavaScript ones prefixed by js_.

In general, if you want to use Python callbacks, you will need to run a bokeh server; if you do not want to or cannot run a bokeh server for some reason, you’ll need to code up the callbacks in JavaScript.

Lastly, for your specific example, it is probably best to plot all of the signals upfront – as your code appears to do – and then use the callback to toggle the visible property of the corresponding lines. In other words, if checkbox one is active/checked, then make Line 1 visible, etc.

There are several ways to do this. Here is one, generalized from the example in the repo, that you can adapt you your specific situation:

import numpy as np
from bokeh.layouts import row
from bokeh.models import CheckboxGroup, CustomJS
from bokeh.plotting import figure, show

x = np.linspace(0, 4 * np.pi, 100)
y0, y1, y1 = np.sin(x), 4 * np.cos(x), np.tan(x)

p = figure()
lines = []
lines.append(p.line(x, y0, color="red",   name="Line 0", visible=False))
lines.append(p.line(x, y1, color="green", name="Line 1", visible=False))
lines.append(p.line(x, y2, color="blue",  name="Line 2", visible=False))

checkbox = CheckboxGroup(labels=[r.name for r in lines], active=[])
callback = CustomJS(args=dict(lines=lines, checkbox=checkbox), code="""
for (let i=0; i<lines.length; ++i) {
    lines[i].visible = i in checkbox.active
}
""")
checkbox.js_on_change('active', callback)

show(row(p, checkbox))

@kirtiswagat as I asked on Twitter, please make sure to update or link your question on SO.

1 Like

Thank you very much. Now i am getting desired result.

The code for the above requirement is as follows:

import pandas as pd
from bokeh.plotting import figure
from bokeh.io import show,output_file
from bokeh.models import CustomJS,HoverTool,ColumnDataSource,Select
from bokeh.models.widgets import CheckboxGroup
from bokeh.models.annotations import Title, Legend
import itertools
from bokeh.palettes import inferno
from bokeh.layouts import row

def creat_plot(dataframe):
    data=dataframe
    #Converting the timestamp Column to Timestamp datatype so that it can be used for Plotting on X-axis
    data['timestamp'] = pd.to_datetime(data['timestamp'])
    
    #Segregating Date and Time from timestamp column. It will be used in Hover Tool
    date = lambda x: str(x)[:10]
    data['date'] = data[['timestamp']].applymap(date)
    time= lambda x: str(x)[11:]
    data['time'] = data[['timestamp']].applymap(time)
    
    #Converting whole dataframe ColumnDatasource for easy usage in hover tool
    source = ColumnDataSource(data)
    
    # List all the tools that you want in your plot separated by comas, all in one string.
    TOOLS="crosshair,pan,wheel_zoom,box_zoom,reset,hover"
    
    # New figure
    t = figure(x_axis_type = "datetime", width=1500, height=600,tools=TOOLS,title="Plot for Engine Heuristics")
    
    #X-axis Legend Formatter
    t.xaxis.formatter.days = '%d/%m/%Y'
    
    #Axis Labels
    t.yaxis.axis_label = 'Count'
    t.xaxis.axis_label = 'Date and Time Span'
    
    #Grid Line Formatter
    t.ygrid.minor_grid_line_color = 'navy'
    t.ygrid.minor_grid_line_alpha = 0.1
    t.xgrid.visible = True
    t.ygrid.visible= True
    
    #Hover Tool Usage
    t.select_one(HoverTool).tooltips = [('Date', '@date'),('Time', '@time')]
    
    #A color iterator creation
    colors = itertools.cycle(inferno(len(data.columns)))
    
    #A Line type iterator creation
    line_types= ['solid','dashed','dotted','dotdash','dashdot']
    lines= itertools.cycle(line_types)
    
    feature_lines = []
    column_name=[]
    #Looping over the columns to plot the Data
    for m in data.columns[2:len(data.columns)-2]:
        column_name.append(m)
        #Solution to my question is here
        feature_lines.append(t.line(data.columns[0], m ,color=next(colors),source=source,line_dash=next(lines), alpha= 1, visible=False))
        
         
    #Adding Label Selection Check Box List
    column_name= list(column_name)
    
   #Solution to my question, 
    checkbox = CheckboxGroup(labels=column_name, active=[])
    #Solution to my question
    callback = CustomJS(args=dict(feature_lines=feature_lines, checkbox=checkbox), code="""
                                                            for (let i=0; i<feature_lines.length; ++i) {
                                                                feature_lines[i].visible = i in checkbox.active
                                                            }
                                                            """)
    checkbox.js_on_change('active', callback)
    output_file('Interactive_Engine_Heuristics.html')
    show(row(t, checkbox))
1 Like