Python之Matplotlib數據可視化(三):配置顏色條(超級詳細,爆肝推薦)

圖例通過離散的標籤表示離散的圖形元素。然而,對於圖形中由彩色的點、線、面構成的連續標籤,用顏色條來表示的效果比較好。在 Matplotlib 裏面,顏色條是一個獨立的座標軸,可以指明圖形中顏色的含義。

首先導入需要使用的畫圖工具:

import matplotlib.pyplot as plt
plt.style.use('classic')
import numpy as np

一個簡易的顏色條圖例

通過 plt.colorbar 函數就可以創建最簡單的顏色條:

x = np.linspace(0, 10, 1000)
I = np.sin(x) * np.cos(x[:, np.newaxis])
plt.imshow(I)
plt.colorbar();
import matplotlib.pyplot as plt
plt.style.use('classic')
import numpy as np
x = np.linspace(0, 10, 1000)
I = np.sin(x) * np.cos(x[:, np.newaxis])
plt.imshow(I)
plt.colorbar();
plt.show()

在這裏插入圖片描述
下面將介紹一些顏色條的個性化配置方法,讓你能將它們有效地應用於不同場景中。

一個採用灰度配色方案的圖形

可以通過 cmap 參數爲圖形設置顏色條的配色方案

plt.imshow(I, cmap='gray');
import matplotlib.pyplot as plt
plt.style.use('classic')
import numpy as np
x = np.linspace(0, 10, 1000)
I = np.sin(x) * np.cos(x[:, np.newaxis])
plt.imshow(I, cmap='gray');
plt.colorbar();
plt.show()

在這裏插入圖片描述
所有可用的配色方案都在 plt.cm 命名空間裏面,在 IPython 裏通過 Tab 鍵就可以查看所有的配置方案:

plt.cm.<TAB>

有了這麼多能夠作爲備選的配色方案只是第一步,更重要的是如何確定用哪種方案!最終的選擇結果可能和你一開始想用的有很大不同。

選擇配色方案

可以參考文章“Ten Simple Rules for Better Figures”。
Matplotlib 的在線文檔中也有關於配色方案選擇的有趣論述(http://matplotlib.org/1.4.1/users/colormaps.html)。

一般情況下,你只需要重點關注三種不同的配色方案:

順序配色方案

由一組連續的顏色構成的配色方案(例如 binary 或 viridis )。

互逆配色方案

通常由兩種互補的顏色構成,表示正反兩種含義(例如 RdBu 或 PuOr )。

定性配色方案

隨機順序的一組顏色(例如 rainbow 或 jet )。

jet 配色方案與非等差的漸變亮度

jet 是一種定性配色方案,曾是 Matplotlib 2.0 之前所有版本的默認配色方案。把它作爲默認配色方案實在不是個好主意,因爲定性配色方案在對定性數據進行可視化時的選擇空間非常有限。隨着圖形亮度的提高,經常會出現顏色無法區分的問題。

可以通過把 jet 轉換爲黑白的灰度圖看看具體的顏色:

import matplotlib.pyplot as plt
plt.style.use('classic')
import numpy as np
from matplotlib.colors import LinearSegmentedColormap
def grayscale_cmap(cmap):
	"""爲配色方案顯示灰度圖"""
	cmap = plt.cm.get_cmap(cmap)
	colors = cmap(np.arange(cmap.N))
	# 將RGBA色轉換爲不同亮度的灰度值
	# 參考鏈接http://alienryderflex.com/hsp.html
	RGB_weight = [0.299, 0.587, 0.114]
	luminance = np.sqrt(np.dot(colors[:, :3] ** 2, RGB_weight))
	colors[:, :3] = luminance[:, np.newaxis]
	return LinearSegmentedColormap.from_list(cmap.name + "_gray", colors, cmap.N)

def view_colormap(cmap):
	"""用等價的灰度圖表示配色方案"""
	cmap = plt.cm.get_cmap(cmap)
	colors = cmap(np.arange(cmap.N))
	cmap = grayscale_cmap(cmap)
	grayscale = cmap(np.arange(cmap.N))
	fig, ax = plt.subplots(2, figsize=(6, 2),
	subplot_kw=dict(xticks=[], yticks=[]))
	ax[0].imshow([colors], extent=[0, 10, 0, 1])
	ax[1].imshow([grayscale], extent=[0, 10, 0, 1])

view_colormap('jet')
plt.show()

在這裏插入圖片描述
注意觀察灰度圖裏比較亮的那部分條紋。這些亮度變化不均勻的條紋在彩色圖中對應某一段彩色區間,由於色彩太接近容易突顯出數據集中不重要的部分,導致眼睛無法識別重點。

viridis 配色方案和漸變亮度 scale

更好的配色方案是 viridis (已經成爲 Matplotlib 2.0 的默認配色方案)。它採用了精心設計的亮度漸變方式,這樣不僅便於視覺觀察,而且轉換成灰度圖後也更清晰:

view_colormap('viridis')

在這裏插入圖片描述

cubehelix 配色方案和漸變亮度

如果你喜歡彩虹效果,可以用 cubehelix 配色方案來可視化連續的數值

view_colormap('cubehelix')

在這裏插入圖片描述

RdBu 配色方案和漸變亮度

至於其他的場景,例如要用兩種顏色表示正反兩種含義時,可以使用 RdBu 雙色配色方案(紅色 - 藍色,Red-Blue 簡稱)。但正如圖 所示,用紅色、藍色表示的正反兩種信息在灰度圖上看不出差別!

view_colormap('RdBu')

在這裏插入圖片描述
Matplotlib 裏面有許多配色方案,在 IPython 裏面用 Tab 鍵瀏覽 plt.cm 模塊就可以看到所有內容。關於 Python 語言中配色的更多基本原則,可以參考 Seaborn 程序庫的工具和文檔。

顏色條刻度的限制與擴展功能的設置

設置顏色條擴展屬性

Matplotlib 提供了豐富的顏色條配置功能。由於可以將顏色條本身僅看作是一個 plt.Axes實例,因此所有關於座標軸和刻度值的格式配置技巧都可以派上用場。顏色條有一些有趣的特性。例如,我們可以縮短顏色取值的上下限,對於超出上下限的數據,通過 extend 參數用三角箭頭表示比上限大的數或者比下限小的數。這種方法很簡單,比如你想展示一張噪點圖

import matplotlib.pyplot as plt
plt.style.use('classic')
import numpy as np
x = np.linspace(0, 10, 1000)
I = np.sin(x) * np.cos(x[:, np.newaxis])
# 爲圖形像素設置1%噪點
speckles = (np.random.random(I.shape) < 0.01)
I[speckles] = np.random.normal(0, 3, np.count_nonzero(speckles))
plt.figure(figsize=(10, 3.5))
plt.subplot(1, 2, 1)
plt.imshow(I, cmap='RdBu')
plt.colorbar()
plt.subplot(1, 2, 2)
plt.imshow(I, cmap='RdBu')
plt.colorbar(extend='both')
plt.clim(-1, 1);
plt.show()

在這裏插入圖片描述
左邊那幅圖是用默認的顏色條刻度限制實現的效果,噪點的範圍完全覆蓋了我們感興趣的數據。而右邊的圖形設置了顏色條的刻度上下限,並在上下限之外增加了擴展功能,這樣的數據可視化圖形顯然更有效果。

離散型顏色條

雖然顏色條默認都是連續的,但有時你可能也需要表示離散數據。最簡單的做法就是使用plt.cm.get_cmap() 函數,將適當的配色方案的名稱以及需要的區間數量傳進去即可

import matplotlib.pyplot as plt
plt.style.use('classic')
import numpy as np
x = np.linspace(0, 10, 1000)
I = np.sin(x) * np.cos(x[:, np.newaxis])
# 爲圖形像素設置1%噪點
speckles = (np.random.random(I.shape) < 0.01)
I[speckles] = np.random.normal(0, 3, np.count_nonzero(speckles))
plt.imshow(I, cmap=plt.cm.get_cmap('Blues', 6))
plt.colorbar()
plt.clim(-1, 1);
plt.show()

在這裏插入圖片描述
這種離散型顏色條和其他顏色條的用法相同。

案例:手寫數字

讓我們來看一些有趣的手寫數字可視化圖,這可能是一個比較實用的案例。數據在 Scikit-Learn 裏面,包含近 2000 份 8×8 的手寫數字縮略圖

手寫數字樣本

先下載數據,然後用 plt.imshow() 對一些圖形進行可視化:

import matplotlib.pyplot as plt
plt.style.use('classic')
# 加載數字0~5的圖形,對其進行可視化
from sklearn.datasets import load_digits
digits = load_digits(n_class=6)
fig, ax = plt.subplots(8, 8, figsize=(6, 6))
for i, axi in enumerate(ax.flat):
    axi.imshow(digits.images[i], cmap='binary')
    axi.set(xticks=[], yticks=[])
plt.show()

在這裏插入圖片描述

手寫數字像素的流形學習結果

由於每個數字都由 64 像素的色相(hue)構成,因此可以將每個數字看成是一個位於 64維空間的點,即每個維度表示一個像素的亮度。但是想通過可視化來描述如此高維度的空間是非常困難的。一種解決方案是通過降維技術,在儘量保留數據內部重要關聯性的同時降低數據的維度,例如流形學習(manifold learning)。降維是無監督學習的重要內容。

先來看看如何用流形學習將這些數據投影到二維空間進行可視化:

import matplotlib.pyplot as plt
plt.style.use('classic')
# 加載數字0~5的圖形,對其進行可視化
from sklearn.datasets import load_digits
digits = load_digits(n_class=6)

# 用IsoMap方法將數字投影到二維空間
from sklearn.manifold import Isomap
iso = Isomap(n_components=2)
projection = iso.fit_transform(digits.data)
 # 畫圖用離散型顏色條來顯示結果,調整 ticks 與 clim 參數來改善顏色條
plt.scatter(projection[:, 0], projection[:, 1], lw=0.1,
c=digits.target, cmap=plt.cm.get_cmap('cubehelix', 6))
plt.colorbar(ticks=range(6), label='digit value')
plt.clim(-0.5, 5.5)
plt.show()

在這裏插入圖片描述
這個投影結果還向我們展示了一些數據集的有趣特性。例如,數字 5 與數字 3 在投影中有大面積重疊,說明一些手寫的 5 與 3 難以區分,因此自動分類算法也更容易搞混它們。其他的數字,像數字 0 與數字 1,隔得特別遠,說明兩者不太可能出現混淆。這個觀察結果也符合我們的直觀感受,因爲 5 和 3 看起來確實要比 0 和 1 更像。

備註

各位老鐵來個“關注”、“點贊”、“評論”三連擊哦
各位老鐵來個“關注”、“點贊”、“評論”三連擊哦
各位老鐵來個“關注”、“點贊”、“評論”三連擊哦

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章