离散色条缺少颜色

时间:2019-06-05 12:42:17

标签: python pandas matplotlib colorbar scatter

Matplotlibs离散色条缺少我的颜色图中定义的一种颜色,也用于绘图中。

在我的示例代码中,我有七种颜色,但是颜色栏仅显示六种颜色,尽管用于创建颜色图和颜色栏的代码似乎与我在互联网上找到的示例相同。缺少带有标签“ 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()    

如何修复颜色条以包括缺失的红色?

2 个答案:

答案 0 :(得分:2)

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

对于您而言,您实际上并未执行任何映射,因此您所要做的就是确保边界数量比颜色数量多一。

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

enter image description here

如果您想真正地使用某个地方的映射,则可以定义

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()

答案 1 :(得分:1)

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

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)

输出:

enter image description here