无法播放?请 点击这里 跳转到Youtube
切换视频源:

上一章我们学习了折线图和散点图,这一章来学习柱状图和直方图。首先导入我们需要的库:

import matplotlib.pyplot as plt
import numpy as np

柱状图 Bar Plot

柱状图是一种使用矩形条,对不同类别进行数值比较的统计图表。最基础的柱状图,需要一个分类变量和一个数值变量。分类变量的每个实体为一个单独的矩形,而数值决定了柱子的高度。

如下我们用柱状图来表示一家鞋店在不同月份的销售情况,其中label就是分类变量,而values则是数值变量,代表每个月份的销售情况:

fig, axe = plt.subplots()
label = ["Jan", "Feb", "Mar", "Apr", "May", "Jun"]
values = [100, 150, 300, 220, 660, 320]
axe.bar(label, values)
plt.show()

如果要对多组数值进行对比,比如比较两个店铺在不同月份的销售情况,可以在bar函数中传入left参数(下面的index,代表x轴的位置序列),height参数(下面的values1和values2,代表y轴的数值), 和width参数(代表单个柱子的宽度):

fig, axe = plt.subplots()

label = ["Jan", "Feb", "Mar", "Apr", "May", "Jun"]
index = np.arange(len(label))
values1 = [100, 150, 300, 220, 660, 320]
values2 = [200, 160, 200, 300, 800, 400]
axe.bar(index, values1, width=0.4)
axe.bar(index + 0.4, values2, width=0.4)
axe.set_xticks(index+0.15)
axe.set_xticklabels(label)

plt.show()

如果想要画堆叠柱状图(Stacked Bar Chart),可以通过定义bottom参数来设定堆叠的顺序,以下的代码就会把values2堆叠在values1之上:

fig, axe = plt.subplots()
label = ["Jan", "Feb", "Mar", "Apr", "May", "Jun"]
index = np.arange(len(label))
values1 = [100, 150, 300, 220, 660, 320]
values2 = [200, 160, 200, 300, 800, 400]
axe.bar(index, values1)
axe.bar(index, values2, bottom=values1)
plt.show()

如果想要画水平柱状图,可以直接使用barh函数来实现:

fig, axe = plt.subplots()
label = ["Jan", "Feb", "Mar", "Apr", "May", "Jun"]
index = np.arange(len(label))
values1 = [100, 150, 300, 220, 660, 320]
values2 = [200, 160, 200, 300, 800, 400]
axe.barh(index, values1)
axe.barh(index, values2, left=values1)
axe.set_yticks(index)
axe.set_yticklabels(label)
plt.show()

直方图 Histogram Plot

直方图是另一种很常见的统计图表,用于表示数据的分布情况。一般横轴表示数据区间,纵轴表示分布情况,柱子越高,代表落在该区间的数量越大。

构建直方图,需要确定“组距”,对数值的范围进行分区,也就是划定有几根柱子 (比如0 ~ 100之间,每隔20分划一个区间,总5个区间),接着对每个区间的数值进行频次计算(比如80~100之间有10人,60~80之间20人,以此类推),而每个柱子高度由频数决定。

以下代码使用hist函数为1000个随机点画直方图,默认情况下会被分成10个区域:

fig, axe = plt.subplots(figsize = (8, 5))

np.random.seed(66)
data = np.random.randn(1000) 
axe.hist(data) # 默认区间数量为10
plt.show()

hist也有很多参数可以自定义,以下把设有不同参数的直方图放到同一窗口进行比较:

fig, axe = plt.subplots(nrows=2, ncols=2, figsize=(12, 6))

np.random.seed(66)
data = np.random.randn(1000)
axe[0][0].set_title("bins=30")
axe[0][0].hist(data, bins=30)
axe[0][1].set_title("normalized")
axe[0][1].hist(data, density=True) # 曲线下方面积总和为1
axe[1][0].set_title("set color as green")
axe[1][0].hist(data, color="g")
axe[1][1].set_title("step")
axe[1][1].hist(data, histtype='step') # 直方图形状设置为不填充面积的线图

plt.tight_layout()
plt.show()

如果想要对比多组数据的分布,可以执行多次hist画出多个直方图:

fig, axe = plt.subplots(figsize = (8, 5))

np.random.seed(66)
data1 = np.random.normal(-1, 1, 5000)
data2 = np.random.normal(-2, 1, 5000)
data3 = np.random.normal(-1, 2, 5000)
axe.hist(data1, bins=50, density=True, alpha=0.35, label="data1") # alpha代表透明度
axe.hist(data2, bins=50, density=True, alpha=0.35, label="data1")
axe.hist(data3, bins=50, density=True, alpha=0.35, label="data3")

axe.legend()
plt.show()

如果想要画出一条涵盖直方图的线,我们可以通过以下的代码实现:

fig, axe = plt.subplots(figsize = (8, 5))

sigma = 1
mu = 0
np.random.seed(66)
data = np.random.normal(mu, sigma, 5000)
n, bins, _ = axe.hist(data, bins=50, alpha=0.35, density=True) # n: 区间数量, bins: 区间的边界

y = ((1 / (np.sqrt(2 * np.pi) * sigma)) *
     np.exp(-0.5 * (1 / sigma * (bins - mu))**2))
axe.plot(bins, y, '--r')

plt.show()

以上就是柱状图和直方图相关的内容啦,下一章我们来学习一下面积图。