使用Matplotlib绘制平行坐标系的示例详解
作者:databook
平行坐标系,是一种含有多个垂直平行坐标轴的统计图表,这篇文章主要为大家介绍了如何使用绘制平行坐标系,需要的小伙伴可以参考一下
平行坐标系,是一种含有多个垂直平行坐标轴的统计图表。
一般的分析图表都是分析二维的数据,而平行坐标系特别适合于分析维度较多的数据。
比如,对于学生成绩,每门学科都是一个维度,且每门学科的最高分也不一样,用单一的坐标系很难展示分析结果。
平行坐标系的图大概是下面这样的:
多个Y轴代表数据不同的属性(维度),每个Y轴的刻度可以是不一样的。
1. 准备示例数据
准备一些学生各个科目的成绩数据,用来分析整体学习情况以及是否有偏科的情况。
姓名 | 语文 | 数学 | 英语 | 物理 | 化学 |
---|---|---|---|---|---|
学生A | 100 | 120 | 98 | 88 | 78 |
学生B | 105 | 133 | 109 | 87 | 89 |
学生C | 80 | 112 | 87 | 90 | 95 |
学生D | 90 | 89 | 76 | 89 | 88 |
学生E | 102 | 60 | 90 | 66 | 65 |
假设:
- 语文满分 120
- 数学满分 150
- 英语满分 110
- 物理满分 90
- 化学满分100
2. 封装绘图函数
python
的绘图函数库matplotlib
中,默认没有提供绘制平行坐标系的接口。
但是,基于matplotlib
提供的绘图底层接口,也可以很容易封装一个绘制平行坐标系的类。
2.1. 属性封装
根据平行坐标系上的常用元素,封装的属性主要包括:
名称 | 类型 | 说明 |
---|---|---|
title | string 字符串 | 标题 |
x_labels | list 列表 | 每一行数据的名称,list的长度就是数据的行数 |
y_labels | list 列表 | 每一个平行的Y轴的名称,list的长度就是平行的Y轴的个数 |
y_data | list[list] 二维列表 | 数据行数就是x_labels的长度,数据的列数就是y_labels的长度 |
y_mins | list 列表 | 每个平行的Y轴的最小值 |
y_maxs | list 列表 | 每个平行的Y轴的最大值 |
class ParallelCoord: """ 平行坐标系 """ def __init__(self, title, x_labels, y_labels, y_data, y_min, y_max): self.title = title self.x_labels = x_labels self.y_labels = y_labels self.y_data = y_data self.y_min = y_min self.y_max = y_max
2.2. 绘图封装
绘图的步骤主要有:
- 设置画布
- 设置标题
- 设置各个平行的Y轴
- 设置X轴
- 在平行坐标系中绘制曲线
- 绘制图例
import matplotlib.pyplot as plt from matplotlib.path import Path import matplotlib.patches as patches import numpy as np class ParallelCoord: """ 平行坐标系 """ def __init__(self, title, x_labels, y_labels, y_data, y_mins, y_maxs): self.title = title self.x_labels = x_labels self.y_labels = y_labels self.y_data = y_data self.y_mins = y_mins self.y_maxs = y_maxs def draw(self): # 1. 设置画布 fig, host = plt.subplots(figsize=(10, 4)) # 2. 设置标题 host.set_title(self.title, fontsize=18, pad=12) # 3. 设置各个平行的Y轴 # 每个坐标系的上下限不一样,调整显示方式 dys = np.array(self.y_maxs) - np.array(self.y_mins) zs = np.zeros_like(self.y_data) zs[:, 0] = self.y_data[:, 0] zs[:, 1:] = (self.y_data[:, 1:] - self.y_mins[1:]) / dys[1:] * dys[ 0 ] + self.y_mins[0] axes = [host] + [host.twinx() for i in range(len(self.y_labels) - 1)] for i, ax in enumerate(axes): ax.set_ylim(self.y_mins[i], self.y_maxs[i]) ax.spines["top"].set_visible(False) ax.spines["bottom"].set_visible(False) if ax != host: ax.spines["left"].set_visible(False) ax.yaxis.set_ticks_position("right") ax.spines["right"].set_position(("axes", i / (len(self.y_labels) - 1))) # 4. 设置X轴 host.set_xlim(0, len(self.y_labels) - 1) host.set_xticks(range(len(self.y_labels))) host.set_xticklabels(self.y_labels, fontsize=14) host.tick_params(axis="x", which="major", pad=7) host.spines["right"].set_visible(False) host.xaxis.tick_top() # 5. 在平行坐标系中绘制曲线 colors = plt.cm.Set1.colors legend_handles = [None for _ in self.x_labels] for j in range(len(self.x_labels)): verts = list( zip( [ x for x in np.linspace( 0, len(self.y_data) - 1, len(self.y_data) * 3 - 2, endpoint=True, ) ], np.repeat(zs[j, :], 3)[1:-1], ) ) codes = [Path.MOVETO] + [Path.CURVE4 for _ in range(len(verts) - 1)] path = Path(verts, codes) patch = patches.PathPatch( path, facecolor="none", lw=2, alpha=0.7, edgecolor=colors[j] ) legend_handles[j] = patch host.add_patch(patch) # 6. 绘制图例 host.legend( self.x_labels, loc="lower center", bbox_to_anchor=(0.5, -0.18), ncol=len(self.x_labels), fancybox=True, shadow=True, ) # 显示图形 plt.tight_layout() plt.show()
3. 绘制效果
封装好函数之后,绘制起来就很简单了。
#根据示例数据设置变量 title = "学生各科成绩" x_labels = ["学生A", "学生B", "学生C", "学生D", "学生E"] y_labels = ["语文", "数学", "英语", "物理", "化学"] y_data = np.array( [ [100, 120, 98, 88, 78], [105, 133, 109, 87, 89], [80, 112, 87, 90, 95], [90, 89, 76, 89, 88], [102, 60, 90, 66, 65], ] ) y_mins = [0, 0, 0, 0, 0] y_maxs = [120, 150, 110, 90, 100] #绘制 pc = ParallelCoord(title, x_labels, y_labels, y_data, y_mins, y_maxs) pc.draw()
这里为了演示,只有5条数据。
从平行坐标系的图中,可以看出,大部分物理都不错,黄色的学生E,数学偏科比较严重。
有兴趣的朋友,可以把手头的数据导入这个封装好的平行坐标系类中,看看能否从数据中发现新的东西。
到此这篇关于使用Matplotlib绘制平行坐标系的示例详解的文章就介绍到这了,更多相关Matplotlib绘制平行坐标系内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!