Issues about empty row in Table when indices are selected

Hello,

I have the following code with this table but I am not able to make that only the selected rows of the selected points in the chart appear, that is to say, when I select points, the blank rows of unselected points do not appear.

Would it be possible that these rows do not appear?

Something aesthetic but I would like to know if it is possible to have the values that appear in the table centered in some way.

Thanks in advance.

import pandas as pd
import numpy as np

from bokeh.models import (ColumnDataSource,  DataTable, TableColumn
                         )

from bokeh.plotting import figure, curdoc, show
from bokeh.layouts import  row




x = np.random.sample(10)
y = np.random.sample(10)
z = np.random.sample(10)

l = ['P'+str(n) for n in range(len(z))]
c = ['skyblue']*len(x)
cl= ['c1']*4 + ['c2']*3 + ['c3']*3

dataf = pd.DataFrame({'Var1': x, 'Var2': y, 'Var3': z, 'Label': l, 'color': c, 'class': cl} )



source = ColumnDataSource(data=dict(x=dataf['Var1'],
                                    y=dataf['Var2'],
                                    z=dataf['Var3'],
                                    l=dataf['Label'],
                                    c=dataf['color']
                                   ))

p1 = figure(plot_width=800, plot_height=700,
            tools="tap,pan,lasso_select,wheel_zoom,save,reset",
            toolbar_location="above",
           )


p1.circle(x="x", y="y",color='c' ,fill_alpha=0.8 ,source=source, size=10,
           selection_line_color="darkblue")

columns = [TableColumn(field=n,title=n) for n in ['Var1','Var2','Var3','Label']]
table = DataTable(source=source,columns=columns, width=800, height=300)

    
def update_table(data):
    table.source = ColumnDataSource(data)
    
        
def selection_change(attrname, old, new):
    data = dataf.copy()
    selected = source.selected.indices
    if selected:
        data = data.iloc[selected, :]
        
    update_table(data)


source.selected.on_change('indices', selection_change) 

display = row(p1,table)

curdoc().add_root(display)

Since you are sharing the same source the table is hanging onto the elements that are still in the cds, just not selected. You should be able to pass a CDSView to the table to get rid of the extra rows.

Something like…

table_view = CDSView(source=source, filter=... )
...
table = DataTable(source=source, view=table_view)
..
def update_table(data):
    *update your filter view**
1 Like

Hello, thank you for your reply.

This is the last thing I tried because it seemed to me the most coherent thing to do.

But so that ‘table_view.filters’ does not update.

import pandas as pd
import numpy as np

from bokeh.models import (ColumnDataSource,  DataTable, TableColumn,
                         CDSView, IndexFilter)

from bokeh.plotting import figure, curdoc, show
from bokeh.layouts import  row




x = np.random.sample(10)
y = np.random.sample(10)
z = np.random.sample(10)

l = ['P'+str(n) for n in range(len(z))]
c = ['skyblue']*len(x)
cl= ['c1']*4 + ['c2']*3 + ['c3']*3

dataf = pd.DataFrame({'Var1': x, 'Var2': y, 'Var3': z, 'Label': l, 'color': c, 'class': cl} )



source = ColumnDataSource(data=dict(x=dataf['Var1'],
                                    y=dataf['Var2'],
                                    z=dataf['Var3'],
                                    l=dataf['Label'],
                                    c=dataf['color']
                                   ))

p1 = figure(plot_width=800, plot_height=700,
            tools="tap,pan,lasso_select,wheel_zoom,save,reset",
            toolbar_location="above",
           )


p1.circle(x="x", y="y",color='c' ,fill_alpha=0.8 ,source=source, size=10,
           selection_line_color="darkblue")


table_view = CDSView(source=source, filters=[] )

table = DataTable(source=source, view=table_view)


columns = [TableColumn(field=n,title=n) for n in ['Var1','Var2','Var3','Label']]
table = DataTable(source=source,columns=columns, width=800, height=300)

    
def update_table(data):
    table.source = ColumnDataSource(data)
    table_view.source = ColumnDataSource(data)
    table_view.filters = [IndexFilter(data.index)]
    
update_table(dataf)
    
def selection_change(attrname, old, new):
    data = dataf.copy()
    selected = source.selected.indices
    if selected:
        data = data.iloc[selected, :]
        
    update_table(data)


source.selected.on_change('indices', selection_change) 

display = row(p1,table)

curdoc().add_root(display)

Thanks again!

You had some duplicate/unnecessary things messing up the flow, incorporate the changes below and it should work for you.

x = np.random.sample(10)
y = np.random.sample(10)
z = np.random.sample(10)
l = ['P'+str(n) for n in range(len(z))]
c = ['skyblue']*len(x)
cl= ['c1']*4 + ['c2']*3 + ['c3']*3

dataf = pd.DataFrame({'x': x, 'y': y, 'z': z, 'l': l, 'c': c, 'cl': cl} )

source = ColumnDataSource(dataf)

p1 = figure(plot_width=800, plot_height=700,
        tools="tap,pan,lasso_select,wheel_zoom,save,reset",
        toolbar_location="above",
       )
p1.circle(x="x", y="y",color='c' ,fill_alpha=0.8 ,source=source, size=10,
           selection_line_color="darkblue")

table_view = CDSView(source=source, filters=[])
columns = [TableColumn(field=n,title=n) for n in ['x','y','z','l']]
table = DataTable(source=source, columns=columns, view=table_view, visible=False, width=800)

def selection_change(attrname, old, new):
    table.visible = True
    table.view = CDSView(source=source, filters=[IndexFilter(source.selected.indices)])

source.selected.on_change('indices', selection_change) 

doc.add_root(column(p1,table))
1 Like

Hello,

Thank you very much because it worked perfectly for me.

One last thing:
would you know if there is a possibility to filter the indexes in a specific order? That is, if I define IndexFilter([4,0,1,3]) that the table above shows them in that order. This would be a very interesting functionality as it would be very easy to determine that they are sorted, but if by default they are always sorted, there is no possibility to control it.

Thank you very much for everything.

I think you are out of luck if you are trying to do that in a DataTable. If you had to have a static table w/ explicit ordering you could construct a html table and pitch to a Div.

1 Like

Hello,

well, it’s a pity because it would be tremendously practical but it’s still beneficial for the DataTable to connect directly to any figure.

One last question, is it not possible to control the position of the headers, that is to say, to center for example the title of the columns?

Thank you very much for all your attention, it is all very pedagogical and very helpful.

You’ll have to dig around in the model formatters (StringFormatter(), CellFormater(), HTMLTemplateFormatter(), etc.) to see if you can get something to touch the header.

Just for quick example you can pass a StringFormatter() to your TableColumn and center the row text with
TableColumn(field=n, title=n, formatter=StringFormatter(text_align='center'))

1 Like

Hello,

I’ll have a look and if I find it I’ll paste it here in case it could be of help to anyone.

Thanks again for everything.