Dash Plotly不通过pandas处理实现多条trace数值累加为单条trace的方案
实现方案
方案1:Dash服务端直接处理已生成的figure trace数据
该方案不需要对原始数据集做pandas预处理,直接读取你已经生成的fig_a中所有trace的坐标数据,按时间对齐累加后生成新的汇总图表即可,实现成本最低。
修改后的完整代码如下:
import pandas as pd import numpy as np import plotly.express as px import plotly.graph_objects as go from dash.dependencies import Output, Input from dash import dcc from dash import html import dash # 原始生成数据和分类型图表的逻辑不变 df_a = pd.DataFrame({"time":pd.Series(pd.date_range("1-nov-2021","2-nov-2021", freq="S")).sample(60), "bacteria_count":np.random.randint(0,500, 60), "bacteria_type":np.random.choice(list("ABCDEFGHIJKL"),60)}) df_a["epoch_time_ms"] = df_a["time"].astype(int) / 1000 df_a = df_a.sort_values("time") fig_a = px.line(df_a, x="time", y="bacteria_count", line_shape="hv", color='bacteria_type') fig_a.update_layout(hovermode='x unified') # 新增:直接从fig_a的trace中提取数据累加,不需要碰原始df all_x = set() trace_data = [] for trace in fig_a.data: x_list = list(trace.x) y_list = list(trace.y) all_x.update(x_list) trace_data.append(dict(zip(x_list, y_list))) # 按时间排序后累加y值 sorted_x = sorted(all_x) sum_y = [] for x in sorted_x: current_sum = 0 for td in trace_data: current_sum += td.get(x, 0) sum_y.append(current_sum) # 生成汇总图表 fig_total = go.Figure(go.Scatter(x=sorted_x, y=sum_y, line_shape='hv', name='总细菌数')) fig_total.update_layout(title='所有类型细菌总数', hovermode='x unified') app = dash.Dash(__name__) app.layout = html.Div(children=[ html.Div([ html.Div([ html.H1(children='G_A'), dcc.Graph(id='fig_a-graph', figure=fig_a) ], className='row'), # 新增汇总图表容器 html.Div([ html.H1(children='总计数'), dcc.Graph(id='fig_total-graph', figure=fig_total) ], className='row') ]) ]) if __name__ == '__main__': app.run_server(debug=True, port=8086)
方案2:客户端JS回调实现纯前端累加(和Grafana前端堆叠逻辑一致)
如果你需要完全在浏览器端完成计算(不需要服务端参与,和你提到的Grafana功能逻辑完全相同),可以使用Dash的客户端回调,通过JS读取已有图表的trace数据累加后渲染,不需要修改服务端数据处理逻辑。
核心实现逻辑是添加如下客户端回调:
dash.clientside_callback( """ function(fig_a) { // 收集所有x值 const allX = new Set(); const traceMap = []; fig_a.data.forEach(trace => { const xList = trace.x; const yList = trace.y; const map = {}; for(let i=0;i<xList.length;i++) { map[xList[i]] = yList[i]; allX.add(xList[i]); } traceMap.push(map); }); // 排序后累加 const sortedX = Array.from(allX).sort(); const sumY = sortedX.map(x => { return traceMap.reduce((sum, map) => sum + (map[x] || 0), 0); }); // 返回新的figure return { data: [{x: sortedX, y: sumY, line_shape: 'hv', name: '总细菌数', type: 'scatter'}], layout: {title: '所有类型细菌总数', hovermode: 'x unified'} } } """, Output('fig_total-graph', 'figure'), Input('fig_a-graph', 'figure') )
该方案的优势是完全在前端执行计算,即便后续你通过交互过滤了fig_a中的部分trace,汇总图表也会自动同步更新,和Grafana的堆叠功能表现一致。
内容的提问来源于stack exchange,提问作者HCSF
相关产品推荐
相关产品推荐

