Python 在plotly dash 3d散射中选择和删除数据点
我正在尝试将互动性添加到plotly 3d散点图中,我正在使用dash托管该散点图。我的问题包括两个相关部分: (i) 我想在3d散射中手动选择点,并将所选点的颜色更改为红色。选择应包括单击事件和选择事件 (ii)我希望能够在按下键(例如“删除”键)时从绘图中删除这些点 第(i)部分类似于《绘图指南》中的示例,但“单击”作为三维散点图的方法不可用 我一直在尝试使用FigureWidget,因为它显然提供了捕获点击和选择的方法,但两天后我正在努力取得进展 示例数据(将下面的数据复制到剪贴板并运行df=pd.read_剪贴板(sep=',')) 我有下面的示例代码,我希望它几乎就在那里(但不是完全在那里)。想法是“处理点击”应该捕获点击事件。我还应该处理“选择”事件,尽管我不确定如何处理,因为3d散点图不提供选择框或lassoo工具。对于回调,我甚至不知道如何启动,因为我无法利用具有3d散点图的clickData/selectionData事件(因此Python 在plotly dash 3d散射中选择和删除数据点,python,plotly-dash,scatter3d,Python,Plotly Dash,Scatter3d,我正在尝试将互动性添加到plotly 3d散点图中,我正在使用dash托管该散点图。我的问题包括两个相关部分: (i) 我想在3d散射中手动选择点,并将所选点的颜色更改为红色。选择应包括单击事件和选择事件 (ii)我希望能够在按下键(例如“删除”键)时从绘图中删除这些点 第(i)部分类似于《绘图指南》中的示例,但“单击”作为三维散点图的方法不可用 我一直在尝试使用FigureWidget,因为它显然提供了捕获点击和选择的方法,但两天后我正在努力取得进展 示例数据(将下面的数据复制到剪贴板并运行d
[Input('subindustry-dropdown','value'))
是不正确的,请注意,我在示例中没有提供subindustry dropdown,但我从下拉列表中选择ID,该下拉列表在我的开发版本中返回子行业值。)
以下是一个解决方案,它允许:
- 通过单独单击来选择点
- 按html按钮删除选定的点
- 按html按钮清除选择
以下是一个解决方案,它允许:
- 通过单独单击来选择点
- 按html按钮删除选定的点
- 按html按钮清除选择
谢谢你知道如何一次选择多个点吗?与dash 2d散点图不同,没有可用的box/lassoo选择。谢谢Carl:)我的第一笔赏金!根据我贴的链接,盒子/套索不受3d支持。。。我后来觉得你可以做的是,用一个你可以用另一个html按钮触发的函数,在一个(或多个)选定点周围移除圆形/长方体中的点…谢谢。你知道如何一次选择多个点吗?与dash 2d散点图不同,没有可用的box/lassoo选择。谢谢Carl:)我的第一笔赏金!根据我贴的链接,盒子/套索不受3d支持。。。在我看来,你可以做的是用一个函数移除一个(或多个)选定点周围的圆形/长方体中的点,你可以用另一个html按钮触发该函数。。。
id,x_val,z_val,y_val
a,11.313449728149418,0.13039110880256777,0.5386387766748618
b,11.321463427315383,0.2360697833061771,1.32441455152796
c,10.127132005050942,0.23085014016641864,1.0961116175427044
d,11.639819269465233,0.0958798324712593,0.6506370305953094
e,8.892696370438149,0.08223988244819926,0.6440321391968353
f,6.711586646011124,0.3657515974938044,
g,7.095030650760687,,0.5723062047617504
h,6.4523124528415,,1.293852184258803
i,7.165105300812886,0.4151365420301895,-0.5920674079031845
j,7.480703395137295,0.14284429977557123,1.0600936940126982
k,5.570775744372319,,
l,4.358946555449826,,
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
import plotly.graph_objs as go
import pandas as pd
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
app.css.append_css({
"external_url": "https://codepen.io/chriddyp/pen/bWLwgP.css"
})
app.layout = html.Div([html.Div(id = '3d-scatter'),
])
# Calculate and store data
@app.callback(Output('3d-scatter', 'children'),
[Input('subindustry-dropdown', 'value')])
def chart_3d():
f = go.FigureWidget(px.scatter_3d(df, x = 'x_val', y = 'y_val', z = 'z_val', hover_name = 'company_nm'))
f.layout.clickmode = 'event+select'
f.data[0].on_click(handle_click) # if click, then update point/df.
return dcc.Graph(id = '3d_scat', figure=f)
def handle_click(trace, points, selector):
c = list(f.data[0].marker.color)
s = list(f.data[0].marker.size)
for i in points.point_inds:
c[i] = '#bae2be'
s[i] = 20
with f.batch_update():
f.data[0].marker.color = c
f.data[0].marker.size = s
return f.data[0]
import dash
import plotly.express as px
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State
import plotly.graph_objs as go
import pandas as pd
import json
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
app.css.append_css({
"external_url": "https://codepen.io/chriddyp/pen/bWLwgP.css"
})
import pandas as pd
df = pd.DataFrame(columns=['x_val','z_val','y_val'])
df.loc['a'] = [11.313449728149418,0.13039110880256777,0.5386387766748618]
df.loc['b'] = [11.321463427315383,0.2360697833061771,1.32441455152796]
df.loc['c'] = [10.127132005050942,0.23085014016641864,1.0961116175427044]
df.loc['d'] = [11.639819269465233,0.0958798324712593,0.6506370305953094]
df.loc['e'] = [8.892696370438149,0.08223988244819926,0.6440321391968353]
df.loc['f'] = [6.711586646011124,0.3657515974938044,0]
df.loc['g'] = [7.095030650760687,0,0.5723062047617504]
df.loc['h'] = [6.4523124528415,0,1.293852184258803]
df.loc['i'] = [7.165105300812886,0.4151365420301895,-0.5920674079031845]
df.loc['j'] = [7.480703395137295,0.14284429977557123,1.0600936940126982]
df.loc['k'] = [5.570775744372319,0,0]
df.loc['l'] = [4.358946555449826,0,0]
def create_figure(skip_points=[]):
dfs = df.drop(skip_points)
return px.scatter_3d(dfs, x = 'x_val', y = 'y_val', z = 'z_val')
f= create_figure()
app.layout = html.Div([html.Button('Delete', id='delete'),
html.Button('Clear Selection', id='clear'),
dcc.Graph(id = '3d_scat', figure=f),
html.Div('selected:'),
html.Div(id='selected_points'), #, style={'display': 'none'})),
html.Div('deleted:'),
html.Div(id='deleted_points') #, style={'display': 'none'}))
])
@app.callback(Output('deleted_points', 'children'),
[Input('delete', 'n_clicks')],
[State('selected_points', 'children'),
State('deleted_points', 'children')])
def delete_points(n_clicks, selected_points, delete_points):
print('n_clicks:',n_clicks)
if selected_points:
selected_points = json.loads(selected_points)
else:
selected_points = []
if delete_points:
deleted_points = json.loads(delete_points)
else:
deleted_points = []
ns = [p['pointNumber'] for p in selected_points]
new_indices = [df.index[n] for n in ns if df.index[n] not in deleted_points]
print('new',new_indices)
deleted_points.extend(new_indices)
return json.dumps(deleted_points)
@app.callback(Output('selected_points', 'children'),
[Input('3d_scat', 'clickData'),
Input('deleted_points', 'children'),
Input('clear', 'n_clicks')],
[State('selected_points', 'children')])
def select_point(clickData, deleted_points, clear_clicked, selected_points):
ctx = dash.callback_context
ids = [c['prop_id'] for c in ctx.triggered]
if selected_points:
results = json.loads(selected_points)
else:
results = []
if '3d_scat.clickData' in ids:
if clickData:
for p in clickData['points']:
if p not in results:
results.append(p)
if 'deleted_points.children' in ids or 'clear.n_clicks' in ids:
results = []
results = json.dumps(results)
return results
@app.callback(Output('3d_scat', 'figure'),
[Input('selected_points', 'children'),
Input('deleted_points', 'children')],
[State('deleted_points', 'children')])
def chart_3d( selected_points, deleted_points_input, deleted_points_state):
global f
deleted_points = json.loads(deleted_points_state) if deleted_points_state else []
f = create_figure(deleted_points)
selected_points = json.loads(selected_points) if selected_points else []
if selected_points:
f.add_trace(
go.Scatter3d(
mode='markers',
x=[p['x'] for p in selected_points],
y=[p['y'] for p in selected_points],
z=[p['z'] for p in selected_points],
marker=dict(
color='red',
size=5,
line=dict(
color='red',
width=2
)
),
showlegend=False
)
)
return f
if __name__ == '__main__':
app.run_server(debug=True)