How to add on_change callback to ColorPicker widget on BokehJS?

I’m trying to create a color picker to change the color of a line in my plot.
And I can’t figure out how to properly set the callback on the colorpicker

 let col_pick = new Bokeh.Widgets.ColorPicker({title: "Test picker", color: "#ff0000"});
    let fakefunc = function(){
        console.log("col pick " + col_pick.color);
        line1.color = col_pick.color;
        //Also tried function(a, o, n){ line1.color = n;...}
    };
    col_pick.on_event("change", fakefunc); //This just never runs the call back
    col_pick.on_change("color", fakefunc); //This gives an error that "n is undefined"
    col_pick.addEventListener("change", fakefunc); //can addEventListener to Bokeh Widget

I’m looking for the equivalent of

picker = ColorPicker(title="Line Color")
picker.js_link('color', line.glyph, 'line_color')

Thanks

1 Like

Something like (untested)

picker.connect(picker.color.change, () => my_callback())

Thanks for the reply,
Unfortunately doesn’t work, gives the same error as previously
Could this be a bug?

I get:

Uncaught TypeError: n.connect is not a function
    connect https://cdnjs.cloudflare.com/ajax/libs/bokeh/3.0.3/bokeh.min.js:180
    connect https://cdnjs.cloudflare.com/ajax/libs/bokeh/3.0.3/bokeh.min.js:180

line 180 is:

function _(n,e,t,s,l){s();const r=n(16),i=n(10);class o{constructor(n,e){this.sender=n,this.name=e}connect(n,e=null){t.receivers_for_sender.has(this.sender)||t.receivers_for_sender.set(this.sender,[]);const s=t.receivers_for_sender.get(this.sender);if(null!=f(s,this,n,e))return!1;const l=null!=e?e:n;u.has(l)||u.set(l,[]);const r=u.get(l),i={signal:this,slot:n,context:e};return s.push(i),r.push(i),!0}disconnect(n,e=null){const s=t.receivers_for_sender.get(this.sender);if(null==s||0===s.length)return!1;const l=f(s,this,n,e);if(null==l)return!1;const r=null!=e?e:n,i=u.get(r);return l.signal=null,g(s),g(i),!0}emit(n){var e;const s=null!==(e=t.receivers_for_sender.get(this.sender))&&void 0!==e?e:[];for(const{signal:e,slot:t,context:l}of s)e===this&&t.call(l,n,this.sender)}}t.Signal=o,o.__name__="Signal";class c extends o{emit(){super.emit(void 0)}}t.Signal0=c,c.__name__="Signal0",function(n){n.disconnect_between=function(n,e){const s=t.receivers_for_sender.get(n);if(null==s||0===s.length)return;const l=u.get(e);if(null!=l&&0!==l.length){for(const e of l){if(null==e.signal)return;e.signal.sender===n&&(e.signal=null)}g(s),g(l)}},n.disconnect_sender=function(n){var e;const s=t.receivers_for_sender.get(n);if(null!=s&&0!==s.length){for(const n of s){if(null==n.signal)return;const t=null!==(e=n.context)&&void 0!==e?e:n.slot;n.signal=null,g(u.get(t))}g(s)}},n.disconnect_receiver=function(n,e,s){const l=u.get(n);if(null!=l&&0!==l.length){for(const n of l){if(null==n.signal)return;if(null!=e&&n.slot!=e)continue;const l=n.signal.sender;null!=s&&s.has(l)||(n.signal=null,g(t.receivers_for_sender.get(l)))}g(l)}},n.disconnect_all=function(n){const e=t.receivers_for_sender.get(n);if(null!=e&&0!==e.length){for(const n of e)n.signal=null;g(e)}const s=u.get(n);if(null!=s&&0!==s.length){for(const n of s)n.signal=null;g(s)}}}(o||(t.Signal=o={})),t.Signalable=function(){return class{connect(n,e){return n.connect(e,this)}disconnect(n,e){return n.disconnect(e,this)}}},t.receivers_for_sender=new WeakMap;const u=new WeakMap;function f(n,e,t,s){return(0,i.find)(n,(n=>n.signal===e&&n.slot===t&&n.context===s))}const a=new Set;function g(n){0===a.size&&(async()=>{await(0,r.defer)(),function(){for(const n of a)(0,i.remove_by)(n,(n=>null==n.signal));a.clear()}()})(),a.add(n)}},

The relevant section where the error occurs:
The error occurs at n.connect(e, this)

(o||(t.Signal=o={})),t.Signalable=function(){return class{connect(n,e){return n.connect(e,this)}disconnect(n,e){return n.disconnect(e,this)}}}

I tried: All of these gave the same error

picker.connect(picker.color, () => my_callback())
picker.connect(picker, () => my_callback())
picker.connect(picker.color.change, () => my_callback())

Update: After trying a few more things, I got this which successfully gets the new color and runs the callback BUT doesn’t update the line color

var line1 = plot.line({ field: "x" }, { field: "y" }, {
        source: source,
        line_width: 2,
        line_color: "red",
        legend_label: "Dynamic Phase Noise",
        name: "line1"
    });

let col_pick = new Bokeh.Widgets.ColorPicker({title: "Test picker", color: "#ff0000"});
col_pick.connect(col_pick.properties.color.change, () => line1.glyph.line_color.value = col_pick.color );
Bokeh.Plotting.show(col_pick, "#col-test");

I also tried to set the line_color within the root of the bokeh document (did not work):

bokeh_plot_1.document._roots[0].renderers[0].glyph.line_color.value = "#000000";

@Bryan How could I actually update this property properly?

I think you want this (no .value)

line1.glyph.line_color = col_pick.color

Otherwise, I am happy to play around with an actual Minimal Reproducible Example. (I don’t use BokehJS much directly myself, so I am not going to try to cook up something from scratch)

3 Likes

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.