平行坐标系,是一种含有多个垂直平行坐标轴的统计图表。
一般的剖析图表都是剖析二维的数据,而平行坐标系特别适合于剖析维度较多的数据。

比方,对于学生成果,每门学科都是一个维度,且每门学科的最高分也不一样,用单一的坐标系很难展现剖析结果。

平行坐标系的图大概是下面这样的:

Matplotlib绘制平行坐标系

多个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

假定:

  1. 语文满分 120
  2. 数学满分 150
  3. 英语满分 110
  4. 物理满分 90
  5. 化学满分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. 绘图封装

绘图的过程首要有:

  1. 设置画布
  2. 设置标题
  3. 设置各个平行的Y轴
  4. 设置X轴
  5. 在平行坐标系中制作曲线
  6. 制作图例
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()

Matplotlib绘制平行坐标系

这里为了演示,只要5条数据。
从平行坐标系的图中,能够看出,大部分物理都不错,黄色的学生E,数学偏科比较严重。

有兴趣的朋友,能够把手头的数据导入这个封装好的平行坐标系类中,看看能否从数据中发现新的东西。