数据可视化
Matplotlib绘制可视化图表
一、实验名称
Matplotlib绘制可视化图表
二、实验目的
通过该实验的实践,要求学生能够熟练使用Matplotlib基本图表的可视化展示,掌握使用这工具绘制图表的一般化流程,掌握使用Matplot实现特征分析,掌握使用Matplotlib实现数据分布情况分析,以及基于Matplotlib的复杂场景应用等。
三、实验原理
Matplotlib 是 Python 的可视化基础库,作图风格和 MATLAB 类似,所以称为 Matplotlib
python中的很多可视化库都基于Matplotlib进行了封装,如Seaborn 是一个基于 Matplotlib 的高级可视化效果库,针对 Matplotlib 做了更高级的封装,让作图变得更加容易。你可以用短小的代码绘制更多维度数据的可视化效果图。
使用matplotlib可以展示可视化的多种基本图表
四、实验步骤
1、打开终端Terminal,准备执行安装命令行
2、环境准备
2.1 打开jupyter
在打开的浏览器中,新建python3文件
3、基础图表
柱形图
柱形图通常用于直观的对比数据,在实际工作中使用频率很高,在Matplotlib中可以通过bar()即可绘制出柱形图。
import matplotlib.pyplot as plt
plt.bar([1, 2, 3, 4], [1, 4, 2, 3]) # 绘制图像
plt.show()
如果想修改柱子的颜色,宽度,可以通过color和width参数进行修改;
color:支持通过代码快速配置常见的颜色,如r代表红色,blue代表蓝色,也支持十六进制和RGB(A)格式颜色配置;
width:数值范围0-1,默认0.8;
import matplotlib.pyplot as plt
plt.bar([1, 2, 3, 4], [1, 4, 2, 3], color=(0.2, 1.0, 1.0), width=0.5) # 绘制图像
plt.show()
条形图
条形图同样常用来进行数据的对比展示,可以简单看作是柱形图经过翻转90度后的图表,使用barh()可以进行条形图的绘制;
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = 'Microsoft YaHei'
plt.barh(["深圳", "广州", "北京", "上海"], [1, 4, 2, 3]) # 绘制图像
plt.show()
需要注意,当柱子翻转过来之后,修改柱子的“宽度”在条形图从参数width变成了height;
import matplotlib.pyplot as plt
plt.barh(["深圳", "广州", "北京", "上海"], [1, 4, 2, 3], height=0.5, color="#0aff00") # 绘制图像
plt.show()
折线图
折线图通常用于展示一段时间内的趋势,可以通过plot进行折线图的绘制;
import matplotlib.pyplot as plt
plt.plot([1, 2, 3, 4], [1, 4, 2, 3]) # 绘制图像
plt.show()
通过linewidth和linestyle可以进行线宽和线型的配置;
linestyle可接受的参数如下:
至于展示出来是什么样式,大家可以依次去尝试一下
import matplotlib.pyplot as plt
plt.plot([1, 2, 3, 4], [1, 4, 2, 3], color='blue', linewidth=2, linestyle='-.') # 绘制图像
plt.show()
通过marker和makersize可以绘制带标记点的折线图;
支持的maker样式如下:
输出为:
import matplotlib.pyplot as plt
plt.plot([1, 2, 3, 4], [1, 4, 2, 3], color='blue', linewidth=2, linestyle='-.', marker='*', markersize=15) # 绘制图像
plt.show()
面积图
面积图其实就是折线图的另一种展示显示,相当于是对折线图进行了区域颜色填充,在matplotlib中可以通过stackplot()进行面积图的绘制;
注:其实从Matplotlib的命名来看,stackplot是堆叠折线图,不过默认是填充了颜色的,所以我们可以当作面积图来使用。
import matplotlib.pyplot as plt
plt.stackplot([1, 2, 3, 4], [1, 4, 2, 3], color=(0.4, 0.2, 0.1, 0.1)) # 绘制图像
plt.show()
饼图
饼图通常用于展示各种类别数据的占比,在matplotlib中可以通过pie()进行饼图的绘制;
import matplotlib.pyplot as plt
# labels用于饼图标签的设置
plt.pie([1, 4, 2, 3], labels=["深圳", "广州", "北京", "上海"]) # 绘制图像
plt.show()
在制作饼图的时候我们通常需要展示百分比,在Matplotlib中可以通过atuopct参数进行配置;
import matplotlib.pyplot as plt
# labels用于饼图标签的设置
plt.pie([1, 4, 2, 3], labels=["深圳", "广州", "北京", "上海"], autopct='%.2f%%') # 绘制图像
plt.show()
我们可以通过将其中一块区域分离来进行数据的强调显示;
import matplotlib.pyplot as plt
# labels用于饼图标签的设置
plt.pie([1, 4, 2, 3], labels=["深圳", "广州", "北京", "上海"], autopct='%.2f%%', explode=[0, 0, 0.2, 0]) # 绘制图像
plt.show()
可以通过参数labeldistance和pctdistance进行标签和百分比显示的位置,1表示一个圆心到圆周的距离;
import matplotlib.pyplot as plt
# labels用于饼图标签的设置
plt.pie([1, 4, 2, 3], labels=["深圳", "广州", "北京", "上海"], autopct='%.2f%%', labeldistance=1.2, pctdistance=0.6) # 绘制图像
plt.show()
通过对wedgeprops参数设置还可以绘制圆环图;
import matplotlib.pyplot as plt
# labels用于饼图标签的设置
plt.pie([1, 4, 2, 3], labels=["深圳", "广州", "北京", "上海"],
autopct='%.2f%%', pctdistance=0.8,
wedgeprops={'width': 0.3, 'linewidth': 2, 'edgecolor': 'w'}) # 绘制图像
plt.show()
散点图
散点图通常用于展示数据之间的相关关系,可以通过scatter进行散点图的绘制;
import random
import matplotlib.pyplot as plt
data_x = [random.randint(1, 100) for _ in range(100)]
data_y = [random.randint(1, 100) for _ in range(100)]
plt.scatter(data_x, data_y)
plt.show()
散点图除了可以通过xy轴反映数据之外,还可以通过「点」的颜色和大小来反映数据,可以最多展示4个维度的数据;
import numpy as np
import matplotlib.pyplot as plt
N = 30
x = np.random.rand(N)
y = np.random.rand(N)
colors = np.random.rand(N)
area = np.pi * (15 * np.random.rand(N))**2
plt.scatter(x, y,
# 图形大小
s=area,
# 颜色
c=colors,
# 透明度
alpha=0.2)
plt.show()
除此之外,我们还可以通过Marker去设置标记点的形状,通过edgecolor去设置标记点的边框颜色;
import numpy as np
import matplotlib.pyplot as plt
N = 30
x = np.random.rand(N)
y = np.random.rand(N)
colors = np.random.rand(N)
area = np.pi * (15 * np.random.rand(N))**2
plt.scatter(x, y,
# 图形大小
s=area,
# 颜色
c=colors,
# 透明度
alpha=0.2,
# 标记点形状
marker='*',
# 边框颜色
edgecolor='blue'
)
plt.show()
4、图表元素配置
基础例子
%matplotlib inline
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = 'Microsoft YaHei'
x = ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月']
y = [123, 145, 152, 182, 147, 138, 189, 201, 203, 211, 201, 182]
plt.plot(x, y, linestyle='-.', marker='p', markersize=10) # 绘制图像
plt.show()
修改画布尺寸
可以通过plt.figure来创建一张宽6英寸,长8英寸的画布;
import matplotlib.pyplot as plt
plt.figure(figsize=(8, 6))
x = ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月']
y = [123, 145, 152, 182, 147, 138, 189, 201, 203, 211, 201, 182]
plt.plot(x, y, linestyle='-.', marker='o', markersize=10) # 绘制图像
plt.show()
修改中文字体
Matplotlib中遇到中文显示方块的问题,可以通过plt.rcParams['font.sans-serif'] = 'Microsoft YaHei'解决;
我们还可以设置的中为字体有SimSun(宋体),SimHei(黑体),Kaiti(楷体)等
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = 'Microsoft YaHei'
plt.figure(figsize=(8, 6))
x = ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月']
y = [123, 145, 152, 182, 147, 138, 189, 201, 203, 211, 201, 182]
plt.plot(x, y, linestyle='-.', marker='o', markersize=10) # 绘制图像
plt.show()
添加图表标题
通过plt.title可以在Matplotlib设置标题,字体样式可以通过fontdict进行设置;
通过loc参数可以设置标题显示位置,支持的参数有center(居中),left(靠左),right(靠右)显示;
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = 'Microsoft YaHei'
plt.figure(figsize=(8, 6))
x = ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月']
y = [123, 145, 152, 182, 147, 138, 189, 201, 203, 211, 201, 182]
plt.title("销售趋势图", fontdict={'family':'Microsoft YaHei', 'color': 'k', 'size': 15}, loc='left')
plt.plot(x, y, linestyle='-.', marker='o', markersize=10) # 绘制图像
plt.show()
添加图例
通过plt.legend可以给图表添加图例,图例通常用来说明图表中数据每个系列的数据的;
在下图中,我们添加两条折线,一条表示华东地区销售情况,一条表示华中的销售情况,需要注意的是我们在通过plt.plot()绘制折线的时候,需要通过label参数设置该系列数据的名称,后续才能通过plt.legend添加;
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = 'Microsoft YaHei'
plt.figure(figsize=(8, 6))
x = ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月']
y1 = [123, 145, 152, 182, 147, 138, 189, 201, 203, 211, 201, 182]
y2 = [102, 121, 138, 154, 171, 178, 199, 231, 228, 202, 231, 271]
plt.title("销售趋势图", fontdict={'family':'Microsoft YaHei', 'color': 'k', 'size': 15}, loc='left')
plt.plot(x, y1, linestyle='-.', marker='o', markersize=10, color='r', label='华东') # 绘制图像
plt.plot(x, y2, linestyle='-', marker='o', markersize=10, color='y', label='华中') # 绘制图像
plt.xlabel("月份", fontdict={'family':'Microsoft YaHei', 'color': 'k', 'size': 12}, labelpad=10)
plt.ylabel("销售额(万元)", fontdict={'family':'Microsoft YaHei', 'color': 'k', 'size': 12}, labelpad=10)
plt.legend(loc='best', fontsize=12) # best:matplotlib根据图表自动选择最优位置
plt.show()
添加数据标签
可以通过plt.text对图表添加文本,但是一次只能添加一个点,所以如果要给每个数据项都添加标签的话,我们需要通过for循环来进行</p>
plt.text 有三个重要的参数:x、y 、s,通过x和y确定显示位置,s为需要显示的文本,另外还有va和ha两个参数设置文本的显示位置(靠左、靠右、居中等);
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = 'Microsoft YaHei'
plt.figure(figsize=(8, 6))
x = ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月']
y1 = [123, 145, 152, 182, 147, 138, 189, 201, 203, 211, 201, 182]
y2 = [102, 121, 138, 154, 171, 178, 199, 231, 228, 202, 231, 271]
plt.title("销售趋势图", fontdict={'family':'Microsoft YaHei', 'color': 'k', 'size': 15}, loc='left')
plt.plot(x, y1, linestyle='-.', marker='o', markersize=10, color='r', label='华东') # 绘制图像
plt.plot(x, y2, linestyle='-', marker='o', markersize=10, color='y', label='华中') # 绘制图像
plt.xlabel("月份", fontdict={'family':'Microsoft YaHei', 'color': 'k', 'size': 12}, labelpad=10)
plt.ylabel("销售额(万元)", fontdict={'family':'Microsoft YaHei', 'color': 'k', 'size': 12}, labelpad=10)
plt.legend(loc='best', fontsize=12) # best:matplotlib根据图表自动选择最优位置
for a, b, c in zip(x, y1, y2):
plt.text(a, b, b, va='bottom', fontdict={"size":14})
plt.text(a, c, c, va='top', fontdict={"size":14})
plt.show()
网格线和坐标轴范围
通过可以添加网格线可以方便用户容易看出数据项的大致值,通过上述展示所有数据标签时,可能会让整个图表比较杂乱,我们可以选择使用网格线来展示数据项大致数据值;
参数b为True时展示网格线,axis支持x、y、both三个值,分别表示展示纵向网格线,横向网格线和纵向横向都展示;
其余线型配置与配置折线风格的参数类似;
可以通过plt.ylim和plt.xlim分别对y轴和x轴的坐标范围进行配置,譬如我们可以设置y轴的起点为50;
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = 'Microsoft YaHei'
plt.figure(figsize=(8, 6))
x = ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月']
y1 = [123, 145, 152, 182, 147, 138, 189, 201, 203, 211, 201, 182]
y2 = [102, 121, 138, 154, 171, 178, 199, 231, 228, 202, 231, 271]
plt.title("销售趋势图", fontdict={'family':'Microsoft YaHei', 'color': 'k', 'size': 15}, loc='left')
plt.plot(x, y1, linestyle='-.', marker='o', markersize=10, color='r', label='华东') # 绘制图像
plt.plot(x, y2, linestyle='-', marker='o', markersize=10, color='y', label='华中') # 绘制图像
plt.xlabel("月份", fontdict={'family':'Microsoft YaHei', 'color': 'k', 'size': 12}, labelpad=10)
plt.ylabel("销售额(万元)", fontdict={'family':'Microsoft YaHei', 'color': 'k', 'size': 12}, labelpad=10)
plt.legend(loc='best', fontsize=12) # best:matplotlib根据图表自动选择最优位置
# 设置坐标轴范围
plt.ylim(50, 300)
# 添加网格线
plt.grid(axis='y', linestyle='--', linewidth=1, color='grey')
plt.show()
5、复杂场景
多图
有时候一个图表并不能说明问题,需要通过多子图进行展现;
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = 'Microsoft YaHei'
x = ["深圳", "广州", "北京", "上海"]
y = [1, 3, 2, 5]
plt.subplot(2, 2, 1)
plt.bar(x, y)
plt.subplot(2, 2, 2)
plt.pie(y, labels=x)
plt.subplot(2, 2, 3)
plt.plot(x, y)
plt.subplot(2, 2, 4)
plt.barh(x, y)
plt.show()
plt.subplot(2, 2, 1)表示将整张画布划分成2*2块区域,并置顶在第一块区域中绘制图表;
接下来通过plt.bar(x, y)在指定区域内绘制一个柱形图;
Matplotlib中有两种绘图方式,同样的效果我们可以通过如下代码来实现;
import matplotlib.pyplot as plt
x = ["深圳", "广州", "北京", "上海"]
y = [1, 3, 2, 5]
fig, axs = plt.subplots(2, 2)
axs[0][0].bar(x, y)
axs[0][1].pie(y, labels=x)
axs[1][0].plot(x, y)
axs[1][1].barh(x, y)
plt.show()
不均匀子图
有些情况下,我们并不希望所有的图表都是一样的大小,不然显得整个画布毫无重点;
我们可以通过.add_gridspec()将整个画布划分成不均匀的区域;
spec = fig.add_gridspec(nrows=2, ncols=2, width_ratios=[1, 3], height_ratios=[1,2]) 表示将整个画布裁剪为2行2列的区域,width_ratios=[1, 3]表示横向将两列的宽度按照1:3进行裁剪,同理height_ratios=[1,2]表示纵向按照1:2进行裁剪
import matplotlib.pyplot as plt
x = ["深圳", "广州", "北京", "上海"]
y = [1, 3, 2, 5]
fig = plt.figure(figsize=(10, 8))
spec = fig.add_gridspec(nrows=2, ncols=2, width_ratios=[1, 3], height_ratios=[1,2])
ax = fig.add_subplot(spec[0, 0])
ax.bar(x, y)
ax = fig.add_subplot(spec[0, 1])
ax.plot(x, y)
ax = fig.add_subplot(spec[1, 0])
ax.pie(y, labels=x)
ax = fig.add_subplot(spec[1, 1])
ax.barh(x, y)
plt.show()
spec还支持切片的方式,譬如我们将第二行展示为整个条形图;
import matplotlib.pyplot as plt
x = ["深圳", "广州", "北京", "上海"]
y = [1, 3, 2, 5]
fig = plt.figure(figsize=(10, 8))
spec = fig.add_gridspec(nrows=2, ncols=2, width_ratios=[1, 3], height_ratios=[1,2])
ax = fig.add_subplot(spec[0, 0])
ax.bar(x, y)
ax = fig.add_subplot(spec[0, 1])
ax.plot(x, y)
# 第二行整块区域显示条形图
ax = fig.add_subplot(spec[1, :])
ax.barh(x, y)
# 调整各区域之间的距离
plt.subplots_adjust(hspace=0.3, wspace=0.2)
plt.show()
双Y轴
当我们多个系列的数据值量级差别太大时,依赖同一个坐标轴来展示通常效果很差,比如需要将销售额和利润同时展示出来;
这时候我们可以通过plt.twix()添加次坐标轴;
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = 'Microsoft YaHei'
plt.figure(figsize=(8, 6))
x = ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月']
y1 = [123, 145, 152, 182, 147, 138, 189, 201, 203, 211, 201, 182]
y2 = [2, 11, 18, 14, 11, 18, 19, 21, 28, 22, 21, 21]
# 绘制柱形图
plt.title("销售趋势图", fontdict={'family':'Microsoft YaHei', 'color': 'k', 'size': 15}, loc='left')
plt.bar(x, y1, color='b', alpha=.5, label='销售额') # 绘制图像
plt.ylabel("销售额(万元)", fontdict={'family':'Microsoft YaHei', 'color': 'k', 'size': 12}, labelpad=10)
plt.ylim(100, 250)
# 添加次坐标轴
plt.twinx()
plt.plot(x, y2, linestyle='-', marker='o', markersize=10, color='r', label='利润') # 绘制图像
plt.ylabel("利润(万元)", fontdict={'family':'Microsoft YaHei', 'color': 'k', 'size': 12}, labelpad=10)
plt.show()
另外需要注意一点,twinx或者twiny方法会返回一个共享x轴或者y轴的新的axes,如果我们通过plt.subplots生成ax后,再绘制第二个折线图时,需要在这个新生成的ax1上绘图;
fig, ax = plt.subplots(figsize=(8, 6))
x = ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月']
y1 = [123, 145, 152, 182, 147, 138, 189, 201, 203, 211, 201, 182]
y2 = [2, 11, 18, 14, 11, 18, 19, 21, 28, 22, 21, 21]
# 绘制柱形图
ax.set_title("销售趋势图", fontdict={'family':'Microsoft YaHei', 'color': 'k', 'size': 15}, loc='left')
ax.bar(x, y1, color='b', alpha=.5, label='销售额') # 绘制图像
ax.set_ylabel("销售额(万元)", fontdict={'family':'Microsoft YaHei', 'color': 'k', 'size': 12}, labelpad=10)
ax.set_ylim(100, 250)
# 添加次坐标轴
ax1 = ax.twinx()
ax1.plot(x, y2, linestyle='-', marker='o', markersize=10, color='r', label='利润') # 绘制图像
ax1.set_ylabel("利润(万元)", fontdict={'family':'Microsoft YaHei', 'color': 'k', 'size': 12}, labelpad=10)
plt.show()
五、实验总结
在实验中,通过实践练习,提高学生使用Matplotlib进行基本图表可视化操作的熟练度,掌握Matplotlib绘制图表的一般性的流程,养成规范绘图的习惯。