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 更像。

备注

各位老铁来个“关注”、“点赞”、“评论”三连击哦
各位老铁来个“关注”、“点赞”、“评论”三连击哦
各位老铁来个“关注”、“点赞”、“评论”三连击哦

在这里插入图片描述

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