plt.hist / ax.hist 直方图
直方图:连续数值分布 ,自动分箱统计每个区间样本数量;和柱状图(离散分类)不一样! 函数:
plt.hist(x)或者面向对象写法ax.hist(x)返回值:n, bins, patches
- n:每个箱子里的数量
- bins:箱子边界
- patches:图形对象,可单独修改颜色
✅ 常用参数
| 参数 | 说明 |
|---|---|
| x | 一维数组/列表,原始连续数据 |
| bins | 箱子数量(整数);或者自定义区间边界列表 [0,20,40,60] |
| range | 元组 (min,max),限定统计范围,超出直接丢弃 |
| density | True → 概率密度(总面积=1);False 默认,频数(个数) |
| cumulative | True 累积直方图 |
| histtype | bar(默认), barstacked堆叠, step空心线框, stepfilled填充阶梯 |
| rwidth | 柱子相对宽度,0~1,小于1柱子之间有空隙 |
| edgecolor | 柱子边框颜色,常用 edgecolor='black' |
| color / alpha | 填充颜色、透明度 |
| log | True y轴对数刻度,适合长尾分布 |
重点:bins 列表时,区间是左闭右开 [a,b),最后一个区间是闭区间
📌 最简示例
python
import matplotlib.pyplot as plt
import numpy as np
plt.rcParams['font.sans-serif'] = 'SimHei'
plt.rcParams['axes.unicode_minus'] = False
# 直接给定成绩数据,不再随机生成
data = [56, 62, 78, 65, 81, 72, 68, 59, 77, 85,
74, 66, 70, 88, 79, 63, 75, 82, 71, 69,
90, 76, 67, 83, 73, 55, 86, 78, 64, 80,
72, 61, 74, 84, 77, 68, 87, 75, 66, 79]
print(sorted(data))
data = [55, 56, 59,
61, 62, 63, 64, 65, 66, 66, 67, 68, 68, 69,
70, 71, 72, 72, 73, 74, 74, 75, 75, 76, 77, 77, 78, 78, 79, 79,
80, 81, 82, 83, 84, 85, 86, 87, 88,
90]
fig, ax = plt.subplots(figsize=(8,5))
n, bins, patches = ax.hist(
data,
bins=10,
density=False,
color="#72a0c1",
edgecolor="black",
rwidth=0.8
)
ax.set_title("学生成绩分布直方图")
ax.set_xlabel("分数")
ax.set_ylabel("人数")
print(bins)
# bins 就是所有柱子边界,逐个标注在x轴下方
for b in bins:
ax.text(b, -0.8, f'{b:.1f}', ha='center', fontsize=9, color='red')
plt.tight_layout()
plt.show()

⚠️ 高频易错考点(适合出题)
- 直方图是连续数据,柱子默认紧挨;柱状图是离散类别,柱子分开
bins=10:一共10个箱子,返回11个边界值density=True纵轴不再是个数,是密度,所有矩形面积之和=1- cumulative=True:从左往右累加
- histtype='step':只有轮廓线,没有填充色块
📌 和柱状图对比
- hist 直方图:x是连续数值,自动分箱,看分布
- bar 柱状图:x是分类标签,每个标签单独一根柱子,看类别对比
📌 面向对象写法 vs pyplot写法
# pyplot 写法
plt.hist(data, bins=10)
# 面向对象(推荐,适合多子图、精细标注annotate/text)
fig,ax=plt.subplots()
ax.hist(data,bins=10)
python
# 1. 导入matplotlib绘图库,简写plt
import matplotlib.pyplot as plt
# 2. 导入pandas数据处理库,简写pd
import pandas as pd
# 3. 导入numpy数值计算库,简写np(本段代码其实没有用到np)
import numpy as np
# 4. 注释:读取数据
# 5. 读取csv文件,r""原始字符串防止路径转义;encoding='gbk'适配中文gbk编码
data=pd.read_csv(r"datasource/CommentInfo.csv",encoding='gbk')
# 6. 设置全局字体为SimHei黑体,解决matplotlib中文方框乱码
plt.rcParams['font.sans-serif'] = ['SimHei']
# 7. 解决负号显示成方框的问题,正常显示减号
plt.rcParams['axes.unicode_minus'] = False
# 8. 设置全局默认字体大小14号
plt.rcParams['font.size'] = 14
# 9. 取出data里votes点赞这一列,赋值给vote,是Series序列
vote = data['votes']
# 10. 打印点赞数的最大值、最小值,快速了解数据范围
print(vote.max(),vote.min())
# 11. 创建画布,画布尺寸:宽12英寸,高8英寸
plt.figure(figsize=(12,8))
# 12. 子图划分:2行1列,选中第1个子图(211 = 2行,1列,第1块)
plt.subplot(211)
# 13. 定义第一个直方图的分组区间bins1,间隔5000
bins1=[0,5000,10000,15000,20000,25000,30000,35000,40000,45000,50000,55000,60000,65000,70000]
# 14. 绘制直方图:数据vote,分组bins1;柱子灰色、边框红色、透明度0.7
plt.hist(vote,bins=bins1, facecolor='gray', edgecolor='red', alpha=0.7)
# 15. 设置第一个子图标题,字号16
plt.title('用户评论点赞数分布情况',fontsize=16)
# 16. 设置y轴标签:评论数量(y代表频次,有多少条评论落在区间内)
plt.ylabel('评论数量')
# 17. x轴刻度直接使用我们定义的bins区间
plt.xticks(bins1)
# 18. 选中2行1列里的第2个子图(212)
plt.subplot(212)
# 19. 第二个直方图分组bins2,小间隔,放大看低点赞区域
bins2=[0,100,200,400,1000,2000,3000,4000,5000]
# 20. 绘制第二个直方图,配色、透明度和上图保持一致
plt.hist(vote,bins=bins2, facecolor='gray', edgecolor='red', alpha=0.7)
# 21. 设置第二个子图x轴标签:点赞数
plt.xlabel('点赞数')
# 22. 设置第二个子图y轴标签
plt.ylabel('评论数量')
# 23. x刻度使用bins2,文字旋转45°,防止文字重叠挤在一起
plt.xticks(bins2, rotation=45)
# 24. 固定y轴上限400,让两个子图y轴范围统一,方便对比
plt.ylim(0,400)
# 25. 展示绘制好的全部图形
plt.show()
✅ 代码整体逻辑说明
画两张上下排布的直方图,对比点赞数分布:
- 上图:大区间(步长 5000),看高点赞整体分布
- 下图:小区间(步长很小),重点观察低点赞(0~5000)的密集分布
业务含义:大部分影评点赞都很低,高赞评论很少