Is it possible to link a plot and a data table?

Hi!

I’m trying to link a plot and a data table such as when using box zoom the content of the table is updated as well, in similar fashion to linking two plots through they ranges. I tried to adapt an stackoverflow answer where a box selector should update the table without success. Truth is this project is my first contact with javascript and I also don’t understand bokeh completely yet. Below is a minimal code with my flimsy attempt to write a CustomJS

Many thanks for this wonderful list, I’m learning a lot reading it.

from bokeh.io import show

from bokeh.layouts import row, widgetbox

from bokeh.models import ColumnDataSource, CustomJS

from bokeh.plotting import figure, curdoc

from bokeh.models.widgets import DataTable, TableColumn

import pandas as pd

df = pd.DataFrame({‘x’: [1, 2, 3, 4, 5, 6, 7], ‘A’ : [1, 5, 3, 5, 2, 8, 3], ‘B’ : [2, 4, 3, 1, 5, 6, 2]})

tools_to_show = ‘box_zoom,reset’

p = figure(plot_height =300, plot_width = 600,

       toolbar_location='above', tools=tools_to_show)

columns = [‘A’, ‘B’]

source = ColumnDataSource(df)

for col in columns:

p.line('x', col, source=source)

columns = [

    TableColumn(field="A", title="A"),

    TableColumn(field="B", title="B"),

]

data_table = DataTable(source=source, columns=columns, width=300, height=300)

source.callback = CustomJS(args=dict(s2=source, table=data_table), code="""

var inds = cb_obj.selected['1d'].indices;

var d1 = cb_obj.data;

var d2 = s2.data;

d2['A'] = []

d2['B'] = []

for (i = 0; i < inds.length; i++) {

    d2['A'].push(d1['A'][inds[i]])

    d2['B'].push(d1['B'][inds[i]])

       }

s2.trigger('change');

table.trigger('change');

“”")

curdoc().add_root(row(p, widgetbox(data_table)))

``

Hi,

I believe you are running into this current known bug:

  Error message on the browser console when using CustomJS with args in serve mode · Issue #7970 · bokeh/bokeh · GitHub

Thanks,

Bryan

···

On Jul 28, 2018, at 08:28, Ricardo Melo Ferreira <[email protected]> wrote:

Hi!

I'm trying to link a plot and a data table such as when using box zoom the content of the table is updated as well, in similar fashion to linking two plots through they ranges. I tried to adapt an stackoverflow answer where a box selector should update the table without success. Truth is this project is my first contact with javascript and I also don't understand bokeh completely yet. Below is a minimal code with my flimsy attempt to write a CustomJS

Many thanks for this wonderful list, I'm learning a lot reading it.

from bokeh.io import show
from bokeh.layouts import row, widgetbox
from bokeh.models import ColumnDataSource, CustomJS
from bokeh.plotting import figure, curdoc
from bokeh.models.widgets import DataTable, TableColumn
import pandas as pd

df = pd.DataFrame({'x': [1, 2, 3, 4, 5, 6, 7], 'A' : [1, 5, 3, 5, 2, 8, 3], 'B' : [2, 4, 3, 1, 5, 6, 2]})

tools_to_show = 'box_zoom,reset'
p = figure(plot_height =300, plot_width = 600,
           toolbar_location='above', tools=tools_to_show)

columns = ['A', 'B']
source = ColumnDataSource(df)
for col in columns:
    p.line('x', col, source=source)

columns = [
        TableColumn(field="A", title="A"),
        TableColumn(field="B", title="B"),
    ]
data_table = DataTable(source=source, columns=columns, width=300, height=300)

source.callback = CustomJS(args=dict(s2=source, table=data_table), code="""
    var inds = cb_obj.selected['1d'].indices;
    var d1 = cb_obj.data;
    var d2 = s2.data;
    d2['A'] =
    d2['B'] =
    for (i = 0; i < inds.length; i++) {
        d2['A'].push(d1['A'][inds[i]])
        d2['B'].push(d1['B'][inds[i]])
           }
    s2.trigger('change');
    table.trigger('change');
""")

curdoc().add_root(row(p, widgetbox(data_table)))

--
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/a307c698-589e-4c7b-bc09-8db4d8526657%40continuum.io\.
For more options, visit https://groups.google.com/a/continuum.io/d/optout\.

Hi,

Sorry, but I didn't understood the bug. I didn't get any error massages. However, when removing "args=" as suggested I got the following message:

018-07-29 19:08:35,748 Error running application handler <bokeh.application.handlers.script.ScriptHandler object at 0x7fe552294898>: __init__() takes 1 positional argument but 2 were given
File "zoom_table.py", line 37, in <module>:
""") Traceback (most recent call last):
File "/usr/lib/python3.6/site-packages/bokeh/application/handlers/code_runner.py", line 163, in run
exec(self._code, module.__dict__)
File "/home/ricardo/pesq/ewing/auto_fig/v2/minimal/zoom_table.py", line 37, in <module>
""")
TypeError: __init__() takes 1 positional argument but 2 were given

Thanks

···

Em 29-07-2018 17:01, Bryan Van de ven escreveu:

Hi,

I believe you are running into this current known bug:

  Error message on the browser console when using CustomJS with args in serve mode · Issue #7970 · bokeh/bokeh · GitHub

Thanks,

Bryan

On Jul 28, 2018, at 08:28, Ricardo Melo Ferreira <[email protected]> wrote:

Hi!

I'm trying to link a plot and a data table such as when using box zoom the content of the table is updated as well, in similar fashion to linking two plots through they ranges. I tried to adapt an stackoverflow answer where a box selector should update the table without success. Truth is this project is my first contact with javascript and I also don't understand bokeh completely yet. Below is a minimal code with my flimsy attempt to write a CustomJS

Many thanks for this wonderful list, I'm learning a lot reading it.

from bokeh.io import show
from bokeh.layouts import row, widgetbox
from bokeh.models import ColumnDataSource, CustomJS
from bokeh.plotting import figure, curdoc
from bokeh.models.widgets import DataTable, TableColumn
import pandas as pd

df = pd.DataFrame({'x': [1, 2, 3, 4, 5, 6, 7], 'A' : [1, 5, 3, 5, 2, 8, 3], 'B' : [2, 4, 3, 1, 5, 6, 2]})

tools_to_show = 'box_zoom,reset'
p = figure(plot_height =300, plot_width = 600,
            toolbar_location='above', tools=tools_to_show)

columns = ['A', 'B']
source = ColumnDataSource(df)
for col in columns:
     p.line('x', col, source=source)

columns = [
         TableColumn(field="A", title="A"),
         TableColumn(field="B", title="B"),
     ]
data_table = DataTable(source=source, columns=columns, width=300, height=300)

source.callback = CustomJS(args=dict(s2=source, table=data_table), code="""
     var inds = cb_obj.selected['1d'].indices;
     var d1 = cb_obj.data;
     var d2 = s2.data;
     d2['A'] =
     d2['B'] =
     for (i = 0; i < inds.length; i++) {
         d2['A'].push(d1['A'][inds[i]])
         d2['B'].push(d1['B'][inds[i]])
            }
     s2.trigger('change');
     table.trigger('change');
""")

curdoc().add_root(row(p, widgetbox(data_table)))

--
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/a307c698-589e-4c7b-bc09-8db4d8526657%40continuum.io\.
For more options, visit https://groups.google.com/a/continuum.io/d/optout\.

I had to clean up your code, it had some old deprecated patterns. Once I did, I encountered the linked bug. However, it seems that bug is annoying, but harmless.

Looking more closely, your problems sis actually that you are looking for a change on a selection, but only a selection tool will trigger that, and you have not added one at all. A Box Zoom tool will only exchange the range that is displayed, it will not perform any kind of selection operation. You will have to instead watch for changes on the range, and then manually iterate over all your data to find points that are inside the new range. (This would be much easier in a Bokeh server app, where you could have real python callbacks that use Pandas and Numpy, etc to help figure out which points to include)

Thanks,

Bryan

···

On Jul 29, 2018, at 16:48, Ricardo Melo Ferreira <[email protected]> wrote:

Hi,

Sorry, but I didn't understood the bug. I didn't get any error massages. However, when removing "args=" as suggested I got the following message:

018-07-29 19:08:35,748 Error running application handler <bokeh.application.handlers.script.ScriptHandler object at 0x7fe552294898>: __init__() takes 1 positional argument but 2 were given
File "zoom_table.py", line 37, in <module>:
""") Traceback (most recent call last):
  File "/usr/lib/python3.6/site-packages/bokeh/application/handlers/code_runner.py", line 163, in run
    exec(self._code, module.__dict__)
  File "/home/ricardo/pesq/ewing/auto_fig/v2/minimal/zoom_table.py", line 37, in <module>
    """)
TypeError: __init__() takes 1 positional argument but 2 were given

Thanks

Em 29-07-2018 17:01, Bryan Van de ven escreveu:

Hi,

I believe you are running into this current known bug:

  Error message on the browser console when using CustomJS with args in serve mode · Issue #7970 · bokeh/bokeh · GitHub

Thanks,

Bryan

On Jul 28, 2018, at 08:28, Ricardo Melo Ferreira <[email protected]> wrote:

Hi!

I'm trying to link a plot and a data table such as when using box zoom the content of the table is updated as well, in similar fashion to linking two plots through they ranges. I tried to adapt an stackoverflow answer where a box selector should update the table without success. Truth is this project is my first contact with javascript and I also don't understand bokeh completely yet. Below is a minimal code with my flimsy attempt to write a CustomJS

Many thanks for this wonderful list, I'm learning a lot reading it.

from bokeh.io import show
from bokeh.layouts import row, widgetbox
from bokeh.models import ColumnDataSource, CustomJS
from bokeh.plotting import figure, curdoc
from bokeh.models.widgets import DataTable, TableColumn
import pandas as pd

df = pd.DataFrame({'x': [1, 2, 3, 4, 5, 6, 7], 'A' : [1, 5, 3, 5, 2, 8, 3], 'B' : [2, 4, 3, 1, 5, 6, 2]})

tools_to_show = 'box_zoom,reset'
p = figure(plot_height =300, plot_width = 600,
           toolbar_location='above', tools=tools_to_show)

columns = ['A', 'B']
source = ColumnDataSource(df)
for col in columns:
    p.line('x', col, source=source)

columns = [
        TableColumn(field="A", title="A"),
        TableColumn(field="B", title="B"),
    ]
data_table = DataTable(source=source, columns=columns, width=300, height=300)

source.callback = CustomJS(args=dict(s2=source, table=data_table), code="""
    var inds = cb_obj.selected['1d'].indices;
    var d1 = cb_obj.data;
    var d2 = s2.data;
    d2['A'] =
    d2['B'] =
    for (i = 0; i < inds.length; i++) {
        d2['A'].push(d1['A'][inds[i]])
        d2['B'].push(d1['B'][inds[i]])
           }
    s2.trigger('change');
    table.trigger('change');
""")

curdoc().add_root(row(p, widgetbox(data_table)))

--
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/a307c698-589e-4c7b-bc09-8db4d8526657%40continuum.io\.
For more options, visit https://groups.google.com/a/continuum.io/d/optout\.

--
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/766ff87e-af1b-0bfe-6f5f-4025e6cdfba7%40gmail.com\.
For more options, visit https://groups.google.com/a/continuum.io/d/optout\.

I'm currently running a bokeh server, but I'll try to create a standalone in the future, since my application is intended to be distributed to users so they can plot their own files. Could you point me to some examples or documentation on how to watch for this range change?

Also, as a related question, is there a way to fully implement the widgets functionality as select boxes and tabs in a standalone? If there is not then I'm stuck with server, I guess the users will have to install bokeh, and the answer to my previous question can be implemented through server.

Thanks!

···

Em 29-07-2018 21:04, Bryan Van de ven escreveu:

I had to clean up your code, it had some old deprecated patterns. Once I did, I encountered the linked bug. However, it seems that bug is annoying, but harmless.

Looking more closely, your problems sis actually that you are looking for a change on a selection, but only a selection tool will trigger that, and you have not added one at all. A Box Zoom tool will only exchange the range that is displayed, it will not perform any kind of selection operation. You will have to instead watch for changes on the range, and then manually iterate over all your data to find points that are inside the new range. (This would be much easier in a Bokeh server app, where you could have real python callbacks that use Pandas and Numpy, etc to help figure out which points to include)

Thanks,

Bryan

On Jul 29, 2018, at 16:48, Ricardo Melo Ferreira <[email protected]> wrote:

Hi,

Sorry, but I didn't understood the bug. I didn't get any error massages. However, when removing "args=" as suggested I got the following message:

018-07-29 19:08:35,748 Error running application handler <bokeh.application.handlers.script.ScriptHandler object at 0x7fe552294898>: __init__() takes 1 positional argument but 2 were given
File "zoom_table.py", line 37, in <module>:
""") Traceback (most recent call last):
   File "/usr/lib/python3.6/site-packages/bokeh/application/handlers/code_runner.py", line 163, in run
     exec(self._code, module.__dict__)
   File "/home/ricardo/pesq/ewing/auto_fig/v2/minimal/zoom_table.py", line 37, in <module>
     """)
TypeError: __init__() takes 1 positional argument but 2 were given

Thanks

Em 29-07-2018 17:01, Bryan Van de ven escreveu:

Hi,

I believe you are running into this current known bug:

  Error message on the browser console when using CustomJS with args in serve mode · Issue #7970 · bokeh/bokeh · GitHub

Thanks,

Bryan

On Jul 28, 2018, at 08:28, Ricardo Melo Ferreira <[email protected]> wrote:

Hi!

I'm trying to link a plot and a data table such as when using box zoom the content of the table is updated as well, in similar fashion to linking two plots through they ranges. I tried to adapt an stackoverflow answer where a box selector should update the table without success. Truth is this project is my first contact with javascript and I also don't understand bokeh completely yet. Below is a minimal code with my flimsy attempt to write a CustomJS

Many thanks for this wonderful list, I'm learning a lot reading it.

from bokeh.io import show
from bokeh.layouts import row, widgetbox
from bokeh.models import ColumnDataSource, CustomJS
from bokeh.plotting import figure, curdoc
from bokeh.models.widgets import DataTable, TableColumn
import pandas as pd

df = pd.DataFrame({'x': [1, 2, 3, 4, 5, 6, 7], 'A' : [1, 5, 3, 5, 2, 8, 3], 'B' : [2, 4, 3, 1, 5, 6, 2]})

tools_to_show = 'box_zoom,reset'
p = figure(plot_height =300, plot_width = 600,
            toolbar_location='above', tools=tools_to_show)

columns = ['A', 'B']
source = ColumnDataSource(df)
for col in columns:
     p.line('x', col, source=source)

columns = [
         TableColumn(field="A", title="A"),
         TableColumn(field="B", title="B"),
     ]
data_table = DataTable(source=source, columns=columns, width=300, height=300)

source.callback = CustomJS(args=dict(s2=source, table=data_table), code="""
     var inds = cb_obj.selected['1d'].indices;
     var d1 = cb_obj.data;
     var d2 = s2.data;
     d2['A'] =
     d2['B'] =
     for (i = 0; i < inds.length; i++) {
         d2['A'].push(d1['A'][inds[i]])
         d2['B'].push(d1['B'][inds[i]])
            }
     s2.trigger('change');
     table.trigger('change');
""")

curdoc().add_root(row(p, widgetbox(data_table)))

--
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/a307c698-589e-4c7b-bc09-8db4d8526657%40continuum.io\.
For more options, visit https://groups.google.com/a/continuum.io/d/optout\.

--
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/766ff87e-af1b-0bfe-6f5f-4025e6cdfba7%40gmail.com\.
For more options, visit https://groups.google.com/a/continuum.io/d/optout\.

I'm currently running a bokeh server, but I'll try to create a standalone in the future, since my application is intended to be distributed to users so they can plot their own files. Could you point me to some examples or documentation on how to watch for this range change?

  https://bokeh.pydata.org/en/latest/docs/user_guide/interaction/callbacks.html#customjs-for-range-update

Also, as a related question, is there a way to fully implement the widgets functionality as select boxes and tabs in a standalone? If there is not then I'm stuck with server, I guess the users will have to install bokeh, and the answer to my previous question can be implemented through server.

I don't really understand the question. You can attach CustomJS callbacks to any widget, and do any operation that can be performed in JavaScript. Are you asking if there is some way to run python callbacks in standalone documents? The answer to that is no, because browsers have no ability to run Python code (that's the reason the Bokeh server exists).

Thanks,

···

On Jul 29, 2018, at 17:14, Ricardo Melo Ferreira <[email protected]> wrote:

Thanks for the example on the range update!

I have some checkbox that hide some glyphs and a selector to change line colors. I was wondering if is possible to write CustomJS that perform the same functions as the widgets and provide a standalone. Sorry if I'm not clear or oblivious to something obvious.

Thanks for the help!

···

Em 29-07-2018 21:22, Bryan Van de ven escreveu:

On Jul 29, 2018, at 17:14, Ricardo Melo Ferreira <[email protected]> wrote:

I'm currently running a bokeh server, but I'll try to create a standalone in the future, since my application is intended to be distributed to users so they can plot their own files. Could you point me to some examples or documentation on how to watch for this range change?

  https://bokeh.pydata.org/en/latest/docs/user_guide/interaction/callbacks.html#customjs-for-range-update

Also, as a related question, is there a way to fully implement the widgets functionality as select boxes and tabs in a standalone? If there is not then I'm stuck with server, I guess the users will have to install bokeh, and the answer to my previous question can be implemented through server.

I don't really understand the question. You can attach CustomJS callbacks to any widget, and do any operation that can be performed in JavaScript. Are you asking if there is some way to run python callbacks in standalone documents? The answer to that is no, because browsers have no ability to run Python code (that's the reason the Bokeh server exists).

Thanks,

Hi,

I’m still trying to update the data table from the plot zoom. I tried to write a CustomJS for the range update, but I’m not sure on hoe to update the data. When I introduced the callback below the figure doesn’t appear, however there is no error messages. Could someone help me with the CustomJS?

Thanks!

from bokeh.io import show

from bokeh.layouts import row, widgetbox

from bokeh.models import ColumnDataSource, CustomJS

from bokeh.plotting import figure, curdoc

from bokeh.models.widgets import DataTable, TableColumn

import pandas as pd

df = pd.DataFrame({‘x’: [1, 2, 3, 4, 5, 6, 7], ‘A’ : [1, 5, 3, 5, 2, 8, 3], ‘B’ : [2, 4, 3, 1, 5, 6, 2]})

tools_to_show = ‘box_zoom,reset’

p = figure(plot_height =300, plot_width = 600,

       toolbar_location='above', tools=tools_to_show)

columns = [‘A’, ‘B’]

source = ColumnDataSource(df)

for col in columns:

p.line('x', col, source=source)

tab_source = ColumnDataSource({‘A’ : , ‘B’ : })

orig_source = ColumnDataSource({‘A’ : , ‘B’ : })

tab_source.data = {

'A' : df.A,

'B' : df.B}

orig_source.data = {

'A' : df.A,

'B' : df.B}

columns = [

    TableColumn(field="A", title="A"),

    TableColumn(field="B", title="B"),

]

data_table = DataTable(source=tab_source, columns=columns, width=300, height=300)

p.x_range.callback = CustomJS(args=dict(source=tab_source, orig=orig_source),code=“”"

var start = cb_obj.start;

var end = cb_obj.end;

var d1 = orig.data;

var d2 = source.data;

d2['protein'] = [];

d2['position'] = [];

for (i=start; i<end; i++) {

    d2['protein'].push(d1['protein'][i]);

    d2['position'].push(d1['position'][i]);

source.change.emit();

“”")

curdoc().add_root(row(p, widgetbox(data_table)))

``

···

Em domingo, 29 de julho de 2018 21:22:36 UTC-3, Bryan Van de ven escreveu:

On Jul 29, 2018, at 17:14, Ricardo Melo Ferreira [email protected] wrote:

I’m currently running a bokeh server, but I’ll try to create a standalone in the future, since my application is intended to be distributed to users so they can plot their own files. Could you point me to some examples or documentation on how to watch for this range change?

    [https://bokeh.pydata.org/en/latest/docs/user_guide/interaction/callbacks.html#customjs-for-range-update](https://bokeh.pydata.org/en/latest/docs/user_guide/interaction/callbacks.html#customjs-for-range-update)

Also, as a related question, is there a way to fully implement the widgets functionality as select boxes and tabs in a standalone? If there is not then I’m stuck with server, I guess the users will have to install bokeh, and the answer to my previous question can be implemented through server.

I don’t really understand the question. You can attach CustomJS callbacks to any widget, and do any operation that can be performed in JavaScript. Are you asking if there is some way to run python callbacks in standalone documents? The answer to that is no, because browsers have no ability to run Python code (that’s the reason the Bokeh server exists).

Thanks,

Yes - here is another thread with linked plots, and also a table linked to selected data: Save plot data as csv

…additionally, there is some custom js to save the selected data to a csv