简体   繁体   English

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

[英]creating over 20 unique legend colors using matplotlib

I am plotting 20 different lines on a single plot using matplotlib.我正在使用 matplotlib 在一个图上绘制 20 条不同的线。 I use a for loop for plotting and label every line with its key and then use the legend function我使用 for 循环绘制并用其键标记每一行,然后使用图例函数

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

But using this way, the graph repeats a lot of colors in the legend.但是使用这种方式,图表在图例中重复了很多颜色。 Is there any way to ensure a unique color is assigned to each line using matplotlib and over 20 lines?有什么方法可以确保使用 matplotlib 和 20 多行为每行分配唯一颜色?

thanks谢谢

The answer to your question is related to two other SO questions.您的问题的答案与另外两个 SO 问题有关。

The answer to How to pick a new color for each plotted line within a figure in matplotlib?如何为 matplotlib 中图形中的每条绘制线选择新颜色的答案 explains how to define the default list of colors that is cycled through to pick the next color to plot.解释了如何定义默认的颜色列表,循环选择下一个要绘制的颜色。 This is done with the Axes.set_color_cycle method .这是通过Axes.set_color_cycle 方法完成的。

You want to get the correct list of colors though, and this is most easily done using a color map, as is explained in the answer to this question: Create a color generator from given colormap in matplotlib .不过,您想获得正确的颜色列表,这最容易使用颜色图来完成,如以下问题的答案中所述:从 matplotlib 中的给定颜色图创建颜色生成器 There a color map takes a value from 0 to 1 and returns a color.颜色图从 0 到 1 取值并返回颜色。

So for your 20 lines, you want to cycle from 0 to 1 in steps of 1/20.因此,对于您的 20 行,您希望以 1/20 的步长从 0 循环到 1。 Specifically you want to cycle form 0 to 19/20, because 1 maps back to 0.具体来说,您希望从 0 到 19/20 循环,因为 1 映射回 0。

This is done in this example:这是在这个例子中完成的:

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()

This is the resulting figure:这是结果图:

优胜美地熊山巨人双彩虹1-8-10

Alternative, better (debatable) solution替代的、更好的(有争议的)解决方案

There is an alternative way that uses a ScalarMappable object to convert a range of values to colors.还有一种使用ScalarMappable对象将一系列值转换为颜色的替代方法。 The advantage of this method is that you can use a non-linear Normalization to convert from line index to actual color.这种方法的优点是您可以使用非线性Normalization将线索引转换为实际颜色。 The following code produces the same exact result:以下代码产生完全相同的结果:

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()

Deprecation Note弃用说明
In more recent versions of mplib (1.5+), the set_color_cycle function has been deprecated in favour of ax.set_prop_cycle(color=[...]) .在较新版本的 mplib (1.5+) 中, set_color_cycle函数已被弃用,取而代之的是ax.set_prop_cycle(color=[...])

I had a plot with 12 lines, and I found it hard to distinguish lines with similar colours when I tried Yann's technique .我有一个有 12 条线的图,当我尝试Yann 的技术时,我发现很难区分颜色相似的线。 My lines also appeared in pairs, so I used the same colour for the two lines in each pair, and used two different line widths.我的线条也是成对出现的,所以我对每对中的两条线使用了相同的颜色,并使用了两种不同的线宽。 You could also vary the line style to get more combinations.您还可以改变线条样式以获得更多组合。

You could use set_prop_cycle() , but I just modified the line objects after calling plot() .您可以使用set_prop_cycle() ,但我只是在调用plot()后修改了线对象。

Here is Yann's example with three different line widths:这是 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()

带线宽的示例图

Here's the same example with different line styles.这是具有不同线条样式的相同示例。 Of course you could combine the two if you wanted.当然,如果你愿意,你可以将两者结合起来。

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()

带有线条样式的示例图

To build off of Don Kirkby's answer , if you're willing to install/use seaborn , then you can have colors computed for you:为了建立Don Kirkby 的回答,如果您愿意安装/使用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()

Aside from being able to use seaborn's various color palettes, you can get a list of RGB tuples that can be used/manipulated later on if need be.除了能够使用 seaborn 的各种调色板之外,您还可以获得RGB 元组列表,如果需要,可以稍后使用/操作。 Obviously, you could compute something similar using matplotlib's colormaps, but I find this to be handy.显然,您可以使用 matplotlib 的颜色图计算类似的东西,但我发现这很方便。 带有 20 种颜色的 seaborn husl 颜色图

These answers seemed more complicated than needed.这些答案似乎比需要的更复杂。 If you are looping through a list to plot lines, then just enumerate on the list and assig color to some point on the colormap.如果您要循环遍历列表以绘制线条,则只需在列表上枚举并将颜色分配给颜色图上的某个点。 Say you are looping through all the columns from a pandas dataframe:假设您正在遍历 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))

This works because cm is just an iterable dictionary of color numerics.这是有效的,因为 cm 只是一个可迭代的颜色数字字典。 Multiplying those by some factor gets you further along in the colormap (more difference in color).将这些乘以某个因素会使您在颜色图中更进一步(颜色差异更大)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM