在破折号数据表中取消选择 active_cell (python)

Unselect active_cell in dash datatable (python)

全部,

我正在尝试实现一个破折号数据表,其中我 select 行通过直接单击它(没有单选按钮)。目前,我正在使用 active_cell 执行此操作并且效果很好: 无论用户单击行中的哪个单元格,图表都会使用该行中的数据进行更新。如果他单击同一行中的另一个单元格,则数据未被select编辑(通过 dcc.storage)

我的问题来了:如果用户再次单击同一个单元格,则不会触发 active_cell 事件。因此,我的回调没有被触发,也没有任何反应。 我想在用户第二次单击该单元格时取消select该单元格。我该如何实施?

谢谢!

所以...我解决了这个...它不是很漂亮但它有效 - 它包括一个循环断路器,我必须实施它以避免循环依赖,但是是的 - 我绝对愿意接受更清洁的解决方案。

在回调下面找到

    # takes user selected cell (active_cell) and the current state of a dcc.storage (tableclick) which stores the last saved row that was clicked
# output: updated selected_rows for the datatable, styling for the selected row and update for dcc.storage
# if no cell is selected, do nothing
# if no cell is selected, but there is a row stored as selected, highlight that row (this is a consequence from the circular dependency)
# if a cell is selected that is different from the previous cell, highlight that new row. Otherwise, deselect the row.
@app.callback(
    [Output('performancedatatable', 'style_data_conditional'), Output('tableclick', 'data'),
     Output('performancedatatable', 'selected_rows')],
    [
        Input('performancedatatable', 'active_cell'),
    ], [State('tableclick', 'data')]
)
def highlight_row(cell, prevrow):
    if cell is None:
        if prevrow is None:
            return [{}], None, []
        else:
            return [{}], None, prevrow
    elif "row" in cell:
        if cell.get("row", "") == prevrow:
            return [{}], None, []
        else:
            return ([{
                "if": {"row_index": cell.get("row", "")},
                "backgroundColor": "rgba(146, 192, 234, 0.5)",
            }], cell.get("row", ""), [cell.get("row", "")])


# Is triggered by changing the dcc.storage "tableclick"
# resets active cell and selected cell via callback below
@app.callback([Output('loopbreaker_div', "children")], [Input('tableclick', 'data')])
def reset_active_cell(input):
    return [html.Div(id='loopbreaker', children=True)]


#loopbreaker to avoid circular dependency
@app.callback([Output('performancedatatable', "active_cell"), Output('performancedatatable', 'selected_cells')], [Input('loopbreaker', 'children')])
def reset_active_cell(input):
    time.sleep(1)
    return (None, [])

感谢http://yaaics.blogspot.com/2019/03/circular-references-in-plotlydash.html帮助解决循环依赖

一个更简单的解决方案(但它有其他缺点)是 select 隐藏单元格。这让用户看起来什么都没有 selected.

在下面的示例中,一个单元格由回调处理和取消select。显然,此回调也可以用于“deselect all”按钮或您需要的任何其他内容。

添加名为“cant_see”的列:

df = pd.read_csv("my_data.csv")
df.insert(0, "cant_see", ["" for i in df.iloc[:, 0] ]) 

使用 style_data_conditionalstyle_header_conditional 创建 DataTable 时隐藏它:

dash_table.DataTable(
    id="table",
    columns=[{"name": i, "id": i} for i in df.columns],
    data=df.to_dict("records"),
    is_focused=True,
    style_data_conditional=[
        {'if': {'column_id': 'cant_see',}, 'display': 'None',}
    ],
    style_header_conditional=[
        {'if': {'column_id': 'cant_see',}, 'display': 'None',}
    ], 
)

然后回调可以设置table的“active_cell”and/or“selected_cells”

@app.callback(
    Output("table", "active_cell"),
    Output("table", "selected_cells"),
    Input("table", "active_cell"),)

def cell_clicked(cell):
    # Do something useful with cell, 
    # such as toggling it's style to mimic select/de-select

    # Now make it look like the cell is de-selected
    # by selecting a hidden cell
    #
    # return active cell 0,0 and selected_cells list [ 0,0 ]
    return {'column':0, 'row':0}, [{'column':0, 'row':0}]