【问题标题】:How to generate random colors in matplotlib?如何在 matplotlib 中生成随机颜色?
【发布时间】:2013-01-21 03:14:56
【问题描述】:

如何生成随机颜色以传递给绘图函数的简单示例是什么?

我在循环中调用 scatter 并希望每个绘图都具有不同的颜色。

for X,Y in data:
   scatter(X, Y, c=??)

c: 一种颜色。 c 可以是单个颜色格式字符串,也可以是长度为 N 的颜色规范序列,或者是要使用 cmap 和通过 kwargs 指定的规范映射到颜色的 N 数字序列(见下文)。请注意,c 不应是单个数字 RGB 或 RGBA 序列,因为它与要进行颜色映射的值数组无法区分。 c 可以是一个二维数组,其中的行是 RGB 或 RGBA。

【问题讨论】:

标签: python matplotlib


【解决方案1】:

我在循环中调用 scatter 并希望每个图都具有不同的颜色。

基于此,并根据您的回答:在我看来,您实际上需要 n distinct 数据集的颜色; 您希望将整数索引 0, 1, ..., n-1 映射到不同的 RGB 颜色。 类似于:

这是执行此操作的函数:

import matplotlib.pyplot as plt

def get_cmap(n, name='hsv'):
    '''Returns a function that maps each index in 0, 1, ..., n-1 to a distinct 
    RGB color; the keyword argument name must be a standard mpl colormap name.'''
    return plt.cm.get_cmap(name, n)

在你的pseudo中使用-code sn-p in the question:

cmap = get_cmap(len(data))
for i, (X, Y) in enumerate(data):
   scatter(X, Y, c=cmap(i))

我使用以下代码在我的答案中生成了该图:

import matplotlib.pyplot as plt

def get_cmap(n, name='hsv'):
    '''Returns a function that maps each index in 0, 1, ..., n-1 to a distinct 
    RGB color; the keyword argument name must be a standard mpl colormap name.'''
    return plt.cm.get_cmap(name, n)

def main():
    N = 30
    fig=plt.figure()
    ax=fig.add_subplot(111)   
    plt.axis('scaled')
    ax.set_xlim([ 0, N])
    ax.set_ylim([-0.5, 0.5])
    cmap = get_cmap(N)
    for i in range(N):
        rect = plt.Rectangle((i, -0.5), 1, 1, facecolor=cmap(i))
        ax.add_artist(rect)
    ax.set_yticks([])
    plt.show()

if __name__=='__main__':
    main()

使用 Python 2.7 和 matplotlib 1.5 以及 Python 3.5 和 matplotlib 2.0 进行测试。它按预期工作。

【讨论】:

  • @user1941407 谢谢! :) 我希望我知道为什么有人匿名否决了答案。
  • 可能很复杂
  • 似乎不起作用?似乎根本没有插入 python 控制台。
  • @mjwrazor 对不起,我不关注。你能详细说明什么“不起作用”吗?
  • 我试图将方法放在 python 控制台中,控制台从不读取它。方法末尾的逻辑也没有意义。为什么返回一个调用另一个返回执行方法的方法的方法。为什么不直接返回执行的方法?
【解决方案2】:
for X,Y in data:
   scatter(X, Y, c=numpy.random.rand(3,))

【讨论】:

  • 如果要绘制三个值怎么办?
  • 3代表R、G、B分量的3个值吗?
  • 不用numpy,可以使用color=(random.uniform(0, 1), random.uniform(0, 1), random.uniform(0, 1))
  • 效率更高,打字更少:scatter(X,Y, c=numpy.random.rand(len(X),3)
【解决方案3】:

详细说明@john-mee 的答案,如果您有任意长的数据但不需要严格唯一的颜色:

对于python 2:

from itertools import cycle
cycol = cycle('bgrcmk')

for X,Y in data:
    scatter(X, Y, c=cycol.next())

对于python 3:

from itertools import cycle
cycol = cycle('bgrcmk')

for X,Y in data:
    scatter(X, Y, c=next(cycol))

这样的好处是颜色容易控制,而且很短。

【讨论】:

    【解决方案4】:

    有一段时间我对 matplotlib 不生成具有随机颜色的颜色图这一事实感到非常恼火,因为这是分割和聚类任务的常见需求。

    仅通过生成随机颜色,我们可能会以一些太亮或太暗结束,从而使可视化变得困难。此外,通常我们需要第一个或最后一个颜色为黑色,代表背景或异常值。所以我为我的日常工作写了一个小函数

    这是它的行为:

    new_cmap = rand_cmap(100, type='bright', first_color_black=True, last_color_black=False, verbose=True)
    

    你只是使用 new_cmap 作为 matplotlib 上的颜色图:

    ax.scatter(X,Y, c=label, cmap=new_cmap, vmin=0, vmax=num_labels)
    

    代码在这里:

    def rand_cmap(nlabels, type='bright', first_color_black=True, last_color_black=False, verbose=True):
        """
        Creates a random colormap to be used together with matplotlib. Useful for segmentation tasks
        :param nlabels: Number of labels (size of colormap)
        :param type: 'bright' for strong colors, 'soft' for pastel colors
        :param first_color_black: Option to use first color as black, True or False
        :param last_color_black: Option to use last color as black, True or False
        :param verbose: Prints the number of labels and shows the colormap. True or False
        :return: colormap for matplotlib
        """
        from matplotlib.colors import LinearSegmentedColormap
        import colorsys
        import numpy as np
    
    
        if type not in ('bright', 'soft'):
            print ('Please choose "bright" or "soft" for type')
            return
    
        if verbose:
            print('Number of labels: ' + str(nlabels))
    
        # Generate color map for bright colors, based on hsv
        if type == 'bright':
            randHSVcolors = [(np.random.uniform(low=0.0, high=1),
                              np.random.uniform(low=0.2, high=1),
                              np.random.uniform(low=0.9, high=1)) for i in xrange(nlabels)]
    
            # Convert HSV list to RGB
            randRGBcolors = []
            for HSVcolor in randHSVcolors:
                randRGBcolors.append(colorsys.hsv_to_rgb(HSVcolor[0], HSVcolor[1], HSVcolor[2]))
    
            if first_color_black:
                randRGBcolors[0] = [0, 0, 0]
    
            if last_color_black:
                randRGBcolors[-1] = [0, 0, 0]
    
            random_colormap = LinearSegmentedColormap.from_list('new_map', randRGBcolors, N=nlabels)
    
        # Generate soft pastel colors, by limiting the RGB spectrum
        if type == 'soft':
            low = 0.6
            high = 0.95
            randRGBcolors = [(np.random.uniform(low=low, high=high),
                              np.random.uniform(low=low, high=high),
                              np.random.uniform(low=low, high=high)) for i in xrange(nlabels)]
    
            if first_color_black:
                randRGBcolors[0] = [0, 0, 0]
    
            if last_color_black:
                randRGBcolors[-1] = [0, 0, 0]
            random_colormap = LinearSegmentedColormap.from_list('new_map', randRGBcolors, N=nlabels)
    
        # Display colorbar
        if verbose:
            from matplotlib import colors, colorbar
            from matplotlib import pyplot as plt
            fig, ax = plt.subplots(1, 1, figsize=(15, 0.5))
    
            bounds = np.linspace(0, nlabels, nlabels + 1)
            norm = colors.BoundaryNorm(bounds, nlabels)
    
            cb = colorbar.ColorbarBase(ax, cmap=random_colormap, norm=norm, spacing='proportional', ticks=None,
                                       boundaries=bounds, format='%1i', orientation=u'horizontal')
    
        return random_colormap
    

    它也在github上: https://github.com/delestro/rand_cmap

    【讨论】:

    • 需要将xrange 替换为range 以与Python 3 兼容,通常您希望将False 传递为verbose。 (还有为什么没有 pypi 发布?)
    【解决方案5】:

    当少于 9 个数据集时:

    colors = "bgrcmykw"
    color_index = 0
    
    for X,Y in data:
        scatter(X,Y, c=colors[color_index])
        color_index += 1
    

    【讨论】:

      【解决方案6】:

      由于问题是How to generate random colors in matplotlib?,并且当我正在寻找有关pie plots 的答案时,我认为值得在这里回答(pies

      import numpy as np
      from random import sample
      import matplotlib.pyplot as plt
      import matplotlib.colors as pltc
      all_colors = [k for k,v in pltc.cnames.items()]
      
      fracs = np.array([600, 179, 154, 139, 126, 1185])
      labels = ["label1", "label2", "label3", "label4", "label5", "label6"]
      explode = ((fracs == max(fracs)).astype(int) / 20).tolist()
      
      for val in range(2):
          colors = sample(all_colors, len(fracs))
          plt.figure(figsize=(8,8))
          plt.pie(fracs, labels=labels, autopct='%1.1f%%', 
                  shadow=True, explode=explode, colors=colors)
          plt.legend(labels, loc=(1.05, 0.7), shadow=True)
          plt.show()
      

      输出

      【讨论】:

      • 嘿,这正是我要找的。然而,在你的第二张照片中(这也发生在我身上)你得到几乎相同的颜色(米色/白色)。是否可以使用这种方法,但以挑选出更多不同颜色的方式进行采样?
      【解决方案7】:

      这是 Ali 的答案的更简洁版本,每个情节提供一种不同的颜色:

      import matplotlib.pyplot as plt
      
      N = len(data)
      cmap = plt.cm.get_cmap("hsv", N+1)
      for i in range(N):
          X,Y = data[i]
          plt.scatter(X, Y, c=cmap(i))
      

      【讨论】:

        【解决方案8】:

        基于 Ali 和 Champitoad 的回答:

        如果您想尝试不同的调色板,只需几行即可:

        cmap=plt.cm.get_cmap(plt.cm.viridis, 143)
        

        143 是您要采样的颜色数

        我选择 143 是因为颜色图上的整个颜色范围都在这里发挥作用。您可以做的是每次迭代都对第 n 个颜色进行采样以获得颜色图效果。

        n=20
        for i,(x,y) in enumerate(points):
            plt.scatter(x, y, c=cmap(n*i))
        

        【讨论】:

          【解决方案9】:

          改进答案https://stackoverflow.com/a/14720445/6654512 以使用 Python3。这段代码有时会生成大于 1 的数字,matplotlib 会抛出错误。

          for X,Y in data:
             scatter(X, Y, c=numpy.random.random(3))
          

          【讨论】:

            【解决方案10】:
            enter code here
            
            import numpy as np
            
            clrs = np.linspace( 0, 1, 18 )  # It will generate 
            # color only for 18 for more change the number
            np.random.shuffle(clrs)
            colors = []
            for i in range(0, 72, 4):
                idx = np.arange( 0, 18, 1 )
                np.random.shuffle(idx)
                r = clrs[idx[0]]
                g = clrs[idx[1]]
                b = clrs[idx[2]]
                a = clrs[idx[3]]
                colors.append([r, g, b, a])
            

            【讨论】:

            • 在绘制图形时在颜色中分配此颜色列表
            【解决方案11】:

            如果您想确保颜色不同 - 但不知道需要多少种颜色。尝试这样的事情。它从光谱的相对两侧选择颜色并系统地增加粒度。

            import math
            
            def calc(val, max = 16):
                if val < 1:
                    return 0
                if val == 1:
                    return max
            
                l = math.floor(math.log2(val-1))    #level 
                d = max/2**(l+1)                    #devision
                n = val-2**l                        #node
                return d*(2*n-1)
            
            import matplotlib.pyplot as plt
            
            N = 16
            cmap = cmap = plt.cm.get_cmap('gist_rainbow', N)
            
            fig, axs = plt.subplots(2)
            for ax in axs:
                ax.set_xlim([ 0, N])
                ax.set_ylim([-0.5, 0.5])
                ax.set_yticks([])
            
            for i in range(0,N+1):
                v = int(calc(i, max = N))
                rect0 = plt.Rectangle((i, -0.5), 1, 1, facecolor=cmap(i))
                rect1 = plt.Rectangle((i, -0.5), 1, 1, facecolor=cmap(v))
                axs[0].add_artist(rect0)
                axs[1].add_artist(rect1)
            
            plt.xticks(range(0, N), [int(calc(i, N)) for i in range(0, N)])
            plt.show()
            

            output

            感谢 @Ali 提供基本实现。

            【讨论】:

              【解决方案12】:

              可重现的结果

              # generate random colors
              colors_ = lambda n: list(map(lambda i: "#" + "%06x" % random.randint(0, 0xFFFFFF),range(n)))
              
              fig = plt.figure()
              fig.subplots_adjust(hspace=0.4, wspace=0.4)
              
              # how many random colors to generate?
              colors = colors_(6)
              for i,color in zip(range(1, 7), colors):
                  ax = fig.add_subplot(2, 3, i)
                  ax.text(0.5, 0.5, str((2, 3, i)),
                         fontsize=18, ha='center', color=color)
              

              输出

              【讨论】:

                猜你喜欢
                • 2023-01-05
                • 1970-01-01
                • 2010-12-07
                • 2012-06-13
                • 1970-01-01
                • 1970-01-01
                • 2013-07-15
                • 2011-08-13
                • 1970-01-01
                相关资源
                最近更新 更多