Announcing Dash Bio 1.0.0 🎉 : a one-stop-shop for bioinformatics and drug development visualizations.

Manually update Dash table from user Input

I am trying to build a dashboard with Dash. One of the feature of this dashboard is that after dynamically updating dropdowns a user will be able to select multiple options and group them together.

I am able to group options together but when I go to group other options it rewrites my previous changes.

Such as when I group t1 and t2 in Group1 it is done but when I remove these selection from dropdown and select t3 and t4 in Group2 it rewrites my previous group.

Following is my code:

import dash
from dash.dependencies import Input, Output, State
import dash_core_components as dcc
import dash_html_components as html
import dash_bootstrap_components as dbc
import dash_table

import pandas as pd

data = [['tom', 'nick','t1',''], ['tom', 'nick','t2',''], ['tom', 'john','t3',''], ['tom','john','t4','']]
df = pd.DataFrame(data, columns = ['Captain', 'VCaptain', 'Teams','Groups']) 

external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']

app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
server = app.server

colors = {
    "graphBackground": "#F5F5F5",
    "background": "#ffffff",
    "text": "#000000"
}

app.layout = dbc.Container(
    [
        dbc.Row(
            [
               dbc.Col(dbc.Card([
                    dbc.FormGroup([
                        dbc.Label(html.B("Select Captains from list below:")),
                        dcc.Dropdown(id="captains",
                                     options=[{'label': i, 'value': i} for i in df['Captain'].unique()],
                                     value=[i for i in df['Captain'].unique()],)
                    ]),
                    dbc.FormGroup([
                            dbc.Label(html.B("Select Vice Captains from below:")),
                            dcc.Dropdown(id="vcaptains")
                    ]
                    ),
                    dbc.FormGroup([
                            dbc.Label(html.B("Select Teams which needs to be grouped together:")),
                            dcc.Dropdown(id="teams",multi = True),
                    ]
                    ),
                    dbc.FormGroup([
                            dbc.Label(html.B("Input new group name:")),
                            dbc.Input(id="group", placeholder="Type group name...", type="text"),
                        ]
                    ),
                    html.I("Write a Name for the Group of the selected teams.",
                          style={"color":"#737373", "font-size":"0.8rem"}),
                    html.Br(),
                    dbc.Button("Add Group", id="assign", block=False,
                               outline=True, color="primary", #className = "mr-2",
                               style = {"margin-right": "10.5rem"}),
                    html.Br(),
                ], body = True,
                    style={"top": "20px",
                           "left":10,
                           "height":"900px",
                           "width": "20rem",
                           "padding": "2rem 1rem",
                           "background-color": "#f8f9fa",}
                ), width=2),
                dbc.Col(width = 1),
                dbc.Col(id='table',width=6, style={"top":-120})
            ],
            align="center",
        ),
    ],fluid=True)

# # Dropdown to filter Captains
# @app.callback(
#     Output('captains', 'options'),
#     [Input('captains', 'value')])
# def captain_options(value):
#     opts=[]
#     if value is not None:
#         opts = df['Captain'].unique()
#     return [{'label': i, 'value': i} for i in opts]

# Dropdown to filter Vice Captains
@app.callback(
    Output('vcaptains', 'options'),
    [Input('captains', 'value')])
def vice_captain_options(value):
    opts=[]
    if value is not None:
        opts = df[df['Captain'].isin([value])]['VCaptain'].unique()
    return [{'label': i, 'value': i} for i in opts]

# Dropdown to filter Vice Captains
@app.callback(
    Output('teams','options'),
    [Input('captains', 'value'),
    Input('vcaptains', 'value')])
def teams_options(captains, vcaptains):
    opts=[]
    if captains is not None:
        opts = df[df['Captain'].isin([captains])]['Teams'].unique()
    
    if vcaptains is not None:
        opts = df[df['Captain'].isin([captains]) & 
                  df['VCaptain'].isin([vcaptains])]['Teams'].unique()
        
    return [{'label': i, 'value': i} for i in opts]


@app.callback(
    Output('table', 'data'),
    [Input('captains', 'value'),
     Input('vcaptains', 'value')])
def table(captains, vcaptains):
    df1 = df
    if captains is not None:
        df1 = df[(df['Captain'].isin([captains]))]
    if vcaptains is not None:
        df1 = df[(df['VCaptain'].isin([vcaptains]))]
    if df1 is not None:
        return df1.to_dict('records')
    
@app.callback(
    Output('table', 'children'),
    [Input('table', 'data'),
     Input('assign', 'n_clicks')],
    [State('teams', 'value'),
     State('group', 'value')])
def table(data,n,teams,group):
    df1 = pd.DataFrame.from_dict(data)
    changed_id = [p['prop_id'] for p in dash.callback_context.triggered][0]
    if 'assign' in changed_id:
        if teams is not None:
            if type(teams)==str:
                df1.loc[df1['Teams'].isin([teams]), 'Groups'] = group
            else:
                df1.loc[df1['Teams'].isin(teams), 'Groups'] = group
    if df is not None:
        return dash_table.DataTable(data = df1.to_dict('records'),
                                    columns=[{'id': c, 'name': c} for c in df1.columns])

if __name__ == '__main__':
    app.run_server(debug=False)