在破折号数据表中取消选择 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_conditional 和 style_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}]
全部,
我正在尝试实现一个破折号数据表,其中我 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_conditional 和 style_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}]