【问题标题】:Getting individual colors from a color map in matplotlib从 matplotlib 中的颜色图中获取单个颜色
【发布时间】:2026-02-20 05:35:01
【问题描述】:

如果你有Colormapcmap,例如:

cmap = matplotlib.cm.get_cmap('Spectral')

如何从 0 到 1 之间获取特定颜色,其中 0 是地图中的第一种颜色,而 1 是地图中的最后一种颜色?

理想情况下,我可以通过以下方式获得地图中的中间颜色:

>>> do_some_magic(cmap, 0.5) # Return an RGBA tuple
(0.1, 0.2, 0.3, 1.0)

【问题讨论】:

    标签: python matplotlib colors


    【解决方案1】:

    您可以使用下面的代码执行此操作,并且您问题中的代码实际上非常接近您的需要,您所要做的就是调用您拥有的cmap 对象。

    import matplotlib
    
    cmap = matplotlib.cm.get_cmap('Spectral')
    
    rgba = cmap(0.5)
    print(rgba) # (0.99807766255210428, 0.99923106502084169, 0.74602077638401709, 1.0)
    

    对于 [0.0, 1.0] 范围之外的值,它将返回下颜色和上颜色(分别)。默认情况下,这是该范围内的最小和最大颜色(因此为 0.0 和 1.0)。可以使用cmap.set_under()cmap.set_over() 更改此默认值。

    对于“特殊”数字,例如 np.nannp.inf,默认使用 0.0 值,这可以使用 cmap.set_bad() 更改,类似于上面的 under 和 over。

    最后,您可能需要对数据进行规范化,使其符合[0.0, 1.0] 范围。这可以使用matplotlib.colors.Normalize 来完成,如下面的小示例所示,其中参数vminvmax 分别描述了应该将哪些数字映射到0.0 和1.0。

    import matplotlib
    
    norm = matplotlib.colors.Normalize(vmin=10.0, vmax=20.0)
    
    print(norm(15.0)) # 0.5
    

    对数归一化器 (matplotlib.colors.LogNorm) 也可用于具有大范围值的数据范围。

    (感谢Joe Kingtontcaswell 提供有关如何改进答案的建议。)

    【讨论】:

    • 实际上,对于小于 0 或大于 1 的值,它将返回“over”或“under”颜色。默认情况下,它是颜色图底部/顶部的颜色,但这是可以更改的。例如:cmap.set_under('red'); print cmap(0.0), cmap(-0.01)
    • 嗨@Joe,感谢您的更正,我已经修改了我的答案:)
    • 还有set_bad 定义了np.nannp.inf iirc 的作用。您也应该在此处提及Normalize 方法。
    • 非常有用的信息,为什么在文档中找不到这个!?!
    • 如果这对任何人都不起作用,并且您看到 module 'matplotlib' has no attribute 'cm',请尝试将前两行替换为 import matplotlib.pyplot as plt; cmap = plt.cm.get_cmap('Spectral')
    【解决方案2】:

    为了得到rgba整数值而不是浮点值,我们可以这样做

    rgba = cmap(0.5,bytes=True)
    

    因此,为了根据 Ffisegydd 的回答简化代码,代码如下:

    #import colormap
    from matplotlib import cm
    
    #normalize item number values to colormap
    norm = matplotlib.colors.Normalize(vmin=0, vmax=1000)
    
    #colormap possible values = viridis, jet, spectral
    rgba_color = cm.jet(norm(400),bytes=True) 
    
    #400 is one of value between 0 and 1000
    

    【讨论】:

      【解决方案3】:

      我曾经遇到过类似的情况,我需要“n”号。颜色映射中的颜色,以便我可以将每种颜色分配给我的数据。 我在一个名为“mycolorpy”的包中编译了一个代码。 你可以使用 pip 安装它:

      pip install mycolorpy
      

      你可以这样做:

      from mycolorpy import colorlist as mcp
      import numpy as np
      

      示例:从 camp "winter

      创建一个包含 5 个十六进制字符串的列表
      color1=mcp.gen_color(cmap="winter",n=5)
      print(color1)
      

      输出:

      ['#0000ff', '#0040df', '#0080bf', '#00c09f', '#00ff80']
      

      另一个从 camp bwr 生成 16 种颜色列表的示例:

      color2=mcp.gen_color(cmap="bwr",n=16)
      print(color2)
      

      输出:

      ['#0000ff', '#2222ff', '#4444ff', '#6666ff', '#8888ff', '#aaaaff', '#ccccff', '#eeeeff', '#ffeeee', '#ffcccc', '#ffaaaa', '#ff8888', '#ff6666', '#ff4444', '#ff2222', '#ff0000']
      

      有一个python notebook 带有使用示例,可​​以更好地可视化这一点。

      假设您想从 cmap 生成一个颜色列表,该列表已标准化为给定数据。你可以这样做:

      a=random.randint(1000, size=(200))
      a=np.array(a)
      color1=mcp.gen_color_normalized(cmap="seismic",data_arr=a)
      plt.scatter(a,a,c=color1)
      

      输出:

      您还可以使用以下方法反转颜色:

      color1=mcp.gen_color_normalized(cmap="seismic",data_arr=a,reverse=True)
      plt.scatter(a,a,c=color1)
      

      输出:

      【讨论】:

      • 这没有回答 OP 的问题,虽然它已经有一个很好的认可答案。除此之外,已经有一些工具可以很好地执行您描述的过程,例如 CMasher (cmasher.readthedocs.io/index.html)。
      • @1313e:“优秀的批准答案”不再起作用。所以就是这样。不过,感谢您提供指向这个优秀图书馆的链接。
      • 非常感谢!拯救了我的一天。
      【解决方案4】:

      我正好遇到了这个问题,但我需要连续的图来具有高度对比的颜色。我还使用包含参考数据的公共子图进行绘图,因此我希望颜色序列始终可重复。

      我最初尝试简单地随机生成颜色,在每个绘图之前重新播种 RNG。这工作正常(在下面的代码中注释掉),但可以生成几乎无法区分的颜色。我想要高度对比的颜色,最好是从包含所有颜色的颜色图中采样。

      我可以在一个图中拥有多达 31 个数据系列,因此我将颜色图分成了这么多步骤。然后我按照确保我不会很快回到给定颜色附近的顺序走台阶。

      我的数据是一个非常不规则的时间序列,所以我想查看点和线,点与线的颜色“相反”。

      鉴于以上所有情况,最简单的方法是生成带有相关参数的字典以绘制单个系列,然后将其扩展为调用的一部分。

      这是我的代码。也许不漂亮,但实用。

      from matplotlib import cm
      cmap = cm.get_cmap('gist_rainbow')  #('hsv') #('nipy_spectral')
      
      max_colors = 31   # Constant, max mumber of series in any plot.  Ideally prime.
      color_number = 0  # Variable, incremented for each series.
      
      def restart_colors():
          global color_number
          color_number = 0
          #np.random.seed(1)
      
      def next_color():
          global color_number
          color_number += 1
          #color = tuple(np.random.uniform(0.0, 0.5, 3))
          color = cmap( ((5 * color_number) % max_colors) / max_colors )
          return color
      
      def plot_args():  # Invoked for each plot in a series as: '**(plot_args())'
          mkr = next_color()
          clr = (1 - mkr[0], 1 - mkr[1], 1 - mkr[2], mkr[3])  # Give line inverse of marker color
          return {
              "marker": "o",
              "color": clr,
              "mfc": mkr,
              "mec": mkr,
              "markersize": 0.5,
              "linewidth": 1,
          }
      
      

      我的上下文是 JupyterLab 和 Pandas,所以这里是示例绘图代码:

      restart_colors()  # Repeatable color sequence for every plot
      
      fig, axs = plt.subplots(figsize=(15, 8))
      plt.title("%s + T-meter"%name)
      
      # Plot reference temperatures:
      axs.set_ylabel("°C", rotation=0)
      for s in ["T1", "T2", "T3", "T4"]:
          df_tmeter.plot(ax=axs, x="Timestamp", y=s, label="T-meter:%s" % s, **(plot_args()))
      
      # Other series gets their own axis labels
      ax2 = axs.twinx()
      ax2.set_ylabel(units)
      
      for c in df_uptime_sensors:
          df_uptime[df_uptime["UUID"] == c].plot(
              ax=ax2, x="Timestamp", y=units, label="%s - %s" % (units, c), **(plot_args())
          )
      
      fig.tight_layout()
      plt.show()
      

      生成的图可能不是最好的例子,但是当交互式放大时它变得更加相关。

      【讨论】:

        【解决方案5】:

        为了构建来自 Ffisegyddamaliammr 的解决方案,下面是我们为自定义颜色图制作 CSV 表示的示例:

        #! /usr/bin/env python3
        import matplotlib
        import numpy as np 
        
        vmin = 0.1
        vmax = 1000
        
        norm = matplotlib.colors.Normalize(np.log10(vmin), np.log10(vmax))
        lognum = norm(np.log10([.5, 2., 10, 40, 150,1000]))
        
        cdict = {
            'red':
            (
                (0., 0, 0),
                (lognum[0], 0, 0),
                (lognum[1], 0, 0),
                (lognum[2], 1, 1),
                (lognum[3], 0.8, 0.8),
                (lognum[4], .7, .7),
            (lognum[5], .7, .7)
            ),
            'green':
            (
                (0., .6, .6),
                (lognum[0], 0.8, 0.8),
                (lognum[1], 1, 1),
                (lognum[2], 1, 1),
                (lognum[3], 0, 0),
                (lognum[4], 0, 0),
            (lognum[5], 0, 0)
            ),
            'blue':
            (
                (0., 0, 0),
                (lognum[0], 0, 0),
                (lognum[1], 0, 0),
                (lognum[2], 0, 0),
                (lognum[3], 0, 0),
                (lognum[4], 0, 0),
            (lognum[5], 1, 1)
            )
        }
        
        
        mycmap = matplotlib.colors.LinearSegmentedColormap('my_colormap', cdict, 256)   
        norm = matplotlib.colors.LogNorm(vmin, vmax)
        colors = {}
        count = 0
        step_size = 0.001
        for value in np.arange(vmin, vmax+step_size, step_size):
            count += 1
            print("%d/%d %f%%" % (count, vmax*(1./step_size), 100.*count/(vmax*(1./step_size))))
            rgba = mycmap(norm(value), bytes=True)
            color = (rgba[0], rgba[1], rgba[2])
            if color not in colors.values():
                colors[value] = color
        
        print ("value, red, green, blue")
        for value in sorted(colors.keys()):
            rgb = colors[value]
            print("%s, %s, %s, %s" % (value, rgb[0], rgb[1], rgb[2]))
        

        【讨论】:

          【解决方案6】:

          颜色图带有自己的标准化方法,因此如果您已经制作了绘图,则可以访问特定值的颜色。

          import matplotlib.pyplot as plt
          import numpy as np
          
          cmap = plt.cm.viridis
          
          cm = plt.pcolormesh(np.random.randn(10, 10), cmap=cmap)
          
          print(cmap(cm.norm(2.2)))
          

          【讨论】: