matplotlib 如何将颜色分配给热图上的特定值

mnowg1ta  于 2023-06-23  发布在  其他
关注(0)|答案(4)|浏览(163)

我在做一张海运热图。我使用的是'viridis',但我稍微修改了一下,使一些值获得特定的颜色。在我的MWE中,.set_over用于将90以上的值设置为'black'.set_under用于将10以下的值设置为'white'。我还屏蔽了部分热图。一切正常。
如何将中间范围值20Map到'orange',而不影响当前颜色条的外观?如您所见,.set_over.set_under不会更改颜色条的外观。

import matplotlib
import seaborn as sns
import numpy as np
np.random.seed(7)
A = np.random.randint(0,100, size=(20,20))
mask_array = np.zeros((20, 20), dtype=bool)
mask_array[:, :5] = True
cmap = matplotlib.colormaps["viridis"]
# Set the under color to white
cmap.set_under("white")
# Set the voer color to white
cmap.set_over("black")
# Set the background color

g = sns.heatmap(A, vmin=10, vmax=90, cmap=cmap, mask=mask_array)
# Set color of masked region
g.set_facecolor('lightgrey')

Map value to specific color in seaborn heatmap我看过,但我不确定如何用它来解决我的问题。

zaq34kh6

zaq34kh61#

考虑以下几点:

import matplotlib as mpl
import seaborn as sns
import numpy as np

A = np.random.randint(0,100, size=(20,20))
mask_array = np.zeros((20, 20), dtype=bool)
mask_array[:, :5] = True
cmap = mpl.colormaps["viridis"]

newcolors = cmap(np.linspace(0, 1, 100))
newcolors[:10] = np.array([1,1,1,1])
newcolors[90:] = np.array([0,0,0,1])
newcolors[20] = mpl.colors.to_rgb('tab:orange') + (1,)

newcmap = mpl.colors.ListedColormap(newcolors)

g = sns.heatmap(A, cmap=newcmap, mask=mask_array)
# Set color of masked region
g.set_facecolor('lightgrey')

样品结果:

下面的代码(附加到上面的脚本中)将使颜色条具有可见的轮廓。

cbar_ax = g.figure.axes[-1]

for spine in cbar_ax.spines.values():
    spine.set(visible=True)

带大纲的示例结果:

要遮罩热图的颜色,但不显示更新的颜色条,请设置cbar=False,然后附加自定义颜色条,如Standalone colorbar所示。

g = sns.heatmap(A, cmap=newcmap, mask=mask_array, cbar=False)

# add a new axes of the desired shape
cb = g.figure.add_axes([0.93, 0.11, 0.025, 0.77])

# attach a new colorbar to the axes
mpl.colorbar.ColorbarBase(cb, cmap='viridis', norm=mpl.colors.Normalize(10, 90),  # vmax and vmin
                          label=None, ticks=range(10, 91, 10))

fnvucqvd

fnvucqvd2#

this answer中提取,这里有一个使用遮罩而不是自定义颜色条的解决方案:

import matplotlib
import seaborn as sns
import numpy as np
from matplotlib.colors import ListedColormap

np.random.seed(7)
A = np.random.randint(0,100, size=(20,20))
mask_array = np.zeros((20, 20), dtype=bool)
mask_array[:, :5] = True
# cmap = matplotlib.colormaps["viridis"]
cmap = matplotlib.cm.get_cmap('viridis')

# Set the under color to white
cmap.set_under("white")

# Set the voer color to white
cmap.set_over("black")

# Set the background color

g = sns.heatmap(A, vmin=10, vmax=90, cmap=cmap, mask=mask_array)
# Set color of masked region
g.set_facecolor('lightgrey')

special_data = np.ma.masked_where(A==20, A)
sns.heatmap(special_data, cmap=ListedColormap(['orange']), 
            mask=(special_data != 1), cbar=False)
knpiaxh1

knpiaxh13#

  • 困难来自于需要使用多于一个掩模。
  • mask_array,如果数组仅为int,则掩码为A == 20,如果数组为float,则掩码为20 <= A < 21
  • matplotlib.colors.Colormap仅提供3种设置颜色的方法。
  1. set_under
  2. set_over
  3. set_bad-设置已用于mask_array**的掩码值的颜色。
  • with_extremes-将三者合并。
  • cmap = mpl.colormaps['viridis'].with_extremes(bad='orange', under='w', over='k')

  • 使用这些方法不会影响颜色条的外观。

导入和样本数据

import numpy as np
import seaborn as sns
import matplotlib as mpl

# set for repeatable sample
np.random.seed(2023)

# random 20 x 20 array
# A = np.random.randint(0, 100, size=(20, 20))  # random integers
A = np.random.random(size=(20, 20)) * 100  # random floats

1.不显示切片列

  • 这是最简单的选择,因为它释放了mask
# remove the unneeded columns
A = A[:, 5:]

# create the value mask
mask = np.logical_and(A >= 20, A < 21)

# create the colormap with extremes
cmap = mpl.colormaps["viridis"].with_extremes(bad='orange', under='w', over='k')

# plot
g = sns.heatmap(A, vmin=10, vmax=90, cmap=cmap, mask=mask)

# reset the xticklabels to show the correct column labels
_ = g.set_xticks(ticks=g.get_xticks(), labels=range(5, 20))

2.显示所有列

  • 这是一个比较麻烦的选项,因为像Ben提供的answer一样,这需要手动添加颜色到cmap,并添加自定义颜色条。
  • 使用mask,或数组中的任何np.nan值,都用set_bad着色。
  • 这重用了我之前添加到Ben的答案中的颜色条创建方法,该方法来自Standalone colorbar
  • Creating Colormaps in Matplotlib中所示,可以将新颜色添加到重采样色图中的颜色切片中。
  • 如果使用了vminvmax,则不会获得正确的值,因为这些选项会更改颜色条的范围。
# create the column mask
mask = np.zeros((20, 20), dtype=bool)
mask[:, :5] = True  # A[:, :5] = np.nan has the same effect

# slice the colors into the range of values in the array
colors = mpl.colormaps["viridis"].resampled(100).colors

# map a specific value range to a color; use a range for floats, and / or set a hight number to resampled
colors[19:21] = mpl.colors.to_rgba('tab:orange')

# create the new colormap with extremes
cmap = mpl.colors.ListedColormap(colors).with_extremes(bad='lightgray', under='w', over='k')

# draw the heatmap
g = sns.heatmap(A, cmap=cmap, mask=mask, cbar=False)

# add a new axes of the desired shape
cb_ax = g.figure.add_axes([0.93, 0.11, 0.025, 0.77])

# attach a new colorbar to the axes without an outline
cb = mpl.colorbar.ColorbarBase(cb_ax, cmap='viridis', norm=mpl.colors.Normalize(10, 90),  # vmax and vmin
                               label=None, ticks=range(10, 91, 10)).outline.set_visible(False)

3.让列和坏值共享颜色

# create the value mask
mask = np.logical_and(A >= 20, A < 21)

# add the unwanted column to the mask as np.nan
mask[:, :5] = np.nan

# create the colormap with extremes
cmap = mpl.colormaps["viridis"].with_extremes(bad='orchid', under='w', over='k')

# plot
g = sns.heatmap(A, vmin=10, vmax=90, cmap=cmap, mask=mask)

57hvy0tb

57hvy0tb4#

创建自定义颜色Mapmatplotlib.colors.LinearSegmentedColormap.from_list .当使用连续颜色Map(如“viridis”)时,这里没有一种直接方法来将特定值(如20)设置为特定颜色(如橙子)。

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

np.random.seed(7)
A = np.random.randint(0,100, size=(20,20))
mask_array = np.zeros((20, 20), dtype=bool)
mask_array[:, :5] = True

# Create a colormap for each part
colormap_under_10 = plt.cm.viridis(np.linspace(0, 0.1, 10))
colormap_10_30 = plt.cm.Oranges(np.linspace(0.5, 1, 20))
colormap_above_30 = plt.cm.viridis(np.linspace(0.1, 1, 70))

# Combine them and build a new colormap
colors_combined = np.vstack((colormap_under_10, colormap_10_30, colormap_above_30))
mymap = colors.LinearSegmentedColormap.from_list('colormap_combined', colors_combined)

ax = sns.heatmap(A, vmin=0, vmax=100, cmap=mymap, mask=mask_array)

# Set color of masked region
ax.set_facecolor('lightgrey')

plt.show()

相关问题