使用matplotlib创建超过20种独特的图例颜色

时间:2011-12-05 17:54:02

标签: python matplotlib legend

我正在使用matplotlib在单个地块上绘制20条不同的线条。我使用for循环绘制并用其键标记每一行,然后使用图例函数

for key in dict.keys():
    plot(x,dict[key], label = key)
graph.legend()

但是使用这种方式,图表会在图例中重复出现很多颜色。有没有办法确保使用matplotlib和超过20行为每一行分配一个独特的颜色?

感谢

4 个答案:

答案 0 :(得分:90)

您的问题的答案与另外两个SO问题有关。

How to pick a new color for each plotted line within a figure in matplotlib?的答案解释了如何定义循环的默认颜色列表以选择要绘制的下一个颜色。这是通过Axes.set_color_cycle method完成的。

您希望获得正确的颜色列表,这最容易使用颜色映射完成,如此问题的答案中所述:Create a color generator from given colormap in matplotlib。颜色贴图采用0到1之间的值并返回颜色。

因此,对于20行,您希望以1/20的步长从0循环到1。具体而言,您希望将表单0循环到19/20,因为1映射回到0.

这是在这个例子中完成的:

import matplotlib.pyplot as plt
import numpy as np

NUM_COLORS = 20

cm = plt.get_cmap('gist_rainbow')
fig = plt.figure()
ax = fig.add_subplot(111)
ax.set_color_cycle([cm(1.*i/NUM_COLORS) for i in range(NUM_COLORS)])
for i in range(NUM_COLORS):
    ax.plot(np.arange(10)*(i+1))

fig.savefig('moreColors.png')
plt.show()

这是结果:

Yosemitebear Mountain Giant Double Rainbow 1-8-10

替代方案,更好(有争议)的解决方案

有一种替代方法可以使用ScalarMappable对象将一系列值转换为颜色。此方法的优点是您可以使用非线性Normalization将线索引转换为实际颜色。以下代码生成相同的确切结果:

import matplotlib.pyplot as plt
import matplotlib.cm as mplcm
import matplotlib.colors as colors
import numpy as np

NUM_COLORS = 20

cm = plt.get_cmap('gist_rainbow')
cNorm  = colors.Normalize(vmin=0, vmax=NUM_COLORS-1)
scalarMap = mplcm.ScalarMappable(norm=cNorm, cmap=cm)
fig = plt.figure()
ax = fig.add_subplot(111)
# old way:
#ax.set_color_cycle([cm(1.*i/NUM_COLORS) for i in range(NUM_COLORS)])
# new way:
ax.set_color_cycle([scalarMap.to_rgba(i) for i in range(NUM_COLORS)])
for i in range(NUM_COLORS):
    ax.plot(np.arange(10)*(i+1))

fig.savefig('moreColors.png')
plt.show()

弃用说明
在更新版本的mplib(1.5 +)中,set_color_cycle函数已被弃用,而不是ax.set_prop_cycle(color=[...])

答案 1 :(得分:15)

我有一个12行的情节,当我尝试Yann's technique时,我发现很难区分具有相似颜色的线条。我的线也成对出现,所以我对每对中的两条线使用相同的颜色,并使用两种不同的线宽。您还可以改变线条样式以获得更多组合。

您可以使用set_prop_cycle(),但我在调用plot()后修改了线对象。

这是Yann的三个不同线宽的例子:

import matplotlib.pyplot as plt
import numpy as np

NUM_COLORS = 20

cm = plt.get_cmap('gist_rainbow')
fig = plt.figure()
ax = fig.add_subplot(111)
for i in range(NUM_COLORS):
    lines = ax.plot(np.arange(10)*(i+1))
    lines[0].set_color(cm(i//3*3.0/NUM_COLORS))
    lines[0].set_linewidth(i%3 + 1)

fig.savefig('moreColors.png')
plt.show()

Example plot with line widths

这是具有不同线型的相同示例。当然,如果你愿意,你可以将两者结合起来。

import matplotlib.pyplot as plt
import numpy as np

NUM_COLORS = 20
LINE_STYLES = ['solid', 'dashed', 'dashdot', 'dotted']
NUM_STYLES = len(LINE_STYLES)

cm = plt.get_cmap('gist_rainbow')
fig = plt.figure()
ax = fig.add_subplot(111)
for i in range(NUM_COLORS):
    lines = ax.plot(np.arange(10)*(i+1))
    lines[0].set_color(cm(i//NUM_STYLES*float(NUM_STYLES)/NUM_COLORS))
    lines[0].set_linestyle(LINE_STYLES[i%NUM_STYLES])

fig.savefig('moreColors.png')
plt.show()

Example plot with line styles

答案 2 :(得分:8)

要构建Don Kirkby's answer,如果您愿意安装/使用seaborn,那么您可以为您计算颜色:

import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np

NUM_COLORS = 20
LINE_STYLES = ['solid', 'dashed', 'dashdot', 'dotted']
NUM_STYLES = len(LINE_STYLES)

sns.reset_orig()  # get default matplotlib styles back
clrs = sns.color_palette('husl', n_colors=NUM_COLORS)  # a list of RGB tuples
fig, ax = plt.subplots(1)
for i in range(NUM_COLORS):
    lines = ax.plot(np.arange(10)*(i+1))
    lines[0].set_color(clrs[i])
    lines[0].set_linestyle(LINE_STYLES[i%NUM_STYLES])

fig.savefig('moreColors.png')
plt.show()

除了能够使用seaborn的各种调色板外,您还可以获得 RGB元组列表,以便以后可以使用/操作。显然,你可以使用matplotlib的色彩图来计算类似的东西,但我觉得这很方便。 seaborn husl color map with 20 colors

答案 3 :(得分:0)

这些答案似乎比需要的更复杂。如果您要循环遍历列表以绘制线条,则只需在列表上枚举并将颜色分配给颜色图上的某个点。假设您正在遍历 Pandas 数据框中的所有列:

fig, ax = plt.subplots()
cm = plt.get_cmap('gist_rainbow')
 for count, col in enumerate(df.columns):
    ax.plot(df[col], label = col, linewidth = 2, color = cm(count*20))

这是可行的,因为 cm 只是一个可迭代的颜色数字字典。将这些乘以某个因素会使您在颜色图中走得更远(颜色差异更大)。