Bokeh CustomJS - passing multiple sources, variables to CustomJS

Hello,

I’ve been trying to find out the way to pass multiple data sources and variable from/to CustomJS.

To illustrate my questions, you will find the corresponding code below:

  • How can python variables ( L, x,y and z) be passed to callback CustomsJS ?
  • in CustomJS : L must replace 6 in all formulas , the projected xAz, yAz must be computer
  • How can the slider (azimuth variable) can be passed to be displayed as x-label ?

Thanks

Philippe

···

==========================================================================

import numpy as np

import pandas as pd

from math import *

from ipywidgets import interact

from bokeh.io import push_notebook, show, output_notebook

from bokeh.plotting import *

from bokeh.layouts import widgetbox, gridplot

from bokeh.models import CustomJS, Slider, Range1d, formatters

output_notebook()

– Dataset 3D xt,yt,zt trajectory

df = pd.DataFrame({‘East’ : np.array([1,2,3,4]),

‘North’ : np.array([4,3,2,1]),

‘Depth’ : np.array([0,-10,-20,-30])})

xt = df[‘North’]

yt = df[‘North’]

zt = df[‘Depth’]

Az = Azimuth

Az =30

Crosshair definition

L = 6

Crosshair Line length L=3, Az=30

Xp1 = Lsin(Azpi/180)

Yp1 = Lcos(Azpi/180)

Xp2 = L*sin((90+Az)*pi/180)/2

Yp2 = L*cos((90+Az)*pi/180)/2

create arrays

xC = np.array([-Xp1/2,Xp1,0,-Xp2,Xp2])

yC = np.array([-Yp1/2,Yp1,0,-Yp2,Yp2])

computing xAz, yAz projection on vertical plane with Azimuth Az

xAz = pd.Series(ytcos(Azpi/180) + xtsin(Azpi/180))

yAz = pd.Series(yt*cos((Az+90)pi/180) + xtsin((Az+90)*pi/180))

sourceC = ColumnDataSource(data=dict(x=xC, y=yC))

sourceAz = ColumnDataSource(data=dict(x=xAz, y=yAz))

Bokeh figures ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

left, right, bottom, top = -5,5, -5,5

TopViewFig = figure(width=300, height=300, title=“Top View (TopViewFig)”,

x_range=Range1d(left, right), y_range=Range1d(bottom, top))

@@@@@

AzViewFig = figure(width=450, height=300,title=“Projection on vertical section with Az (AzViewFig)”,

x_axis_label=‘Azimuth Projection [m]: (’+str(Az)+’ degrees)’)

Plots ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

TopViewFig.line(xt,yt,color="#2222aa",line_width=3)

TopViewFig.line(‘x’,‘y’,source=sourceC, color="#999999", line_alpha=.8 )

AzViewFig.line(‘x’,‘y’,source=sourceAz,color="#999999", line_alpha=.8 )

callback = CustomJS(args=dict(source=sourceC), code="""

var data = source.data;

var a = Azimuth.value;

x = data[‘x’]

y = data[‘y’]

x[0] = -6/2Math.sin(aMath.PI/180);

y[0] = -6/2Math.cos(aMath.PI/180);

x[1] = 6Math.sin(aMath.PI/180);

y[1] = 6Math.cos(aMath.PI/180);

x[2] = 0;

y[2] = 0;

x[3] = -6/2*Math.sin((90+a)*Math.PI/180);

y[3] = -6/2*Math.cos((90+a)*Math.PI/180);

x[4] = 6/2*Math.sin((90+a)*Math.PI/180);

y[4] = 6/2*Math.cos((90+a)*Math.PI/180);

source.trigger(‘change’);

“”")

Azimuth_slider = Slider(start=0, end=360, value=Az, step=1,

title=“Azimuth (deg) 0-360”, callback=callback)

callback.args[“Azimuth”] = Azimuth_slider

layout = gridplot([TopViewFig, AzViewFig],

[widgetbox(Azimuth_slider)])

show(layout)

The callback code is a string. If you have a variable in your python code you can just convert it to a string when you pass it to the callback code . And I also added the axis label update

callback = CustomJS(args=dict(source=sourceC,azview=AzViewFig.xaxis[0]), code="""
var data = source.data;
var a = Azimuth.value;
x = data[‘x’]
y = data[‘y’]
azview.axis_label = ‘Azimuth Projection [m]: (’+a.toString()+’ degrees)’;
x[0] = -Lvar/2Math.sin(aMath.PI/180);
y[0] = -Lvar/2Math.cos(aMath.PI/180);
x[1] = 6Math.sin(aMath.PI/180);
y[1] = 6Math.cos(aMath.PI/180);
x[2] = 0;
y[2] = 0;
x[3] = -Lvar/2*Math.sin((90+a)Math.PI/180);
y[3] = -Lvar/2
Math.cos((90+a)Math.PI/180);
x[4] = Lvar/2
Math.sin((90+a)Math.PI/180);
y[4] = Lvar/2
Math.cos((90+a)*Math.PI/180);
source.trigger(‘change’);
“”".replace(‘Lvar’,str(L)))

``

It’s better to use {Lvar} and format instead of replace.
Also, especially if you want to use multiple variables, you can create a dummy source that will store all your variables.

···

On Sunday, February 19, 2017 at 8:55:12 AM UTC+7, [email protected] wrote:

The callback code is a string. If you have a variable in your python code you can just convert it to a string when you pass it to the callback code . And I also added the axis label update

callback = CustomJS(args=dict(source=sourceC,azview=AzViewFig.xaxis[0]), code="""
var data = source.data;
var a = Azimuth.value;
x = data[‘x’]
y = data[‘y’]
azview.axis_label = ‘Azimuth Projection [m]: (’+a.toString()+’ degrees)’;
x[0] = -Lvar/2Math.sin(aMath.PI/180);
y[0] = -Lvar/2Math.cos(aMath.PI/180);
x[1] = 6Math.sin(aMath.PI/180);
y[1] = 6Math.cos(aMath.PI/180);
x[2] = 0;
y[2] = 0;
x[3] = -Lvar/2*Math.sin((90+a)Math.PI/180);
y[3] = -Lvar/2
Math.cos((90+a)Math.PI/180);
x[4] = Lvar/2
Math.sin((90+a)Math.PI/180);
y[4] = Lvar/2
Math.cos((90+a)*Math.PI/180);
source.trigger(‘change’);
“”".replace(‘Lvar’,str(L)))

``

Just to elaborate on a few points: since CustomJS callbacks are *JavaScript* and execute in the browser, they know nothing at all about python and it is not possible to directly "pass" basic python values to a CustomJS callback. The only thing you can do is a textual substitution as described in other responses.

It is possible to use the args parameter to "pass" Bokeh model objects. There is a 1-1 correspondence between python and JS Bokeh models, and when you pass things in args, Bokeh automagically makes the right JS model available based on the python one you passed in. But this only works for Bokeh models (i.e. column data sources, ranges, tick formatters, etc.) and not general python types.

In a release or two, there will be a "namespace" model that will make it possible to exchange basic types more like real variables.

Thanks,

Bryan

···

On Feb 19, 2017, at 01:42, Eugene Pakhomov <[email protected]> wrote:

It's better to use `{Lvar}` and `format` instead of `replace`.
Also, especially if you want to use multiple variables, you can create a dummy source that will store all your variables.

On Sunday, February 19, 2017 at 8:55:12 AM UTC+7, [email protected] wrote:
The callback code is a string. If you have a variable in your python code you can just convert it to a string when you pass it to the callback code . And I also added the axis label update

callback = CustomJS(args=dict(source=sourceC,azview=AzViewFig.xaxis[0]), code="""
    var data = source.data;
    var a = Azimuth.value;
    x = data['x']
    y = data['y']
    azview.axis_label = 'Azimuth Projection [m]: ('+a.toString()+' degrees)';
    x[0] = -Lvar/2*Math.sin(a*Math.PI/180);
    y[0] = -Lvar/2*Math.cos(a*Math.PI/180);
    x[1] = 6*Math.sin(a*Math.PI/180);
    y[1] = 6*Math.cos(a*Math.PI/180);
    x[2] = 0;
    y[2] = 0;
    x[3] = -Lvar/2*Math.sin((90+a)*Math.PI/180);
    y[3] = -Lvar/2*Math.cos((90+a)*Math.PI/180);
    x[4] = Lvar/2*Math.sin((90+a)*Math.PI/180);
    y[4] = Lvar/2*Math.cos((90+a)*Math.PI/180);
    source.trigger('change');
""".replace('Lvar',str(L)))

--
You received this message because you are subscribed to the Google Groups "Bokeh Discussion - Public" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit https://groups.google.com/a/continuum.io/d/msgid/bokeh/b2e65244-ace3-4eb3-a2a3-5003da065bcf%40continuum.io.
For more options, visit https://groups.google.com/a/continuum.io/d/optout.

Thanks you all, great help.

By creating a column data source (with all data needed) along with the textual substitution, the CustomsJS callback now does all the processing needed. The future “namespace” model will be great.

Is there an example to illustrate a way to export a column data source as csv/excel ?
(let’s say the plots are tuned with right azimuth slider and when all is ready, a separate button to export all the column data)

Thanks, Philippe

···

On Sunday, February 19, 2017 at 10:01:50 PM UTC+2, Bryan Van de ven wrote:

Just to elaborate on a few points: since CustomJS callbacks are JavaScript and execute in the browser, they know nothing at all about python and it is not possible to directly “pass” basic python values to a CustomJS callback. The only thing you can do is a textual substitution as described in other responses.

It is possible to use the args parameter to “pass” Bokeh model objects. There is a 1-1 correspondence between python and JS Bokeh models, and when you pass things in args, Bokeh automagically makes the right JS model available based on the python one you passed in. But this only works for Bokeh models (i.e. column data sources, ranges, tick formatters, etc.) and not general python types.

In a release or two, there will be a “namespace” model that will make it possible to exchange basic types more like real variables.

Thanks,

Bryan

On Feb 19, 2017, at 01:42, Eugene Pakhomov [email protected] wrote:

It’s better to use {Lvar} and format instead of replace.

Also, especially if you want to use multiple variables, you can create a dummy source that will store all your variables.

On Sunday, February 19, 2017 at 8:55:12 AM UTC+7, [email protected] wrote:

The callback code is a string. If you have a variable in your python code you can just convert it to a string when you pass it to the callback code . And I also added the axis label update

callback = CustomJS(args=dict(source=sourceC,azview=AzViewFig.xaxis[0]), code="""

var data = source.data;
var a = Azimuth.value;
x = data['x']
y = data['y']
azview.axis_label = 'Azimuth Projection [m]: ('+a.toString()+' degrees)';
x[0] = -Lvar/2*Math.sin(a*Math.PI/180);
y[0] = -Lvar/2*Math.cos(a*Math.PI/180);
x[1] = 6*Math.sin(a*Math.PI/180);
y[1] = 6*Math.cos(a*Math.PI/180);
x[2] = 0;
y[2] = 0;
x[3] = -Lvar/2*Math.sin((90+a)*Math.PI/180);
y[3] = -Lvar/2*Math.cos((90+a)*Math.PI/180);
x[4] = Lvar/2*Math.sin((90+a)*Math.PI/180);
y[4] = Lvar/2*Math.cos((90+a)*Math.PI/180);
source.trigger('change');

“”".replace(‘Lvar’,str(L)))


You received this message because you are subscribed to the Google Groups “Bokeh Discussion - Public” group.

To unsubscribe from this group and stop receiving emails from it, send an email to [email protected].

To post to this group, send email to [email protected].

To view this discussion on the web visit https://groups.google.com/a/continuum.io/d/msgid/bokeh/b2e65244-ace3-4eb3-a2a3-5003da065bcf%40continuum.io.

For more options, visit https://groups.google.com/a/continuum.io/d/optout.