访问可编辑注释
Accessing Editable Annotations
我有一个简单的 Dash 应用程序,其中的绘图会在单击 'Update' 按钮时更新。我在此图上包含了一个可编辑的注释。我希望能够访问用户在注释中键入的任何内容,以便在更新图形时,注释保持不变。我主要想知道是否有办法访问他们的编辑方式。
我一直在尝试将当前注释保存到创建图形时访问的存储组件中。我尝试制作一个 'Save' 按钮,将存储数据更改为当前注释文本 我唯一的猜测是,当编辑注释时,新文本不会存储在与默认文本相同的位置。那个,或者某些事情只是在我的头上,我没有意识到。
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, State, Output
import random
app = dash.Dash(__name__)
app.config['suppress_callback_exceptions'] = True
app.layout = html.Div(
id = 'top_level',
children=[
html.Div(
id='plot_div',
children=[],
),
html.Button(
id = 'update',
children="Update",
),
dcc.Store(
id='annotation_storage',
data='Editable Annotation',
)
]
)
@app.callback(
Output('plot_div', 'children'),
[Input('update', 'n_clicks')],
[State('annotation_storage', 'data')]
)
def plot_update(clicked, annotation):
if clicked:
x = random.sample(range(1,101), 20)
y = random.sample(range(1,101), 20)
figure = {'data': [{'x': x, 'y': y,
'type': 'scatter', 'mode': 'markers'}],
'layout': {
'xaxis': {
'fixedrange': True,
'zeroline': False,
},
'yaxis': {
'fixedrange': True,
'zeroline': False,
},
'annotations': [{
'x': -0.05,
'y': 0.5,
'showarrow':False,
'text':annotation,
'xref':'paper',
'yref':'paper',
}],
}
}
return [dcc.Graph(
id = 'plot_output',
figure = figure,
config = {
'editable': True,
'edits': {
'axisTitleText': False,
'titleText': False,
},
'displayModeBar': False,
},
),
html.Button(
id = 'save_annotation',
children='Save',
),
]
@app.callback(
Output('annotation_storage', 'data'),
[Input('save_annotation', 'n_clicks')],
[State('plot_output', 'figure')]
)
def save_annotation(clicked, figure):
if clicked:
annotation = figure['layout']['annotations'][0]['text']
return annotation
if __name__ == '__main__':
app.run_server(debug=True, port=1000)
目前,当图表更新时,注释只是恢复为默认文本 "Editable Annotation",即使用户对其进行编辑也是如此。我希望注释即使在图形更新时也保持不变。任何见解将不胜感激!谢谢!
如 Dash user guide 中所写:
The dcc.Graph
component has four attributes that can change through
user-interaction: hoverData
, clickData
, selectedData
, relayoutData
.
这意味着当用户与图表交互时,您使用的 figure
属性不会更新。
要解决您的问题,请更新您的回调函数以使用 relayoutData
而不是 figure
:
@app.callback(
Output('annotation_storage', 'data'),
[Input('save_annotation', 'n_clicks')],
[State('plot_output', 'relayoutData')]
)
def save_annotation(clicked, relayout_data):
if clicked:
annotation = relayout_data['annotations[0].text']
return annotation
您可以 运行 您的应用程序处于调试模式,并在回调函数内添加一个断点以探索上述四个属性给出的值。这就是我在 relayout_data
.
中找到注释文本键的方法
fig = px.scatter(df, x="x", y="y")
## TODO - load init annotations to fig.layout.annotations
dash_app1.layout = html.Div([
html.H1('Hi there, I am dashboard1'),
dcc.Graph(
id='example-graph',
figure=fig,
config={
'editable': True,
'edits': {
'axisTitleText': False,
'titleText': False,
},
}
)
])
@dash_app1.callback(
Output('example-graph', 'figure'),
[Input('example-graph', 'clickData'),
Input('example-graph', 'relayoutData')],
prevent_initial_call=True)
def annotation(clickData, relayoutData):
if clickData:
# get click xy
point = clickData["points"][0]
# if not exist, add
if f"'x': {point['x']}, 'y': {point['y']}" not in str(fig.layout.annotations):
fig.add_annotation(x=point["x"], y=point["y"], text="Click Here To Edit")
print("Add: ", fig.layout.annotations)
else:
# if exist, edit
if relayoutData:
fig.plotly_relayout(relayoutData)
print("Edit: ", fig.layout.annotations)
## TODO - save fig.layout.annotation
return fig
Shovalt 的回答很棒,感谢您的启发。我使用 clickData
事件添加注释,使用 relayoutData
事件记录编辑和拖动位置。此更新可以简单地由 fig.plotly_relayout
完成,这不包含在文档中。我巧妙地利用了 JS。老实说,Plotly Dash 的文档还不够 developer-friendly,尤其是对于像我这样的初学者。确保您在 IDE 中启用了代码完成功能,有时它比文档更有帮助...
此外,dcc.Store
在这里有点重复,因为您可以在 fig.layout.annotations
中找到所有注释。小心 dcc.Store
,如文档所述,它有内存限制:It's generally safe to store up to 2MB in most environments, and 5~10MB in most desktop-only applications.
更新:
我发现这个 relayoutData 侦听器可能会导致缩放不可用,但我认为它现在适用于此
@dash_app1.callback(
Output('example-graph', 'figure'),
[Input('example-graph', 'clickData'),
Input('example-graph', 'relayoutData')],
prevent_initial_call=True)
def annotation(clickData, relayoutData):
print("Click")
print(clickData)
print("Relayout")
print(relayoutData)
if clickData:
## get click xy
point = clickData["points"][0]
## if not exist, add
if f"'x': {point['x']}, 'y': {point['y']}" not in str(fig.layout.annotations):
fig.add_annotation(x=point["x"], y=point["y"], text="Click Here To Edit")
print("Add: ", fig.layout.annotations)
## TODO - save fig.layout.annotations to SQLite
return fig
if relayoutData:
## initial loading or refreshing action
if str(relayoutData) == "{'autosize': True}":
return fig
## zooming action
## enable zooming after resetting zooming
if 'xaxis.range' in str(relayoutData) and 'yaxis.range' in str(relayoutData):
fig.layout.xaxis.autorange = False
fig.layout.yaxis.autorange = False
## edit annotation position or text | also enable zooming after resetting
fig.plotly_relayout(relayoutData)
print("Edit: ", fig.layout.annotations)
## TODO - If edit, then update fig.layout.annotations to SQLite
return fig
我有一个简单的 Dash 应用程序,其中的绘图会在单击 'Update' 按钮时更新。我在此图上包含了一个可编辑的注释。我希望能够访问用户在注释中键入的任何内容,以便在更新图形时,注释保持不变。我主要想知道是否有办法访问他们的编辑方式。
我一直在尝试将当前注释保存到创建图形时访问的存储组件中。我尝试制作一个 'Save' 按钮,将存储数据更改为当前注释文本 我唯一的猜测是,当编辑注释时,新文本不会存储在与默认文本相同的位置。那个,或者某些事情只是在我的头上,我没有意识到。
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, State, Output
import random
app = dash.Dash(__name__)
app.config['suppress_callback_exceptions'] = True
app.layout = html.Div(
id = 'top_level',
children=[
html.Div(
id='plot_div',
children=[],
),
html.Button(
id = 'update',
children="Update",
),
dcc.Store(
id='annotation_storage',
data='Editable Annotation',
)
]
)
@app.callback(
Output('plot_div', 'children'),
[Input('update', 'n_clicks')],
[State('annotation_storage', 'data')]
)
def plot_update(clicked, annotation):
if clicked:
x = random.sample(range(1,101), 20)
y = random.sample(range(1,101), 20)
figure = {'data': [{'x': x, 'y': y,
'type': 'scatter', 'mode': 'markers'}],
'layout': {
'xaxis': {
'fixedrange': True,
'zeroline': False,
},
'yaxis': {
'fixedrange': True,
'zeroline': False,
},
'annotations': [{
'x': -0.05,
'y': 0.5,
'showarrow':False,
'text':annotation,
'xref':'paper',
'yref':'paper',
}],
}
}
return [dcc.Graph(
id = 'plot_output',
figure = figure,
config = {
'editable': True,
'edits': {
'axisTitleText': False,
'titleText': False,
},
'displayModeBar': False,
},
),
html.Button(
id = 'save_annotation',
children='Save',
),
]
@app.callback(
Output('annotation_storage', 'data'),
[Input('save_annotation', 'n_clicks')],
[State('plot_output', 'figure')]
)
def save_annotation(clicked, figure):
if clicked:
annotation = figure['layout']['annotations'][0]['text']
return annotation
if __name__ == '__main__':
app.run_server(debug=True, port=1000)
目前,当图表更新时,注释只是恢复为默认文本 "Editable Annotation",即使用户对其进行编辑也是如此。我希望注释即使在图形更新时也保持不变。任何见解将不胜感激!谢谢!
如 Dash user guide 中所写:
The
dcc.Graph
component has four attributes that can change through user-interaction:hoverData
,clickData
,selectedData
,relayoutData
.
这意味着当用户与图表交互时,您使用的 figure
属性不会更新。
要解决您的问题,请更新您的回调函数以使用 relayoutData
而不是 figure
:
@app.callback(
Output('annotation_storage', 'data'),
[Input('save_annotation', 'n_clicks')],
[State('plot_output', 'relayoutData')]
)
def save_annotation(clicked, relayout_data):
if clicked:
annotation = relayout_data['annotations[0].text']
return annotation
您可以 运行 您的应用程序处于调试模式,并在回调函数内添加一个断点以探索上述四个属性给出的值。这就是我在 relayout_data
.
fig = px.scatter(df, x="x", y="y")
## TODO - load init annotations to fig.layout.annotations
dash_app1.layout = html.Div([
html.H1('Hi there, I am dashboard1'),
dcc.Graph(
id='example-graph',
figure=fig,
config={
'editable': True,
'edits': {
'axisTitleText': False,
'titleText': False,
},
}
)
])
@dash_app1.callback(
Output('example-graph', 'figure'),
[Input('example-graph', 'clickData'),
Input('example-graph', 'relayoutData')],
prevent_initial_call=True)
def annotation(clickData, relayoutData):
if clickData:
# get click xy
point = clickData["points"][0]
# if not exist, add
if f"'x': {point['x']}, 'y': {point['y']}" not in str(fig.layout.annotations):
fig.add_annotation(x=point["x"], y=point["y"], text="Click Here To Edit")
print("Add: ", fig.layout.annotations)
else:
# if exist, edit
if relayoutData:
fig.plotly_relayout(relayoutData)
print("Edit: ", fig.layout.annotations)
## TODO - save fig.layout.annotation
return fig
Shovalt 的回答很棒,感谢您的启发。我使用 clickData
事件添加注释,使用 relayoutData
事件记录编辑和拖动位置。此更新可以简单地由 fig.plotly_relayout
完成,这不包含在文档中。我巧妙地利用了 JS。老实说,Plotly Dash 的文档还不够 developer-friendly,尤其是对于像我这样的初学者。确保您在 IDE 中启用了代码完成功能,有时它比文档更有帮助...
此外,dcc.Store
在这里有点重复,因为您可以在 fig.layout.annotations
中找到所有注释。小心 dcc.Store
,如文档所述,它有内存限制:It's generally safe to store up to 2MB in most environments, and 5~10MB in most desktop-only applications.
更新:
我发现这个 relayoutData 侦听器可能会导致缩放不可用,但我认为它现在适用于此
@dash_app1.callback(
Output('example-graph', 'figure'),
[Input('example-graph', 'clickData'),
Input('example-graph', 'relayoutData')],
prevent_initial_call=True)
def annotation(clickData, relayoutData):
print("Click")
print(clickData)
print("Relayout")
print(relayoutData)
if clickData:
## get click xy
point = clickData["points"][0]
## if not exist, add
if f"'x': {point['x']}, 'y': {point['y']}" not in str(fig.layout.annotations):
fig.add_annotation(x=point["x"], y=point["y"], text="Click Here To Edit")
print("Add: ", fig.layout.annotations)
## TODO - save fig.layout.annotations to SQLite
return fig
if relayoutData:
## initial loading or refreshing action
if str(relayoutData) == "{'autosize': True}":
return fig
## zooming action
## enable zooming after resetting zooming
if 'xaxis.range' in str(relayoutData) and 'yaxis.range' in str(relayoutData):
fig.layout.xaxis.autorange = False
fig.layout.yaxis.autorange = False
## edit annotation position or text | also enable zooming after resetting
fig.plotly_relayout(relayoutData)
print("Edit: ", fig.layout.annotations)
## TODO - If edit, then update fig.layout.annotations to SQLite
return fig