调色板的中点

时间:2018-02-02 13:53:27

标签: python matplotlib bokeh

对于我目前的项目,我需要一张热图。热图需要可缩放的调色板,因为这些值仅在很小的范围内才有意义。这意味着,即使我的值从0到1,有趣的只是介于0.6和0.9之间;所以我想相应地调整热图颜色,再显示图表旁边的比例。

在Matplotlib中,我无法设置调色板的中点,除了重载原始类,如shown here in the matplotlib guide

这正是我所需要的,但没有Matplotlib中不洁净数据结构的缺点。

所以我尝试了Bokeh。 在五分钟内,我在一小时内取得了比Matplotlib更多的成就,然而,当我想在热图旁边显示色标时以及当我想要改变调色板的比例时,我陷入困境。

所以,这是我的问题:

如何在Bokeh或Matplotlib中缩放调色板?

有没有办法在热图旁边显示带注释的颜色条?

import pandas
scores_df = pd.DataFrame(myScores, index=c_range, columns=gamma_range)

import bkcharts
from bokeh.palettes import Inferno256
hm = bkcharts.HeatMap(scores_df, palette=Inferno256)
# here: how to insert a color bar?
# here: how to correctly scale the inferno256 palette?
hm.ylabel = "C"
hm.xlabel = "gamma"
bkcharts.output_file('heatmap.html')

按照Aarons提示,我现在实现如下:

import matplotlib.pyplot as plt
import matplotlib.colors as colors
from bokeh.palettes import Inferno256


def print_scores(scores, gamma_range, C_range):
    # load a color map
    # find other colormaps here
    # https://bokeh.pydata.org/en/latest/docs/reference/palettes.html
    cmap = colors.ListedColormap(Inferno256, len(Inferno256))
    fig, ax = plt.subplots(1, 1, figsize=(6, 5))

    # adjust lower, midlle and upper bound of the colormap
    cmin = np.percentile(scores, 10)
    cmid = np.percentile(scores, 75)
    cmax = np.percentile(scores, 99)
    bounds = np.append(np.linspace(cmin, cmid), np.linspace(cmid, cmax))
    norm = colors.BoundaryNorm(boundaries=bounds, ncolors=len(Inferno256))

    pcm = ax.pcolormesh(np.log10(gamma_range),
                    np.log10(C_range),
                    scores,
                    norm=norm,
                    cmap=cmap)
    fig.colorbar(pcm, ax=ax, extend='both', orientation='vertical')
    plt.show()

1 个答案:

答案 0 :(得分:0)

ImportanceOfBeingErnest正确地指出我的第一条评论并不完全清楚(或措辞准确)..

mpl中的大多数绘图函数都有一个kwarg:norm=这表示一个类(mpl.colors.Normalize的子类),它将您的数据数组映射到值[0 - 1]映射到色彩映射的目的,但实际上不会影响数据的数值。有几个内置子类,您也可以创建自己的子类。对于这个应用程序,我可能会使用BoundaryNorm。此类将N-1个均匀间隔的颜色映射到N个离散边界之间的空间。

我稍微修改了example以更好地适应您的应用程序:

#adaptation of https://matplotlib.org/users/colormapnorms.html#discrete-bounds

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors as colors
from matplotlib.mlab import bivariate_normal

#example data
N = 100
X, Y = np.mgrid[-3:3:complex(0, N), -2:2:complex(0, N)]
Z1 = (bivariate_normal(X, Y, 1., 1., 1.0, 1.0))**2  \
    - 0.4 * (bivariate_normal(X, Y, 1.0, 1.0, -1.0, 0.0))**2
Z1 = Z1/0.03

'''
BoundaryNorm: For this one you provide the boundaries for your colors,
and the Norm puts the first color in between the first pair, the
second color between the second pair, etc.
'''

fig, ax = plt.subplots(3, 1, figsize=(8, 8))
ax = ax.flatten()
# even bounds gives a contour-like effect
bounds = np.linspace(-1, 1)
norm = colors.BoundaryNorm(boundaries=bounds, ncolors=256)
pcm = ax[0].pcolormesh(X, Y, Z1,
                       norm=norm,
                       cmap='RdBu_r')
fig.colorbar(pcm, ax=ax[0], extend='both', orientation='vertical')

# clipped bounds emphasize particular region of data:
bounds = np.linspace(-.2, .5)
norm = colors.BoundaryNorm(boundaries=bounds, ncolors=256)
pcm = ax[1].pcolormesh(X, Y, Z1, norm=norm, cmap='RdBu_r')
fig.colorbar(pcm, ax=ax[1], extend='both', orientation='vertical')

# now if we want 0 to be white still, we must have 0 in the middle of our array
bounds = np.append(np.linspace(-.2, 0), np.linspace(0, .5))
norm = colors.BoundaryNorm(boundaries=bounds, ncolors=256)
pcm = ax[2].pcolormesh(X, Y, Z1, norm=norm, cmap='RdBu_r')
fig.colorbar(pcm, ax=ax[2], extend='both', orientation='vertical')

fig.show()

enter image description here