python入门系列二十六(matplotlib数据可视化神器)

48 阅读5分钟

1.引言

在数据分析应用场景,当我们想要知道数据的分布,或者结果展示,一堆堆数字是不那么优美的!图形化展示多好!这个时候,可以考虑选择matplotlib库,matplotlib库是python最著名的2D绘图库,应用场景非常丰富。比如:

  • 数据探索与可视化呈现
  • 报表图表制作
  • 交互式数据分析
  • 机器学习深度学习结果展示

等等。在绘图应用场景,matplotlib库提供了相关核心组件。

  • 画布(顶层容器):Figure
  • 子图(坐标系区域):Axes
  • 标尺(坐标轴):Axis
  • 绘画元素(所有可见元素):Artist

今天,我们通过一篇文章完成matplotlib库的全面入门。开始吧!

2.案例

2.1.环境准备

使用matplotlib库,需要安装

pip install matplotlib

# 标准导入方式
import matplotlib.pyplot as plt

如上环境准备好,即可以愉快的使用了。

2.2.直观体验

在进一步学习使用前,先来一个案例直观感受一下。案例场景画一幅正弦曲线图。

准备数据:

import numpy as np

# 生成数字序列数据,以及求取相应的正弦值
x = np.linspace(0, 2*np.pi, 10)
y = np.sin(x)

print(f"x轴序列值:{x}")
print(f"y轴序列值:{y}")

image.png

针对上述序列值:x,y来绘制曲线

import numpy as np

# 生成数字序列数据,以及求取相应的正弦值
x = np.linspace(0, 2*np.pi, 10)
y = np.sin(x)

print(f"x轴序列值:{x}")
print(f"y轴序列值:{y}")

import matplotlib.pyplot as plt
# 显示中文设置(解决中文乱码)
plt.rcParams['font.sans-serif'] = ['SimHei']  # 微软雅黑
plt.rcParams['axes.unicode_minus'] = False   # 解决负号显示

# 创建图形
plt.figure(figsize=(6,3))  # 设置画布尺寸

# 绘制曲线
plt.plot(x, y,
         color='red',
         linestyle='--',
         linewidth=2,
         marker='o',
         markersize=5,
         label='正弦曲线')

# 添加装饰
plt.title("基本正弦曲线图")   # 标题
plt.xlabel("X轴")           # X轴标签
plt.ylabel("Y轴")           # Y轴标签
plt.grid(True)              # 显示网格
plt.legend()                # 显示图例

# 显示图形
plt.show()

image.png

2.3.基础图表类型

在实际应用中,基于不同的需求场景目标,需要不同类型的图表来做展示,如何选择?

  • 趋势分析:折线图
  • 相关性分析:散点图
  • 分类比较:柱状图
  • 比例分析:饼图

以上是常用场景以及相应的图表类型,我们来各看一个案例。

2.3.1.折线图(plot)

import numpy as np
import matplotlib.pyplot as plt
# 显示中文设置(解决中文乱码)
plt.rcParams['font.sans-serif'] = ['SimHei']  # 微软雅黑
plt.rcParams['axes.unicode_minus'] = False   # 解决负号显示

# 生成股票模拟数据
days = np.arange(1, 31)
price = 50 + np.cumsum(np.random.randn(30))
print(f"x轴:{days}")
print(f"y轴:{price}")

plt.figure(figsize=(10,5))
plt.plot(days, price,
        color='steelblue',
        marker='D',
        label='每日收盘价')

plt.title("股票价格趋势分析")
plt.xlabel("交易日")
plt.ylabel("价格(人民币)")
plt.legend()
plt.show()

数据:

image.png

图表:

image.png

2.3.2.散点图(scatter)

import numpy as np
import matplotlib.pyplot as plt
# 显示中文设置(解决中文乱码)
plt.rcParams['font.sans-serif'] = ['SimHei']  # 微软雅黑
plt.rcParams['axes.unicode_minus'] = False   # 解决负号显示

# 生成身高体重数据
height = np.random.normal(170, 10, 100)
weight = 0.7*height - 50 + np.random.randn(100)*5
print(f"x轴数据:{height}")
print(f"y轴数据:{weight}")

plt.figure(figsize=(8,6))
plt.scatter(height, weight,
           c='purple',       # 颜色
           alpha=0.6,        # 透明度
           edgecolors='w',   # 边缘色
           s=50)             # 点大小

plt.title("身高体重相关性分析")
plt.xlabel("身高(cm)")
plt.ylabel("体重(kg)")
plt.grid(True)
plt.show()

数据:

image.png 图表:

image.png

2.3.3.柱状图(bar)

import numpy as np
import matplotlib.pyplot as plt
# 显示中文设置(解决中文乱码)
plt.rcParams['font.sans-serif'] = ['SimHei']  # 微软雅黑
plt.rcParams['axes.unicode_minus'] = False   # 解决负号显示

# 销售数据
products = ['手机', '笔记本', '平板', '耳机']
sales = [235, 180, 92, 156]

plt.figure(figsize=(6,3))
bars = plt.bar(products, sales,
              color=['#2ecc71','#3498db','#e74c3c','#f1c40f'],
              edgecolor='black')

# 添加数据标签
for bar in bars:
    height = bar.get_height()
    plt.text(bar.get_x() + bar.get_width()/2., height,
             f'{height}',
             ha='center', va='bottom')

plt.title("季度产品销量对比")
plt.ylabel("销量(万台)")
plt.ylim(0, 250)
plt.show()

image.png

2.3.4.饼图(pie)

import numpy as np
import matplotlib.pyplot as plt
# 显示中文设置(解决中文乱码)
plt.rcParams['font.sans-serif'] = ['SimHei']  # 微软雅黑
plt.rcParams['axes.unicode_minus'] = False   # 解决负号显示

# 市场份额数据
labels = ['苹果', '三星', '华为', '其他']
sizes = [45, 25, 20, 10]
explode = (0.1, 0, 0, 0)  # 突出显示第一块

plt.figure(figsize=(6,6))
plt.pie(sizes,
       explode=explode,
       labels=labels,
       autopct='%1.1f%%',
       startangle=90,
       shadow=True,
       colors=['#ff9999','#66b3ff','#99ff99','#ffcc99'])

plt.title("智能手机市场份额")
plt.show()

image.png

2.4.图表美化

2.4.1.样式定制

我们可以根据需要,对图表进行相应样式定制。比如

# 使用预置样式
plt.style.use('ggplot')

# 自定义样式
plt.rcParams.update({
    'font.size': 12,
    'axes.titlesize': 16,
    'axes.labelsize': 14,
    'xtick.labelsize': 10,
    'ytick.labelsize': 10,
    'figure.figsize': (10,6)
})

2.4.2.多子图布局

在一块画布上展示多个子类型图表

import numpy as np
import matplotlib.pyplot as plt
# 显示中文设置(解决中文乱码)
plt.rcParams['font.sans-serif'] = ['SimHei']  # 微软雅黑
plt.rcParams['axes.unicode_minus'] = False   # 解决负号显示

fig, axs = plt.subplots(2, 2, figsize=(13,8))

# 子图1:折线图
x = np.linspace(0, 2*np.pi, 10)
y = np.sin(x)
axs[0,0].plot(x, np.sin(x), 'r--')
axs[0,0].set_title('正弦曲线')

# 子图2:散点图
axs[0,1].scatter(np.random.rand(50), np.random.rand(50))
axs[0,1].set_title('随机散点')

# 子图3:柱状图
axs[1,0].bar(['A','B','C'], [3,7,5])
axs[1,0].set_title('分类比较')

# 子图4:饼图
axs[1,1].pie([30,20,50], labels=['X','Y','Z'])
axs[1,1].set_title('比例分布')

plt.tight_layout()  # 自动调整间距
plt.show()

image.png

2.4.3.绘制3D图

import numpy as np
import matplotlib.pyplot as plt
# 显示中文设置(解决中文乱码)
plt.rcParams['font.sans-serif'] = ['SimHei']  # 微软雅黑
plt.rcParams['axes.unicode_minus'] = False   # 解决负号显示

fig = plt.figure(figsize=(10,7))
ax = fig.add_subplot(111, projection='3d')

# 生成数据
x = np.linspace(-5,5,100)
y = np.linspace(-5,5,100)
X,Y = np.meshgrid(x,y)
Z = np.sin(np.sqrt(X**2 + Y**2))

# 绘制曲面
surf = ax.plot_surface(X,Y,Z, cmap='viridis')

# 添加颜色条
fig.colorbar(surf, shrink=0.5, aspect=5)

ax.set_title("3D曲面图")
ax.set_xlabel("X轴")
ax.set_ylabel("Y轴")
ax.set_zlabel("Z轴")
plt.show()

image.png

2.5.实战案例

通过折线图,柱状图混合模拟之前新冠疫情发展态势,更好的做好疫情监控。

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

# 模拟疫情数据
dates = pd.date_range('2023-01-01', periods=30)
data = {
    '日期': dates,
    '新增确诊': np.random.randint(100,500,30),
    '治愈人数': np.random.randint(80,400,30),
    '死亡人数': np.random.randint(0,20,30)
}
df = pd.DataFrame(data)
df['累计确诊'] = df['新增确诊'].cumsum()

# 显示中文设置(解决中文乱码)
plt.rcParams['font.sans-serif'] = ['SimHei']  # 微软雅黑
plt.rcParams['axes.unicode_minus'] = False   # 解决负号显示
plt.figure(figsize=(12,6))

# 绘制双轴曲线
ax1 = plt.gca()  # 获取当前坐标系
line1 = ax1.plot(df['日期'], df['累计确诊'],
                'b-', label='累计确诊')

# 创建次坐标轴
ax2 = ax1.twinx()
line2 = ax2.bar(df['日期'], df['新增确诊'],
               alpha=0.3,
               color='orange',
               label='每日新增')

# 统一图例
lines = line1 + [line2]
labels = [l.get_label() for l in lines]
ax1.legend(lines, labels, loc='upper left')

# 设置标签
ax1.set_xlabel("日期")
ax1.set_ylabel("累计确诊人数", color='b')
ax2.set_ylabel("每日新增人数", color='orange')
plt.title("新冠疫情发展趋势")
plt.xticks(rotation=45)
plt.show()

image.png