我先说说文章标题中的"够用版"啥意思,为什么这么写。
按照我个人观点,在使用Python进行数据分析时,我们有时候肯定要结合到图表去进行分析,去直观展现数据的规律和特定,那么我们肯定要做一些简单的可视化,但是呢,也不需要太过精美的图,简单的图简单到包含基本功能、看得懂就行。假如我们不会用python去绘制一些简单的图,我们可能要将数据导入到其他绘图工具(比如Excel等),然后再绘图,这太麻烦了;又假如我们很熟悉Python的各种专门绘图的库,也会用Python做很精美的图表,那当然最好,不过效率自然没有专业的绘图工具(比如Power BI、Tableau、Excel等)高,因为python写代码很费时间和精力,专业的绘图软件往往是拖拽式的,不用写代码,巨方便。我写这篇文章呢,就是保证我们能够用python做简单的可视化图表,但是不会很深入学习,都是常见的图表,所以说我才说"够用"哈。当然了,个人观点,谨慎采纳。
还有就是,本文只讲matplotlib库,不讲别的绘图相关的库,因为matplotlib太实用了。
目录
[1.1 单个折线图](#1.1 单个折线图)
[1.2 多个折线(在同一张图,且同一纵轴)](#1.2 多个折线(在同一张图,且同一纵轴))
[1.3 "双纵坐标"折线图](#1.3 “双纵坐标”折线图)
[1.4 带数据标记的折线图](#1.4 带数据标记的折线图)
[3.1 简单的散点图](#3.1 简单的散点图)
[3.2 带数据标记的散点图](#3.2 带数据标记的散点图)
[4.1 带数据标记的柱状图](#4.1 带数据标记的柱状图)
[4.2 并列柱状图(带数据标记)](#4.2 并列柱状图(带数据标记))
[4.3 堆积柱状图](#4.3 堆积柱状图)
一、基本概念
1、matplotlib图表元素组成
图形(figure)、坐标图形(axes)、图名或标题(title)、图例(legend)、主要刻度(major tick)、次要刻度(minor tick)、主要刻度标签(major tick labe l)、次要刻度标签(minor tick label)、Y轴名(Y axis label)、X轴名(X axis label)、边框图(line)、数据标记(markers)、网格(grid)线等。
下图以及部分文本内容取自于《Python数据可视化之美:专业图表绘制指南》。
matplotlib主要包含两类元素
- 基础类:线(line)、点(maker)、文字(text)、图例(legend)、标题(title)等;
- 容器类:图形(figure)、坐标图形(axes)、坐标轴(axis)、刻度(tick)
2、层级结构
图形 (figure)→坐标图形(axes)→坐标轴(axis)→刻度(tick)
- figure对象:整个图形即是一个figure对象,也是一个容器。figure对象至少包含一个子图(也就是axis对象)。它还包含一些特殊对象,比如图名(title)等。
- axes对象:字面上理解,axes是axis(坐标轴)的复数,但它并不是指坐标轴,而是子图对象。可以这样理解,每一个子图都有X轴和Y轴,axes则用于代表这两个坐标轴所对应的一个子图对象。比如axes[0,0],表示第一个子图,而不是坐标轴,axes[0,1]表示第二个子图。
- axis对象:axis是数据轴对象,是比figure低一级的容器,主要用于控制数据轴上的刻度位置和显示数值。axis有locator和formatter两个子对象,分别用于 控制刻度位置和显示数值。
- tick对象:常见的二维直角坐标系(axes)都有两条坐标轴 (axis),横轴(X axis)和纵轴(Y axis)。每个坐标轴都包含两 个元素:刻度(容器类元素),该对象里还包含刻度本身和刻度标 签;标签(基础类元素),该对象包含的是坐标轴标签。
3、图表主要元素调整函数说明
|----------------------|-----------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------|
| 函数 | 核心参数说明 | 功能 |
| subplots() | nrows(子图的行数), ncols(子图的列数), figsize(图表大小), dpi(分辨率)、sharex、sharey(子图之间是否共享坐标轴,布尔类型) | 用于创建一个或多个子图(通过设置nrows、ncols实现),返回值为Figure对象(用于控制整个图形)和包含多个子图的Axes对象(对象用于控制每个子图) |
| figure() | figsize(图表大小)、dpi(分辨率)、facecolor(背景色)、edgecolor | 设置图表大小、分辨率 |
| title() | str(图名)、fontsize、color | 设置标题 |
| xlabel() ylabel() | xlabel(x轴名称)、ylabel(y轴名称)、rotation(设置标签显示方向,取值为0或1) | 设置x、y坐标轴名称 |
| axis() xlim() ylim() | xmin、xmax 或 ymin、ymax | 设置x、y轴的范围 |
| xticks() yticks() | ticks(刻度数值)、labels(刻度名称)、fontdict | 设置x、y轴的刻度大小 |
| grid() | b(有无网格线)、which(主/次网格线)、axis(x、y轴网格线,取值主要有'x'、'y'、'both')、color、linestyle、linewidth、alpha(透明度) | 设置x、y轴的主/次网格线 |
| legend() | loc(大致位置,比如左上角)、bbox_to_anchor(图例的锚点具体坐标位置) | 控制图例显示 |
4、常见二维图表的绘制函数
|-----------|-----------------------------------------------------------------------------------------------------------------------------------|-------------|
| 函数 | 主要参数说明 | 图表类型 |
| plot() | x、y、color、linewidth、marker(标记类型)、markersize(标记大小、label(线条标签)、markerfacecolor(标记填充色) | 折线图、带标记的折线图 |
| scatter() | x、y、s(散点图大小)、color、marker(散点类型)、markerfacecolor(标记填充色) | 散点图、气泡图 |
| bar() | x、y、width、align(柱形位置)、color、edgecolor(柱子边框颜色) | 柱状图、堆积柱状图 |
| pie() | x、colors(要求颜色列表)、labels(标签)、autopct(百分比文本的格式)、labeldistance(控制标签的位置,默认值为1.1)、pctdistance(控制百分比标签距离饼图中心的距离,默认值0.6)、radius(控制饼图的半径) | 饼图 |
| hist() | x、bins(箱数)、range(设定直方图的x轴的最小值和最大值)、density(是否为频率统计)、align(柱形位置)、label(标签)、color、edgecolor | 统计直方图 |
| boxplot() | x、notch(有无凹槽)、sym(散点类型)、vert(水平或竖直方向,布尔型)、widths、labels(标签)、patch_artist(是否填充箱体颜色) | 箱型图 |
| text() | x、y、s(设置标记值字符串)、ha(水平对齐)、va(垂直对齐)、fontsize | 给图形生成数据标记 |
5、函数常用参数取值说明
部分的参数的取值说明:
|------------------|------------------------|---------|-----------------------------------------------------------------------|
| 参数 | 作用 | 取值类型 | 取值 |
| figsize | 设置图形大小 | 二维数值元组型 | 形如(1,1)、(1,1)等 |
| dip | 设置图形分辨率 | 数值型 | |
| fontsize | 设置字体大小 | 数值型 | |
| linestyle | 设置线(网格线、折线等)的类型 | 字符串 | 实线(' - ')、虚线(' -- ')、点线(' : ')、点划线(' -. ') |
| marker | 设置数据点的标记样式 | 字符串 | 圆点(o)、方块(s,square)、上三角(^)、菱形(D, diamond)、星状(*)等 |
| alpha | 设置透明度 | 浮点型 | 取值范围为 0(完全透明)到 1(完全不透明) |
| xlim、ylim | 设置 X 、Y 轴范围 | 数值型元组 | 形如 (0, 10)
、(-5, 5)
等 |
| xticks、yticks | 标记 X 、Y 轴刻度位置 | 数值型列表 | 形如 [0, 2, 4, 6, 8]
|
| loc | 设置图例位置 | 字符串 | 'upper right'
、'lower left'
、'best'
等 |
| bbox_to_anchor
| 设置图例的锚点位置 | 数值型元组 | 形如 (1.05, 1)
|
| align | 控制条形图或箱线图的对齐方式 | 字符串 | 'center'
(默认,居中对齐)、'edge'
(沿边缘对齐)、None
(并排放置) |
| vert | 是否将箱线图垂直摆放 | 布尔值 | True
(默认,垂直摆放)、False
(水平摆放) |
| sym | 指定箱线图中异常点的形状 | 字符串 | 默认为 '+'
(加号),也可以是其他标记符号(如 'o'
、'*'
、'r^'
等) |
| va | 控制文本的垂直对齐方式 | 字符串 | 'center'
(默认,居中对齐)、'top'
(顶部对齐)、'bottom'
(底部对齐)、'baseline'
(基线对齐) |
| ha | 控制文本的水平对齐方式 | 字符串 | 'center'
(默认,居中对齐)、'left'
(左对齐)、'right'
(右对齐) |
| rotation | 设置标签显示方向(竖直或水平) | 数值型 | 取值为0或1 |
| autopct | 自动计算饼图每个扇形的百分比,要设置显示格式 | 字符串 | 只显示一位小数百分比:'%1.1f%%' |
二、常见图表绘制演示
进行可视化前,除了导入必要的库以外,还需要设置中文字体,避免图形中显示中文字体时出现乱码的情况。
python
import pandas as pd
import matplotlib.pyplot as plt
# 设置字体,避免图形中显示中文字体时出现乱码
plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']
# 创建示例数据
data = {
'Category': ['A', 'B', 'C', 'D', 'E'],
'Value1': [10, 20, 35, 50, 100],
'Value2': [5, 15, 18, 35, 45],
'Value3': [12, 22, 17, 27, 32],
'index1': [2, 4, 6, 8, 10]
}
df = pd.DataFrame(data)
++注:后面所有代码都包含上述代码++。
(一)折线图
1.1 单个折线图
需要注意的是,plt.plot()并不接受x和y作为关键字参数,只接受位置参数,因此,"x=df['index1'], y=df['Value1']"这样写会报错。
python
# 折线图
plt.plot(df['index1'], df['Value1'], linestyle='-', label='v1') # 注意要使用位置参数传入x、y
plt.title('示例1')
plt.legend() # 显示图例'v1'
plt.show()
如果需要调横坐标或纵坐标的刻度范围,可以使用plt.xlim([xmin, xmax])、plt.ylim([ymin, ymax])或plt.axis([xmin, xmax, ymin, ymax]),其中plt.axis()可以一次性修改x、y坐标的刻度范围,演示如下:
python
# 折线图
plt.plot(df['index1'], df['Value1'], label='v1')
# y轴坐标刻度范围改为[0, 200]
plt.ylim([0,200])
plt.title('示例1')
plt.legend(loc='upper left') # 显示图例'v1'
plt.show()
如果,需要在y轴刻度上显示出75、180、200的点位,并将该点标记为A、B、'200'这三个刻度标签,则可以使用plt.yticks()方法。注意的是,其中的ticks参数的数值只能是y坐标轴的刻度范围内的值(比如示例的y坐标刻度范围是0~200,则ticks参数里的值不能大于200),演示如下:
python
# 折线图
plt.plot(df['index1'], df['Value1'], label='v1')
# y轴坐标刻度范围改为[0, 200]
plt.ylim([0,200])
# 显示y坐标轴的特定点位
plt.yticks(ticks=[77, 100, 200], labels=['A', 'B','200'])
plt.title('示例1')
plt.legend(loc='upper left') # 显示图例'v1'
plt.show()
1.2 多个折线(在同一张图,且同一纵轴)
python
plt.plot(df['index1'], df['Value1'], label='v1') # 绘制 Value1 对应的折线
plt.plot(df['index1'], df['Value2'], label='v2') # 绘制 Value2 对应的折线
plt.title('示例2')
plt.legend(loc='best') # 显示图例'v1'和'v2'
plt.show()
1.3 "双纵坐标"折线图
有时候两条折线的的纵坐标尺度相差太大,导致另一条在该统一的y轴刻度范围变化幅度不大,甚至显示成了一条直线。可以使用"双纵坐标轴"绘制,演示如下:
python
# 创建一个含1*1张子图的图形。看不懂这行代码可以先忽略,后面会讲到。
fig, ax1 = plt.subplots(1, 1, figsize=(8,5)) # 设置图形窗口(即容器)的大小为5*8
ax1.plot(df['index1'], df['Value1'], label='v1') # 绘制 Value1 对应的折线
# 创建ax1子图第二个纵坐标轴 ax2
ax2 = ax1.twinx()
ax2.plot(df['index1'], df['Value2'], label='v2', color='red') # 绘制 Value2 对应的折线
ax1.set_title('示例2')
ax1.legend(loc='upper left') # 显示图例'v1'
ax2.legend(loc='upper left', bbox_to_anchor=(0,0.9)) # 显示图例'v2',并设置具体位置,避免与'v1'位置重叠而只显示一个图例
plt.show()
1.4 带数据标记的折线图
演示如下:
python
# 绘制添加标记线
plt.plot(df['index1'], df['Value1'], linestyle='-', marker='*', label='v1', markersize=10)
# 绘制不带标记的线
plt.plot(df['index1'], df['Value2'], linestyle='--', marker=None, label='v2')
# 添加数据值标记
for i in range(len(df)):
plt.text(df['index1'][i], df['Value1'][i], s=str(df['Value1'][i]), ha='center', va='bottom', fontsize=12) # 显示数据值
plt.title('带数据标记的折线图')
plt.legend() # 显示图例'v1'
plt.grid(True, axis='both', alpha=0.3) #显示网格线
plt.show()
(二)在一个图形(figure)中绘制多张子图
图形(figure)作为一个容器,包含大标题和子图(至少一张)等元素,而其子图又含有子图自己的元素(如子图的标题,子图的横纵坐标,子图的图例等)。下面演示如何在一个图形(figure)中绘制多张子图,来理解这些概念。
python
# 创建一个含2*2张子图的图形fig。其每张子图(对象)用ax1[0,0],ax1[0,1],...表示。若只有一张图,可以直接用ax1表示子图。
fig, ax1 = plt.subplots(2, 2, figsize=(10,9)) # 设置图形(即容器)的大小为9*10
# 设置图形分辨率、可忽略
fig.dpi = 100
# 绘制子图1,柱状图
ax1[0,0].bar(df['index1'], df['Value1'], label='v1')
ax1[0,0].set_title('图1', color='red')
ax1[0,0].legend()
ax1[0,0].set_xlabel('index1')
ax1[0,0].set_ylabel('Value1')
# 绘制子图4,折线图
ax1[1,1].plot(df['index1'], df['Value1'], label='v1')
ax1[1,1].plot(df['index1'], df['Value2'], label='v2')
ax1[1,1].set_title('图4', color='red')
ax1[1,1].legend()
ax1[1,1].set_xlabel('index1')
ax1[1,1].set_ylabel('y 值')
# 图2、图3我就不绘制了。图1、图4做了演示。
fig.suptitle('总标题', color='green', fontsize=20) # 设置总标题
fig.tight_layout() # 自动调整子图的布局,使得元素之间不会重叠
plt.show()
(三)散点图
3.1 简单的散点图
python
plt.scatter(df['index1'], df['Value1'], color='green', label='v1')
plt.scatter(df['index1'], df['Value2'], color='red', label='v2')
plt.title('散点图', color='blue')
plt.xlabel('index1')
plt.ylabel('value')
plt.legend() # 显示图例
plt.show()
3.2 带数据标记的散点图
python
plt.scatter(df['index1'], df['Value1'], color='green', label='v1', marker='^')
plt.scatter(df['index1'], df['Value2'], color='red', label='v2')
# 使用text()添加给'Value1'标记数值
for i in range(len(df)):
plt.text(df['index1'][i], df['Value1'][i], s=str(df['Value1'][i]), ha='center', va='bottom')
# 使用text()添加给'Value2'标记数值
for i in range(len(df)):
plt.text(df['index1'][i], df['Value2'][i], s=str(df['Value2'][i]), ha='center', va='bottom')
plt.title('带数据标记的散点图', color='blue')
plt.xlabel('index1')
plt.ylabel('value', rotation=1)
plt.legend() # 显示图例
plt.show()
(四)柱状图(竖直型)
水平柱状图就不做演示了,因为我觉得平时用python进行数据分析时,用竖直型就够了,避免与竖直型的代码搞混淆,真要用到水平柱状图可以用其他工具(比如Excel或其他专业绘图工具)。
4.1 带数据标记的柱状图
python
plt.bar(df['Category'], df['Value1'], width=0.5, label='v1', color='red')
plt.title('简单的柱状图')
plt.xlabel('类别', fontsize=9)
plt.ylabel('value', fontsize=9, rotation=1)
plt.legend(loc='upper left')
plt.show()
4.2 并列柱状图(带数据标记)
也叫分组柱状图。在同一个坐标系中绘制多组数据时,可以通过多次调用 plt.bar()
,并调整每组柱状图的位置,以避免它们重叠。通常,我们会通过偏移每组柱子的位置来实现并排显示。
关键步骤:
-
计算柱子的位置(难点):每组类别的 x 轴坐标需要调整,使得三根柱子能够并排显示。
-
设置柱子的宽度:确保柱子不会重叠,并留有适当间距。
-
绘制多个柱状图:使用
plt.bar()
分别绘制每一组柱子,并调整它们的 x 轴位置。
两组数据示例(带数据标记):
python
import numpy as np
# 定义柱子的宽度
width=0.4
# 获取规律的x坐标,用于设置柱子的位置
x = np.arange(len(df)) # 输出[0, 1, 2, 3, 4]
# 绘制两组柱状图
bar1 = plt.bar(x-width/2, df['Value1'], width=width, label='v1类', color='orange', edgecolor='black') # 左移width/2。其中x-width/2为每根柱子底部中心点的横坐标
bar2 = plt.bar(x+width/2, df['Value2'], width=width, label='v2类', color='skyblue', edgecolor='black') # 右移width/2。其中x+width/2为每根柱子底部中心点的横坐标
# 这里有点特别,bar.get_x()获取的是每根柱子底部左下角的横坐标,而不是中心点了。
# 给bar1添加数据标记
for bar in bar1:
plt.text(bar.get_x()+bar.get_width()/2, bar.get_height(), s=str(bar.get_height()), ha='center', va='bottom')
# 给bar2添加数据标记
for bar in bar2:
plt.text(bar.get_x()+bar.get_width()/2, bar.get_height(), s=str(bar.get_height()), ha='center', va='bottom')
# 将中心坐标标签由[0, 1, 2, 3, 4]更改为['A', 'B', 'C', 'D', 'E']
plt.xticks(ticks=x, labels=df['Category'])
plt.grid(axis='y', linestyle='--', alpha=0.5) # 显示网格线
plt.title('两组柱状图(带数据标记)', fontsize=13)
plt.ylabel('value值', rotation=1)
plt.xlabel('类别')
plt.legend(loc='upper left')
plt.show()
三组数据(带数据标记),难点也是在于计算柱子的坐标,示例:
python
import numpy as np
plt.figure(figsize=(10, 5))
x = np.arange(len(df))
width = 0.25
bar1 = plt.bar(x-width, df['Value1'], width=width, label='v1', color='skyblue', edgecolor='black') # 左移width
bar2 = plt.bar(x, df['Value2'], width=width, label='v2', color='red', edgecolor='black') # 不偏移
bar3 = plt.bar(x+width, df['Value3'], width=width, label='v3', color='orange', edgecolor='black') # 右移width
for bar in bar1:
plt.text(bar.get_x()+width/2, bar.get_height(), s=str(bar.get_height()), va='bottom', ha='center')
for bar in bar2:
plt.text(bar.get_x()+width/2, bar.get_height(), s=str(bar.get_height()), va='bottom', ha='center')
for bar in bar3:
plt.text(bar.get_x()+width/2, bar.get_height(), s=str(bar.get_height()), va='bottom', ha='center')
# 将中心坐标标签由[0, 1, 2, 3, 4]更改为['A', 'B', 'C', 'D', 'E']
plt.xticks(ticks=x, labels=df['Category'])
plt.grid(axis='y', linestyle='--', alpha=0.5) # 显示网格线
plt.title('三组柱状图(带数据标记)', fontsize=13)
plt.ylabel('value值', rotation=1)
plt.xlabel('类别')
plt.legend(loc='upper left')
plt.show()
4.3 堆积柱状图
堆积直方图的优点:
- 适用于比较多个类别在相同区间内的数量或频率。
- 通过堆叠显示每个类别的贡献,可以更直观地了解各类别在总数中的占比。
演示如下:
python
import numpy as np
x = np.arange(len(df['Category'])) # x轴位置
# 绘制第一类数据
plt.bar(x, df['Value1'], width=0.4, label='Category 1', color='b')
# 绘制第二类数据,堆积在第一类数据上(bottom参数表示当前柱子数据堆叠的起始位置,默认为0,即高度为0的位置开始绘制)
plt.bar(x, df['Value2'], width=0.4, bottom=df['Value1'], label='Category 2', color='g')
# 绘制第三类数据,堆积在前两类数据上
plt.bar(x, df['Value3'], width=0.4, bottom=df['Value1'] + df['Value2'], label='Category 3', color='r')
plt.xlabel('类别')
plt.ylabel('Value')
plt.title('堆积柱状图示例')
plt.xticks(x, labels=df['Category']) # 设置x轴标签
plt.legend()
plt.show()
(五)饼图
演示如下:
python
# pie()会自动计算df['Value1']的占比,不用手动计算
plt.pie(df['Value1'], labels=df['Category'], autopct='%0.2f%%', labeldistance=1.05)
plt.title('饼图')
plt.show()
(六)统计直方图
统计直方图主要有两种:频率(分布)直方图、概率密度直方图。
两者的区别如下:
|----------|------------------------|----------------------------------|
| 特性 | 频率直方图 | 概率密度直方图 |
| 定义 | 显示每个区间内数据的频数(数据点的数量) | 显示每个区间内数据的相对概率密度(每个柱子的总面积为 1) |
| 总面积 | 总面积(所有柱子的高度总和)等于数据点的总数 | 总面积等于 1(归一化后) |
| 计算方式 | 频数 / 区间宽度(没有归一化) | (频数 / 总数据量) / 区间宽度,即归一化 |
| 用途 | 适合展示数据集的实际分布和频数情况 | 适合展示数据的概率分布,便于进行统计分析和比较不同数据集的分布 |
| 典型应用 | 展示单一数据集的实际频数分布 | 用于概率密度估计、正态分布拟合等,需要考虑数据相对概率分布的情况 |
频率直方图:
python
import numpy as np
# 生成示例数据(1000个正态分布的数据)
data = np.random.randn(1000)
# 绘制直方图
plt.hist(data, bins=50, color='red', edgecolor='black', alpha=0.7, label='数据分布')
plt.title('频率直方图示例')
plt.xlabel('数据值')
plt.ylabel('频数')
plt.legend()
plt.show()
概率密度直方图(只要设置参数 density=True即可):
python
# 绘制归一化(概率密度)直方图
plt.hist(data, bins=30, color='skyblue', edgecolor='black', alpha=0.7, density=True, label='概率密度')
# 添加标题和标签
plt.title('归一化(概率密度)直方图示例')
plt.xlabel('数据值')
plt.ylabel('频数')
plt.legend()
plt.show()
(七)箱线图
python
import matplotlib.pyplot as plt
import numpy as np
# 生成示例数据(1000个正态分布的数据)
data = np.random.randn(1000)
plt.boxplot(data, patch_artist=True)
plt.title('箱型图示例')
plt.ylabel('数据值')
plt.show()
# 文章如有错误,欢迎大家指正,我们下期文章见。