You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 00:01:39