Open document from column datatable

I would like to be able to build a datatable that contains a file name in a column (pdf for example).
With a click or a double click on the column I would like to open the file.
Is it possible to create this with bokeh?
Kind Regards

More information is needed. Is this:

  • A Bokeh server app?
  • Or standalone HTML output?
  • Are these files local files on the same computer as the browser?
  • Or files on the server that is serving the Bokeh server app?
  • Something else? (e.g. remote S3 or URL links?)

It’s not possible to speculate or offer guidance without more details.

More information;

  1. I wish do this in A Bokeh server app
  2. The file are on the server that is serving the Bokeh server app
    Thanks You

Something along the lines of this maybe, leveraging two things:

  1. When the user clicks a row in a bokeh DataTable, the CDS driving it actually changes its selected indices property to the selected row/index of the source, and;
  2. os.system to open stuff locally

So stashing the location of your pdfs into the CDS itself and launching that pdf location via os.system when the user selects a row…

import os
from bokeh.models import ColumnDataSource, DataTable,TableColumn
from bokeh.io import curdoc

table_source = ColumnDataSource(data={'thing':['pdf0','pdf1'],'pdf':['where_is_pdf0.pdf','where_is_pdf1.pdf']})

def file_launcher(attr,old,new):
    #get the index of the selected row in the table
    ind = table_source.selected.indices[0]
    #get the pdf associated with it
    pdf = table_source.data['pdf'][ind]
    #launch that sucker
    os.system(pdf)


tbl = DataTable(columns=[TableColumn(field='Thing',title='Thing')],source)
#tell that function to happen when the selected indices of the datasource driving the table change
table_source.selected.on_change('indices',file_launcher)

hello gmerritt123
I have tested your suggestion and everything works very well.
I realized that I explained myself badly in the last part.
I would like to open the file on the browser which is connected to the bokeh server.
Basically replace the os.system (pdf) command with something that opens the pdf in the client

Not sure what you mean by “in the client”? I’m probably out of my element at this point but I’ll chime in if I can.

@mauroDia I think to view the PDF in the browser, you will need to take the data that is returned (in a CDS possibly, or a DataModel is another option) and then in a JS callback pass it off to something like PDF.js:

However, I’ve never tried to string all these pieces together, and I have not heard of anyone else doing so either. So it will take some experimentation on your end. You will probably need a custom page template for the Bokeh app to load the PDF.js source and make it available in a Bokeh CustomJS callback.

A more sophisticated approach would be to create a Bokeh custom extension that wraps PDF.js (or a similar tool) but that is a fairly advanced undertaking:

Hello everybody

Sorry for my English.

My purpose is not advanced enough to be able to see it inside the browser using PDF.js, but it is limited to being able to see it.
So for example a pop up window that opens the pdf or any thing that, acting on the datatable, allows me to open a client window which would be fine to see it.

I enclose an example of what I would like to do.
The problem is that the js command doesn’t open the file.
What am I doing wrong?

import os
from bokeh.models import ColumnDataSource, DataTable,TableColumn,Column,CustomJS
from bokeh.io import curdoc
from bokeh.models.widgets import TextInput

table_source = ColumnDataSource(data=
                {'thing':['pdf0','pdf1'],
                 'pdf':['C:\\A\\diapdf\\art1.pdf','C:\\A\\diapdf\\art12.pdf']})

# widget to generate event
widgetEventoOpenFile = TextInput(width=10,visible=False,value='X')
nomeFileWeb=""
openFileCustomJS=CustomJS(code="""
    var A= '{0}'; 
    window.open(A);
    """ .format (str(nomeFileWeb)))
widgetEventoOpenFile.js_on_change('value',openFileCustomJS)

def file_launcher(attr,old,new):
    global widgetEventoOpenFile
    global openFileCustomJS
    global nomeFileWeb
    
    #get the index of the selected row in the table
    ind = table_source.selected.indices[0]
    #get the pdf associated with it
    nomeFilePDF = table_source.data['pdf'][ind]
    nomeRidottoFilePDF=os.path.basename(nomeFilePDF)
    nomeFileStatic=" C:\\DiaBi\\static\\pdf\\"+nomeRidottoFilePDF
    cmd="copy "+nomeFilePDF+" "+nomeFileStatic+" /Y"  
    print(cmd)
    os.system(cmd)

    nomeFileWeb="http://localhost:5006/DiaBi/static/pdf/"+nomeRidottoFilePDF
    js_code="""var A= '{0}';window.open(A);""" .format (nomeFileWeb)  
    print("js_code=",js_code)  
    openFileCustomJS.code = js_code  # update js code
    if widgetEventoOpenFile.value=='X':  
        widgetEventoOpenFile.value = "Y" # call JS
    else:
        widgetEventoOpenFile.value = "X" # call JS
    print("widgetEventoOpenFile.value=",widgetEventoOpenFile.value)
    return

tbl = DataTable(columns=[TableColumn(field='thing',title='Thing')],source=table_source)
#tell that function to happen when the selected indices of the datasource driving the table change
table_source.selected.on_change('indices',file_launcher)

layout=Column(tbl)
curdoc().add_root(layout)

# bokeh serve C:\DiaBi C:\Eclipse\eclipse-workspace\BiDia64\testDocumentale.py
# localhost:5006/testDocumentale

Sorry,
I have found my error.
This is the code that do what I wish.
Thanks YOU!!!

import os
from bokeh.models import ColumnDataSource, DataTable,TableColumn,Column,CustomJS,OpenURL
from bokeh.io import curdoc
from bokeh.models.widgets import TextInput

table_source = ColumnDataSource(data=
                {'thing':['pdf0','pdf1'],
                 'pdf':['C:\\A\\diapdf\\art1.pdf','C:\\A\\diapdf\\art12.pdf']})


# widget to generate event
widgetEventoOpenFile = TextInput(width=10,visible=False,value='X')
nomeFileWeb=""
openFileCustomJS=CustomJS(code="""
    var A= '{0}'; 
    window.open(A);
    """ .format (nomeFileWeb))
widgetEventoOpenFile.js_on_change('value',openFileCustomJS)

def file_launcher(attr,old,new):
    global widgetEventoOpenFile
    global openFileCustomJS
    global nomeFileWeb
    #get the index of the selected row in the table
    ind = table_source.selected.indices[0]
    #get the pdf associated with it
    nomeFilePDF = table_source.data['pdf'][ind]    
    nomeRidottoFilePDF=os.path.basename(nomeFilePDF)
    nomeFileStatic=" C:\\DiaBi\\static\\pdf\\"+nomeRidottoFilePDF
    cmd="copy "+nomeFilePDF+" "+nomeFileStatic+" /Y"  
    os.system(cmd)

    nomeFileWeb="http://localhost:5006/DiaBi/static/pdf/"+nomeRidottoFilePDF
    
    js_code="""var A= '{0}';window.open(A);""" .format (nomeFileWeb)  
    openFileCustomJS.code = js_code  # update js code
    
    if widgetEventoOpenFile.value=='X':  
        widgetEventoOpenFile.value = "Y" # call JS
    else:
        widgetEventoOpenFile.value = "X" # call JS
    return

tbl = DataTable(columns=[TableColumn(field='thing',title='Thing')],source=table_source)
#tell that function to happen when the selected indices of the datasource driving the table change
table_source.selected.on_change('indices',file_launcher)

layout=Column(tbl,widgetEventoOpenFile)
curdoc().add_root(layout)

# bokeh serve C:\DiaBi C:\Eclipse\eclipse-workspace\BiDia64\testDocumentale.py
# localhost:5006/testDocumentale
1 Like