I am trying to represent data organized as a matrix of vector-valued timeseries. Given a vector timeseries placed at position (i,j) in the matrix, the scalar timeseries components are obtained by some parameter 'order'. The size of the matrix is arbitrary and cannot be hard-coded. I want to
I managed to do what I want on an example where the callback is written explicitly for each component of my matrix, by adapting an example seen here: Filtering data source for Bokeh plot using MultiChoice and CustomJS
import pandas as pd
import numpy as np
from bokeh.plotting import figure, show, row, column
from bokeh.models import ColumnDataSource, CustomJS, MultiChoice
# Generate some data structure
tau = np.linspace(0,2*np.pi,100)
N = 2
orders = [1,2,3]
df = pd.DataFrame()
for o in orders:
df_o = pd.DataFrame()
for i in range(N):
for j in range(N):
df_o[f'{i}{j}'] = i+j + np.cos(tau+o)
df_o['order'] = str(o)
df_o['tau' ] = tau
df = df.append(df_o,ignore_index=True)
# Bokeh plot
order_dict = {}
plots = []
for i in range(N):
plots_line_i = []
for j in range(N):
plot_ij = figure(width=400, height=400)
name_ij = f'{i}{j}'
order_dict[name_ij] = {'order':[],'label':[]}
for order in df.order.unique():
source = ColumnDataSource(df[df['order']==order])
order_glyph_ij = plot_ij.line('tau', name_ij, source=source)
order_dict[name_ij]['order'].append(order_glyph_ij)
order_dict[name_ij]['label'].append(order)
plots_line_i.append(plot_ij)
plots.append(plots_line_i)
# Set up MultiChoice widget
initial_value = [df.order[0]]
options = list(df.order.unique())
multi_choice = MultiChoice(value=initial_value, options=options, max_items=3, title='Selection:')
# Set up callback: how to automatically loop within the dict keys '00', '01', '10', '11' ?
callback = CustomJS(args=dict(order_dict=order_dict, multi_choice=multi_choice), code="""
var selected_vals = multi_choice.value;
var index_check = [];
for (var i = 0; i < order_dict['00']['order'].length; i++) {
index_check[i]=selected_vals.indexOf(order_dict['00']['label'][i]);
if ((index_check[i])>= 0) {
order_dict['00']['order'][i].visible = true;
}
else {
order_dict['00']['order'][i].visible = false;
}
}
for (var i = 0; i < order_dict['11']['order'].length; i++) {
index_check[i]=selected_vals.indexOf(order_dict['11']['label'][i]);
if ((index_check[i])>= 0) {
order_dict['11']['order'][i].visible = true;
}
else {
order_dict['11']['order'][i].visible = false;
}
}
for (var i = 0; i < order_dict['01']['order'].length; i++) {
index_check[i]=selected_vals.indexOf(order_dict['01']['label'][i]);
if ((index_check[i])>= 0) {
order_dict['01']['order'][i].visible = true;
}
else {
order_dict['01']['order'][i].visible = false;
}
}
for (var i = 0; i < order_dict['10']['order'].length; i++) {
index_check[i]=selected_vals.indexOf(order_dict['10']['label'][i]);
if ((index_check[i])>= 0) {
order_dict['10']['order'][i].visible = true;
}
else {
order_dict['10']['order'][i].visible = false;
}
}
""")
multi_choice.js_on_change('value', callback)
# Display the grid plot
rows = []
for i in range(N):
rows.append(row(*plots[i]))
show(column(*rows,multi_choice))
This code normally shows a 2x2 matrix plot:
In the above code, you will see four 'for' loops in the JavaScript code (one for each entry '00', '01', '10', '11') of the matrix. Would it be possible to do that automatically by somehow going through the keys of the dictionary 'order_dict' ?
This may be a stupid question, but I don't know JavaScript so I'm having trouble debugging my code...
You can simplify your JS-Code to
callback = CustomJS(args=dict(order_dict=order_dict, multi_choice=multi_choice), code="""
var selected_vals = multi_choice.value;
var index_check = [];
for (var k in order_dict){
for (var i = 0; i < order_dict[k]['order'].length; i++) {
index_check[i]=selected_vals.indexOf(order_dict[k]['label'][i]);
order_dict[k]['order'][i].visible = index_check[i] >= 0
}
}
""")
This is working exactly the same like your code.
The solution is based on this post.
Your python code gives my a deprecation warning using pandas 1.4.+.
FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
You can avoid this, changing
df = df.append(df_o,ignore_index=True)
df = pd.concat([df, df_o],ignore_index=True)
If you don't see this warning, you should consider to update your pandas version.