如何在Plotly散点图当前视图添点并统计点数、获取轴范围?
1. 在Plotly散点图当前视图添加多个点
方法1:Jupyter环境用FigureWidget
直接更新散点数据,视图会自动保留当前缩放/位置,无需重绘整个图表:
import plotly.graph_objects as go import numpy as np # 初始化散点图 x = np.random.randn(100) y = np.random.randn(100) fig = go.FigureWidget(data=[go.Scatter(x=x, y=y, mode='markers')]) # 批量添加新点的函数 def add_points(new_x, new_y): with fig.batch_update(): fig.data[0].x = np.append(fig.data[0].x, new_x) fig.data[0].y = np.append(fig.data[0].y, new_y) # 示例:添加两个新点 add_points([1.2, 3.4], [0.5, -2.1]) fig
方法2:Web应用用Dash
通过回调监听按钮点击更新数据,Dash默认保留用户交互后的视图状态:
from dash import Dash, dcc, html, Input, Output, State import plotly.graph_objects as go import numpy as np app = Dash(__name__) # 初始数据 x = np.random.randn(100) y = np.random.randn(100) app.layout = html.Div([ dcc.Graph(id='scatter-graph', figure=go.Figure(data=[go.Scatter(x=x, y=y, mode='markers')])), html.Button('添加新点', id='add-btn'), ]) @app.callback( Output('scatter-graph', 'figure'), Input('add-btn', 'n_clicks'), State('scatter-graph', 'figure'), prevent_initial_call=True ) def update_graph(n_clicks, current_fig): # 生成随机新点 new_x = np.random.randn(2) new_y = np.random.randn(2) # 更新现有数据 current_fig['data'][0]['x'] += list(new_x) current_fig['data'][0]['y'] += list(new_y) return current_fig if __name__ == '__main__': app.run_server(debug=True)
2. 统计当前视图内散点数量/获取轴范围计算统计值
通过监听图表的relayout事件(缩放、平移、框选都会触发),获取当前轴范围后筛选数据计算:
方法1:Jupyter环境用FigureWidget
import plotly.graph_objects as go import numpy as np # 初始化1000个随机点 x = np.random.randn(1000) y = np.random.randn(1000) fig = go.FigureWidget(data=[go.Scatter(x=x, y=y, mode='markers')]) # 监听视图变化事件 def on_relayout(layout, relayoutData): # 确保获取到完整的X/Y轴范围 if all(key in relayoutData for key in ['xaxis.range[0]', 'xaxis.range[1]', 'yaxis.range[0]', 'yaxis.range[1]']): x_min, x_max = relayoutData['xaxis.range[0]'], relayoutData['xaxis.range[1]'] y_min, y_max = relayoutData['yaxis.range[0]'], relayoutData['yaxis.range[1]'] # 筛选当前视图内的点 mask = (x >= x_min) & (x <= x_max) & (y >= y_min) & (y <= y_max) filtered_x = x[mask] filtered_y = y[mask] # 计算并输出统计值 count = len(filtered_x) x_mean = filtered_x.mean() y_min_val = filtered_y.min() print(f"当前视图内点数: {count}") print(f"X轴均值: {x_mean:.2f}, Y轴最小值: {y_min_val:.2f}") fig.on_relayout(on_relayout) fig
方法2:Web应用用Dash
通过回调实时更新统计结果到页面:
from dash import Dash, dcc, html, Input, Output import plotly.graph_objects as go import numpy as np app = Dash(__name__) # 初始1000个随机点 x = np.random.randn(1000) y = np.random.randn(1000) app.layout = html.Div([ dcc.Graph(id='scatter-graph', figure=go.Figure(data=[go.Scatter(x=x, y=y, mode='markers')])), html.Div(id='stats-output', style={'margin-top': 20}) ]) @app.callback( Output('stats-output', 'children'), Input('scatter-graph', 'relayoutData'), prevent_initial_call=False ) def update_stats(relayoutData): # 初始状态显示全部数据统计 if relayoutData is None: count = len(x) x_mean = x.mean() y_min = y.min() return html.Div([ html.P(f"当前视图内点数: {count}"), html.P(f"X轴均值: {x_mean:.2f}"), html.P(f"Y轴最小值: {y_min:.2f}") ]) # 处理完整X/Y轴范围变化 if all(key in relayoutData for key in ['xaxis.range[0]', 'xaxis.range[1]', 'yaxis.range[0]', 'yaxis.range[1]']): x_min, x_max = relayoutData['xaxis.range[0]'], relayoutData['xaxis.range[1]'] y_min, y_max = relayoutData['yaxis.range[0]'], relayoutData['yaxis.range[1]'] mask = (x >= x_min) & (x <= x_max) & (y >= y_min) & (y <= y_max) filtered_x = x[mask] filtered_y = y[mask] count = len(filtered_x) x_mean = filtered_x.mean() if count > 0 else 0 y_min_val = filtered_y.min() if count > 0 else 0 return html.Div([ html.P(f"当前视图内点数: {count}"), html.P(f"X轴均值: {x_mean:.2f}"), html.P(f"Y轴最小值: {y_min_val:.2f}") ]) # 处理单一轴范围变化(如仅缩放X轴) if 'xaxis.range[0]' in relayoutData: x_min, x_max = relayoutData['xaxis.range[0]'], relayoutData['xaxis.range[1]'] count = len(x[(x >= x_min) & (x <= x_max)]) return html.P(f"当前视图内点数: {count}") if 'yaxis.range[0]' in relayoutData: y_min, y_max = relayoutData['yaxis.range[0]'], relayoutData['yaxis.range[1]'] count = len(y[(y >= y_min) & (y <= y_max)]) return html.P(f"当前视图内点数: {count}") return html.P("等待视图交互...") if __name__ == '__main__': app.run_server(debug=True)
内容的提问来源于stack exchange,提问作者twistfire
相关产品推荐
相关产品推荐

