The Goal:
Create a widget that uses a CustomJS callback to control a number of glyphs at the same time … BUT the number of glyphs (and how many underlying ColumnDataSources there are) is unspecified, because it depends on input data.
The Problem:
While there are plenty of examples on this forum of a single widget controlling multiple glyphs, I’ve never seen it implemented in such a way as to accommodate an unspecified number of sources. I will not know how many glyphs will be required beforehand, as they are created as part of a for-loop that iterates through user data.
Suppose I have some dictionaries with data that I want to turn into ColumnDataSources - originating from a for loop such that:
sources = []
original_dict: = {'x_value': 1,
'y_value': 2}
q = 0
for q < int('user_input_value'):
new_dict = original_dict[key] += 1
new_source = ColumnDataSource(data=new_dict)
sources.append(new_source)
q += 1
Then we use the list of sources and make glyphs for each:
p = figure(width=400, height=400)
for source in sources:
p.circle(x='x_value', y='y_value', source=source)
Now suppose I want to throw down a slider:
callback = CustomJS(args=dict(source=source), code="""
const data = source.data;
const f = cb_obj.value
const x = data['x']
const y = data['y']
for (let i = 0; i < x.length; i++) {
y[i] = Math.pow(x[i], f)
}
source.change.emit();
""")
slider = Slider(start=0.1, end=4, value=1, step=.1, title="power")
slider.js_on_change('value', callback)
But the source
argument in the callback
is the rub - I know I could specifiy sources in sequence - source1=source1, source2=source2, etc., but that presupposes a known number of sources.
I thought to try a list comprehension of sorts:
callback = CustomJS(args=dict(source = [source for source in sources]),
code="""
JS code goes here
"""
Which proved ineffective.
Is there a way to do this?