2
votes

I have a Plotty DataTable showing a Pandas DataFrame. The DataFrame has one LineChart for each column in the data frame. Each line chart has one line for each ID represented in the data. I am trying to make it easier to correlate odd looking graphical data to the raw input data.

I want to be able to click on a data point (or better yet select a line in the ChartLegend), doing this would cause the DataTable to filter and only show rows associated with the selected id.

Here is the code snippet for how i produce make the DataTable and Charts

def Make_PlottyFigures(df, xcol_name, device_type_dict, device_names, columns_to_plot):
    figs = []
    for col_i in range(0, len(columns_to_plot)):            
        figs.append(go.Figure())

    #Go over each device, and add a trace for each column to the appropriate figure. We want each colun in its own figure 
    for device in device_names:
        if df[df['id'] == device].shape[0] > 0:
            axs_index = 0
            for col in columns_to_plot:
                figs[axs_index].add_trace(go.Scatter(x=df[xcol_name], y=df[df['id'] == device][col],
                        mode='lines+markers',
                        name=f"{device_type_dict[device]}-{device}"))
                axs_index += 1

    index = 0;
    for col in columns_to_plot:
        figs[index].update_layout(
        title=f"{col}",
        xaxis_title="",
        yaxis_title="",
        font=dict(
                family="Courier New, monospace",
                size=18,
                color="#7f7f7f"
            )
        )
        index += 1
    return figs


def DASH_dataTable_from_pd(id, df):
    return dash_table.DataTable(
        id=f'datatable-{id}',
        columns=[
            {"name": i, "id": i, "deletable": False, "selectable": False} for i in df.columns
        ],
        data=df.to_dict('records'),
        editable=False,
        filter_action="native",
        sort_action="native",
        sort_mode="multi",
        column_selectable="single",
        row_selectable="multi",
        row_deletable=False,
        selected_columns=[],
        selected_rows=[],
        page_action="native",
        page_current= 0,
        page_size= 10,
    )

I have tried looking online for something similar but havent found anything. https://dash.plotly.com/datatable/interactivity has a 'sorta' example but its in the opposite direction( Making selections in the Table highlight the equivilant chart data entry). https://dash-docs.herokuapp.com/interactive-graphing has examples on how to react to the events I am interested in, I am just stuck on how to get the Table filtered off these events firing (also making this releasable would be nice)

Are there any samples that i missed out on or is this dead obvious and i'm missing something

1

1 Answers

2
votes

The straightforward approach is to re-set the data property of the table, passing only rows you want to display. You can listen to trace click events, determine the clicked trace by index, customdata or any other property the clickData object comes with.

This basic example illustrates the idea:

df = [...]

@app.callback(
    Output("my-table", "data"),
    [Input("my-plot", "clickData")]
)
def on_trace_click(click_data):
    """Listen to click events and update table, passing filtered rows"""
    p = trace_click['points'][0]

    # here, use 'customdata' property of clicked point, 
    # could also use 'curveNumber', 'pointIndex', etc.
    if 'customdata' in p:
        key = p['customdata']['my-key']

    df_f = get_corresponding_rows(df, key)

    return df_f.to_dict('records')

def get_corresponding_rows(df, my_key):
    """Filter df, return rows that match my_key"""
    return df[df['key-column'] == my_key]

It's important that your row ids don't change just because of filtering. That way, any styling, selected state etc. will still be applied properly.