Matplotlib imshow - 在某些值范围内“加速"颜色变化 [英] Matplotlib imshow - 'speed up' colour change in certain value ranges

查看:44
本文介绍了Matplotlib imshow - 在某些值范围内“加速"颜色变化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在 imshow 中在 x,y 轴上绘制一些标签,但超过 95% 的点位于 0-0.2 范围内,而不到 10% 位于 0.2-1.0 范围内.使用默认的jet"颜色图,这会导致几乎所有图都显示为蓝色,即使 95% 的数据存在视觉上无法观察到的差异.

有没有办法告诉 matplotlib,例如,将颜色在 0.0-0.1 范围内变化的速率增加四倍,并相应地缩放剩余的 0.2-1.0 范围?任何帮助将不胜感激.

提前致谢!

看到这只是一种视觉表示,我意识到我必须采取的一种选择是将0.2范围内的数据重新缩放到我认为合适的任何值,以使更改更明显,然后手动进行相应地创建颜色条.我仍然希望能够在所有可能的情况下让matplotlib的imshow本地执行此操作.

解决方案

如果您想在图像图中强调数据中的小值,我绝不会更改实际数据本身.这会导致很多混乱.相反,正如我在评论中所说,更改颜色图.

I'm currently working to plot some labels over the x,y axis in imshow, but over 95% of the points sit in the 0-0.2 range, whereas less than 10% sit in the 0.2-1.0 range. Using the default 'jet' colourmap, this results in almost all the plots showing up as blue, even though there is variance in 95% of the data that becomes visually unobservable.

Is there a way to tell matplotlib to, for example, quadruple the rate at which the colours change in the 0.0-0.1 range, and scale the remaining 0.2-1.0 range accordingly? Any help would be greatly appreciated.

Thanks in advance!

EDIT: Seeing at this is just a visual representation, I realised that one option I have is to instead re-scale the data in the 0.2 range down to whatever value I see fit so that the changes are more visible, then manually create the colour bar accordingly. I would still prefer to be able to have matplotlib's imshow do this natively if at all possible though.

解决方案

In case you want to emphazise small values in your data in an image plot, I would never change the actual data itself. That can lead to a lot of confusion. Instead, as I said in the comments, change the colormap.

Ways of doing so are documented in the Matplotlib Color Normalization Tutorial as well as here on SO. Especially this article and the answers within are really illustrative of the possibilities one has.

I combined two concepts in the example below to show the options.

  • One is to rescale the colormap such that the value that initially was at the middle (midpoint) of your colormap is shifted down. In this way more variation is added between 0 and the new midpoint, while everything above is stretched. One can think of this as two linear colormaps spliced together.
  • The other is to simply use a logarithmic scaling of the colors.

This is the example code

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


def shiftedColorMap(cmap, start=0, midpoint=0.5, stop=1.0, name='shiftedcmap'):
    '''
    function taken from
    https://stackoverflow.com/questions/7404116/...
        ...defining-the-midpoint-of-a-colormap-in-matplotlib
    Function to offset the "center" of a colormap. Useful for
    data with a negative min and positive max and you want the
    middle of the colormap's dynamic range to be at zero

    Input
    -----
      cmap : The matplotlib colormap to be altered
      start : Offset from lowest point in the colormap's range.
          Defaults to 0.0 (no lower ofset). Should be between
          0.0 and `midpoint`.
      midpoint : The new center of the colormap. Defaults to 
          0.5 (no shift). Should be between 0.0 and 1.0. In
          general, this should be  1 - vmax/(vmax + abs(vmin))
          For example if your data range from -15.0 to +5.0 and
          you want the center of the colormap at 0.0, `midpoint`
          should be set to  1 - 5/(5 + 15)) or 0.75
      stop : Offset from highets point in the colormap's range.
          Defaults to 1.0 (no upper ofset). Should be between
          `midpoint` and 1.0.
    '''
    cdict = {  'red': [],  'green': [], 'blue': [],  'alpha': []  }

    # regular index to compute the colors
    reg_index = np.linspace(start, stop, 257)

    # shifted index to match the data
    shift_index = np.hstack([
        np.linspace(0.0, midpoint, 128, endpoint=False), 
        np.linspace(midpoint, 1.0, 129, endpoint=True)
    ])

    for ri, si in zip(reg_index, shift_index):
        r, g, b, a = cmap(ri)

        cdict['red'].append((si, r, r))
        cdict['green'].append((si, g, g))
        cdict['blue'].append((si, b, b))
        cdict['alpha'].append((si, a, a))

    newcmap = matplotlib.colors.LinearSegmentedColormap(name, cdict)
    plt.register_cmap(cmap=newcmap)

    return newcmap


x = np.linspace(-3, 3, num=601)
X,Y = np.meshgrid(x,x)
Z = np.sinc( (X*np.cos(1)+Y*np.sin(1))**2 +(-X*np.sin(1)+0.2*Y*np.cos(1))**2 )**2 

orig_cmap = matplotlib.cm.viridis 
shifted_cmap = shiftedColorMap(orig_cmap, midpoint=0.05, name='shifted')


fig = plt.figure(figsize=(4,9))
ax = [fig.add_subplot(3,1,n+1) for n in range(3)]

# normal cmap
im0 = ax[0].imshow(Z, interpolation="none", cmap=orig_cmap)
fig.colorbar(im0, ax=ax[0])
ax[0].set_title('Default behavior (hard to see small values)', fontsize=10)

#example using the custom shiftedColorMap function
#taken from https://stackoverflow.com/questions/7404116/defining-the-midpoint-of-a-colormap-in-matplotlib
im1 = ax[1].imshow(Z, interpolation="none", cmap=shifted_cmap)
fig.colorbar(im1, ax=ax[1])
ax[1].set_title('Center of colormap shifted to 0.05', fontsize=10)

#example using colors.LogNorm()
#taken from http://matplotlib.org/users/colormapnorms.html
im2 = ax[2].imshow(Z, interpolation="none", norm=colors.LogNorm(vmin=10e-5, vmax=Z.max()), cmap=orig_cmap)
fig.colorbar(im2, ax=ax[2])
ax[2].set_title('Logarithmically scaled Colormap', fontsize=10)

for axis in ax:
    axis.set_yticks([])
    axis.set_xticks([])
plt.tight_layout()    
plt.show() 

producing

这篇关于Matplotlib imshow - 在某些值范围内“加速"颜色变化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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