Asymmetric Color Bar with Fair Diverging Color Map

前端 未结 2 889
隐瞒了意图╮
隐瞒了意图╮ 2021-01-28 03:33

I\'m trying to plot an asymmetric color range in a scatter plot. I want the colors to be a fair representation of the intensity using a diverging color map. I am having trouble

相关标签:
2条回答
  • 2021-01-28 03:54

    Based on @Asmus's answer I created a MidpointNormalizeFair class that does this scaling based on the data.

    class MidpointNormalizeFair(mpl.colors.Normalize):
        """ From: https://matplotlib.org/users/colormapnorms.html"""
        def __init__(self, vmin=None, vmax=None, midpoint=None, clip=False):
            self.midpoint = midpoint
            mpl.colors.Normalize.__init__(self, vmin, vmax, clip)
    
        def __call__(self, value, clip=None):
            # I'm ignoring masked values and all kinds of edge cases to make a
            # simple example...
    
            result, is_scalar = self.process_value(value)
            self.autoscale_None(result)
    
            vlargest = max( abs( self.vmax - self.midpoint ), abs( self.vmin - self.midpoint ) )
            x, y = [ self.midpoint - vlargest, self.midpoint, self.midpoint + vlargest], [0, 0.5, 1]
            return np.ma.masked_array(np.interp(value, x, y))
    
    0 讨论(0)
  • 2021-01-28 04:11

    If I get you correctly, the issue at hand is that your midpoint-centered map is scaling the color evenly from -2 to 0 (blue) and similarly (red) from 0 to 10.

    Instead of scaling [self.vmin, self.midpoint, self.vmax] = [-2, 0, 10], you should rather rescale between [-v_ext, self.midpoint, v_ext] = [-10, 0, 10] where:

    v_ext = np.max( [ np.abs(self.vmin), np.abs(self.vmax) ] )  ## = np.max( [ 2, 10 ] )
    

    The complete code could look like:

    import numpy as np
    import matplotlib.pyplot as plt
    import matplotlib.colors as mcolors
    
    x = np.arange( 0, 1, 1e-1 )
    xlen = x.shape[ 0 ]
    z = np.random.random( xlen**2 )*12 - 2
    
    class MidpointNormalize(mcolors.Normalize):
        def __init__(self, vmin=None, vmax=None, midpoint=None, clip=False):
            self.midpoint = midpoint
            mcolors.Normalize.__init__(self, vmin, vmax, clip)
    
        def __call__(self, value, clip=None):
            v_ext = np.max( [ np.abs(self.vmin), np.abs(self.vmax) ] )
            x, y = [-v_ext, self.midpoint, v_ext], [0, 0.5, 1]
            return np.ma.masked_array(np.interp(value, x, y))
    
    x = np.arange( 0, 1, 1e-1 )
    xlen = x.shape[ 0 ]
    z = np.random.random( xlen**2 )*12 - 2
    
    norm = MidpointNormalize( midpoint = 0 )
    
    splt = plt.scatter( 
        np.repeat( x, xlen ), 
        np.tile( x, xlen ), 
        c = z, cmap = 'seismic', s = 400,
        norm = norm
    )
    
    plt.colorbar( splt )
    plt.show()
    

    0 讨论(0)
提交回复
热议问题