如何在同一直方图中同时展示频数(frequency)与密度(density)
如何在Matplotlib直方图中同时展示频数和密度(双Y轴)
当然可以实现,核心思路是用双Y轴分别展示频数和密度。下面是修改后的代码,直接满足你的需求:
import numpy as np import pandas as pd import matplotlib.pyplot as plt x = [6.950915827194559, 0.5704464713012669, -1.655326152372283, 5.867122206816244, -1.809359944941513, -6.164821482653027, -2.538999462076397, 0.2108693568484643, -8.740600769897465, 2.121232876712331, 7.967032967032961, 10.61701196601832, 1.847419201771516, 0.6858006670780847, -2.008695652173909, 2.86991153132885, 1.703131050506168, -1.346913193356314, 3.334927671049193, -15.64688995215311, 20.00022688856367, 10.05956454173731, 2.044936877124148, 3.06513409961684, -0.9973614775725559, 1.190631873030967, -1.509991311902692, -0.3333827233664155, 1.898473282442747, 1.618299899267539, -0.1897860593512823, 1.000000000000001, 3.03501945525293, -7.646697418593529, -0.9769069279216391, -2.918403811792736, -3.90929422276739, 9.609846259653532, 3.240690674452962, 10.08973134408675, 1.98356309650054, 1.915301127899549, -0.7792207792207684, -3.308682400714091, -3.312977099236647, 19.98101265822785, 3.661973444534827, -5.770676691729326, 0.5268044012063156, -1.573767040370533, 3.234974862888484, -1.514352732634994, 6.564849624060143, 9.956794019127146, 3.232590278195024, 2.042007001166857, 1.601164483260553, -2.384737678855331, -2.731242556570068, 0.6069707315088602, 1.40561881957264, -6.805306861851957, 2.492102492102499, -3.639688275501762, 0.7958485384154335, 2.799187725631769, 0.9195966872689088, -2.366608280379856, 0.797679477882518, -3.80380434782609] df = pd.DataFrame(x, columns=["Returns"]) def plot_histogram(): bins = range(-11, 12, 1) bins_str = [f"{i}%" for i in bins] bins_str[-1] = "Over" bins_str[0] = "Under" fig, ax = plt.subplots(figsize=(9, 5)) # 绘制频数直方图,获取区间计数 counts, bins, patches = ax.hist(np.clip(df.Returns, bins[0], bins[-1]), bins=bins, density=False, rwidth=0.8, color='#1f77b4') # 手动计算密度:密度 = 频数 / (总样本数 × 区间宽度) total_samples = len(df.Returns) bin_width = bins[1] - bins[0] density = counts / (total_samples * bin_width) # 创建右侧Y轴用于展示密度 ax2 = ax.twinx() # 绘制密度条形图,调整宽度避免和频数图重叠 ax2.bar(bins[:-1] + bin_width*0.1, density, width=bin_width*0.6, alpha=0.6, color='#ff7f0e') # 设置X轴样式 ax.set_xticks(bins) ax.set_xticklabels(bins_str) ax.set_xlim([bins[0], bins[-1]]) # 设置Y轴标签与样式区分 ax.set_ylabel('频数', fontsize=12) ax2.set_ylabel('密度', fontsize=12, color='#ff7f0e') ax2.tick_params(axis='y', labelcolor='#ff7f0e') # 标题与网格 ax.set_title("Returns Distribution(频数+密度)", fontsize=14) ax.grid(axis="y", linewidth=0.5) # 添加图例 ax.legend(['频数'], loc='upper left') ax2.legend(['密度'], loc='upper right') plt.tight_layout() plt.show() plot_histogram()
关键逻辑说明:
- 优先获取频数:关闭
density=True,用默认的density=False绘制频数直方图,得到每个区间的样本计数 - 手动计算密度:根据密度的数学定义,用频数除以「总样本数×区间宽度」得到密度值
- 双Y轴分离展示:通过
ax.twinx()创建右侧独立Y轴,绘制密度条形图时微调位置避免重叠 - 视觉区分:用不同颜色、图例区分频数和密度,让图表可读性更强
内容的提问来源于stack exchange,提问作者iSkyun
相关产品推荐
相关产品推荐

