Python:对数颜色条偏移,白色偏移到中心 [英] Python: Shifted logarithmic colorbar, white color offset to center

查看:29
本文介绍了Python:对数颜色条偏移,白色偏移到中心的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在努力使用 pyplot.imshow 绘制数据.我使用 'RdBu_r' 颜色图,并且我需要白色在对数刻度上的值 1 不以 1 为中心.但是我该怎么做呢?我试过 'center=1' 其中

<小时>适用于 nan 值的更新解决方案:您需要用某个值(数组中值范围之外的最佳值)替换 nan 值,然后用这些数字屏蔽数组.在 MidPointLogNorm 内部,我们需要注意nan值,如这个问题.

将 numpy 导入为 np导入matplotlib.pyplot作为plt从 matplotlib.colors 导入 LogNormx,y = np.meshgrid(np.linspace(-3,0,19), np.arange(10))f = λ x,y : 10**x*(1+y)z = f(x,y)z[1:3,1:3] = np.NaN#由于nan值不能在对数刻度上使用,因此我们需要将其更改为# nan 以外的东西,替换 = np.nanmax(z)+900z = np.where(np.isnan(z), 替换, z)# 现在我们可以屏蔽数组z = np.ma.masked_where(z == 替换,z)图, (ax,ax2) = plt.subplots(ncols=2, figsize=(12,4.8))im = ax.pcolormesh(x,y,z, cmap="RdBu_r", norm=LogNorm(vmin=z.min(), vmax=z.max()))fig.colorbar(im,ax = ax)ax.set_title("LogNorm")类 MidPointLogNorm(LogNorm):def __init __(self,vmin = None,vmax = None,midpoint = None,clip = False):LogNorm .__ init __(self,vmin = vmin,vmax = vmax,clip = clip)self.midpoint=中点def __call __(自身,值,剪辑=无):结果,is_scalar = self.process_value(value)x, y = [np.log(self.vmin), np.log(self.midpoint), np.log(self.vmax)], [0, 0.5, 1]返回np.ma.array(np.interp(np.log(value),x,y),mask = result.mask,copy = False)im2 = ax2.pcolormesh(x,y,z, cmap="RdBu_r",norm=MidPointLogNorm(vmin=z.min(), vmax=z.max(), midpoint=1))fig.colorbar(im2, ax=ax2)ax2.set_title("MidPointLogNorm")plt.show()

I am struggling to plot my data using pyplot.imshow. I use the 'RdBu_r' colormap, and I need the white color to be at value 1 on a logarithmic scale which is not centered at 1. But how can I do it? I tried 'center=1' which works for seaborn, but there is no such attribute in matplotlib. I also tried this:

import matplotlib.pyplot as plt
im=plt.imshow(proportion, cmap="RdBu_r", norm=LogNorm(), vmin=0.01, vmax=10)
axs=plt.gca()
cb = plt.colorbar(im, ax=axs,extend="both")

where proportion is my data array, ranging from 0.01 to 10. However there seems to be no way to specify that the white should be at 1 on this scale. Is there a way to do that?

Note again that I need to make use a gradient of colors here and a logarithmic normalization.

解决方案

There are some questions and answers about defining a midpoint on a colorscale. Especially this one, which is also now part of the matplotlib documentation.

The idea is to subclass matplotlib.colors.Normalize and let it take a further argument midpoint. This can then be used to linearly interpolate the two ranges on either side of the midpoint to the ranges [0,0.5] and [0.5,1].

To have a midpoint on a logarithmic scale, we can in principle do the same thing, just that we subclass matplotlib.colors.LogNorm and take the logarithm of all values, then interpolate this logarithm on the ranges [0,0.5] and [0.5,1].

In the following example we have data between 0.001 and 10. Using the usual LogNorm this results in the middle of the colormap (white in the case of the RdBu colormap) to be at 0.1. If we want to have white at 1, we specify 1 as the midpoint in the MidPointLogNorm.

import numpy as np
import matplotlib.pyplot as plt
from  matplotlib.colors import LogNorm

x,y = np.meshgrid(np.linspace(-3,0,19), np.arange(10))
f = lambda x,y : 10**x*(1+y)
z = f(x,y)

fig, (ax,ax2) = plt.subplots(ncols=2, figsize=(12,4.8))

im = ax.pcolormesh(x,y,z, cmap="RdBu_r", norm=LogNorm(vmin=z.min(), vmax=z.max()))
fig.colorbar(im, ax=ax)
ax.set_title("LogNorm")

class MidPointLogNorm(LogNorm):
    def __init__(self, vmin=None, vmax=None, midpoint=None, clip=False):
        LogNorm.__init__(self,vmin=vmin, vmax=vmax, clip=clip)
        self.midpoint=midpoint
    def __call__(self, value, clip=None):
        # I'm ignoring masked values and all kinds of edge cases to make a
        # simple example...
        x, y = [np.log(self.vmin), np.log(self.midpoint), np.log(self.vmax)], [0, 0.5, 1]
        return np.ma.masked_array(np.interp(np.log(value), x, y))


im2 = ax2.pcolormesh(x,y,z, cmap="RdBu_r", 
                            norm=MidPointLogNorm(vmin=z.min(), vmax=z.max(), midpoint=1))
fig.colorbar(im2, ax=ax2)
ax2.set_title("MidPointLogNorm")
plt.show()


Updated solution which works for nan values: You need to replace the nan values by some value (best one outside the range of values from the array) then mask the array by those numbers. Inside the MidPointLogNorm we need to take care of nan values, as shown in this question.

import numpy as np
import matplotlib.pyplot as plt
from  matplotlib.colors import LogNorm

x,y = np.meshgrid(np.linspace(-3,0,19), np.arange(10))
f = lambda x,y : 10**x*(1+y)
z = f(x,y)
z[1:3,1:3] = np.NaN

#since nan values cannot be used on a log scale, we need to change them to 
# something other than nan, 
replace = np.nanmax(z)+900
z = np.where(np.isnan(z), replace, z)
# now we can mask the array
z = np.ma.masked_where(z == replace, z)

fig, (ax,ax2) = plt.subplots(ncols=2, figsize=(12,4.8))

im = ax.pcolormesh(x,y,z, cmap="RdBu_r", norm=LogNorm(vmin=z.min(), vmax=z.max()))
fig.colorbar(im, ax=ax)
ax.set_title("LogNorm")

class MidPointLogNorm(LogNorm):
    def __init__(self, vmin=None, vmax=None, midpoint=None, clip=False):
        LogNorm.__init__(self,vmin=vmin, vmax=vmax, clip=clip)
        self.midpoint=midpoint
    def __call__(self, value, clip=None):
        result, is_scalar = self.process_value(value)
        x, y = [np.log(self.vmin), np.log(self.midpoint), np.log(self.vmax)], [0, 0.5, 1]
        return np.ma.array(np.interp(np.log(value), x, y), mask=result.mask, copy=False)


im2 = ax2.pcolormesh(x,y,z, cmap="RdBu_r", 
                            norm=MidPointLogNorm(vmin=z.min(), vmax=z.max(), midpoint=1))
fig.colorbar(im2, ax=ax2)
ax2.set_title("MidPointLogNorm")
plt.show()

这篇关于Python:对数颜色条偏移,白色偏移到中心的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆