返回介绍

6.1 matplotlib

发布于 2024-01-27 22:10:03 字数 9109 浏览 0 评论 0 收藏 0

matplotlib 是一个绘图库,创建的图形可达到出版的质量要求。它可以创建常用的统计图,包括条形图、箱线图、折线图、散点图和直方图。它还有一些扩展工具箱,比如 basemap 和 cartopy,用于制作地图,以及 mplot3d,用于进行 3D 绘图。

matplotlib 提供了对图形各个部分进行定制的功能。例如,它可以设置图形的形状和大小、x 轴与 y 轴的范围和标度、x 轴与 y 轴的刻度线和标签、图例以及图形的标题。你可以参考一下 matplotlib 初学者指南和 API(http://matplotlib.org/users/beginner.html),以获得更多的关于定制图形的信息。

下面的示例演示了如何使用 matplotlib 创建最常用的统计图形。

6.1.1 条形图

条形图表示一组分类数值,比如计数值。常用的条形图包括垂直图、水平图、堆积图和分组图。下面的脚本 bar_plot.py 演示了如果创建一个垂直条形图:

 1 #!/usr/bin/env python3
 2 import matplotlib.pyplot as plt
 3 plt.style.use('ggplot')
 4 customers = ['ABC', 'DEF', 'GHI', 'JKL', 'MNO']
 5 customers_index = range(len(customers))
 6 sale_amounts = [127, 90, 201, 111, 232]
 7 fig = plt.figure()
 8 ax1 = fig.add_subplot(1,1,1)
 9 ax1.bar(customers_index, sale_amounts, align='center', color='darkblue')
10 ax1.xaxis.set_ticks_position('bottom')
11 ax1.yaxis.set_ticks_position('left')
12 plt.xticks(customers_index, customers, rotation=0, fontsize='small')
13 plt.xlabel('Customer Name')
14 plt.ylabel('Sale Amount')
15 plt.title('Sale Amount per Customer')
16 plt.savefig('bar_plot.png', dpi=400, bbox_inches='tight')
17 plt.show()

第 2 行代码是惯常的 import 语句。第 3 行代码使用 ggplot 样式表来模拟 ggplot2 风格的图形,ggplot2 是一个常用的 R 语言绘图包。

第 4、5 和 6 行代码为条形图准备数据。我创建了一个客户索引列表,因为 xticks 函数在设置标签时要求索引位置和标签值。

使用 matplotlib 绘图时,首先要创建一个基础图,然后在基础图中创建一个或多个子图。脚本中的第 7 行代码创建了一个基础图。第 8 行代码向基础图中添加了一个子图。因为可以向基础图中添加多个子图,所以必须指定要创建几行和几列子图,以及使用哪个子图。 1, 1, 1 表示创建 1 行 1 列的子图,并使用第 1 个也是唯一的一个子图。

第 9 行代码创建条形图。customer_index 设置条形左侧在 x 轴上的坐标。sale_amounts 设置条形的高度。align='center' 设置条形与标签中间对齐。color='darkblue' 设置条形的颜色。

第 10 和 11 行代码通过设置刻度线位置在 x 轴底部和 y 轴左侧,使图形的上部和右侧不显示刻度线。

第 12 行代码将条形的刻度线标签由客户索引值更改为实际的客户名称。rotation=0 表示刻度标签应该是水平的,而不是倾斜一个角度。fontsize='small' 将刻度标签的字体设为小字体。

第 13、14 和 15 行代码向图中添加 x 轴标签、y 轴标签和图形标题。

第 16 行代码将统计图保存在当前文件夹中,文件名为 bar_plot.png。dpi=400 设置图形分辨率 [ 每英寸(1 英寸 =2.54 厘米)的点数)],bbox_inches='tight' 表示在保存图形时,将图形四周的空白部分去掉。

第 17 行代码指示 matplotlib 在一个新窗口中显示统计图。结果如图 6-1 所示。

图 6-1:matplotlib 制作的条形图

6.1.2 直方图

直方图用来表示数值分布。常用的直方图包括频率分布、频率密度分布、概率分布和概率密度分布。下面的脚本 histogram.py 演示了如何创建一个频率分布图:

 1 #!/usr/bin/env python3
 2 import numpy as np
 3 import matplotlib.pyplot as plt
 4 plt.style.use('ggplot')
 5 mu1, mu2, sigma = 100, 130, 15
 6 x1 = mu1 + sigma*np.random.randn(10000)
 7 x2 = mu2 + sigma*np.random.randn(10000)
 8 fig = plt.figure()
 9 ax1 = fig.add_subplot(1,1,1)
10 n, bins, patches = ax1.hist(x1, bins=50, normed=False, color='darkgreen')
11 n, bins, patches = ax1.hist(x2, bins=50, normed=False, color='orange', alpha=0.5)
12 ax1.xaxis.set_ticks_position('bottom')
13 ax1.yaxis.set_ticks_position('left')
14 plt.xlabel('Bins')
15 plt.ylabel('Number of Values in Bin')
16 fig.suptitle('Histograms', fontsize=14, fontweight='bold')
17 ax1.set_title('Two Frequency Distributions')
18 plt.savefig('histogram.png', dpi=400, bbox_inches='tight')
19 plt.show()

第 6 和 7 行代码使用 Python 的随机数生成器创建两个正态分布变量 x1 和 x2。x1 的均值是 100,x2 的均值是 130,所以两个分布会有一些重叠,但不会是一个覆盖掉另一个。第 10 和 11 行代码为这两个变量创建两个柱形图,或称频率分布图。bins=50 表示每个变量的值应该被分成 50 份。normed=False 表示直方图显示的是频率分布,而不是概率密度。第一个直方图是暗绿色,第二个直方图是橙色。alpha=0.5 表示第二个直方图应该是透明的,这样我们就可以看到两个直方图重叠部分的暗绿色图。

第 16 行代码为基础图添加一个居中的标题,字体大小为 14,粗体。第 17 行代码为子图添加一个居中的标题,位于基础图标题下面。我们用这两行代码为统计图创建标题和副标题,如图 6-2 所示。

图 6-2:matplotlib 制作的两个直方图

6.1.3 折线图

折线图中的数值点在一条折线上。它通常用来表示数据随着时间发生的变化。下面的脚本 line_plot.py 演示了如何创建一幅折线图:

 1 #!/usr/bin/env python3
 2 from numpy.random import randn
 3 import matplotlib.pyplot as plt
 4 plt.style.use('ggplot')
 5 plot_data1 = randn(50).cumsum()
 6 plot_data2 = randn(50).cumsum()
 7 plot_data3 = randn(50).cumsum()
 8 plot_data4 = randn(50).cumsum()
 9 fig = plt.figure()
10 ax1 = fig.add_subplot(1,1,1)
11 ax1.plot(plot_data1, marker=r'o', color=u'blue', linestyle='-',\
12 label='Blue Solid')
13 ax1.plot(plot_data2, marker=r'+', color=u'red', linestyle='--',\
14 label='Red Dashed')
15 ax1.plot(plot_data3, marker=r'*', color=u'green', linestyle='-.',\
16 label='Green Dash Dot')
17 ax1.plot(plot_data4, marker=r's', color=u'orange', linestyle=':',\
18 label='Orange Dotted')
19 ax1.xaxis.set_ticks_position('bottom')
20 ax1.yaxis.set_ticks_position('left')
21 ax1.set_title('Line Plots: Markers, Colors, and Linestyles')
22 plt.xlabel('Draw')
23 plt.ylabel('Random Number')
24 plt.legend(loc='best')
25 plt.savefig('line_plot.png', dpi=400, bbox_inches='tight')
26 plt.show()

同样,我们在第 5~8 行代码中使用 randn 创建绘图所用的随机数据。第 11~18 行代码创建 4 条折线。每条折线都可以通过选项进行设置,使用不同的数据点类型、颜色和线型。 label 参数保证折线在图例中可以正确标记。

第 24 行代码为统计图创建图例。loc='best' 指示 matplotlib 根据图中的空白部分将图例放在最合适的位置。或者,你也可以使用这个参数为图例指定一个具体位置。图 6-3 展示了这个脚本创建的折线图。

图 6-3:matplotlib 创建的折线图(包含 4 条折线)

6.1.4 散点图

散点图表示两个数值变量之间的相对关系,这两个变量分别位于两个数轴上。例如,身高与体重,或者供给与需求。散点图有助于识别出变量之间是否具有正相关(图中的点集中于某个具体参数)或负相关(图中的点像云一样发散)。你还可以画一条回归曲线,也就是使方差最小的曲线,通过图中的点基于一个变量的值预测另一个变量的值。

下面的脚本 scatter_plot.py 演示了如何创建一幅散点图,并在各个点之间画一条回归曲线:

 1 #!/usr/bin/env python3
 2 import numpy as np
 3 import matplotlib.pyplot as plt
 4 plt.style.use('ggplot')
 5 x = np.arange(start=1., stop=15., step=1.)
 6 y_linear = x + 5. * np.random.randn(14.)
 7 y_quadratic = x**2 + 10. * np.random.randn(14.)
 8 fn_linear = np.poly1d(np.polyfit(x, y_linear, deg=1))
 9 fn_quadratic = np.poly1d(np.polyfit(x, y_quadratic, deg=2))
10 fig = plt.figure()
11 ax1 = fig.add_subplot(1,1,1)
12 ax1.plot(x, y_linear, 'bo', x, y_quadratic, 'go', \
13               x, fn_linear(x), 'b-', x, fn_quadratic(x), 'g-', linewidth=2.)
14 ax1.xaxis.set_ticks_position('bottom')
15 ax1.yaxis.set_ticks_position('left')
16 ax1.set_title('Scatter Plots Regression Lines')
17 plt.xlabel('x')
18 plt.ylabel('f(x)')
19 plt.xlim((min(x)-1., max(x)+1.))
20 plt.ylim((min(y_quadratic)-10., max(y_quadratic)+10.))
21 plt.savefig('scatter_plot.png', dpi=400, bbox_inches='tight')
22 plt.show()

这里我使用了一点小技巧,在第 6 和 7 行代码中,通过随机数使数据与一条直线和一条二次曲线稍稍偏离。然后,在第 8 和 9 行代码中,使用 numpy 的 polyfit 函数通过两组数据点 (x, y_linear) 和 (x, y_quadratic) 拟合出一条直线和一条二次曲线,再使用 poly1d 函数根据直线和二次曲线的参数生成一个线形方程和二次方程。如果是实际数据,你可以使用 polyfit 函数计算出某个阶数的多项式拟合模型的系数。poly1d 函数可以使用这些系数创建实际的多项式方程。

第 12 行代码创建带有两条回归曲线的散点图。'bo' 表示 (x, y_linear)点是蓝色圆圈,'go' 表示 (x, y_quadratic) 点是绿色圆圈。同样,'b-' 表示 (x, y_linear) 点之间的线是一条蓝色实线,'g-' 表示 (x, y_quadratic) 点之间的线是一条绿色实线。通过 linewidth 可以设置线的宽度。

你可以尝试改变这些显示变量,做出符合自己风格的统计图。

第 19 和 20 行代码设置了 x 轴和 y 轴的范围。这两条曲线使用 min 和 max 函数基于实际数据设置坐标轴范围。你也可以使用具体的数值设置范围,例如 xlim(0, 20) 和 ylim(0, 200)。如果你没有设置坐标轴范围,那么 matplotlib 会替你设置。脚本运行的结果如图 6-4 所示。

图 6-4:matplotlib 生成的散点图以及线形拟合曲线和二次拟合曲线

6.1.5 箱线图

箱线图可以表示出数据的最小值、第一四分位数、中位数、第三四分位数和最大值。箱体的下部和上部边缘线分别表示第一四分位数和第三四分位数,箱体中间的直线表示中位数。箱体上下两端延伸出去的直线(whisker,亦称为“须”)表示非离群点的最小值和最大值,在直线(须)之外的点表示离群点。

下面的脚本 box_plot.py 演示了如何创建一幅箱线图:

 1 #!/usr/bin/env python3
 2 import numpy as np
 3 import matplotlib.pyplot as plt
 4 plt.style.use('ggplot')
 5 N = 500
 6 normal = np.random.normal(loc=0.0, scale=1.0, size=N)
 7 lognormal = np.random.lognormal(mean=0.0, sigma=1.0, size=N)
 8 index_value = np.random.random_integers(low=0, high=N-1, size=N)
 9 normal_sample = normal[index_value]
10 lognormal_sample = lognormal[index_value]
11 box_plot_data = [normal,normal_sample,lognormal,lognormal_sample]
12 fig = plt.figure()
13 ax1 = fig.add_subplot(1,1,1)
14 box_labels = ['normal','normal_sample','lognormal','lognormal_sample']
15 ax1.boxplot(box_plot_data, notch=False, sym='.', vert=True, whis=1.5, \
16                    showmeans=True, labels=box_labels)
17 ax1.xaxis.set_ticks_position('bottom')
18 ax1.yaxis.set_ticks_position('left')
19 ax1.set_title('Box Plots: Resampling of Two Distributions')
20 ax1.set_xlabel('Distribution')
21 ax1.set_ylabel('Value')
22 plt.savefig('box_plot.png', dpi=400, bbox_inches='tight')
23 plt.show()

第 14 行代码创建了一个列表 box_labels,里面保存着每个箱线图的标签。在下一行代码中的 boxplot 函数中将使用这个列表。

第 15 行代码使用 boxplot 函数创建 4 个箱线图。notch=False 表示箱体是矩形,而不是在中间收缩。sym='.' 表示离群点(就是直线之外的点)使用圆点,而不是默认的 + 符号。vert=True 表示箱体是垂直的,不是水平的。whis=1.5 设定了直线从第一四分位数和第三四分位数延伸出的范围(例如:Q3+whis*IQR,IQR 就是四分位距,等于 Q3-Q1)。 showmeans=True 表示箱体在显示中位数的同时也显示均值。labels=box_labels 表示使用 box_labels 中的值来标记箱线图。

这个脚本的运行结果如图 6-5 所示。

图 6-5:正态分布和对数正态分布数据的箱线图,以及这两个分布中抽样数据的箱线图,由 matplotlib 生成

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文