如何在Plotly/Plotly-Dash图表中动态展示可见数据的统计指标?
动态显示Plotly图表可见区域数据统计值
方案1:纯Plotly(导出HTML后仍可交互)
如果需要生成可独立运行的HTML文件,可通过嵌入JavaScript回调监听图表的视图变化,实时计算当前可见数据的统计值并更新标题。
完整代码
import plotly.graph_objects as go import numpy as np from plotly.io import write_html # 生成示例数据 x = np.linspace(0, 2 * np.pi, 1000) y = np.sin(x) # 初始统计值 avg = np.mean(y) min_val = np.min(y) max_val = np.max(y) std_dev = np.std(y) # 创建图表 fig = go.Figure( data=go.Scatter(x=x, y=y, mode='lines'), layout=go.Layout( title=f'Sine Waveform\nAverage: {avg:.2f}, StdDev: {std_dev:.2f}, Min: {min_val:.2f}, Max: {max_val:.2f}', xaxis=dict(title='x'), yaxis=dict(title='y'), height=500 ) ) # 添加JavaScript回调,监听视图变化 js_callback = """ <script> var plot = document.getElementById('plot').data[0]; var x = plot.x; var y = plot.y; document.getElementById('plot').on('plotly_relayout', function(eventData) { // 获取当前x轴的可见范围 var xRange = eventData['xaxis.range'] || [x[0], x[x.length-1]]; // 筛选出可见范围内的y值 var visibleY = y.filter((val, idx) => x[idx] >= xRange[0] && x[idx] <= xRange[1]); // 计算统计值 var avg = visibleY.reduce((a, b) => a + b, 0) / visibleY.length; var stdDev = Math.sqrt(visibleY.reduce((a, b) => a + Math.pow(b - avg, 2), 0) / visibleY.length); var minVal = Math.min(...visibleY); var maxVal = Math.max(...visibleY); // 更新图表标题 Plotly.relayout('plot', { title: `Sine Waveform\nAverage: ${avg.toFixed(2)}, StdDev: ${stdDev.toFixed(2)}, Min: ${minVal.toFixed(2)}, Max: ${maxVal.toFixed(2)}` }); }); </script> """ # 导出带回调的HTML文件 write_html(fig, 'dynamic_stats_plot.html', include_plotlyjs='cdn', post_script=js_callback, full_html=True)
说明
- 运行代码后生成
dynamic_stats_plot.html,打开后缩放/平移x轴,标题会自动更新为当前可见区域数据的统计值 - 核心是通过
plotly_relayout事件监听视图变化,筛选可见数据后计算统计值,再调用Plotly.relayout更新标题
方案2:Plotly Dash(交互式Web应用)
如果需要构建更复杂的交互式应用,用Dash框架可以更便捷地实现回调逻辑,还能添加额外的统计展示组件。
完整代码
import dash from dash import dcc, html, Input, Output, State import plotly.graph_objects as go import numpy as np # 生成示例数据 x = np.linspace(0, 2 * np.pi, 1000) y = np.sin(x) # 初始化Dash应用 app = dash.Dash(__name__) # 应用布局 app.layout = html.Div([ dcc.Graph(id='sine-plot', figure=go.Figure( data=go.Scatter(x=x, y=y, mode='lines'), layout=go.Layout( title='Sine Waveform', xaxis=dict(title='x'), yaxis=dict(title='y'), height=500 ) )), html.Div(id='stats-display', style={'margin-top': 20, 'font-size': 16}) ]) # 回调函数:根据可见区域更新统计值 @app.callback( [Output('sine-plot', 'figure'), Output('stats-display', 'children')], [Input('sine-plot', 'relayoutData')], [State('sine-plot', 'figure')] ) def update_stats(relayout_data, fig): # 获取当前x轴范围,默认显示全部数据 if relayout_data and 'xaxis.range[0]' in relayout_data: x_min = relayout_data['xaxis.range[0]'] x_max = relayout_data['xaxis.range[1]'] else: x_min = x[0] x_max = x[-1] # 筛选可见数据 mask = (x >= x_min) & (x <= x_max) visible_y = y[mask] # 计算统计值 avg = np.mean(visible_y) std_dev = np.std(visible_y) min_val = np.min(visible_y) max_val = np.max(visible_y) # 更新图表标题 fig['layout']['title'] = f'Sine Waveform\nAverage: {avg:.2f}, StdDev: {std_dev:.2f}, Min: {min_val:.2f}, Max: {max_val:.2f}' # 更新统计展示文本 stats_text = [ html.P(f'**Average**: {avg:.2f}'), html.P(f'**StdDev**: {std_dev:.2f}'), html.P(f'**Min Value**: {min_val:.2f}'), html.P(f'**Max Value**: {max_val:.2f}') ] return fig, stats_text if __name__ == '__main__': app.run_server(debug=True)
说明
- 运行后打开本地服务器地址(默认http://127.0.0.1:8050/),操作图表缩放/平移后,标题和下方的统计区域会同步更新
- 相比纯HTML方案,Dash更适合扩展,比如添加下拉框选择统计类型、切换数据源等功能
内容的提问来源于stack exchange,提问作者bobbolous
相关产品推荐
相关产品推荐

