本文的前半部分来自书《科研论文配图绘制指南–基于Python》,后半部分来自matplotlib官网(v3.7)
太复杂了,实操有难度
试了试,不太好用
https://colorbrewer2.org/#type=sequential&scheme=BuGn&n=3
在线的配色方案辅助工具,尝试了一下,确实非常好用
① 表示可选的数据类别数。
② 表示可选择的颜色主题。ColorBrewer 2.0 提供了单色系、双色渐变色系和多色系。
③ 表示选定颜色主题后的配色方案。
④ 表示配色方案输出时的注意事项,即用户 是否需要考虑色盲情形、是否友好打印等。
⑤ 表示具体搭配色系的输出模式及对应的颜 色码,可选择的格式HEX、RGB 和 CMYK。
⑥ 用于控制不同颜色搭配方案的一些属性,
⑦ 表示背景设置区域。
⑧ 展示不同颜色搭配方案的预览效果
https://colorsinspo.com/
比较简单,点击复制颜色
因为总是需要特定的包版本,所以在anaconda新开一个环境,环境全部按照书中的来。conda create -n plotspec python=3.8.13
conda activate plotspec
pip install matplotlib==3.4.3 seaborn==0.11.2 ProPlot==0.9.5 Geopandas==0.11.0 Numpy==1.23.0 pandas==1.4.3 scipy==1.8.1
运行1-1-1,说我没有science主题,根据提示安装了对应包,还是包同样的错误。干脆注释了设置主题这一行代码。
重新运行,报错没有openpyxl,继续pip安装。安装后就画出来了。
后面的代码基本上都可以运行出来,报错的地方是用不上的包和保存图片的部分,注释即可。
RGB RGBA, [0,1] 之间的浮点数tuple 其中透明度A:0是完全透明 |
- (0.1, 0.2, 0.5) - (0.1, 0.2, 0.5, 0.3) |
---|---|
十六进制RGB/RGBA字符串,支持缩写 | - ‘#0f0f0f’ - ‘#0f0f0f80’ - ‘#abc’ as ‘#aabbcc’ - ‘#fb1’ as ‘#ffbb11’ |
表示灰度 度:[0,1]浮点数字符串 |
- ‘0’ as black - ‘1’ as white - ‘0.8’ as light gray |
单字符表示特定颜色 | - ‘b’ as blue - ‘g’ as green - ‘r’ as red - ‘c’ as cyan - ‘m’ as magenta - ‘y’ as yellow - ‘k’ as black - ‘w’ as white |
来自T10的tableau colors | - ‘tab:blue’ - ‘tab:orange’ - ‘tab:green’ - ‘tab:red’ - ‘tab:purple’ - ‘tab:brown’ - ‘tab:pink’ - ‘tab:gray’ - ‘tab:olive’ - ‘tab:cyan’ |
CN格式 | - ‘C0’ - ‘C1’ |
不同主题下CN不同:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
th = np.linspace(0, 2*np.pi, 128)
def demo(sty):
mpl.style.use(sty) # 设置style的方法
fig, ax = plt.subplots(figsize=(3, 3))
ax.set_title('style: {!r}'.format(sty), color='C0')
ax.plot(th, np.cos(th), 'C1', label='C1')
ax.plot(th, np.sin(th), 'C2', label='C2')
ax.legend()
demo('default')
demo('seaborn-v0_8')
colorbar 需要一个"mappable" (matplotlib.cm.ScalarMappable) 对象(典例是一张图片)。想要不用图片创建,可以使用ScalarMappable。
使用colorbar创建。调用 colorbar 的参数包括ScalarMappable对象(ScalarMappable由norm
, cmap
构建),应绘制 colorbar 的坐标轴以及 colorbar 的方向。
import matplotlib.pyplot as plt
import matplotlib as mpl
fig, ax = plt.subplots(figsize=(6, 1))
fig.subplots_adjust(bottom=0.5)
cmap = mpl.cm.cool
norm = mpl.colors.Normalize(vmin=5, vmax=10)
fig.colorbar(mpl.cm.ScalarMappable(norm=norm, cmap=cmap),
cax=ax, orientation='horizontal', label='Some Units')
fig, ax = plt.subplots(figsize=(6, 1))
fig.subplots_adjust(bottom=0.5)
cmap = mpl.cm.viridis
bounds = [-1, 2, 5, 7, 12, 15]
norm = mpl.colors.BoundaryNorm(bounds, cmap.N, extend='both')
fig.colorbar(mpl.cm.ScalarMappable(norm=norm, cmap=cmap),
cax=ax, orientation='horizontal',
label="Discrete intervals with extend='both' keyword")
fig, ax = plt.subplots(figsize=(6, 1))
fig.subplots_adjust(bottom=0.5)
cmap = (mpl.colors.ListedColormap(['red', 'green', 'blue', 'cyan'])
.with_extremes(over='0.25', under='0.75'))
bounds = [1, 2, 4, 7, 8]
norm = mpl.colors.BoundaryNorm(bounds, cmap.N)
fig.colorbar(
mpl.cm.ScalarMappable(cmap=cmap, norm=norm),
cax=ax,
extend='both',
ticks=bounds,
spacing='proportional',
orientation='horizontal',
label='Discrete intervals, some other units',
)
Matplotlib 有许多内置的colormap,可通过 matplotlib.colormaps 访问。还有一些外部库(如 palettable)也有许多额外的颜色图。
不过,我们经常希望在 Matplotlib 中创建或操作colormap。这可以使用 ListedColormap或 LinearSegmentedColormap 类来实现。从外观上看,这两个颜色图类都是将 0 和 1 之间的值映射到一系列颜色。不过,它们之间还是有细微差别的,部分差异将在下文中展示。
在手动创建或操作colormap之前,让我们先看看如何从现有的colormap类中获取colormap及其颜色。
首先,从Choosing Colormaps in Matplotlib获取已有名字的colormap, 可以使用 matplotlib.colormaps, 这将返回一个colormap对象。
通过 Colormap.resampled,可以调整内部用于定义色谱的颜色列表长度。下面我们使用的是适中的 8 值,因此可查看的值并不多。
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
from matplotlib.colors import ListedColormap, LinearSegmentedColormap
viridis = mpl.colormaps['viridis'].resampled(8)
对象 viridis 是一个可调用对象,当传递一个介于 0 和 1 之间的浮点数时,它会从颜色映射表中返回一个 RGBA 值:
print(viridis(0.56))
# out:(0.122312, 0.633153, 0.530398, 1.0)
ListedColormap 将颜色值存储在 .colors 属性中。可以使用 colors 属性直接访问组成颜色映射的颜色列表,也可以使用与颜色映射长度相匹配的值数组调用 viridis 来间接访问。请注意,返回的列表是 RGBA Nx4 数组形式,其中 N 是颜色映射表的长度。
print('viridis.colors', viridis.colors)
print('viridis(range(8))', viridis(range(8)))
print('viridis(np.linspace(0, 1, 8))', viridis(np.linspace(0, 1, 8)))
'''
viridis.colors [[0.267004 0.004874 0.329415 1. ]
[0.275191 0.194905 0.496005 1. ]
[0.212395 0.359683 0.55171 1. ]
[0.153364 0.497 0.557724 1. ]
[0.122312 0.633153 0.530398 1. ]
[0.288921 0.758394 0.428426 1. ]
[0.626579 0.854645 0.223353 1. ]
[0.993248 0.906157 0.143936 1. ]]
viridis(range(8)) [[0.267004 0.004874 0.329415 1. ]
[0.275191 0.194905 0.496005 1. ]
[0.212395 0.359683 0.55171 1. ]
[0.153364 0.497 0.557724 1. ]
[0.122312 0.633153 0.530398 1. ]
[0.288921 0.758394 0.428426 1. ]
[0.626579 0.854645 0.223353 1. ]
[0.993248 0.906157 0.143936 1. ]]
viridis(np.linspace(0, 1, 8)) [[0.267004 0.004874 0.329415 1. ]
[0.275191 0.194905 0.496005 1. ]
[0.212395 0.359683 0.55171 1. ]
[0.153364 0.497 0.557724 1. ]
[0.122312 0.633153 0.530398 1. ]
[0.288921 0.758394 0.428426 1. ]
[0.626579 0.854645 0.223353 1. ]
[0.993248 0.906157 0.143936 1. ]]
'''
颜色映射表是一个查找表,因此对颜色映射表进行 "过采样 "会返回最近邻插值(请注意下面列表中的重复颜色)。
print('viridis(np.linspace(0, 1, 12))', viridis(np.linspace(0, 1, 12)))
'''
viridis(np.linspace(0, 1, 12)) [[0.267004 0.004874 0.329415 1. ]
[0.267004 0.004874 0.329415 1. ]
[0.275191 0.194905 0.496005 1. ]
[0.212395 0.359683 0.55171 1. ]
[0.212395 0.359683 0.55171 1. ]
[0.153364 0.497 0.557724 1. ]
[0.122312 0.633153 0.530398 1. ]
[0.288921 0.758394 0.428426 1. ]
[0.288921 0.758394 0.428426 1. ]
[0.626579 0.854645 0.223353 1. ]
[0.993248 0.906157 0.143936 1. ]
[0.993248 0.906157 0.143936 1. ]]
'''
LinearSegmentedColormaps 没有 .colors 属性。不过,我们仍然可以使用整数数组或介于 0 和 1 之间的浮点数组调用colormap。
copper = mpl.colormaps['copper'].resampled(8)
print('copper(range(8))', copper(range(8)))
print('copper(np.linspace(0, 1, 8))', copper(np.linspace(0, 1, 8)))
这部分暂时用不到,用到再学。链接
这部分暂时也用不到,时间关系先不看。链接
选择一个好的色彩映射图背后的理念是在三维色彩空间中为数据集找到一个好的表示方法。对于任何给定的数据集来说,最佳的色彩映射取决于很多方面,包括
对于许多应用而言,感知统一的色彩图是最佳选择;也就是说,在色彩图中,数据中的等阶被感知为色彩空间中的等阶。研究人员发现,人脑将明度参数的变化视为数据的变化要比色调的变化好得多。因此,通过色图单调增加明度的色图更容易被观众理解。
要了解人类对颜色图的感知,[IBM]是一个很好的入门资源。
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import cm
from matplotlib.colors import ListedColormap, LinearSegmentedColormap
nipy_spectral = cm.get_cmap('nipy_spectral', 16)
# define a list of markevery cases to plot
cases = [
None,
8,
(30, 8),
[16, 24, 32],
[0, -1],
slice(100, 200, 3),
0.1,
0.4,
(0.2, 0.4)
]
# data points
delta = 0.11
x = np.linspace(0, 10 - 2 * delta, 200) + delta
y = np.sin(x) + 1.0 + delta
fig, axs = plt.subplots(3, 3, figsize=(10, 6))
fig.subplots_adjust(hspace=0.465)
i = 0
for ax, markevery in zip(axs.flat, cases):
ax.set_title(f'markevery={markevery}')
ax.plot(x, y, 'o', ls='-', ms=4, markevery=markevery, c=nipy_spectral(x[i]))
i+=1
plt.show()
tab20的效果
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.collections import LineCollection
from matplotlib.colors import ListedColormap, BoundaryNorm
x = np.linspace(0, 3 * np.pi, 500)
y = np.sin(x)
dydx = np.cos(0.6 * (x[:-1] + x[1:])) # first derivative
# Create a set of line segments so that we can color them individually
# This creates the points as an N x 1 x 2 array so that we can stack points
# together easily to get the segments. The segments array for line collection
# needs to be (numlines) x (points per line) x 2 (for x and y)
points = np.array([x, y]).T.reshape(-1, 1, 2)
segments = np.concatenate([points[:-1], points[1:]], axis=1)
fig, axs = plt.subplots(1, 1, sharex=True, sharey=True)
fig.subplots_adjust(top=0.6, bottom=0.2)
# Create a continuous norm to map from data points to colors
norm = plt.Normalize(dydx.min(), dydx.max())
lc = LineCollection(segments, cmap='tab20', norm=norm)
# Set the values used for colormapping
lc.set_array(dydx)
lc.set_linewidth(2)
line = axs.add_collection(lc)
fig.colorbar(line, ax=axs)
axs.set_xlim(x.min(), x.max())
axs.set_ylim(-1.1, 1.1)
plt.show()