Plotly Express直方图叠加分箱均值散点线实现问题
问题描述
用Plotly Express绘制两个直方图:
- 第一个展示汽车广告的里程分布计数
- 第二个基于相同的20个里程分箱,展示对应汽车的价格总和分布
希望在第二个直方图上叠加散点线,每个点对应分箱中点,值为该分箱内汽车总价除以车辆数量(即均价)。但当前代码中price_histogram_trace.data[0]['x']是7万条原始数据,而mileage_histogram_trace.data[0]['x']是分箱后的7千条数据,导致生成的均价点数量不对,无法得到对应20个分箱的结果。
解决方案
核心是提前用Pandas统一分箱规则并聚合数据,避免依赖Plotly自动分箱的结果,确保分箱数据完全匹配:
- 手动生成统一分箱边界:用
pd.cut计算里程的20个分箱边界,保证两个图表用同一套分箱 - 聚合分箱统计数据:对原始数据按分箱分组,直接计算每个分箱的车辆数、总价、均价
- 基于聚合数据绘图:用预处理好的统计数据绘制直方图和散点线,确保每个分箱的数据一一对应
修正后的代码
import plotly.graph_objects as go from plotly.subplots import make_subplots import pandas as pd import numpy as np # 1. 统一生成20个里程分箱的边界 bin_edges = pd.cut(df['mileage'], bins=20, retbins=True)[1] # 2. 对原始数据按分箱分组,计算每个分箱的统计值 df['mileage_bin'] = pd.cut(df['mileage'], bins=bin_edges) bin_stats = df.groupby('mileage_bin').agg( count=('mileage', 'size'), # 分箱内车辆数量 total_price=('price', 'sum'), # 分箱内总价 avg_price=('price', 'mean') # 分箱内均价 ).reset_index() # 计算每个分箱的中点,作为散点线的x坐标 bin_stats['bin_midpoint'] = bin_stats['mileage_bin'].apply(lambda x: (x.left + x.right) / 2) # 3. 创建子图,右图启用次坐标轴 fig = make_subplots(rows=1, cols=2, specs=[[{"secondary_y": False}, {"secondary_y": True}]]) # 添加左图:里程分布计数直方图 fig.add_trace( go.Bar(x=bin_stats['bin_midpoint'], y=bin_stats['count'], name='里程分布计数'), row=1, col=1 ) # 添加右图:分箱总价直方图 fig.add_trace( go.Bar(x=bin_stats['bin_midpoint'], y=bin_stats['total_price'], name='分箱总价'), row=1, col=2, secondary_y=False ) # 添加右图次坐标轴:分箱均价散点线 fig.add_trace( go.Scatter(x=bin_stats['bin_midpoint'], y=bin_stats['avg_price'], mode='lines+markers', name='分箱均价'), row=1, col=2, secondary_y=True ) # 更新布局,调整坐标轴和标题 fig.update_layout( title_text="里程分布与分箱价格统计", xaxis=dict(title="里程", domain=[0, 0.45]), xaxis2=dict(title="里程", domain=[0.55, 1.0]), yaxis=dict(title="车辆数量"), yaxis2=dict(title="均价", side="right") ) fig.show()
关键改进点
- 避免了Plotly自动分箱导致的两个图表分箱不匹配问题,所有统计数据基于同一套分箱规则生成
- 直接用Pandas计算分箱统计值,比通过Plotly Trace提取数据更高效且不易出错
- 分箱中点的计算保证了散点线与直方图的分箱位置完全对齐
- 用
secondary_y参数清晰区分总价(主坐标轴)和均价(次坐标轴),图表可读性更强
内容的提问来源于stack exchange,提问作者Zohan
相关产品推荐
相关产品推荐

