Python 使用 matplotlib 创建自己的颜色图并绘制色标

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16834861/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-18 23:46:56  来源:igfitidea点击:

Create own colormap using matplotlib and plot color scale

pythonmatplotlibplot

提问by Trollbrot

I have the following problem, I want to create my own colormap (red-mix-violet-mix-blue) that maps to values between -2 and +2 and want to use it to color points in my plot. The plot should then have the colorscale to the right.

That is how I create the map so far. But I am not really sure if it mixes the colors.

我有以下问题,我想创建自己的颜色图(红混合紫混合蓝),映射到 -2 和 +2 之间的值,并想用它来为我的绘图中的点着色。然后该图应该具有右侧的色阶。

到目前为止,这就是我创建地图的方式。但我不确定它是否混合了颜色。

cmap = matplotlib.colors.ListedColormap(["red","violet","blue"], name='from_list', N=None)
m = cm.ScalarMappable(norm=norm, cmap=cmap)


That way I map the colors to the values.


这样我将颜色映射到值。

colors = itertools.cycle([m.to_rgba(1.22), ..])


Then I plot it:


然后我绘制它:

for i in range(0, len(array_dg)):
  plt.plot(array_dg[i], markers.next(),alpha=alpha[i], c=colors.next())


My problems are:
1. I can't plot the color scale.
2. I am not completely sure if my scale is creating a continues (smooth) colorscale.


我的问题是:
1. 我无法绘制色标。
2. 我不完全确定我的比例是否创建了连续(平滑)的色阶。

采纳答案by unutbu

There is an illustrative example of how to create custom colormaps here. The docstring is essential for understanding the meaning of cdict. Once you get that under your belt, you might use a cdictlike this:

这里有一个关于如何创建自定义颜色图的说明性示例。文档字符串对于理解 cdict. 一旦你明白了,你可能会使用cdict这样的:

cdict = {'red':   ((0.0, 1.0, 1.0), 
                   (0.1, 1.0, 1.0),  # red 
                   (0.4, 1.0, 1.0),  # violet
                   (1.0, 0.0, 0.0)), # blue

         'green': ((0.0, 0.0, 0.0),
                   (1.0, 0.0, 0.0)),

         'blue':  ((0.0, 0.0, 0.0),
                   (0.1, 0.0, 0.0),  # red
                   (0.4, 1.0, 1.0),  # violet
                   (1.0, 1.0, 0.0))  # blue
          }

Although the cdictformat gives you a lot of flexibility, I find for simple gradients its format is rather unintuitive. Here is a utility function to help generate simple LinearSegmentedColormaps:

尽管该cdict格式为您提供了很大的灵活性,但我发现对于简单的渐变,其格式相当不直观。这是一个帮助生成简单 LinearSegmentedColormaps 的实用函数:

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors as mcolors


def make_colormap(seq):
    """Return a LinearSegmentedColormap
    seq: a sequence of floats and RGB-tuples. The floats should be increasing
    and in the interval (0,1).
    """
    seq = [(None,) * 3, 0.0] + list(seq) + [1.0, (None,) * 3]
    cdict = {'red': [], 'green': [], 'blue': []}
    for i, item in enumerate(seq):
        if isinstance(item, float):
            r1, g1, b1 = seq[i - 1]
            r2, g2, b2 = seq[i + 1]
            cdict['red'].append([item, r1, r2])
            cdict['green'].append([item, g1, g2])
            cdict['blue'].append([item, b1, b2])
    return mcolors.LinearSegmentedColormap('CustomMap', cdict)


c = mcolors.ColorConverter().to_rgb
rvb = make_colormap(
    [c('red'), c('violet'), 0.33, c('violet'), c('blue'), 0.66, c('blue')])
N = 1000
array_dg = np.random.uniform(0, 10, size=(N, 2))
colors = np.random.uniform(-2, 2, size=(N,))
plt.scatter(array_dg[:, 0], array_dg[:, 1], c=colors, cmap=rvb)
plt.colorbar()
plt.show()

enter image description here

在此处输入图片说明



By the way, the for-loop

顺便说一下, for-loop

for i in range(0, len(array_dg)):
  plt.plot(array_dg[i], markers.next(),alpha=alpha[i], c=colors.next())

plots one point for every call to plt.plot. This will work for a small number of points, but will become extremely slow for many points. plt.plotcan only draw in one color, but plt.scattercan assign a different color to each dot. Thus, plt.scatteris the way to go.

为每次调用绘制一个点plt.plot。这将适用于少量点,但对于许多点会变得非常慢。plt.plot只能绘制一种颜色,但plt.scatter可以为每个点指定不同的颜色。因此,plt.scatter是要走的路。

回答by Steven C. Howell

If you want to automate the creating of a custom divergent colormap commonly used for surface plots, this module combined with @unutbu method worked well for me.

如果你想自动创建一个通常用于表面图的自定义发散颜色,这个模块结合@unutbu 方法对我来说效果很好。

def diverge_map(high=(0.565, 0.392, 0.173), low=(0.094, 0.310, 0.635)):
    '''
    low and high are colors that will be used for the two
    ends of the spectrum. they can be either color strings
    or rgb color tuples
    '''
    c = mcolors.ColorConverter().to_rgb
    if isinstance(low, basestring): low = c(low)
    if isinstance(high, basestring): high = c(high)
    return make_colormap([low, c('white'), 0.5, c('white'), high])

The high and low values can be either string color names or rgb tuples. This is the result using the surface plot demo: enter image description here

高值和低值可以是字符串颜色名称或 rgb 元组。这是使用表面图演示的结果: 在此处输入图片说明

回答by ImportanceOfBeingErnest

Since the methods used in other answers seems quite complicated for such easy task, here is a new answer:

由于其他答案中使用的方法对于如此简单的任务来说似乎相当复杂,因此这里有一个新答案:

Instead of a ListedColormap, which produces a discrete colormap, you may use a LinearSegmentedColormap. This can easily be created from a list using the from_listmethod.

ListedColormap您可以使用 a代替产生离散颜色图的 a LinearSegmentedColormap。这可以使用该from_list方法轻松地从列表中创建。

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

x,y,c = zip(*np.random.rand(30,3)*4-2)

norm=plt.Normalize(-2,2)
cmap = matplotlib.colors.LinearSegmentedColormap.from_list("", ["red","violet","blue"])

plt.scatter(x,y,c=c, cmap=cmap, norm=norm)
plt.colorbar()
plt.show()

enter image description here

在此处输入图片说明



More generally, if you have a list of values (e.g. [-2., -1, 2]) and corresponding colors, (e.g. ["red","violet","blue"]), such that the nth value should correspond to the nth color, you can normalize the values and supply them as tuples to the from_listmethod.

更一般地,如果您有一个值列表(例如[-2., -1, 2])和相应的颜色(例如["red","violet","blue"]),使得第nth 个值应该对应于第nth 个颜色,您可以将这些值归一化并将它们作为元组提供给from_list方法。

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

x,y,c = zip(*np.random.rand(30,3)*4-2)

cvals  = [-2., -1, 2]
colors = ["red","violet","blue"]

norm=plt.Normalize(min(cvals),max(cvals))
tuples = list(zip(map(norm,cvals), colors))
cmap = matplotlib.colors.LinearSegmentedColormap.from_list("", tuples)

plt.scatter(x,y,c=c, cmap=cmap, norm=norm)
plt.colorbar()
plt.show()

enter image description here

在此处输入图片说明