Plotly:有没有办法将点击点的数据保存在列表中?
Plotly: is there a way to save the data of a clicked point in a list?
我有一个带有悬停功能的二维绘图。当您将鼠标悬停在每个点上时,会出现与该点关联的标签(例如 'image 2, cluster 1')。如果我要单击该点(而不是将鼠标悬停在该点上),我希望将标签附加到现有列表中。之所以这样,是因为我以后想用这个点的数据来做别的事情。是否有在线示例演示如何执行此操作——已查看文档但尚未找到相关内容。谢谢!
您需要使用回调来执行此类操作(注册 on_click()
)。已将 clicked
定义为点击点列表。演示了如何使用 ipwidgets 或 dash
实现这一点
ip 小部件
import numpy as np
import plotly.express as px
import plotly.graph_objects as go
import ipywidgets as widgets
from pathlib import Path
import json
x = np.random.uniform(-10, 10, size=50)
y = np.sin(x)
clicked = []
# construct figure that has holders for points, interpolated line and final lines
fig = go.FigureWidget(
[
go.Scatter(x=x, y=y, mode="markers", name="base_points"),
]
)
fig.update_layout(template="simple_white")
out = widgets.Output(layout={"border": "1px solid black"})
out.append_stdout("Output appended with append_stdout\n")
# create our callback function
@out.capture()
def base_click(trace, points, selector):
global clicked
clicked.append(points.__dict__)
fig.data[0].on_click(base_click)
widgets.HBox([fig, out])
破折号
from jupyter_dash import JupyterDash
import dash
from dash.dependencies import Input, Output, State
import numpy as np
import json
clicked = []
# Build App
app = JupyterDash(__name__)
app.layout = dash.html.Div(
[
dash.dcc.Graph(
id="fig",
figure=go.Figure(go.Scatter(x=x, y=y, mode="markers", name="base_points")),
),
dash.html.Div(id="debug"),
]
)
@app.callback(
Output("debug", "children"),
Input("fig", "clickData"),
)
def point_clicked(clickData):
global clicked
clicked.append(clickData)
return json.dumps(clickData)
# Run app and display result inline in the notebook
app.run_server(mode="inline")
默认情况下可用的 hoverData
以及一些示例数据是这样的:
{
"points": [
{
"curveNumber": 1,
"pointNumber": 7,
"pointIndex": 7,
"x": 1987,
"y": 74.32,
"bbox": {
"x0": 420.25,
"x1": 426.25,
"y0": 256,
"y1": 262
}
}
]
}
我不太确定你所说的 'label'
是什么意思,所以我只能假设它是跟踪的名称或类似的名称,例如 Plotly 文档中的示例:
但是如您所见,在 hoverData
字典中并不容易获得。这意味着您还必须使用此信息来引用您的图形结构,这样您最终会得到这样的结果:
[['New Zealand', 2002, 79.11]]
只要您愿意使用 Plotly Dash,这都不是问题。我已经为您做了一个完整的设置,应该可以满足您的要求。在下图中的应用程序中,您会发现一个图形以及两个字符串输出字段。第一个字段显示您在图中单击的最后一个点的信息。每次单击时,都会将一个新元素添加到名为 store
的列表中。最后的字段显示来自同一次点击的完整信息。
你的问题的答案是,是的,有一种方法可以将点击点的数据保存在列表中。一种方法是通过以下使用 clickdata 引用图形对象的回调,将这些引用存储在列表中,并在每次单击新元素时附加新元素。
应用程序
完整代码:
import json
from textwrap import dedent as d
import pandas as pd
import plotly.graph_objects as go
import numpy as np
import dash
from dash import dcc
import dash_html_components as html
import plotly.express as px
from dash.dependencies import Input, Output
from jupyter_dash import JupyterDash
import warnings
warnings.simplefilter(action='ignore', category=FutureWarning)
# app info
app = JupyterDash(__name__)
styles = {
'pre': {
'border': 'thin lightgrey solid',
'overflowX': 'scroll'
}
}
# data
df = px.data.gapminder().query("continent=='Oceania'")
# plotly figure
fig = px.line(df, x="year", y="lifeExp", color="country", title="No label selected")
fig.update_traces(mode="markers+lines")
app.layout = html.Div([
dcc.Graph(
id='figure1',
figure=fig,
),
html.Div(className
='row', children=[
html.Div([
dcc.Markdown(d("""Hoverdata using figure references""")),
html.Pre(id='hoverdata2', style=styles['pre']),
], className='three columns'),
html.Div([
dcc.Markdown(d("""
Full hoverdata
""")),
html.Pre(id='hoverdata1', style=styles['pre']),
], className='three columns')
]),
])
# container for clicked points in callbacks
store = []
@app.callback(
Output('figure1', 'figure'),
Output('hoverdata1', 'children'),
Output('hoverdata2', 'children'),
[Input('figure1', 'clickData')])
def display_hover_data(hoverData):
if hoverData is not None:
traceref = hoverData['points'][0]['curveNumber']
pointref = hoverData['points'][0]['pointNumber']
store.append([fig.data[traceref]['name'],
fig.data[traceref]['x'][pointref],
fig.data[traceref]['y'][pointref]])
fig.update_layout(title = 'Last label was ' + fig.data[traceref]['name'])
return fig, json.dumps(hoverData, indent=2), str(store)
else:
return fig, 'None selected', 'None selected'
app.run_server(mode='external', port = 7077, dev_tools_ui=True,
dev_tools_hot_reload =True, threaded=True)
我有一个带有悬停功能的二维绘图。当您将鼠标悬停在每个点上时,会出现与该点关联的标签(例如 'image 2, cluster 1')。如果我要单击该点(而不是将鼠标悬停在该点上),我希望将标签附加到现有列表中。之所以这样,是因为我以后想用这个点的数据来做别的事情。是否有在线示例演示如何执行此操作——已查看文档但尚未找到相关内容。谢谢!
您需要使用回调来执行此类操作(注册 on_click()
)。已将 clicked
定义为点击点列表。演示了如何使用 ipwidgets 或 dash
ip 小部件
import numpy as np
import plotly.express as px
import plotly.graph_objects as go
import ipywidgets as widgets
from pathlib import Path
import json
x = np.random.uniform(-10, 10, size=50)
y = np.sin(x)
clicked = []
# construct figure that has holders for points, interpolated line and final lines
fig = go.FigureWidget(
[
go.Scatter(x=x, y=y, mode="markers", name="base_points"),
]
)
fig.update_layout(template="simple_white")
out = widgets.Output(layout={"border": "1px solid black"})
out.append_stdout("Output appended with append_stdout\n")
# create our callback function
@out.capture()
def base_click(trace, points, selector):
global clicked
clicked.append(points.__dict__)
fig.data[0].on_click(base_click)
widgets.HBox([fig, out])
破折号
from jupyter_dash import JupyterDash
import dash
from dash.dependencies import Input, Output, State
import numpy as np
import json
clicked = []
# Build App
app = JupyterDash(__name__)
app.layout = dash.html.Div(
[
dash.dcc.Graph(
id="fig",
figure=go.Figure(go.Scatter(x=x, y=y, mode="markers", name="base_points")),
),
dash.html.Div(id="debug"),
]
)
@app.callback(
Output("debug", "children"),
Input("fig", "clickData"),
)
def point_clicked(clickData):
global clicked
clicked.append(clickData)
return json.dumps(clickData)
# Run app and display result inline in the notebook
app.run_server(mode="inline")
默认情况下可用的 hoverData
以及一些示例数据是这样的:
{
"points": [
{
"curveNumber": 1,
"pointNumber": 7,
"pointIndex": 7,
"x": 1987,
"y": 74.32,
"bbox": {
"x0": 420.25,
"x1": 426.25,
"y0": 256,
"y1": 262
}
}
]
}
我不太确定你所说的 'label'
是什么意思,所以我只能假设它是跟踪的名称或类似的名称,例如 Plotly 文档中的示例:
但是如您所见,在 hoverData
字典中并不容易获得。这意味着您还必须使用此信息来引用您的图形结构,这样您最终会得到这样的结果:
[['New Zealand', 2002, 79.11]]
只要您愿意使用 Plotly Dash,这都不是问题。我已经为您做了一个完整的设置,应该可以满足您的要求。在下图中的应用程序中,您会发现一个图形以及两个字符串输出字段。第一个字段显示您在图中单击的最后一个点的信息。每次单击时,都会将一个新元素添加到名为 store
的列表中。最后的字段显示来自同一次点击的完整信息。
你的问题的答案是,是的,有一种方法可以将点击点的数据保存在列表中。一种方法是通过以下使用 clickdata 引用图形对象的回调,将这些引用存储在列表中,并在每次单击新元素时附加新元素。
应用程序
完整代码:
import json
from textwrap import dedent as d
import pandas as pd
import plotly.graph_objects as go
import numpy as np
import dash
from dash import dcc
import dash_html_components as html
import plotly.express as px
from dash.dependencies import Input, Output
from jupyter_dash import JupyterDash
import warnings
warnings.simplefilter(action='ignore', category=FutureWarning)
# app info
app = JupyterDash(__name__)
styles = {
'pre': {
'border': 'thin lightgrey solid',
'overflowX': 'scroll'
}
}
# data
df = px.data.gapminder().query("continent=='Oceania'")
# plotly figure
fig = px.line(df, x="year", y="lifeExp", color="country", title="No label selected")
fig.update_traces(mode="markers+lines")
app.layout = html.Div([
dcc.Graph(
id='figure1',
figure=fig,
),
html.Div(className
='row', children=[
html.Div([
dcc.Markdown(d("""Hoverdata using figure references""")),
html.Pre(id='hoverdata2', style=styles['pre']),
], className='three columns'),
html.Div([
dcc.Markdown(d("""
Full hoverdata
""")),
html.Pre(id='hoverdata1', style=styles['pre']),
], className='three columns')
]),
])
# container for clicked points in callbacks
store = []
@app.callback(
Output('figure1', 'figure'),
Output('hoverdata1', 'children'),
Output('hoverdata2', 'children'),
[Input('figure1', 'clickData')])
def display_hover_data(hoverData):
if hoverData is not None:
traceref = hoverData['points'][0]['curveNumber']
pointref = hoverData['points'][0]['pointNumber']
store.append([fig.data[traceref]['name'],
fig.data[traceref]['x'][pointref],
fig.data[traceref]['y'][pointref]])
fig.update_layout(title = 'Last label was ' + fig.data[traceref]['name'])
return fig, json.dumps(hoverData, indent=2), str(store)
else:
return fig, 'None selected', 'None selected'
app.run_server(mode='external', port = 7077, dev_tools_ui=True,
dev_tools_hot_reload =True, threaded=True)