💻 Python Matplotlib库
环境安装
Python 虚拟环境
- matplotlib==3.10.0
- numpy==2.2.2
- pandas==2.2.3
- tables==3.10.1
- jupyter==1.1.1
- notebook==7.3.2
jupyter notebook
原IPython Notebook
- Julia + Python + R
- .ipynb 文件
- Cell: 一对In/Out会话称为一个Cell,Cell是Jupyter Notebook中的基本单元
- Markdown: 用于编写文档
- Code: 用于编写代码
- Raw: 用于转换文件格式
- 模式
- 命令模式 Enter
- 编辑模式 Esc
- 常用快捷键
- Shift+Enter: 运行本单元格,并移动到下一个单元格
- Cmd+Enter: 运行本单元格,并保留在原地
- Alt+Enter: 运行本单元格,并插入一个新单元格
- 扩展 extensions → jupyterlab
注意:老版本的扩展使用的是nbextensions, 新版本则使用的是jupyterlab。# 安装扩展: $ pip install jupyterlab-lsp # 代码补全 $ pip install jupyterlab-kite # 代码补全 $ pip install jupyterlab-github # github 集成 $ pip install jupyterlab-latex # latex 支持 $ pip install jupyterlab-drawio # 流程图 $ pip install jupyterlab-dash # 仪表盘
matplotlib
介绍
matplotlib 是 Python 的绘图库,主要用于绘制图表,支持静态、动态、交互式的绘图。
数据可视化是整个数据挖掘的关键辅助工具,可以清晰的理解数据,从而调整我们的分析方法。
核心对象模型:
- Figure: 画布
- Axes: 坐标系
- Axis: 坐标轴
编程接口:
- Pyplot接口:快速绘图
- 面向对象接口: 更灵活,更适合复杂图表
常用依赖:
- numpy
- pandas
图表类型
折线图
折线图(Line Chart):以折线的上升或下降来表示统计数量的增减变化的统计图表。
import matplotlib.pyplot as plt
# 1.创建画布
plt.figure(figsize=(20,8), dpi=100)
plt.xlabel('X label')
plt.ylabel('Y label')
plt.title('Demo Plot')
# 2.绘制图像
plt.plot([1, 2, 3, 4, 5, 6, 7],
[10, 15, 13, 18, 16, 20, 10],
color='blue',
linestyle='--'
)
# 3.图像显示
plt.show()

- 实战:气温图
# 画出某城市11点到12点1小时内每分钟的温度变化折线图,温度范围在15度~18度
import matplotlib.pyplot as plt
import random
# 0.准备x, y坐标的数据
x = range(60)
y_shanghai = [random.uniform(15, 18) for i in x]
# 1.创建画布
plt.figure(figsize=(20, 8), dpi=80)
# 2.绘制折线图
plt.plot(x, y_shanghai)
# 2.1 x轴,y轴刻度标签
x_ticks_label = ["11点{}分".format(i) for i in x]
y_ticks = range(40)
# 修改x,y轴坐标的刻度显示
plt.xticks(x[::5], x_ticks_label[::5])
plt.yticks(y_ticks[::5])
# 3.显示图像
plt.show()

如上,发现:存在字体缺少和中文展示问题。
查询之后,发现问题是:因为系统当前字体(DejaVu Sans)不支持 CJK(中日韩)字符。
解决方案:
- 全局设置中文字体
- 安装支持中文的字体
- 直接指定字体路径
这里我们是在代码中指定了字体,也下载了字体,重启jupyter kernel后,ok了。
另外我们加上一些其他描述信息(x、y、标题)等,完整代码和效果如下:
# 画出某城市11点到12点1小时内每分钟的温度变化折线图,温度范围在15度~18度
import matplotlib.pyplot as plt
import random
from pylab import mpl
mpl.rcParams['font.sans-serif'] = ['SimHei'] # 指定默认字体
mpl.rcParams['axes.unicode_minus'] = False # 解决保存图像是负号'-'显示为方块的问题
# 准备x, y坐标的数据
x = range(60)
y_shanghai = [random.uniform(15, 18) for i in x]
# 创建画布
plt.figure(figsize=(20, 8), dpi=80)
# 绘制折线图
plt.plot(x, y_shanghai)
# x轴,y轴刻度标签
x_ticks_label = ["11点{}分".format(i) for i in x]
y_ticks = range(40)
# 修改x,y轴坐标的刻度显示
plt.xticks(x[::5], x_ticks_label[::5])
plt.yticks(y_ticks[::5])
# 添加网格展示:
plt.grid(True, linestyle='--', alpha=0.5)
# 描述信息:
plt.xlabel("时间")
plt.ylabel("温度")
plt.title("中午11点--12点某城市温度变化图", fontsize=20)
# 图片保存:(会在当前目录下生成图片)
# 注意:plt.show()会释放figure资源,如果在显示图像之后保存图片将只能保存空图片
plt.savefig("./matplotlib-temperature.png")
# 显示图像
plt.show()

柱状图
柱状图(Bar Chart):柱状图是用矩形柱来表示数据数值的图表。
import matplotlib.pyplot as plt
from pylab import mpl
image.png
# 设置中文显示
mpl.rcParams["font.sans-serif"] = ["SimHei"]
mpl.rcParams["axes.unicode_minus"] = False
# 准备数据
cities = ['北京', '上海', '广州', '深圳', '杭州']
temperatures = [20, 21, 25, 24, 22]
# 创建画布
plt.figure(figsize=(12, 6), dpi=100)
# 绘制柱状图
plt.bar(cities, temperatures, width=0.5, color=['r', 'g', 'b', 'y', 'c'])
# 添加数值标签
for i, v in enumerate(temperatures):
plt.text(i, v + 0.5, str(v), ha='center')
# 添加网格
plt.grid(True, linestyle='--', alpha=0.5)
# 添加标题和标签
plt.title('各城市温度对比', fontsize=16)
plt.xlabel('城市')
plt.ylabel('温度(°C)')
# 显示图像
plt.show()

- 横向柱状图
# 使用barh()函数
plt.barh(cities, temperatures)
# -- 堆叠柱状图 --
# 使用bar()函数,并设置stacked=True
plt.bar(cities, temperatures, label='温度')
plt.bar(cities, temperatures, label='温度', bottom=temperatures)
- 分组柱状图
# 准备数据
cities = ['北京', '上海', '广州']
morning_temp = [20, 21, 25]
evening_temp = [15, 16, 20]
x = range(len(cities))
width = 0.3
plt.figure(figsize=(12, 6))
plt.bar(x, morning_temp, width=width, label='早晨')
plt.bar([i + width for i in x], evening_temp, width=width, label='晚上')
plt.xticks([i + width/2 for i in x], cities)
plt.legend()
plt.show()
- 堆叠柱状图
# 准备数据
cities = ['北京', '上海', '广州']
morning_temp = [20, 21, 25]
evening_temp = [15, 16, 20]
plt.figure(figsize=(12, 6))
plt.bar(cities, morning_temp, label='早晨')
plt.bar(cities, evening_temp, bottom=morning_temp, label='晚上')
plt.legend()
plt.show()
散点图
散点图(Scatter Chart):散点图是数据点在直角坐标系平面上的分布图,通常用于展示两个变量之间的关系。
import matplotlib.pyplot as plt
import numpy as np
from pylab import mpl
# 设置中文显示
mpl.rcParams["font.sans-serif"] = ["SimHei"]
mpl.rcParams["axes.unicode_minus"] = False
# 准备数据
np.random.seed(42) # 设置随机种子,确保结果可复现
height = 170 + np.random.randn(100) * 5 # 身高数据,均值170,标准差5
weight = height * 0.7 + np.random.randn(100) * 3 # 体重数据,与身高正相关
# 创建画布
plt.figure(figsize=(10, 6), dpi=100)
# 绘制散点图
plt.scatter(height, weight,
c='blue', # 点的颜色
alpha=0.6, # 透明度
s=50, # 点的大小
marker='o') # 点的形状
# 添加标题和标签
plt.title('身高体重关系散点图', fontsize=14)
plt.xlabel('身高(厘米)')
plt.ylabel('体重(千克)')
# 添加网格
plt.grid(True, linestyle='--', alpha=0.5)
plt.show()

- 带颜色映射的散点图
import matplotlib.pyplot as plt
import numpy as np
# 准备数据
np.random.seed(42)
x = np.random.rand(50)
y = np.random.rand(50)
colors = np.random.rand(50) # 颜色映射值
sizes = 1000 * np.random.rand(50) # 点的大小
# 创建画布
plt.figure(figsize=(10, 6))
# 绘制散点图
scatter = plt.scatter(x, y,
c=colors, # 颜色映射值
s=sizes, # 点的大小
alpha=0.6, # 透明度
cmap='viridis') # 颜色映射方案
# 添加颜色条
plt.colorbar(scatter)
# 添加标题和标签
plt.title('带颜色映射的散点图')
plt.xlabel('X轴')
plt.ylabel('Y轴')
plt.show()

- 带趋势线的散点图:
scipy.stats.linregress()
:计算趋势线
import matplotlib.pyplot as plt
import numpy as np
from scipy import stats
# 准备数据
np.random.seed(42)
x = np.random.rand(50) * 10
y = 2 * x + 1 + np.random.randn(50)
# 计算趋势线
slope, intercept, r_value, p_value, std_err = stats.linregress(x, y)
line = slope * x + intercept
# 创建画布
plt.figure(figsize=(10, 6))
# 绘制散点图和趋势线
plt.scatter(x, y, alpha=0.5, label='数据点')
plt.plot(x, line, color='red', label=f'趋势线 (R² = {r_value**2:.3f})')
# 添加标题和标签
plt.title('带趋势线的散点图')
plt.xlabel('X轴')
plt.ylabel('Y轴')
plt.legend()
plt.grid(True, linestyle='--', alpha=0.5)
plt.show()

饼图
饼图(Pie Chart):饼图是一种圆形统计图表,用于展示各部分数据在整体中的占比情况。
import matplotlib.pyplot as plt
from pylab import mpl
# 设置中文显示
mpl.rcParams["font.sans-serif"] = ["SimHei"]
mpl.rcParams["axes.unicode_minus"] = False
# 准备数据
sizes = [35, 25, 20, 20]
labels = ['苹果', '香蕉', '橙子', '梨']
colors = ['red', 'yellow', 'orange', 'green']
explode = (0.1, 0, 0, 0) # 突出显示第一个扇形
# 创建画布
plt.figure(figsize=(10, 8))
# 绘制饼图
plt.pie(sizes,
explode=explode, # 突出显示
labels=labels, # 标签
colors=colors, # 颜色
autopct='%1.1f%%', # 显示百分比
shadow=True, # 添加阴影
startangle=90) # 起始角度
# 添加标题
plt.title('水果销售比例')
# 保持图形为正圆形
plt.axis('equal')
plt.show()

- 带子图的嵌套饼图
import matplotlib.pyplot as plt
import numpy as np
# 准备数据
# 外圈数据
sizes_outer = [40, 30, 30]
labels_outer = ['A类', 'B类', 'C类']
# 内圈数据
sizes_inner = [15, 25, 10, 20, 30]
labels_inner = ['A1', 'A2', 'B1', 'B2', 'C1']
# 创建画布
plt.figure(figsize=(10, 8))
# 绘制外圈饼图
plt.pie(sizes_outer, labels=labels_outer, radius=1.3,
wedgeprops=dict(width=0.3, edgecolor='white'))
# 绘制内圈饼图
plt.pie(sizes_inner, labels=labels_inner, radius=1.0,
wedgeprops=dict(width=0.3, edgecolor='white'))
plt.title('嵌套饼图示例')
plt.show()

- 带有图例的饼图
import matplotlib.pyplot as plt
# 准备数据
sizes = [30, 20, 25, 15, 10]
labels = ['A', 'B', 'C', 'D', 'E']
colors = ['lightblue', 'lightgreen', 'yellow', 'orange', 'red']
# 创建画布
plt.figure(figsize=(12, 8))
# 绘制饼图
patches, texts, autotexts = plt.pie(sizes,
labels=labels,
colors=colors,
autopct='%1.1f%%',
startangle=90)
# 添加图例
plt.legend(patches, labels,
title="类别",
loc="center left",
bbox_to_anchor=(1, 0, 0.5, 1))
plt.title('带图例的饼图')
plt.axis('equal')
plt.show()

直方图
直方图(Histogram):主要用于展示数据的分布情况,它将连续的数据分成若干个区间(bin),显示每个区间内数据的频数或频率。
import matplotlib.pyplot as plt
import numpy as np
from pylab import mpl
# 设置中文显示
mpl.rcParams["font.sans-serif"] = ["SimHei"]
mpl.rcParams["axes.unicode_minus"] = False
# 生成随机数据
np.random.seed(42)
data = np.random.normal(170, 5, 1000) # 生成1000个均值为170,标准差为5的正态分布数据
# 创建画布
plt.figure(figsize=(10, 6))
# 绘制直方图
plt.hist(data,
bins=30, # 设置区间数
color='skyblue', # 设置颜色
alpha=0.8, # 设置透明度
edgecolor='black' # 设置边框颜色
)
# 添加标题和标签
plt.title('身高分布直方图')
plt.xlabel('身高(cm)')
plt.ylabel('频数')
# 添加网格线
plt.grid(True, linestyle='--', alpha=0.5)
plt.show()

- 多组数据对比的直方图
import matplotlib.pyplot as plt
import numpy as np
# 生成两组数据
np.random.seed(42)
data1 = np.random.normal(170, 5, 1000) # 男性身高
data2 = np.random.normal(160, 4, 1000) # 女性身高
plt.figure(figsize=(12, 6))
# 绘制直方图
plt.hist([data1, data2],
bins=30,
label=['男性', '女性'],
alpha=0.7,
color=['blue', 'red'])
plt.title('男女身高分布对比')
plt.xlabel('身高(cm)')
plt.ylabel('频数')
plt.legend()
plt.grid(True, linestyle='--', alpha=0.5)
plt.show()

- 归一化的直方图(显示密度)
import matplotlib.pyplot as plt
import numpy as np
from scipy import stats
# 生成数据
np.random.seed(42)
data = np.random.normal(0, 1, 1000)
plt.figure(figsize=(10, 6))
# 绘制归一化直方图
plt.hist(data,
bins=30,
density=True, # 归一化
alpha=0.7,
color='skyblue')
# 添加核密度估计曲线
x = np.linspace(data.min(), data.max(), 100)
kde = stats.gaussian_kde(data)
plt.plot(x, kde(x), 'r-', lw=2, label='KDE')
plt.title('归一化直方图与核密度估计')
plt.xlabel('值')
plt.ylabel('密度')
plt.legend()
plt.grid(True, linestyle='--', alpha=0.5)
plt.show()

箱线图
箱线图(Box Plot):箱线图是一种用作显示一组数据分散情况的统计图,包含了最大值、最小值、中位数、上四分位数(Q3)和下四分位数(Q1)等统计量。
箱线图的主要组成部分:
- 箱体(Box)
上边界:上四分位数(Q3)
下边界:下四分位数(Q1)
中间的线:中位数(Q2)- 须(Whisker)
上须:上限值(通常是Q3 + 1.5 IQR)
下须:下限值(通常是Q1 - 1.5 IQR)
其中IQR(四分位距)= Q3 - Q1- 离群点(Outliers):
超出须的范围的点被视为离群值
import matplotlib.pyplot as plt
import numpy as np
from pylab import mpl
# 设置中文显示
mpl.rcParams["font.sans-serif"] = ["SimHei"]
mpl.rcParams["axes.unicode_minus"] = False
# 生成示例数据
np.random.seed(42)
data = [np.random.normal(100, 10, 200),
np.random.normal(90, 20, 200),
np.random.normal(110, 15, 200)]
# 创建画布
plt.figure(figsize=(10, 6))
# 绘制箱线图
plt.boxplot(data,
labels=['A组', 'B组', 'C组'], # 设置标签
notch=True, # 显示凹槽
patch_artist=True, # 填充箱体颜色
boxprops={'facecolor': 'lightblue'}) # 设置箱体颜色
# 添加标题和标签
plt.title('三组数据的箱线图对比')
plt.xlabel('组别')
plt.ylabel('值')
# 添加网格线
plt.grid(True, linestyle='--', alpha=0.3)
plt.show()

- 带有不同颜色的多组箱线图
import matplotlib.pyplot as plt
import numpy as np
# 生成示例数据
np.random.seed(42)
data = [np.random.normal(100, 10, 200),
np.random.normal(90, 20, 200),
np.random.normal(110, 15, 200)]
# 创建画布
plt.figure(figsize=(10, 6))
# 定义颜色
colors = ['lightblue', 'lightgreen', 'pink']
# 绘制箱线图
bp = plt.boxplot(data,
labels=['A组', 'B组', 'C组'],
patch_artist=True) # 允许填充颜色
# 设置箱体颜色
for patch, color in zip(bp['boxes'], colors):
patch.set_facecolor(color)
# 添加标题和标签
plt.title('不同颜色的箱线图')
plt.xlabel('组别')
plt.ylabel('值')
plt.grid(True, linestyle='--', alpha=0.3)
plt.show()

- 水平方向的箱线图
import matplotlib.pyplot as plt
import numpy as np
# 生成示例数据
np.random.seed(42)
data = [np.random.normal(100, 10, 200),
np.random.normal(90, 20, 200),
np.random.normal(110, 15, 200)]
# 创建画布
plt.figure(figsize=(10, 6))
# 绘制水平箱线图
plt.boxplot(data,
labels=['A组', 'B组', 'C组'],
vert=False, # 水平方向
patch_artist=True,
boxprops={'facecolor': 'lightblue'})
plt.title('水平方向的箱线图')
plt.ylabel('组别')
plt.xlabel('值')
plt.grid(True, linestyle='--', alpha=0.3)
plt.show()

多坐标系/多表
一个坐标系绘制多图表
多次plot即可!
import matplotlib.pyplot as plt
import random
from pylab import mpl
# 设置显示中文字体
mpl.rcParams["font.sans-serif"] = ["SimHei"]
# 设置正常显示符号
mpl.rcParams["axes.unicode_minus"] = False
# 0.准备数据
x = range(60)
y_shanghai = [random.uniform(15, 18) for i in x]
y_beijing = [random.uniform(1, 3) for i in x]
# 1.创建画布
plt.figure(figsize=(20, 8), dpi=100)
# 2.绘制图像
plt.plot(x, y_shanghai, label="上海")
plt.plot(x, y_beijing, color="r", linestyle="--", label="北京")
# 2.1 添加x,y轴刻度
# 设置x,y轴刻度
x_ticks_label = ["11点{}分".format(i) for i in x]
y_ticks = range(40)
# 修改x,y轴坐标刻度显示
# plt.xticks(x_ticks_label[::5]) # 坐标刻度不可以直接通过字符串进行修改
plt.xticks(x[::5], x_ticks_label[::5])
plt.yticks(y_ticks[::5])
# 2.2 添加网格显示
plt.grid(True, linestyle="--", alpha=1)
# 2.3 添加描述信息
plt.xlabel("时间")
plt.ylabel("温度")
plt.title("中午11点-12点某城市温度变化图", fontsize=20)
# 2.4 图像保存
plt.savefig("./test.png")
# 2.5 显示图例: legend(): 图例是绘制在图像中的标志,用来表示各曲线所代表的含义。
plt.legend(loc=0)
# 3.图像显示
plt.show()

多个坐标系
使用subplots()函数: 创建一个包含多个子图的画布。
plt.函数名(): 相当于面向过程的画图方法
plt.set_方法名(): 相当于面向对象的画图方法
import matplotlib.pyplot as plt
import random
from pylab import mpl
# 设置显示中文字体
mpl.rcParams["font.sans-serif"] = ["SimHei"]
# 设置正常显示符号
mpl.rcParams["axes.unicode_minus"] = False
# 0.准备数据
x = range(60)
y_shanghai = [random.uniform(15, 18) for i in x]
y_beijing = [random.uniform(1, 3) for i in x]
# 1.创建画布
# plt.figure(figsize=(20, 8), dpi=100)
fig, axes = plt.subplots(nrows=1, ncols=2, figsize=(20, 8), dpi=100)
# 2.绘制图像
# plt.plot(x, y_shanghai, label="上海")
# plt.plot(x, y_beijing, color="r", linestyle="--", label="北京")
axes[0].plot(x, y_shanghai, label="上海")
axes[1].plot(x, y_beijing, color="r", linestyle="--", label="北京")
# 2.1 添加x,y轴刻度
# 设置x,y轴刻度
x_ticks_label = ["11点{}分".format(i) for i in x]
y_ticks = range(40)
# 修改x,y轴坐标刻度显示
# plt.xticks(x_ticks_label[::5]) # 坐标刻度不可以直接通过字符串进行修改
# plt.xticks(x[::5], x_ticks_label[::5])
# plt.yticks(y_ticks[::5])
axes[0].set_xticks(x[::5])
axes[0].set_yticks(y_ticks[::5])
axes[0].set_xticklabels(x_ticks_label[::5])
axes[1].set_xticks(x[::5])
axes[1].set_yticks(y_ticks[::5])
axes[1].set_xticklabels(x_ticks_label[::5])
# 2.2 添加网格显示
# plt.grid(True, linestyle="--", alpha=1)
axes[0].grid(True, linestyle="--", alpha=1)
axes[1].grid(True, linestyle="--", alpha=1)
# 2.3 添加描述信息
# plt.xlabel("时间")
# plt.ylabel("温度")
# plt.title("中午11点-12点某城市温度变化图", fontsize=20)
axes[0].set_xlabel("时间")
axes[0].set_ylabel("温度")
axes[0].set_title("中午11点-12点某城市温度变化图", fontsize=20)
axes[1].set_xlabel("时间")
axes[1].set_ylabel("温度")
axes[1].set_title("中午11点-12点某城市温度变化图", fontsize=20)
# 2.4 图像保存
plt.savefig("./test.png")
# 2.5 显示图例
# plt.legend(loc=0)
axes[0].legend(loc=0)
axes[1].legend(loc=0)
# 3.图像显示
plt.show()

与其他工具集成
numpy
numpy: 用于生成数据
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(-1, 1, 50)
y = x**2
plt.plot(x, y)
plt.xlabel("x")
plt.ylabel("y")
plt.title("y=x^2")
plt.show()

seaborn
热力图是一种使用颜色的深浅来显示数值大小的图表,通常用于展示矩阵数据,非常适合展示多个变量之间的关系或者数据的模式。在Python中,我们通常使用seaborn库来绘制热力图,因为它提供了更好的接口和视觉效果。
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
from pylab import mpl
# 设置中文显示
mpl.rcParams["font.sans-serif"] = ["SimHei"]
mpl.rcParams["axes.unicode_minus"] = False
# 生成示例数据
np.random.seed(42)
data = np.random.rand(10, 10)
# 创建画布
plt.figure(figsize=(10, 8))
# 绘制热力图
sns.heatmap(data,
annot=True, # 显示数值
fmt='.2f', # 数值格式
cmap='YlOrRd', # 颜色映射
cbar=True) # 显示颜色条
plt.title('基础热力图示例')
plt.show()

- 相关性热力图
import pandas as pd
import seaborn as sns
import numpy as np
# 生成示例数据
np.random.seed(42)
df = pd.DataFrame(np.random.randn(100, 5),
columns=['A', 'B', 'C', 'D', 'E'])
# 计算相关系数矩阵
corr = df.corr()
# 创建画布
plt.figure(figsize=(10, 8))
# 绘制相关性热力图
sns.heatmap(corr,
annot=True, # 显示数值
cmap='coolwarm', # 使用红蓝对比色
center=0, # 将颜色中心设为0
square=True, # 保持方形
fmt='.2f', # 数值格式
mask=np.triu(corr)) # 只显示下三角
plt.title('相关性热力图')
plt.show()

- 带聚类的热力图
import seaborn as sns
import numpy as np
# 生成示例数据
np.random.seed(42)
data = np.random.randn(20, 20)
# 创建画布
plt.figure(figsize=(12, 10))
# 绘制带聚类的热力图
sns.clustermap(data,
cmap='vlag',
center=0,
standard_scale=1, # 标准化
dendrogram_ratio=0.1, # 聚类树的比例
annot=True,
fmt='.2f')
plt.title('带聚类的热力图')
plt.show()

plotly
Matplotlib适合:
- 生成静态图表用于论文或报告
- 需要精确控制图表细节
- 生成高质量的出版物图表
- 与其他科学计算库(如numpy, scipy)配合使用
Plotly适合:
- 创建交互式数据可视化
- 构建Web应用的数据展示
- 需要用户交互的数据探索
- 制作数据仪表板