1

全部,

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

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

谢谢!

4

2 回答 2

1

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

在回调下方查找

    # 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帮助解决循环依赖

于 2020-07-29T16:45:27.843 回答
1

一个更简单的解决方案(但它有其他缺点)是选择一个隐藏的单元格。这使用户觉得没有选择任何内容。

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

添加名为“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',}
    ], 
)

然后回调可以设置表的“active_cell”和/或“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}]

于 2021-06-10T15:48:42.503 回答