【问题标题】:Discrete colorbar is missing a color离散颜色条缺少颜色
【发布时间】:2019-10-20 23:27:24
【问题描述】:

Matplotlibs 离散颜色条在我的颜色图中缺少一种颜色定义,并且也在图中使用。

在我的示例代码中,我有七种颜色,但颜色条只显示六种颜色,尽管创建颜色图和颜色条的代码似乎与我在互联网上找到的示例相同。缺少带有 eh 标签“180”的红色。即使我更改了边界并打勾,颜色栏中的米色或浅蓝色也会被扩展。

import matplotlib.pyplot as plt
import matplotlib
import numpy as np
import pandas as pd

# 4 marker
# 7 color
n=100
c = np.random.randint(1,8,size=n)
m = np.random.randint(1,5,size=n)
x = np.random.uniform(size=n)
y = np.random.uniform(size=n)

d_data = {'P':x, 'f':y, 'node':c, 'arch':m}
df = pd.DataFrame(d_data)

# Creating a unique list of elements
l_arch = df.arch.unique() 
l_node = df.node.unique()  

# Sorting is needd for good colormap
l_arch.sort()
l_node.sort()

# Creating a markers dictionary
zti_markers = ["v","^","s","o","x","+","D"]
d_marker = dict(zip(l_arch,zti_markers[:len(l_arch)] ))

# Creating a colormap and a color dictionary; A little cheat here: I know how 
many different colors I need.
color_list = ['#a6cee3','#1f78b4','#b2df8a','#33a02c','#fb9a99','#e31a1c','#fdbf6f']
cmap = matplotlib.colors.ListedColormap(color_list)
norm = matplotlib.colors.BoundaryNorm(l_node, cmap.N)
d_color = dict(zip(l_node, color_list))

fig, ax = plt.subplots()

df['color']  = df['node'].apply(lambda x: d_color[x])
df['marker'] = df['arch'].apply(lambda x: d_marker[x])

for idx, row in df.iterrows():
    ax.scatter(row['P'], row['f'], color=row['color'], marker=row['marker'])

cax, _ = matplotlib.colorbar.make_axes(ax)
cb     = matplotlib.colorbar.ColorbarBase(cax, cmap=cmap, norm=norm, 
spacing='uniform', orientation='vertical', extend='neither') #, ticks=l_node, 
boundaries=l_node)
# cb     = matplotlib.colorbar.ColorbarBase(cax, cmap=cmap, norm=norm, 
spacing='uniform', orientation='vertical', extend='neither', ticks=l_node, boundaries=l_node)
# cb     = matplotlib.colorbar.ColorbarBase(cax, cmap=cmap, norm=norm, 
spacing='uniform', orientation='vertical', extend='neither', boundaries=[i-0.5 for i in l_node])
cb.set_ticklabels(['22','38','45','65','90','130','180'])
cb.set_ticks([0.5,1.5,2.5,3.5,4.5,5.5,6.5],update_ticks=True)
# cb.update_ticks()
cb.set_label('colorbar', rotation=90)
print(plt.gci()) # --> None
# gci(): Get the current colorable artist. Specifically, returns the current ScalarMappable instance (image or patch collection), or None if no images or patch collections have been defined.
plt.show()    

如何修复颜色栏以包含丢失的红色?

【问题讨论】:

    标签: python pandas matplotlib colorbar scatter


    【解决方案1】:

    问题是你需要用一个额外的值0定义BoundaryNorm

    norm = matplotlib.colors.BoundaryNorm([0] + list(l_node), cmap.N)
    

    (如果你有 7 种颜色,则需要 8 个边界)。或者更一般地说:

    norm = matplotlib.colors.BoundaryNorm([l_node[0]-1] + list(l_node), cmap.N)
    

    输出:

    【讨论】:

    • 嗯,那个多余的 0 不应该出现在颜色栏中。
    • 没错,我加了最小值,而你加了最大值。
    • 没关系,因为该映射不会在任何地方使用。点更多 0 甚至不在列表中 ['22','38','45','65','90','130','180']
    • 哈,是的,我在探索选项时将0 添加到标签中。
    【解决方案2】:

    BoundaryNorm,顾名思义,定义了颜色映射的边界。你需要比颜色多一个边界。例如,如果要将 20 到 50 之间的所有值映射到颜色图的第一种颜色,并将 50 到 60 之间的所有值映射到颜色图的第二种颜色,则需要 BoundaryNorm([20,50,60], 2)

    在您的情况下,您实际上并没有执行任何映射,因此您需要做的就是确保边界的数量比颜色的数量多一。

    norm = matplotlib.colors.BoundaryNorm(np.arange(len(l_node)+1), cmap.N)
    

    如果您想在某处实际使用映射,您可以定义

    norm = matplotlib.colors.BoundaryNorm(np.arange(len(l_node)+1)-0.5, cmap.N)
    

    并在

    中使用它
    ax.scatter(..., color=cmap(norm(row['node'])), )
    

    我将在此处提供后者的完整代码,其中我还简化了一些内容,

    import matplotlib.pyplot as plt
    import matplotlib
    import numpy as np
    import pandas as pd
    
    # 4 marker
    # 7 color
    n=100
    c = np.random.randint(1,8,size=n)
    m = np.random.randint(1,5,size=n)
    x = np.random.uniform(size=n)
    y = np.random.uniform(size=n)
    
    d_data = {'P':x, 'f':y, 'node':c, 'arch':m}
    df = pd.DataFrame(d_data)
    
    # Creating a unique list of elements
    l_arch = df.arch.unique() 
    l_node = df.node.unique()
    
    # Sorting is needd for good colormap
    l_arch.sort()
    l_node.sort()
    
    # Creating a markers dictionary
    zti_markers = ["v","^","s","o","x","+","D"]
    d_marker = dict(zip(l_arch,zti_markers[:len(l_arch)] ))
    
    # Creating a colormap and a color dictionary; A little cheat here: I know how 
    #many different colors I need.
    color_list = ['#a6cee3','#1f78b4','#b2df8a','#33a02c','#fb9a99','#e31a1c','#fdbf6f']
    cmap = matplotlib.colors.ListedColormap(color_list)
    norm = matplotlib.colors.BoundaryNorm(np.arange(len(l_node)+1)-0.5, cmap.N)
    d_color = dict(zip(l_node, color_list))
    
    fig, ax = plt.subplots()
    
    df['marker'] = df['arch'].apply(lambda x: d_marker[x])
    
    for idx, row in df.iterrows():
        ax.scatter(row['P'], row['f'], color=cmap(norm(row['node'])), marker=row['marker'])
    
    sm = matplotlib.cm.ScalarMappable(cmap=cmap, norm=norm)
    cb = fig.colorbar(sm, spacing='uniform', extend='neither')
    
    cb.set_ticklabels(['22','38','45','65','90','130','180'])
    cb.set_ticks(np.arange(len(l_node)), update_ticks=True)
    
    cb.set_label('colorbar', rotation=90)
    
    plt.show()
    

    上面假设“节点”是从 0 开始的后续整数。如果不是这种情况,定义边界会有点复杂,例如在唯一值之间取中间,

    import matplotlib.pyplot as plt
    import matplotlib
    import numpy as np
    import pandas as pd
    
    # 4 marker
    # 7 color
    n=100
    c = np.random.choice([5,8,19,23,44,61,87], size=n)
    m = np.random.randint(1,5,size=n)
    x = np.random.uniform(size=n)
    y = np.random.uniform(size=n)
    
    d_data = {'P':x, 'f':y, 'node':c, 'arch':m}
    df = pd.DataFrame(d_data)
    
    # Creating a unique list of elements
    l_arch = df.arch.unique() 
    l_node = df.node.unique()
    
    # Sorting is needd for good colormap
    l_arch.sort()
    l_node.sort()
    
    # Creating a markers dictionary
    zti_markers = ["v","^","s","o","x","+","D"]
    d_marker = dict(zip(l_arch,zti_markers[:len(l_arch)] ))
    
    # Creating a colormap and a color dictionary; A little cheat here: I know how 
    #many different colors I need.
    color_list = ['#a6cee3','#1f78b4','#b2df8a','#33a02c','#fb9a99','#e31a1c','#fdbf6f']
    cmap = matplotlib.colors.ListedColormap(color_list)
    bounds = np.concatenate(([l_node[0]-1], l_node[:-1] + np.diff(l_node)/2,[l_node[-1]+1] ))
    norm = matplotlib.colors.BoundaryNorm(bounds, cmap.N)
    d_color = dict(zip(l_node, color_list))
    
    fig, ax = plt.subplots()
    
    df['marker'] = df['arch'].apply(lambda x: d_marker[x])
    
    for idx, row in df.iterrows():
        ax.scatter(row['P'], row['f'], color=cmap(norm(row['node'])), marker=row['marker'])
    
    sm = matplotlib.cm.ScalarMappable(cmap=cmap, norm=norm)
    cb = fig.colorbar(sm, spacing='uniform', extend='neither')
    
    cb.set_ticklabels(['22','38','45','65','90','130','180'])
    cb.set_ticks(bounds[:-1]+np.diff(bounds)/2, update_ticks=True)
    
    cb.set_label('colorbar', rotation=90)
    
    plt.show()
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-12-20
      • 2016-04-07
      • 1970-01-01
      • 1970-01-01
      • 2017-01-28
      相关资源
      最近更新 更多