Search code examples
bokeh

Changing Bokeh table row count


Below is a working example of a Bokeh table that is populated with selections from a scatter plot.

Once the table is first initialized, it always shows that many rows (too many or too few).

Is there a way to make the number of rows dynamic to fit the number of records selected?

Thank you

import numpy as np
import pandas as pd
from bokeh.layouts import  row
from bokeh.models import ColumnDataSource
from bokeh.plotting import figure, curdoc, show
from bokeh.models.widgets import DataTable, DateFormatter, TableColumn


#Plotting points on chart.
initial_df = pd.DataFrame(np.random.randint(0,100,size=(500, 2)), 
                          columns=["X","Y"], 
                          index=[str(i) for i in range(1,500+1)])

pointchart=figure(plot_width=800, plot_height=700, 
                  tools=['lasso_select','box_select'],
                  title="Points for selection")

pointchart_source= ColumnDataSource(initial_df )
pointchart_glyph= pointchart.circle("X","Y",source=pointchart_source,size=3.5)


#Source for table
source_df=initial_df 
source_df['ID']=source_df.index

#Making initial table source from dataframe. The table will always have this number of rows.
initial_source_for_table = ColumnDataSource(source_df)

columns =  [TableColumn(field='ID', title="Col1"),
           TableColumn(field="X", title="Col2"), 
           TableColumn(field="Y", title="Col3")]

global data_table #lets you access it in the callback.
data_table = DataTable(source=initial_source_for_table, columns=columns, width=800, height=400)


def on_selection_change(attr, old, new):
    newdataframe= pd.DataFrame(pointchart_source.data).loc[new]
    newdataframe['ID']=newdataframe.index
    newsource=ColumnDataSource(newdataframe[['ID',"X","Y"]].dropna(how='all'))


    data_table.source=newsource
    data_table.width=500
    data_table.height=500


pointchart_glyph.data_source.selected.on_change('indices',on_selection_change) 


#Show
layout=row(pointchart,data_table)
curdoc().add_root(layout)
!powershell -command {'bokeh serve --show Test_Table.ipynb'}

Solution

  • I don't have Jupyter Notebook but this example should help you on your way. Just count the number of selected points and alter the number of table rows with table.height = number_points * 25. Run the code with: bokeh serve --show app.py

    from bokeh.io import curdoc, show
    from bokeh.layouts import widgetbox
    from bokeh.models import ColumnDataSource, Slider, DataTable, TableColumn
    
    max_i = 200
    init_i = 6
    
    def get_square(n):
        return dict(x = list(range(n)), y = [x ** 2 for x in range(n)])
    
    source = ColumnDataSource(get_square(init_i))
    columns = [
        TableColumn(field = "x", title = "x"),
        TableColumn(field = "y", title = "x**2"),
    ]
    
    table = DataTable(source = source, columns = columns, width = 320)
    slider = Slider(start = 1, end = max_i, value = init_i, step = 1, title = "i", width = 300)
    
    def update_data(attrname, old, new):
        i = slider.value
        table.source.data = get_square(i)
        table.height = i * 25 + 25
    
    slider.on_change('value', update_data)
    
    layout = widgetbox(slider, table)
    curdoc().add_root(layout)
    

    BTW: you should not replace the entire ColumnDataSource in your callback but just assign a new data to it like in my example, that is use:

    table.source.data = new_data 
    

    instead of:

    table.source = new_source