使用 matplotlib 颜色图进行颜色循环
use matplotlib color map for color cycle
如果我通过以下方式创建颜色:
import numpy as np
from matplotlib import pyplot as plt
n = 6
color = plt.cm.coolwarm(np.linspace(0.1,0.9,n))
color
color 是一个 numpy 数组:
array([[ 0.34832334, 0.46571115, 0.88834616, 1. ],
[ 0.56518158, 0.69943844, 0.99663507, 1. ],
[ 0.77737753, 0.84092121, 0.9461493 , 1. ],
[ 0.93577377, 0.8122367 , 0.74715647, 1. ],
[ 0.96049006, 0.61627642, 0.4954666 , 1. ],
[ 0.83936494, 0.32185622, 0.26492398, 1. ]])
但是,如果我在我的 .mplstyle
文件 (map(tuple,color[:,0:-1])
) 中插入 RGB 值(没有 alpha 值 1)作为元组,我会得到一个类似于这个的错误:
in file "/home/moritz/.config/matplotlib/stylelib/ggplot.mplstyle"
Key axes.color_cycle: [(0.34832334141176474 does not look like a color arg
(val, error_details, msg))
知道为什么吗?
编辑 04/2021: 从 matplotlib 2.2.0 开始,键 axes.color_cycle
已被弃用 (source: API changes)。
新方法是使用 set_prop_cycle
(source: matplotlib.axes.Axes.set_prop_cycle API)
细节在 matplotlibrc 本身,实际上:它需要一个字符串 rep(十六进制或字母或单词,而不是元组)。
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
fig, ax1 = plt.subplots(1,1)
ys = np.random.random((5, 6))
ax1.plot(range(5), ys)
ax1.set_title('Default color cycle')
plt.show()
# From the sample matplotlibrc:
#axes.color_cycle : b, g, r, c, m, y, k # color cycle for plot lines
# as list of string colorspecs:
# single letter, long name, or
# web-style hex
# setting color cycle after calling plt.subplots doesn't "take"
# try some hex values as **string** colorspecs
mpl.rcParams['axes.color_cycle'] = ['#129845','#271254', '#FA4411', '#098765', '#000009']
fig, ax2 = plt.subplots(1,1)
ax2.plot(range(5), ys)
ax2.set_title('New color cycle')
n = 6
color = plt.cm.coolwarm(np.linspace(0.1,0.9,n)) # This returns RGBA; convert:
hexcolor = map(lambda rgb:'#%02x%02x%02x' % (rgb[0]*255,rgb[1]*255,rgb[2]*255),
tuple(color[:,0:-1]))
mpl.rcParams['axes.color_cycle'] = hexcolor
fig, ax3 = plt.subplots(1,1)
ax3.plot(range(5), ys)
ax3.set_title('Color cycle from colormap')
plt.show()
对于 Matplotlib 2.2,使用 cycler
模块即可,无需转换为十六进制值。
import cycler
n = 100
color = pyplot.cm.viridis(np.linspace(0, 1,n))
mpl.rcParams['axes.prop_cycle'] = cycler.cycler('color', color)
"Continuous" 颜色图
如果您想循环使用 "continous" 颜色图中的 N
颜色,例如默认的 viridis 贴图, 效果很好。
import matplotlib.pyplot as plt
N = 6
plt.rcParams["axes.prop_cycle"] = plt.cycler("color", plt.cm.viridis(np.linspace(0,1,N)))
fig, ax = plt.subplots()
for i in range(N):
ax.plot([0,1], [i, 2*i])
plt.show()
"Discrete" 颜色图
Matplotlib 提供了一些 "discrete" 的颜色图,因为它们为定性视觉效果保留了一些不同的颜色,例如 tab10
颜色图。要循环使用此类颜色图,解决方案可能是不使用 N
,而只是将地图的所有颜色移植到循环仪。
import matplotlib.pyplot as plt
plt.rcParams["axes.prop_cycle"] = plt.cycler("color", plt.cm.tab20c.colors)
fig, ax = plt.subplots()
for i in range(15):
ax.plot([0,1], [i, 2*i])
plt.show()
请注意,只有 ListedColormaps
具有 .colors
属性,因此这仅适用于那些颜色图,但不适用于例如jet
地图。
组合解决方案
以下是一个通用函数,它将颜色图作为输入并输出相应的循环器。我最初在 this matplotlib issue 中提出了这个解决方案。
from matplotlib.pyplot import cycler
import numpy as np
from matplotlib.colors import LinearSegmentedColormap, ListedColormap
import matplotlib.cm
def get_cycle(cmap, N=None, use_index="auto"):
if isinstance(cmap, str):
if use_index == "auto":
if cmap in ['Pastel1', 'Pastel2', 'Paired', 'Accent',
'Dark2', 'Set1', 'Set2', 'Set3',
'tab10', 'tab20', 'tab20b', 'tab20c']:
use_index=True
else:
use_index=False
cmap = matplotlib.cm.get_cmap(cmap)
if not N:
N = cmap.N
if use_index=="auto":
if cmap.N > 100:
use_index=False
elif isinstance(cmap, LinearSegmentedColormap):
use_index=False
elif isinstance(cmap, ListedColormap):
use_index=True
if use_index:
ind = np.arange(int(N)) % cmap.N
return cycler("color",cmap(ind))
else:
colors = cmap(np.linspace(0,1,N))
return cycler("color",colors)
"continuous" 案例的用法:
import matplotlib.pyplot as plt
N = 6
plt.rcParams["axes.prop_cycle"] = get_cycle("viridis", N)
fig, ax = plt.subplots()
for i in range(N):
ax.plot([0,1], [i, 2*i])
plt.show()
"discrete" 案例的用法
import matplotlib.pyplot as plt
plt.rcParams["axes.prop_cycle"] = get_cycle("tab20c")
fig, ax = plt.subplots()
for i in range(15):
ax.plot([0,1], [i, 2*i])
plt.show()
如果我通过以下方式创建颜色:
import numpy as np
from matplotlib import pyplot as plt
n = 6
color = plt.cm.coolwarm(np.linspace(0.1,0.9,n))
color
color 是一个 numpy 数组:
array([[ 0.34832334, 0.46571115, 0.88834616, 1. ],
[ 0.56518158, 0.69943844, 0.99663507, 1. ],
[ 0.77737753, 0.84092121, 0.9461493 , 1. ],
[ 0.93577377, 0.8122367 , 0.74715647, 1. ],
[ 0.96049006, 0.61627642, 0.4954666 , 1. ],
[ 0.83936494, 0.32185622, 0.26492398, 1. ]])
但是,如果我在我的 .mplstyle
文件 (map(tuple,color[:,0:-1])
) 中插入 RGB 值(没有 alpha 值 1)作为元组,我会得到一个类似于这个的错误:
in file "/home/moritz/.config/matplotlib/stylelib/ggplot.mplstyle"
Key axes.color_cycle: [(0.34832334141176474 does not look like a color arg
(val, error_details, msg))
知道为什么吗?
编辑 04/2021: 从 matplotlib 2.2.0 开始,键 axes.color_cycle
已被弃用 (source: API changes)。
新方法是使用 set_prop_cycle
(source: matplotlib.axes.Axes.set_prop_cycle API)
细节在 matplotlibrc 本身,实际上:它需要一个字符串 rep(十六进制或字母或单词,而不是元组)。
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
fig, ax1 = plt.subplots(1,1)
ys = np.random.random((5, 6))
ax1.plot(range(5), ys)
ax1.set_title('Default color cycle')
plt.show()
# From the sample matplotlibrc:
#axes.color_cycle : b, g, r, c, m, y, k # color cycle for plot lines
# as list of string colorspecs:
# single letter, long name, or
# web-style hex
# setting color cycle after calling plt.subplots doesn't "take"
# try some hex values as **string** colorspecs
mpl.rcParams['axes.color_cycle'] = ['#129845','#271254', '#FA4411', '#098765', '#000009']
fig, ax2 = plt.subplots(1,1)
ax2.plot(range(5), ys)
ax2.set_title('New color cycle')
n = 6
color = plt.cm.coolwarm(np.linspace(0.1,0.9,n)) # This returns RGBA; convert:
hexcolor = map(lambda rgb:'#%02x%02x%02x' % (rgb[0]*255,rgb[1]*255,rgb[2]*255),
tuple(color[:,0:-1]))
mpl.rcParams['axes.color_cycle'] = hexcolor
fig, ax3 = plt.subplots(1,1)
ax3.plot(range(5), ys)
ax3.set_title('Color cycle from colormap')
plt.show()
对于 Matplotlib 2.2,使用 cycler
模块即可,无需转换为十六进制值。
import cycler
n = 100
color = pyplot.cm.viridis(np.linspace(0, 1,n))
mpl.rcParams['axes.prop_cycle'] = cycler.cycler('color', color)
"Continuous" 颜色图
如果您想循环使用 "continous" 颜色图中的 N
颜色,例如默认的 viridis 贴图,
import matplotlib.pyplot as plt
N = 6
plt.rcParams["axes.prop_cycle"] = plt.cycler("color", plt.cm.viridis(np.linspace(0,1,N)))
fig, ax = plt.subplots()
for i in range(N):
ax.plot([0,1], [i, 2*i])
plt.show()
"Discrete" 颜色图
Matplotlib 提供了一些 "discrete" 的颜色图,因为它们为定性视觉效果保留了一些不同的颜色,例如 tab10
颜色图。要循环使用此类颜色图,解决方案可能是不使用 N
,而只是将地图的所有颜色移植到循环仪。
import matplotlib.pyplot as plt
plt.rcParams["axes.prop_cycle"] = plt.cycler("color", plt.cm.tab20c.colors)
fig, ax = plt.subplots()
for i in range(15):
ax.plot([0,1], [i, 2*i])
plt.show()
请注意,只有 ListedColormaps
具有 .colors
属性,因此这仅适用于那些颜色图,但不适用于例如jet
地图。
组合解决方案
以下是一个通用函数,它将颜色图作为输入并输出相应的循环器。我最初在 this matplotlib issue 中提出了这个解决方案。
from matplotlib.pyplot import cycler
import numpy as np
from matplotlib.colors import LinearSegmentedColormap, ListedColormap
import matplotlib.cm
def get_cycle(cmap, N=None, use_index="auto"):
if isinstance(cmap, str):
if use_index == "auto":
if cmap in ['Pastel1', 'Pastel2', 'Paired', 'Accent',
'Dark2', 'Set1', 'Set2', 'Set3',
'tab10', 'tab20', 'tab20b', 'tab20c']:
use_index=True
else:
use_index=False
cmap = matplotlib.cm.get_cmap(cmap)
if not N:
N = cmap.N
if use_index=="auto":
if cmap.N > 100:
use_index=False
elif isinstance(cmap, LinearSegmentedColormap):
use_index=False
elif isinstance(cmap, ListedColormap):
use_index=True
if use_index:
ind = np.arange(int(N)) % cmap.N
return cycler("color",cmap(ind))
else:
colors = cmap(np.linspace(0,1,N))
return cycler("color",colors)
"continuous" 案例的用法:
import matplotlib.pyplot as plt
N = 6
plt.rcParams["axes.prop_cycle"] = get_cycle("viridis", N)
fig, ax = plt.subplots()
for i in range(N):
ax.plot([0,1], [i, 2*i])
plt.show()
"discrete" 案例的用法
import matplotlib.pyplot as plt
plt.rcParams["axes.prop_cycle"] = get_cycle("tab20c")
fig, ax = plt.subplots()
for i in range(15):
ax.plot([0,1], [i, 2*i])
plt.show()