使用色图在matplotlib中设置线条颜色

81

如何在matplotlib中使用运行时提供的标量值和颜色映射(例如jet)设置线条的颜色?我在这里尝试了几种不同的方法,但仍然无法解决问题。 values []是排序后的标量数组。曲线是一组1d数组,标签是文本字符串数组。每个数组的长度相同。

fig = plt.figure()
ax = fig.add_subplot(111)
jet = colors.Colormap('jet')
cNorm  = colors.Normalize(vmin=0, vmax=values[-1])
scalarMap = cmx.ScalarMappable(norm=cNorm, cmap=jet)
lines = []
for idx in range(len(curves)):
    line = curves[idx]
    colorVal = scalarMap.to_rgba(values[idx])
    retLine, = ax.plot(line, color=colorVal)
    #retLine.set_color()
    lines.append(retLine)
ax.legend(lines, labels, loc='upper right')
ax.grid()
plt.show()
5个回答

92
你收到的错误是由于你定义jet的方式导致的。你使用名称“jet”创建基类Colormap,但这与获取“jet”颜色映射的默认定义非常不同。这个基类永远不应该直接创建,只有子类才应该实例化。
你在示例中发现的是Matplotlib中的一个错误行为。运行此代码时应生成更清晰的错误消息。
这是你示例的更新版本:
import matplotlib.pyplot as plt
import matplotlib.colors as colors
import matplotlib.cm as cmx
import numpy as np

# define some random data that emulates your indeded code:
NCURVES = 10
np.random.seed(101)
curves = [np.random.random(20) for i in range(NCURVES)]
values = range(NCURVES)

fig = plt.figure()
ax = fig.add_subplot(111)
# replace the next line 
#jet = colors.Colormap('jet')
# with
jet = cm = plt.get_cmap('jet') 
cNorm  = colors.Normalize(vmin=0, vmax=values[-1])
scalarMap = cmx.ScalarMappable(norm=cNorm, cmap=jet)
print scalarMap.get_clim()

lines = []
for idx in range(len(curves)):
    line = curves[idx]
    colorVal = scalarMap.to_rgba(values[idx])
    colorText = (
        'color: (%4.2f,%4.2f,%4.2f)'%(colorVal[0],colorVal[1],colorVal[2])
        )
    retLine, = ax.plot(line,
                       color=colorVal,
                       label=colorText)
    lines.append(retLine)
#added this to get the legend to work
handles,labels = ax.get_legend_handles_labels()
ax.legend(handles, labels, loc='upper right')
ax.grid()
plt.show()

结果如下:

enter image description here

使用ScalarMappable优于我相关回答中提出的方法: 创建超过20个唯一图例颜色使用matplotlib


7
这个答案不够简洁明了。代码示例包含了很多不必要的冗余内容,也没有很好地展示对matplotlib的理解。应该接受blahreport的答案。 - olq_plo
@Yann我们能否像这样为'plt.scatter'生成不同的颜色呢? - Blade
注意:对于Python3,print scalarMap.get_clim()一行应该在print后面加上括号而不是空格。看起来建议的编辑队列已经满了。 - jvriesem

86

我认为使用numpy的linspace和matplotlib的cm-type对象结合起来的方法更加简单易懂。上面的解决方案可能是针对旧版本的。我使用的是python 3.4.3、matplotlib 1.4.3和numpy 1.9.3,我的解决方案如下。

import matplotlib.pyplot as plt

from matplotlib import cm
from numpy import linspace

start = 0.0
stop = 1.0
number_of_lines= 1000
cm_subsection = linspace(start, stop, number_of_lines) 

colors = [ cm.jet(x) for x in cm_subsection ]

for i, color in enumerate(colors):
    plt.axhline(i, color=color)

plt.ylabel('Line Number')
plt.show()

这将产生1000条独特颜色的线,跨越整个cm.jet色图,如下图所示。如果您运行此脚本,您会发现可以放大单个线条。

cm.jet between 0.0 and 1.0 with 1000 graduations

现在假设我想要我的1000行颜色仅覆盖400到600行之间的绿色部分。我只需将起始和结束值更改为0.4和0.6,这将导致仅使用cm.jet颜色映射的20%位于0.4和0.6之间。

enter image description here

因此,在一行总结中,您可以根据 matplotlib.cm 色图创建 rgba 颜色列表:

colors = [ cm.jet(x) for x in linspace(start, stop, number_of_lines) ]

在这种情况下,我使用了常用的地图名称为jet,但是您可以通过调用以下命令找到可用于您的matplotlib版本的完整颜色地图列表:
>>> from matplotlib import cm
>>> dir(cm)

3
当然,数字1是最佳值。如果您想要更多颜色的范围,只需增加“number_of_lines”。如果您只需要带子中的部分颜色,则根据需要减少“stop”并增加“start”。 - chidimo
2
一个快速的问题:如何在绘图中添加颜色条而不是图例? - TNg
这个 jet() 方法是什么?我在 cm 文档 中没有看到它。 - topher217

19

使用matplotlib中的线条样式、标记和定性颜色的组合:

import itertools
import matplotlib as mpl
import matplotlib.pyplot as plt
N = 8*4+10
l_styles = ['-','--','-.',':']
m_styles = ['','.','o','^','*']
colormap = mpl.cm.Dark2.colors   # Qualitative colormap
for i,(marker,linestyle,color) in zip(range(N),itertools.product(m_styles,l_styles, colormap)):
    plt.plot([0,1,2],[0,2*i,2*i], color=color, linestyle=linestyle,marker=marker,label=i)
plt.legend(bbox_to_anchor=(1.05, 1), loc=2, borderaxespad=0.,ncol=4);

enter image description here

更新:现在支持的不仅是ListedColormap,还有LinearSegmentedColormap

import itertools
import matplotlib.pyplot as plt
Ncolors = 8
#colormap = plt.cm.Dark2# ListedColormap
colormap = plt.cm.viridis# LinearSegmentedColormap
Ncolors = min(colormap.N,Ncolors)
mapcolors = [colormap(int(x*colormap.N/Ncolors)) for x in range(Ncolors)]
N = Ncolors*4+10
l_styles = ['-','--','-.',':']
m_styles = ['','.','o','^','*']
fig,ax = plt.subplots(gridspec_kw=dict(right=0.6))
for i,(marker,linestyle,color) in zip(range(N),itertools.product(m_styles,l_styles, mapcolors)):
    ax.plot([0,1,2],[0,2*i,2*i], color=color, linestyle=linestyle,marker=marker,label=i)
ax.legend(bbox_to_anchor=(1.05, 1), loc=2, borderaxespad=0.,ncol=3,prop={'size': 8})

在这里输入图片描述


1
如何在“coolwarm”色图中实现此操作?在这种情况下,没有“.colors”属性。 - seralouk
coolwarm is of type LinearSegmentedColormap as oppose to type ListedColormap (e.g. Dark2) . I have updated my answer to support also LinearSegmentedColormap colormaps as viridis - Pablo Reyes

8

你可以按照我从被删除的账户中编写的方法(由于新帖子被禁止了:(),进行操作。这很简单,看起来很不错。

通常我使用这三个版本中的第三个,也没有检查过第一和第二版。

from matplotlib.pyplot import cm
import numpy as np

#variable n should be number of curves to plot (I skipped this earlier thinking that it is obvious when looking at picture - sorry my bad mistake xD): n=len(array_of_curves_to_plot)
#version 1:

color=cm.rainbow(np.linspace(0,1,n))
for i,c in zip(range(n),color):
   ax1.plot(x, y,c=c)

#or version 2: - faster and better:

color=iter(cm.rainbow(np.linspace(0,1,n)))
c=next(color)
plt.plot(x,y,c=c)

#or version 3:

color=iter(cm.rainbow(np.linspace(0,1,n)))
for i in range(n):
   c=next(color)
   ax1.plot(x, y,c=c)

第三个例子:

船舶滚动响应幅度A44与Ikeda阻尼之间的关系图


0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接