使用Matplotlib繪制平行坐標系的示例詳解
平行坐標系,是一種含有多個垂直平行坐標軸的統(tǒng)計圖表。
一般的分析圖表都是分析二維的數(shù)據(jù),而平行坐標系特別適合于分析維度較多的數(shù)據(jù)。
比如,對于學(xué)生成績,每門學(xué)科都是一個維度,且每門學(xué)科的最高分也不一樣,用單一的坐標系很難展示分析結(jié)果。
平行坐標系的圖大概是下面這樣的:
多個Y軸代表數(shù)據(jù)不同的屬性(維度),每個Y軸的刻度可以是不一樣的。
1. 準備示例數(shù)據(jù)
準備一些學(xué)生各個科目的成績數(shù)據(jù),用來分析整體學(xué)習(xí)情況以及是否有偏科的情況。
姓名 | 語文 | 數(shù)學(xué) | 英語 | 物理 | 化學(xué) |
---|---|---|---|---|---|
學(xué)生A | 100 | 120 | 98 | 88 | 78 |
學(xué)生B | 105 | 133 | 109 | 87 | 89 |
學(xué)生C | 80 | 112 | 87 | 90 | 95 |
學(xué)生D | 90 | 89 | 76 | 89 | 88 |
學(xué)生E | 102 | 60 | 90 | 66 | 65 |
假設(shè):
- 語文滿分 120
- 數(shù)學(xué)滿分 150
- 英語滿分 110
- 物理滿分 90
- 化學(xué)滿分100
2. 封裝繪圖函數(shù)
python
的繪圖函數(shù)庫matplotlib
中,默認沒有提供繪制平行坐標系的接口。
但是,基于matplotlib
提供的繪圖底層接口,也可以很容易封裝一個繪制平行坐標系的類。
2.1. 屬性封裝
根據(jù)平行坐標系上的常用元素,封裝的屬性主要包括:
名稱 | 類型 | 說明 |
---|---|---|
title | string 字符串 | 標題 |
x_labels | list 列表 | 每一行數(shù)據(jù)的名稱,list的長度就是數(shù)據(jù)的行數(shù) |
y_labels | list 列表 | 每一個平行的Y軸的名稱,list的長度就是平行的Y軸的個數(shù) |
y_data | list[list] 二維列表 | 數(shù)據(jù)行數(shù)就是x_labels的長度,數(shù)據(jù)的列數(shù)就是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. 繪圖封裝
繪圖的步驟主要有:
- 設(shè)置畫布
- 設(shè)置標題
- 設(shè)置各個平行的Y軸
- 設(shè)置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. 設(shè)置畫布 fig, host = plt.subplots(figsize=(10, 4)) # 2. 設(shè)置標題 host.set_title(self.title, fontsize=18, pad=12) # 3. 設(shè)置各個平行的Y軸 # 每個坐標系的上下限不一樣,調(diào)整顯示方式 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. 設(shè)置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. 繪制效果
封裝好函數(shù)之后,繪制起來就很簡單了。
#根據(jù)示例數(shù)據(jù)設(shè)置變量 title = "學(xué)生各科成績" x_labels = ["學(xué)生A", "學(xué)生B", "學(xué)生C", "學(xué)生D", "學(xué)生E"] y_labels = ["語文", "數(shù)學(xué)", "英語", "物理", "化學(xué)"] 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條數(shù)據(jù)。
從平行坐標系的圖中,可以看出,大部分物理都不錯,黃色的學(xué)生E,數(shù)學(xué)偏科比較嚴重。
有興趣的朋友,可以把手頭的數(shù)據(jù)導(dǎo)入這個封裝好的平行坐標系類中,看看能否從數(shù)據(jù)中發(fā)現(xiàn)新的東西。
到此這篇關(guān)于使用Matplotlib繪制平行坐標系的示例詳解的文章就介紹到這了,更多相關(guān)Matplotlib繪制平行坐標系內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
python庫geopy計算多組經(jīng)緯度距離的實現(xiàn)方式
這篇文章主要介紹了python庫geopy計算多組經(jīng)緯度距離的實現(xiàn)方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-08-08關(guān)于Python八大排序?qū)崿F(xiàn)方法(冒泡排序、快速排序等)
這篇文章主要介紹了關(guān)于Python八大排序?qū)崿F(xiàn)方法,主要有基數(shù)排序、歸并排序、堆排序、簡單選擇排序、直接插入排序、希爾排序、快速排序、冒泡排序等,需要的朋友可以參考下2023-03-03基于Python實現(xiàn)簡易文檔格式轉(zhuǎn)換器
這篇文章主要介紹了基于Python和PyQT5實現(xiàn)簡易的文檔格式轉(zhuǎn)換器,支持.txt/.xlsx/.csv格式的轉(zhuǎn)換。感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2021-12-12Python用 KNN 進行驗證碼識別的實現(xiàn)方法
這篇文章主要介紹了Python用 KNN 進行驗證碼識別的相關(guān)資料,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2018-02-02