查看原文
其他

30000字 Matplotlib 实操干货,38个案例带你从入门到进阶!

The following article is from Python数据之道 Author 翻译君

关注上方“Python数据科学”,选择星标,

关键时间,第一时间送达!

☞500g+超全学习资源免费领取 

译文出品:Python数据之道
原文作者:Rizky Maulana Nurhidayat
翻译:Lemon

文末赠送5本书
《Python 数据分析全流程实操指南

前天东哥分享了一篇万字pandas入门教程:太香了!最强的 pandas 入门教程(赠5本书),今天再分享一篇matplotlib的实战入门干货!

数据可视化旨在将数据呈现为更直接的表示形式,例如散点图,密度图,条形图等。通过可视化数据,可以检测到潜在的异常值。在 Python 中,可以使用各种模块或库来可视化数据。Matplotlib 是主流模块之一。可以使用 Matplotlib 以各种绘图样式来可视化数据。但是,Matplotlib 无法显示动态图。如果要创建一个巨大的动态图,则可以从 plotly 中使用 Dash

本文将介绍如何使用 Matplotlib 以各种方式可视化数据。完整的文章可能有 90 个示例,可以从不同的角度创建绘图。这不是使用 Matplotlib 进行数据可视化的最完整的教程,但是我相信本文内容可以满足许多人的需求,并可以应用到许多领域。
如前所述,本文将创建 90 个不同的绘图示例。这些示例分布在 11 种不同的样式图中:散点图,折线图,一维直方图,二维直方图,边际图,条形图,箱形图,小提琴图,饼图,极坐标图,地理投影,3D图和轮廓图。可以通过 图1 大致了解本文的内容。
图1. Matplotlib 中生成的各种图
本文将专注于创建和定制各种图表。因此,文章中假设读者已经了解 Matplotlib 的一些基础知识,例如,在 Matplotlib 中创建多个子图和自定义颜色图。
在开始撰写本文时,本来打算只写一篇文章。但是,我认为由于阅读时间的缘故,需要将其分为几部分。如果我将所有内容写成一篇文章,则将花费很多时间。因此,我将完整的内容分为 2 或 3 部分。
本文是第一部分,共有 38个 案例,让我们开始吧。

Matplotlib 介绍

要安装 Matplotlib,可以使用以下代码通过 pip 安装它:
pip install matplotlib
或者通过 conda 来安装:
conda install -c anaconda matplotlib
本文中,安装了 Matplotlib 3.3.2 版本。可以通过下面的代码检查所安装的版本号:
pip show matplotlib
如果要在 Jupyter Notebook(以下称为 Jupyter)中进行检查,则可以通过下面的代码来进行检查,如图2所示。
图2. 在 Jupyter 中检查 Matplotlib 的版本
如果你想更新 Matplotlib 的版本,可以使用下面的代码:
pip install matplotlib --upgrade
在继续进行第一部分之前,需要告知下,我已经自定义了 Matplotlib 绘图样式,例如使用 LaTeX 字体作为默认样式,更改字体大小和字体,更改 xtick 和 ytick 方向和大小,以及在  x 轴和 y 轴。要将 LaTeX 字体用作 Matplotlib 中的默认字体,可以使用下面的代码:
plt.rcParams['text.usetex'] = True
如果遇到一些错误,则需要阅读下面文章中的内容。我已经解释了在 Matplotlib 中处理 LaTeX 字体的详细过程。
要自定义其他参数(字体大小,字体系列和刻度参数),只需在代码开头编写以下代码:
plt.rcParams['font.size'] = 15
plt.rcParams['font.family'] = "serif"tdir = 'in'
major = 5.0
minor = 3.0
plt.rcParams['xtick.direction'] = tdir
plt.rcParams['ytick.direction'] = tdirplt.rcParams['xtick.major.size'] = major
plt.rcParams['xtick.minor.size'] = minor
plt.rcParams['ytick.major.size'] = major
plt.rcParams['ytick.minor.size'] = minor
如果需要更详细地了解,可以访问下面的内容:
https://towardsdatascience.com/create-professional-plots-using-matplotlib-63a6863b7363

01. 散点图(Scatter plot)

在本部分,有八个散点图的示例。在创建散点图之前,需要使用下面的代码生成模拟数据:
import numpy as np
import matplotlib.pyplot as plt

N = 50

x = np.linspace(0.10., N)
y = np.sin(x)**2 + np.cos(x)
变量 x 是从 0 到 10 的 50 个数据的数组。变量 y 是 sin(x) 和 cos(x) 的平方之和。可以使用以下代码以散点图的形式可视化 x 轴上的变量 x 和 y 轴上的变量 y :
plt.figure()
plt.scatter(x, y)
上面的内容很简单,结果如图3所示:
图3. Matplotlib中的默认散点图
为了使其更美观,可以减少每个数据的大小并给标签添加下面的代码:
plt.scatter(x, y, s = 15, label = r'$y  = sin^2(x) + cos(x)$')
要更改颜色,需要在代码中添加 color 参数:
color = 'r' # r means red
如果要使轴比例尺相同,可以使用下面的代码:
plt.axis('equal')
要为 x 轴和 y 轴创建轴标签,可以添加以下代码:
plt.xlabel(r'$x$ (rad)')
plt.ylabel(r'$y$')
要显示图例,可以使用下面的代码:
plt.legend()
要保存图形,可以使用以下代码:
plt.savefig('scatter2.png', dpi = 300, bbox_inches = 'tight', facecolor='w')
完整的代码如下:
N = 50

x = np.linspace(0.10., N)
y = np.sin(x)**2 + np.cos(x)

plt.figure()
plt.scatter(x, y, s = 15, label = r'$ y  = sin^2(x) + cos(x)$', color = 'r')
plt.axis('equal')

plt.legend()
plt.xlabel(r'$x$ (rad)')
plt.ylabel(r'$y$')

plt.savefig('scatter2.png', dpi = 300, bbox_inches = 'tight', facecolor='w')
创建的散点图如 图4 所示:
图4. 修改后的散点图
上面可以看到轴内部的 x 轴和 y 轴的刻度方向,并且使用的字体为 LaTeX 格式。如果要更改图形尺寸,可以在 plt.figure() 中添加图形尺寸参数
plt.figure(figsize=(74.5))
更改标记样式
要更改标记样式,例如,要从点更改为十字,可以在 plt.scatter 中添加此参数:
marker = 'x'
图5 是更改为十字后的结果:
图5. 修改样式后的散点图
Matplotlib 中有各种各样的样式,可以通过下面的链接来进行了解:
https://matplotlib.org/api/markers_api.html
如果你已阅读以上文档,则可以意识到可以将字母用作标记样式。下面将展示将字母用作标记的示例,如 图6 所示:
图6. Matplotlib 中使用字母为标记样式
为了生成 图6,这里为 x 轴和 y 轴的参数创建了一个不同的函数。以下是生成它的代码:
np.random.seed(100)

N = 50

randx = np.random.random(N) * 100
randy = np.random.random(N) * 100
为了可视化变量 randx 和 randy ,可以运行以下代码:
plt.figure(figsize=(76))

plt.scatter(randx, randy, marker=r'$\beta$', s = 150, color = 'darkorange')

plt.axis('equal')

plt.xlabel('randx')
plt.ylabel('randy')

plt.tight_layout()
这里使用希腊符号 beta 作为标记样式。也可以使用其他字母来更改它,例如  a,B,C,d 或 ** 1、2、3** 等。
自定义每个数据的大小
这里将展示如何为每个数据创建大小不同的散点图,如 图7 所示。
图7. 自定义散点图中数据点的大小
为了创建它,使用以下代码为变量 randx 和 randy 生成了一个随机数据,从 0 到 100
np.random.seed(100)

N = 30

randx = np.random.random(N) * 100
randy = np.random.random(N) * 100
之后,使用下面的代码为 50 到 200 之间的每个数据生成一个随机整数。
size = np.random.randint(50200, size=N)
进行可视化,只需添加下面的参数:
plt.scatter(randx, randy, s = size, color = 'darkorange')
创建 图7 时需要在 x 轴和 y 轴上插入次刻度。要插入它,需要使用以下代码导入子模块 MultipleLocator
from matplotlib.ticker import MultipleLocator
之后,可以添加以下代码,以插入辅助轴:
ax = plt.gca()ax.xaxis.set_minor_locator(MultipleLocator(10))
ax.yaxis.set_minor_locator(MultipleLocator(10))
下面是生成 图7 的完整代码:
np.random.seed(100)

N = 30

plt.figure(figsize=(76))

randx = np.random.random(N) * 100
randy = np.random.random(N) * 100
size = np.random.randint(50200, size=N)

plt.scatter(randx, randy, s = size, color = 'darkorange')
plt.axis('equal')

ax = plt.gca()
ax.xaxis.set_minor_locator(MultipleLocator(10))
ax.yaxis.set_minor_locator(MultipleLocator(10))

plt.xlabel('randx')
plt.ylabel('randy')

plt.savefig('scatter5.png', dpi = 300, bbox_inches = 'tight', facecolor='w')
以颜色编码的散点图
可以使用颜色图更改颜色,这意味着具有不同大小的数据将以不同的颜色进行颜色编码。可以像下面这样在 plt.scatter() 中添加颜色参数:
c = size
要嵌入颜色条,可以使用以下代码:
plt.colorbar()
得到的结果如 图8 所示:
图8. 不同颜色标注的散点图
以下是创建 图8 完整的代码:
np.random.seed(100)

N = 30

randx = np.random.random(N) * 100
randy = np.random.random(N) * 100
ranking = np.random.random(N) * 200
size = np.random.randint(50200, size=N)

plt.figure(figsize=(75))
plt.scatter(randx, randy, s = size, c = size, alpha = .8)
plt.axis('equal')

ax = plt.gca()
ax.xaxis.set_minor_locator(MultipleLocator(10))
ax.yaxis.set_minor_locator(MultipleLocator(10))

plt.xlabel('randx')
plt.ylabel('randy')

plt.colorbar()

plt.savefig('scatter6.png', dpi = 300, bbox_inches = 'tight', facecolor='w')
自定义颜色图
可以使用以下参数更改颜色图:
cmap = 'inferno'
Matplotlib 官方文档对颜色图进行了详细的讲解,可以通过下面链接来访问:
https://matplotlib.org/3.3.2/tutorials/colors/colormaps.html
在本文中,通过组合蓝色和橙色的颜色图创建了自己的颜色图,如 图9 所示:
图9. 自定义颜色图
使用下面的代码,可以将两种颜色结合起来:
from matplotlib import cm
from matplotlib.colors import ListedColormap, LinearSegmentedColormap

top = cm.get_cmap('Oranges_r'128)
bottom = cm.get_cmap('Blues'128)

newcolors = np.vstack((top(np.linspace(01128)),
                       bottom(np.linspace(01128))))

orange_blue = ListedColormap(newcolors, name='OrangeBlue')
我创建了自己的颜色图,名为 orange_blue 。要了解如何在 Matplotlib 中创建和自定义自己的颜色图,可以访问以下链接:
https://towardsdatascience.com/creating-colormaps-in-matplotlib-4d4de78a04b8
要应用它,只需更改颜色参数 c = orange_blue ,可以在 图11 中检查结果:
图11. 自定义颜色
以下是创建 图11 的完整代码:
from matplotlib import cm
from matplotlib.colors import ListedColormap, LinearSegmentedColormap

top = cm.get_cmap('Oranges_r'128)
bottom = cm.get_cmap('Blues'128)

newcolors = np.vstack((top(np.linspace(01128)),
                       bottom(np.linspace(01128))))
orange_blue = ListedColormap(newcolors, name='OrangeBlue')

np.random.seed(100)

N = 30

randx = np.random.random(N) * 100
randy = np.random.random(N) * 100
size = np.random.randint(50200, size=N)

plt.figure(figsize=(75))
plt.scatter(randx, randy, s = size, c = size, alpha = .8, cmap = orange_blue)
plt.axis('equal')

ax = plt.gca()
ax.xaxis.set_minor_locator(MultipleLocator(10))
ax.yaxis.set_minor_locator(MultipleLocator(10))

plt.xlabel('randx')
plt.ylabel('randy')

plt.colorbar(label = 'circle size')

plt.savefig('scatter7.png', dpi = 300, bbox_inches = 'tight', facecolor='w')

02. 线图(Line plot)

为了在 Matplotlib 中绘制线图,将使用以下代码生成模拟数据:
N = 50

x = np.linspace(0.10., N)
y = np.sin(x)**2 + np.cos(x)
要以线图的形式可视化变量 x 和 y ,需要使用以下代码:
plt.plot(x, y)
上面的代码将生成一个图形,如 图12 所示:
图12. Matplotlib 中默认的线形图
自定义线条的样式
可以使用下面的参数在 Matplotlib 中更改线条图的线条样式:
linestyle = '-'
上面的参数应在 plt.plot() 中插入。在本文中将展示四种不同的线条样式。它们是
['-''--''-.'':']
为了自动生成它,使用循环将使其变得简单,以下是完整的代码:
N = 50

x = np.linspace(0.10., N)
y = np.sin(x)**2 + np.cos(x)

rows = 2
columns = 2

grid = plt.GridSpec(rows, columns, wspace = .25, hspace = .25)

linestyles = ['-''--''-.'':']

plt.figure(figsize=(1510))
for i in range(len(linestyles)):
    plt.subplot(grid[i])
    plt.plot(x, y, linestyle = linestyles[i], label = r'$ y  = sin^2(x) + cos(x)$')
    plt.axis('equal')
    plt.xlabel('$x$ (rad)')
    plt.legend()
    plt.annotate("linestyle '" + str(linestyles[i]) + "'", xy = (0.5-2.5), va = 'center', ha = 'left')
    
plt.savefig('line2.png', dpi = 300, bbox_inches = 'tight', facecolor='w')
这里将在一张图中分配 4 种不同的线型,这意味着需要在一个图中创建 4 个轴。在 Matplotlib 中,可以通过使用 GridSpec()subplot()add_subplot() 自定义子图来生成它。在本文中,使用 GridSpec() ,创建了 4 个轴( 2 行 2 列),宽度和高度间距等于 0.25。
正如在文章开始时提到的,本文将只专注于自定义图。如果在 Matplotlib 中自定义子图时需要更多说明,则可以访问下面的链接:
https://towardsdatascience.com/customizing-multiple-subplots-in-matplotlib-a3e1c2e099bc
上面代码运行后的结果如 图13 所示:
图13. 自定义线条样式
该代码将简单地生成 4 种不同的线型,并为每种线型添加标签和注释。Matplotlib 提供了许多可以使用的线型,可以通过下面链接选择自己喜欢的线条样式:
https://matplotlib.org/2.1.2/api/_as_gen/matplotlib.pyplot.plot.html
自定义线条宽度
自定义线条宽度,可以使用下面的代码:
lw = 2.0
四种不同宽度的线条图,如 图14 所示:
图14. 自定义线条宽度
创建 图14 的完整代码如下:
N = 50

rows = 2
columns = 2

x = np.linspace(0.10., N)
y = np.sin(x)**2 + np.cos(x)

grid = plt.GridSpec(rows, columns, wspace = .25, hspace = .25)

linewidth = [2345]

plt.figure(figsize=(1510))
for i in range(len(linestyles)):
    plt.subplot(grid[i])
    plt.plot(x, y, linestyle = '-.', lw = linewidth[i], label = r'$ y  = sin^2(x) + cos(x)$')
    plt.axis('equal')
    plt.xlabel('$x$ (rad)')
    plt.legend()
    plt.annotate("linewidth " + str(linewidth[i]), xy = (0.5-2.5), va = 'center', ha = 'left')
    
plt.savefig('line3.png', dpi = 300, bbox_inches = 'tight', facecolor='w')
创建间隔标记
这里将创建间隔标记(mark every)。为了理解它,将首先显示结果,如 图15 所示:
图15. Matplotlib 中创建间隔标记
在 图15 中,为每 5 个数据创建一个圆圈标记。可以使用以下参数创建:
'o'            # shape for each 5 data
markevery = 5  # mark every 
ms = 7         # size of the circle in mark every
以下是完整的代码:
N = 50

x = np.linspace(0.10., N)
y = np.sin(x)**2 + np.cos(x)

plt.figure(figsize=(74.5))
plt.plot(x, y, 'o', ls = '-.', lw = 2, ms = 7, markevery = 5, label = r'$ y  = sin^2(x) + cos(x)$')
plt.axis('equal')
plt.xlabel('$x$ (rad)')
plt.legend()
plt.annotate("markevery: 5", xy = (0.5-2.5), va = 'center', ha = 'left')

plt.savefig('line4.png', dpi = 300, bbox_inches = 'tight', facecolor='w')
这里需要将参数 "o"  放在第三个参数位置上。
更改线条颜色
更改线条颜色,可以使用以下代码:
color = 'royalblue'
下面将展示如何使用循环生成 4 种不同的颜色和 4 种不同的标记,如 图16 所示:
图16. 自定义线条颜色
创建 图16 的代码如下:
N = 50

x = np.linspace(0.10., N)
y = np.sin(x)**2 + np.cos(x)

rows = 2
columns = 2

grid = plt.GridSpec(rows, columns, wspace = .25, hspace = .25)

mark = [251012]
color = ['#00429d''#627c94''#f4777f''#93003a']

plt.figure(figsize=(1510))
for i in range(len(linestyles)):
    plt.subplot(grid[i])
    plt.plot(x, y, 'o', ls='-.', lw = 2, ms = 8, markevery=mark[i], color = color[i], label = r'$ y  = sin^2(x) + cos(x)$')
    plt.axis('equal')
    plt.annotate("markevery: " + str(mark[i]), xy = (0.5-2.5), va = 'center', ha = 'left')
    plt.xlabel('$x$ (rad)')
    plt.legend()

plt.savefig('line5.png', dpi = 300, bbox_inches = 'tight', facecolor='w')
线条图中添加误差
为了演示折线图中的误差线,需要使用以下代码生成误差:
np.random.seed(100)

noise_x = np.random.random(N) * .2 + .1
noise_y = np.random.random(N) * .7 + .4
该代码将为 noise_x 生成从 0.1 到 0.3 的随机数,为 noise_y 生成从 0.3 到 0.7 的随机数。要为 y 轴插入误差线,可以使用以下代码:
plt.errorbar(x, y, yerr = noise_y)
包含误差的线条图,如 图17 所示:
图17. 创建添加误差的线形图
创建 图17 的完整代码如下:
N = 25
x = np.linspace(0.10., N)
y = np.sin(x)**2 + np.cos(x)

np.random.seed(100)
noise_x = np.random.random(N) * .2 + .1
noise_y = np.random.random(N) * .7 + .4


plt.figure(figsize=(74.5))
plt.errorbar(x, y, yerr = noise_y, xerr = noise_x, label = r'$ y  = sin^2(x) + cos(x)$')
plt.axis('equal')
plt.legend()
plt.xlabel('$x$ (rad)')

plt.savefig('line7.png', dpi = 300, bbox_inches = 'tight', facecolor='w')
在 x 轴添加误差,可以使用以下参数:
xerr = noise_x
可以看到在 图18 的 x 和 y 轴上插入误差线的示例:
图18. 创建添加误差线的线形图
创建 图18 的完整代码如下:
N = 25

x = np.linspace(0.10., N)
y = np.sin(x)**2 + np.cos(x)

np.random.seed(100)
noise_x = np.random.random(N) * .2 + .1
noise_y = np.random.random(N) * .7 + .4

plt.figure(figsize=(74.5))
plt.errorbar(x, y, yerr = noise_y, xerr = noise_x, label = r'$ y  = sin^2(x) + cos(x)$')
plt.axis('equal')
plt.legend()
plt.xlabel('$x$ (rad)')

plt.savefig('line7.png', dpi = 300, bbox_inches = 'tight', facecolor='w')
如果只想显示数据而不显示线图,而仅显示误差线,则可以使用以下参数:
fmt = 'o'    # shape of the data point
color = 'r'  # color of the data point
ecolor ='k'   # color of the error bar
完整代码如下:
N = 25

x = np.linspace(0.10., N)
y = np.sin(x)**2 + np.cos(x)

np.random.seed(100)
noise_x = np.random.random(N) * .2 + .1
noise_y = np.random.random(N) * .7 + .4

plt.figure(figsize=(74.5))
plt.errorbar(x, y, xerr = noise_x, yerr = noise_y, label = r'$ y  = sin^2(x) + cos(x)$', color = 'r', fmt = 'o', ecolor='k', )
plt.axis('equal')
plt.legend()
plt.xlabel('$x$ (rad)')

plt.savefig('line8.png', dpi = 300, bbox_inches = 'tight', facecolor='w')
效果如 图19 所示:
图19. 自定义创建误差线
填充误差区域
如需要填充误差范围区域,可以使用以下代码:
plt.fill_between(x, y + noise, y - noise, alpha = .5)
fill_between 参数是 x 轴的数据,填充区域的上限和下限。在上面的代码中,用 y + noise  和 y-noise 表示。此外,还需要降低填充区域的透明度。以下是完整的代码:
N = 25
x = np.linspace(0.10., N)
y = np.sin(x)**2 + np.cos(x)

np.random.seed(100)
noise = np.random.random(N) * .7 + .4

plt.figure(figsize=(74.5))
plt.plot(x, y, ls='-', label = r'$ y  = sin^2(x) + cos(x)$')
plt.fill_between(x, y + noise, y - noise, alpha = .5)
plt.axis('equal')
plt.legend()
plt.xlabel('$x$ (rad)')

plt.savefig('line9.png', dpi = 300, bbox_inches = 'tight', facecolor='w')
上述代码运行后,结果如 图20 所示:
图20. 创建填充区域
插入水平线和垂直线
可以使用以下代码插入水平线和垂直线:
plt.hlines(0, xmin = 0, xmax = 10)
plt.vlines(2, ymin = -3, ymax = 3)
需要在第一个参数中定义水平线,包括水平线的起点和终点。对于垂直线,它具有类似的参数。
图21 是添加了水平线和垂直线的示例:
图21. 水平线和垂直线
创建 图21 的完整代码如下:
N = 25

x = np.linspace(0.10., N)
y = np.sin(x)**2 + np.cos(x)

np.random.seed(100)
noise = np.random.random(N) * .7 + .4

plt.figure(figsize=(74.5))
plt.plot(x, y, ls = '-', label = r'$ y  = sin^2(x) + cos(x)$', color = 'darkgreen')
plt.fill_between(x, y + noise, y - noise, color = 'darkgreen', alpha = .5)
plt.axis('equal')

plt.hlines(0, xmin = 0, xmax = 10, ls = '--', color = 'royalblue', label = 'hlines')
plt.vlines(2, ymin = -3, ymax = 3, ls = '--', color = 'orange', label = 'vlines')

plt.legend(bbox_to_anchor=(1.551.04)) # position of the legend
plt.xlabel('$x$ (rad)')

plt.savefig('line10.png', dpi = 300, bbox_inches = 'tight', facecolor='w')
垂直填充
下面将在两条垂直线之间绘制一个填充区域,如 图22 所示:
创建 图22 的完整代码如下:
N = 25

x = np.linspace(0.10., N)
y = np.sin(x)**2 + np.cos(x)

np.random.seed(100)
noise = np.random.random(N) * .7 + .4

plt.figure(figsize=(74.5))
plt.plot(x, y, ls='-', label = r'$ y  = sin^2(x) + cos(x)$', color = 'darkgreen')
plt.fill_between(x, y + noise, y - noise, color = 'darkgreen', alpha = .5)

plt.axis('equal')

plt.fill_between((2,4), -3.23.2, facecolor='orange', alpha = 0.4)

plt.xlim(010)
plt.ylim(-33)

plt.legend()
plt.xlabel('$x$ (rad)')

plt.savefig('line11.png', dpi = 300, bbox_inches = 'tight', facecolor='w')

03. 直方图(Histogram)

下面将说明如何在 1D 和 2D 中制作直方图。首先,将介绍一维直方图。在可视化一维直方图之前,将使用以下代码制作一个模拟数据,即正态分布随机数。
N = 1000

np.random.seed(10021)
x = np.random.randn(N) * 2 + 15
默认情况下,Numpy 将生成一个正态分布随机数,其均值/中位数(mu)等于 0 ,方差(sigma)等于 1 。在上面的代码中,将 mu 更改为15,将 sigma 更改为 2 。要在一维直方图中可视化变量 x  ,可以使用以下代码:
plt.hist(x)
结果如 图23 所示:
图23. Matplotlib 中默认的一维直方图
在 Matplotlib 中, 一维直方图中 bins 的默认值为 10, 如果要更改 bins 的默认值,可以修改下面的参数:
bins = 40
bins 设置为 40 后,结果如 图24 所示:
图24. 修改后的一维直方图
以下是创建 图24 的完整代码:
N = 1000

np.random.seed(10021)
x = np.random.randn(N) * 2 + 15

plt.figure(figsize=(96))
plt.hist(x, bins = 40, label = r'$\mu = 15, \sigma = 2$')
plt.legend()
还可以使用以下参数限制直方图的范围:
range = (1218)
该参数将使直方图仅显示 12 到 18 之间的数据,如 图25 所示:
图25. 限制范围的一维直方图
创建 图25 的完整代码如下:
N = 1000

np.random.seed(10021)
x = np.random.randn(N) * 2 + 15

plt.figure(figsize=(96))

plt.hist(x, bins = 40, range = (1218), color = 'darkorange', label = r'$\mu = 15, \sigma = 2$')

plt.legend()
plt.savefig('hist3.png', dpi = 300, bbox_inches = 'tight', facecolor='w')
这里还使用 color 参数更改直方图的颜色。
水平直方图
可以创建一个水平直方图,如 图26 所示:
图25. 水平直方图
使用以下参数来创建水平直方图:
orientation = 'horizontal'
创建 图25 的完整代码如下:
N = 1000

np.random.seed(10021)
x = np.random.randn(N) * 2 + 15

plt.figure(figsize=(96))
plt.hist(x, bins = 25, range = (1218), color = 'royalblue', orientation='horizontal', label = r'$\mu = 15, \sigma = 2$')
plt.legend()

plt.savefig('hist4.png', dpi = 300, bbox_inches = 'tight', facecolor='w')
如果要显示每个直方图的边框,可以使用下面的参数。
edgecolor = 'k'
将直方图边框设为黑色,如 图26 所示:
图26. 自定义直方图的边框
创建 图26 的完整代码如下:
N = 1000

np.random.seed(10021)
x = np.random.randn(N) * 2 + 15

plt.figure(figsize=(96))
plt.hist(x, bins = 25, range = (1218), color = 'royalblue', orientation='horizontal',  edgecolor='k', label = r'$\mu = 15, \sigma = 2$')
plt.legend()

plt.savefig('hist5.png', dpi = 300, bbox_inches = 'tight', facecolor='w')
重叠的直方图
可以在一个图中显示许多个直方图,如 图27 所示:
图27. 创建重叠的直方图
在 图27 中,生成了三个正态分布,分别具有不同的 mu 和 sigma ,代码如下:
N = 1000

mu1 = 5
mu2 = 10
mu3 = 15

sigma1 = 5
sigma2 = 3
sigma3 = 2

x1 = np.random.randn(N) * sigma1 + mu1
x2 = np.random.randn(N) * sigma2 + mu2
x3 = np.random.randn(N) * sigma3 + mu3

plt.figure(figsize=(96))

plt.hist(x1, bins = 30, color = 'royalblue', label = r'$\mu = $ ' + str(mu1) + ', $\sigma = $ ' + str(sigma1))
plt.hist(x2, bins = 30, color = 'tomato', label = r'$\mu = $ ' + str(mu2) + ', $\sigma = $ ' + str(sigma2))
plt.hist(x3, bins = 30, color = 'gray', label = r'$\mu = $ ' + str(mu3) + ', $\sigma = $ ' + str(sigma3))
plt.legend()

plt.savefig('hist6.png', dpi = 300, bbox_inches = 'tight', facecolor='w')
可以通过更改直方图的透明度使其更美观,如 图28 所示:
图28. 更改直方图的透明度
创建 图28 的完整代码如下,与之前的代码的不同之处,在于增加了 alpha 参数:
N = 1000

mu1 = 5
mu2 = 10
mu3 = 15

sigma1 = 5
sigma2 = 3
sigma3 = 2

x1 = np.random.randn(N) * sigma1 + mu1
x2 = np.random.randn(N) * sigma2 + mu2
x3 = np.random.randn(N) * sigma3 + mu3

plt.figure(figsize=(96))

plt.hist(x1, bins = 30, color = 'royalblue', label = r'$\mu = $ ' + str(mu1) + ', $\sigma = $ ' + str(sigma1), alpha = .7)
plt.hist(x2, bins = 30, color = 'tomato', label = r'$\mu = $ ' + str(mu2) + ', $\sigma = $ ' + str(sigma2), alpha = .7)
plt.hist(x3, bins = 30, color = 'gray', label = r'$\mu = $ ' + str(mu3) + ', $\sigma = $ ' + str(sigma3), alpha = .7)
plt.legend()

plt.savefig('hist7.png', dpi = 300, bbox_inches = 'tight', facecolor='w')
还可以使用循环生成 图28,如代码所示:
N = 1000

mu1 = 5
mu2 = 10
mu3 = 15

sigma1 = 5
sigma2 = 3
sigma3 = 2

x1 = np.random.randn(N) * sigma1 + mu1
x2 = np.random.randn(N) * sigma2 + mu2
x3 = np.random.randn(N) * sigma3 + mu3

mu = np.array([mu1, mu2, mu3])
sigma = np.array([sigma1, sigma2, sigma3])
x = np.array([x1, x2, x3])
colors = ['royalblue''tomato''gray']

plt.figure(figsize=(96))

for i in range(len(x)):
    plt.hist(x[i], bins = 30, color = colors[i], 
             label = r'$\mu = $ ' + str(mu[i]) + 
             ', $\sigma = $ ' + str(sigma[i]), alpha = .7)

plt.legend()
看完上面的代码后,也许你想试试,在单个图形中创建很多直方图(超过 3 个)。下面这个是在单个图形中创建和可视化 10 个直方图的代码:
N_func = 10
N_data = 1000

np.random.seed(1000)

mu = np.random.randint(low = -5, high = 5, size = N_func)
sigma = np.random.randint(low = 1, high = 5, size = N_func)

x = []
for i in range(len(mu)):
    xi = np.random.randn(N_data) * sigma[i] + mu[i]
    x.append(xi) 

colors = ['#00429d''#7f40a2''#a653a1''#c76a9f''#e4849c''#d0e848'
          '#b6cf54''#a9b356''#b2914b''#ff0001']
    
plt.figure(figsize=(96))

for i in range(len(mu)):
    plt.hist(x[i], bins = 30, color = colors[i], label = r'$\mu = $ ' + str(mu[i]) + ', $\sigma = $ ' + str(sigma[i]), alpha = .7)

plt.legend(bbox_to_anchor=(1.331.03))
运行代码后,结果如 图29 所示:
图29. 创建多个直方图
颜色的选择参考以下链接:https://gka.github.io/palettes/
生成调色板的详细过程可以参考以下内容:https://towardsdatascience.com/create-professional-plots-using-matplotlib-63a6863b7363
二维直方图
可以使用 Matplotlib 生成 2D 直方图,如 图30 所示。
图30. 二维直方图
要创建 图30,需要使用以下代码生成 2 个正态分布。
N = 1_000

np.random.seed(100)
x = np.random.randn(N)
y = np.random.randn(N)
要在 2D 直方图中可视化变量 x 和 y ,可以使用以下代码:
plt.hist2d(x, y)
与一维直方图一样,Matplotlib 中 bins 的默认值为 10 。要对其进行更改,可以应用与一维直方图中相同的参数,如下面的代码所示:
bins = (2525)
可以在 图31 中看到二维直方图的修改效果:
图31. 修改二维直方图的bins值
还可以使用下面的参数更改二维直方图的颜色图:
cmap = orange_blue
我想将 Viridis 的颜色图( Matplotlib 中的默认颜色图)更改为自己的名为 orange_blue 的颜色图。我已在上文中说明了如何创建自己的颜色图。
以下是修改了颜色图后的完整代码:
from matplotlib import cm
from matplotlib.colors import ListedColormap, LinearSegmentedColormap

top = cm.get_cmap('Oranges_r'128)
bottom = cm.get_cmap('Blues'128)

newcolors = np.vstack((top(np.linspace(01128)),
                       bottom(np.linspace(01128))))
orange_blue = ListedColormap(newcolors, name='OrangeBlue')

N = 10_000

np.random.seed(100)
x = np.random.randn(N)
y = np.random.randn(N)

plt.figure(figsize=(8.57))
plt.hist2d(x, y, bins=(7575), cmap = orange_blue)
cb = plt.colorbar()
cb.set_label('counts each bin', labelpad = 10)

plt.savefig('hist12.png', dpi = 300, bbox_inches = 'tight', facecolor='w')
运行上述代码,结果如 图32 所示:
图32. 修改二维直方图的颜色
同样的,可以通过设置参数应用于 plt.hist2d() 来限制每个计数的范围(更改颜色条的限制)。
cmin = 5, cmax = 25
以下是完整的代码:
N = 10_000

np.random.seed(100)
x = np.random.randn(N)
y = np.random.randn(N)

plt.figure(figsize=(8.57))
plt.hist2d(x, y, bins=(7575), cmap = 'jet', cmin = 5, cmax = 25)
cb = plt.colorbar()
cb.set_label('counts each bin', labelpad = 10)
这里使用 “jet” 颜色图,颜色条的下限等于 5 ,上限为 25 。结果如 图33 所示:
图33. 直方图中设置限制范围
还可以尝试使用以下代码将生成的随机数计数从 10000 更改为 100000 。
N = 100_000

np.random.seed(100)
x = np.random.randn(N)
y = np.random.randn(N)

plt.figure(figsize=(8.57))
plt.hist2d(x, y, bins=(7575), cmap = 'Spectral')
cb = plt.colorbar()
cb.set_label('counts each bin', labelpad = 10)
结果如 图34 所示:
图34. 使用 Matplotlib 可视化二维直方图中的正态分布
图34 在 0 处达到峰值,在 -1 到 1 处分布,因为没有改变 mu 和 sigma 的值。
边际图(Marginal plot)
这里将介绍如何创建边际分布,如 图35 所示:
图35. 散点图和直方图的边际图
图35 由散点图和 2 个直方图构建。要创建它,需要了解如何在单个图形中自定义子图或轴。图35 由 25 个轴( 5 列 5 行)构成。详细信息如 图36 所示。
可以使用以下代码创建 图36 :
你可能需要阅读下面的内容,才能更好的理解:https://towardsdatascience.com/customizing-multiple-subplots-in-matplotlib-a3e1c2e099bc
rows = 5
columns = 5

grid = plt.GridSpec(rows, columns, wspace = .4, hspace = .4)

plt.figure(figsize=(1010))

for i in range(rows * columns):
    plt.subplot(grid[i])   
    plt.annotate('grid '+ str(i), xy = (.5.5), ha = 'center'
                 va = 'center')

for i in range(rows):
    exec (f"plt.subplot(grid[{i}, 0])")
    plt.ylabel('rows ' + str(i), labelpad = 15)

for i in range(columns):
    exec (f"plt.subplot(grid[-1, {i}])")
    plt.xlabel('column ' + str(i), labelpad = 15)
图36. 多子图
图35 显示了 图36 的转换。这里将 图36 中的一些网格合并为仅 3 个较大的网格。第一个网格将网格0 合并到网格3(行1 ,列0 到列 )。我将用直方图填充第一个网格。第二个网格合并从第 1 行到第 4 行以及从第 0 列到第 3 列的 16 个网格。最后一个网格是通过合并网格9、14、19 和 24(行1、2、3、4和列4)构建的。
要创建第一个网格,可以使用以下代码:
rows = 5
columns = 5
grid = plt.GridSpec(rows, columns, wspace = .4, hspace = .4)

plt.figure(figsize=(1010))

plt.subplot(grid[00:-1])
之后,添加以下代码以插入一维直方图:
plt.hist(x, bins = 30, color = 'royalblue', alpha = .7)
要创建第二个网格,可以将以下代码添加到上面的代码中:
plt.subplot(grid[1:rows+10:-1])
添加下面的代码以在第二个网格中生成散点图:
plt.scatter(x, y, color = 'royalblue', s = 10)
plt.axis('equal')
以下是生成第三个网格及其直方图的代码,需要将下面的代码插入第一个网格代码中:
plt.subplot(grid[1:rows+1-1])
plt.hist(y, bins = 30, orientation='horizontal'
         color = 'royalblue', alpha = .7)
合并上面的代码,完整的代码如下:
N = 10_000

np.random.seed(100)
x = np.random.randn(N)
y = np.random.randn(N)

rows = 5
columns = 5

grid = plt.GridSpec(rows, columns, wspace = .4, hspace = .4)

plt.figure(figsize=(1010))

plt.subplot(grid[00:-1])
plt.hist(x, bins = 30, color = 'royalblue', alpha = .7)

plt.subplot(grid[1:rows+10:-1])
plt.scatter(x, y, color = 'royalblue', s = 10)
plt.axis('equal')

plt.subplot(grid[1:rows+1-1])
plt.hist(y, bins = 30, orientation='horizontal', color = 'royalblue', alpha = .7)
接下来,将使用二维直方图更改第二个网格中的散点图,如 图37 所示:
图37. 边际图
创建 图37 的完整代码如下:
N = 10_000

np.random.seed(100)
x = np.random.randn(N)
y = np.random.randn(N)

rows = 5
columns = 5

grid = plt.GridSpec(rows, columns, wspace = .4, hspace = .4)

plt.figure(figsize=(1010))

plt.subplot(grid[00:-1])
plt.hist(x, bins = 40, color = 'royalblue', alpha = .3)
plt.annotate('Normal 1', xy = (2500), va = 'center', ha = 'left')

plt.subplot(grid[1:rows+10:-1])
plt.hist2d(x, y, cmap = 'Blues', bins = (4040))
plt.axis('equal')

plt.subplot(grid[1:rows+1-1])
plt.hist(y, bins = 40, orientation='horizontal', color = 'royalblue', alpha = .3)
plt.annotate('Normal 2', xy = (5002), va = 'bottom', ha = 'center', rotation = -90)

04. 条形图(Bar chart)

如果想用条形图可视化数据,在 Matplotlib 中创建条形图之前,先创建要显示的模拟数据。比如在数学考试成绩中创建六个人的数据,要创建它,使用以下代码。
name = ['Adam''Barry''Corbin''Doe''Evans''Frans']

np.random.seed(100)
N = len(name)
math = np.random.randint(60100, N)
生成的数学考试成绩从 60 到 100 ,代码如下:
plt.bar(name, math, alpha = .7)
添加一些信息之后,生成了一个条形图,如 图38 所示:
图38. 创建条形图
创建 图38 的完整代码如下:
name = ['Adam''Barry''Corbin''Doe''Evans''Frans']

np.random.seed(100)

N = len(name)
math = np.random.randint(60100, N)

plt.figure(figsize=(96))

plt.bar(name, math, alpha = .7)

plt.ylabel('Math Exam')
之后,使用以下代码为物理、生物学和化学考试成绩创建了更多模拟数据。
np.random.seed(100)

N = len(name)

math = np.random.randint(60100, N)
physics = np.random.randint(60100, N)
biology = np.random.randint(60100, N)
chemistry = np.random.randint(60100, N)
也可以使用 Pandas 创建一个表(在 Python 中,我们称为 DataFrame )。从模拟数据创建的 DataFrame 如 图39 所示:
图39. Pandas 中的 DataFrame 数据
默认情况下,这里没有显示有关如何创建 DataFrame 的代码。
然后,将其可视化,如 图40 所示:
图40. 创建多个条形图
创建 图40 的代码如下:
name = ['Adam''Barry''Corbin''Doe''Evans''Frans']

np.random.seed(100)

N = len(name)
math = np.random.randint(60100, N)
physics = np.random.randint(60100, N)
biology = np.random.randint(60100, N)
chemistry = np.random.randint(60100, N)

rows = 2
columns = 2

plt.figure(figsize=(128))
grid = plt.GridSpec(rows, columns, wspace = .25, hspace = .25)

plt.subplot(grid[0])
plt.bar(name, math, alpha = .7)
plt.ylabel('Math Exam')
plt.ylim(60100)

plt.subplot(grid[1])
plt.bar(name, physics, alpha = .7)
plt.ylabel('Physics Exam')
plt.ylim(60100)

plt.subplot(grid[2])
plt.bar(name, biology, alpha = .7)
plt.ylabel('Biology Exam')
plt.ylim(60100)

plt.subplot(grid[3])
plt.bar(name, chemistry, alpha = .7)
plt.ylabel('Chemistry Exam')
plt.ylim(60100)
或使用下面的代码(如果要使用循环):
name = ['Adam''Barry''Corbin''Doe''Evans''Frans']
course_name = ['Math''Physics''Biology''Chemistry']

N = len(name)
rows = 2
columns = 2

plt.figure(figsize=(128))
grid = plt.GridSpec(rows, columns, wspace = .25, hspace = .25)

for i in range(len(course_name)):
    np.random.seed(100)
    course = np.random.randint(60100, N)
    plt.subplot(grid[i])
    plt.bar(name, course, alpha = .7)
    plt.ylabel(course_name[i] + ' Exam')
    plt.ylim(60100)
水平条形图
可以使用下面的代码来创建水平条形图。
想以水平条形图和各种颜色呈现 图40,以下是生成它的完整代码:
name = ['Adam''Barry''Corbin''Doe''Evans''Frans']
course_name = ['Math''Physics''Biology''Chemistry']

colors = ['#00429d''#7f40a2''#a653a1''#c76a9f'
          '#e4849c''#d0e848']

N = len(name)

rows = 2
columns = 2

plt.figure(figsize=(128))
grid = plt.GridSpec(rows, columns, wspace = .25, hspace = .25)

for i in range(len(course_name)):
    np.random.seed(100)
    course = np.random.randint(60100, N)
    plt.subplot(grid[i])
    plt.barh(name, course, color = colors)
    plt.xlabel(course_name[i] + ' Exam')
    plt.xlim(60100)
    plt.gca().invert_yaxis()
运行上面的代码后,将获得结果,如 图41 所示:
图41. 水平条形图
可以使用以下参数在水平条形图中插入误差线:
N = len(name)
noise = np.random.randint(13, N)

plt.barh(name, course, xerr = noise)
这里使用 1 到 3 之间的整数随机数创建了误差,如变量 noise 中所述。在为水平条形图添加一些元素之后,将其显示出来,如 图42 所示:
图42. 添加了误差的水平条形图
创建 图42 的代码如下:
name = ['Adam''Barry''Corbin''Doe''Evans''Frans']
course_name = ['Math''Physics''Biology''Chemistry']

N = len(name)
rows = 2
columns = 2

plt.figure(figsize=(128))
grid = plt.GridSpec(rows, columns, wspace = .25, hspace = .25)
np.random.seed(100)

for i in range(len(course_name)):
    course = np.random.randint(6095, N)
    noise = np.random.randint(13, N)
    plt.subplot(grid[i])
    plt.barh(name, course, color = colors, xerr = noise, 
             ecolor = 'k')
    plt.xlabel(course_name[i] + ' Exam')
    plt.xlim(60100)
    plt.gca().invert_yaxis()
也许已意识到模拟数据不是真实的,但是,我认为这仍然是理解 Matplotlib 中条形图的一个很好的例子。

总结

本文是 Matplotlib 可视化介绍的第 1 部分。本文仅涵盖 Matplotlib 介绍 11 个部分中的4个部分,包括散点图,折线图,直方图和条形图。在后续内容中,我将展示如何创建箱形图,小提琴图,饼图,极坐标图,地理投影,3D图和轮廓图的教程。
原文来源:https://towardsdatascience.com/visualizations-with-matplotlib-part-1-c9651008b6b8

文末赠书福利

赠送书籍《Python数据分析全流程实操指南》5本!由「北京大学出版社」赞助提供,如果等不及也可以入手一本学习。

介绍:本书主要围绕整个数据分析方法论的常规流程,介绍了Python常用的工具包,包括科学计算库Numpy、数据分析库Pandas、数据挖掘库Scikit-Learn,以及数据可视化库Matplotlib和Seaborn的基本知识,并从数据分析挖掘的实际业务应用出发,讲解了互联网、金融及零售等行业的真实案例,比如客户分群、产品精准营销、房价预测、特征降维等,深入浅出、循序渐进地介绍了Python数据分析的全过程。

参与方式:本篇文章底部「在看」+「留言」,文章内容相关的优质留言才可上墙!留言点赞数量最多「前5位」读者将获得这本书,截止时间「11月15日20:00」,最终获赠者通过留言联系我。
PS:禁止恶意刷赞!发现后将进入黑名单,取消上墙资格。


推荐阅读

太香了!最强的 pandas 入门教程
安利3个Python数据分析EDA神器!
骚操作!嵌套 JSON 秒变 Dataframe!
计算机专业几本必看的书!
太强了!一款如操作Excel一样的pandas可视化神器来了!
两篇毕业论文致谢同一个女朋友?哈哈哈哈!
太震撼了!我用Python画出全北京的公交线路动图

🧐分享、点赞、在看,给个三连击呗!👇

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存