Adding a row to a table by clicking a button

Hello,
I was asked to create an interactive dashboard (with figures and tables) to compute different scenarios of a model. In order to track all the scenarios which were tested I wanted to create a table, which is connected to a button, so that everytime when the button is clicked a new row is added to the table containing the values of the current scenario. The different scenarios can be adjusted by the slider and the first table displays the actual value. The second table should save the scenarios. The function “get_data” is the “model”.

I am very new to python and bokeh, therefore not really experienced. I am also thanksfull for other recommendations to improve my working-example.

What I tried:
I wanted to update the second table in the function “update_scen_tab”, however i couldnt find anything that worked. In the working example the function “update_scen_tab” is kind of senseless. I just left in a way that it doesnt produce an error.

import numpy as np
import pandas as pd
from bokeh.io import output_notebook, show
from bokeh.layouts import column, row
from bokeh.models import (ColumnDataSource, Select, TextInput, Button, CustomJS, DataTable,
                          NumberFormatter, RangeSlider, TableColumn, Slider,)

output_notebook()
def modify_doc(doc):
    
    def get_data(a):
        b=a*5

        c = {'A': [a], 'B':[b]}
        df = pd.DataFrame(data=c)
        return df


    # First Table
    source = ColumnDataSource(data=get_data(1))
    columns = [TableColumn(field="A", title="A"),
               TableColumn(field="B", title="B")]
    
    data_table = DataTable(source=source, columns=columns, width=400)

    # Second Table 
    source2 = ColumnDataSource()
    columns2 = [TableColumn(field="A", title="A"),
               TableColumn(field="B", title="B")]
    data_table2 = DataTable(source=source2, columns=columns2, width=400)
    
    #Slider
    input = Slider(title="A", value=1.0, start=0, end=30, step=1)
    

    def update_points(attrname, old, new):
        a = float(input.value)
        source.data = get_data(a)
    input.on_change('value', update_points)

    button = Button(label="Save settings", button_type="success")
    
       
    def update_scen_tab():
        a = float(input.value)
        c=get_data(a)
        d=c
        frames = [d,c]
        source2.data = pd.concat(frames, sort=False)
        return 
    
    button.on_click(update_scen_tab)   
    
    layout = column(row(input, width=400), data_table,button,data_table2)

    doc.add_root(layout)

show(modify_doc)

You probably want to use the CDS stream method

# need to specify column names up front to be able to use stream
source2 = ColumnDataSource(data=dict(A=[], B=[]))

def update_scen_tab():
    # The other data source comes from a DataFrame, so includes its
    # own index column that we probably don't want, so delete it
    new_data = dict(source.data)
    del new_data["index"]

    source2.stream(new_data)

The stream method is documented here:

Providing data — Bokeh 2.3.3 Documentation

1 Like

thanks a lot for the quick answer. It works very well!