nonlinear colormap, matplotlib

后端 未结 2 1959
心在旅途
心在旅途 2021-01-06 12:11

Are there any colormaps or is there a simple way to transform a matplotlib colormap to provide a much bigger color range near 0.5 and a smaller one at the extremes? I am cre

相关标签:
2条回答
  • 2021-01-06 12:26

    Your link provides quite a good solution for the colormap. I edited a bit, but it contained al the necessary. You need to pick some sensible levels for your nonlinear colormap. I used two ranges centered around the mean values, between +- 4 the standard deviation of your sample. by changing that to another number you obtain a different local gradient in the color around the two mean values.

    For the colorbar, you

    • either leave the colors nonlinearly spaced with linearly spaced labels
    • you have linearly spaced colors with nonlinearly spaced labels.

    The second allows greater resolution when looking at the data, looks nicer and is implemented below:

    import numpy as np
    import matplotlib.pyplot as plt
    
    x = y = np.linspace(1, 10, 10)
    
    t1mean, t2mean = 2, 9
    sigma1, sigma2 = .3, .01
    t1 = np.random.normal(t1mean, sigma1, 10)
    t2 = np.random.normal(t2mean, sigma2, 10)
    
    class nlcmap(object):
        def __init__(self, cmap, levels):
            self.cmap = cmap
            self.N = cmap.N
            self.monochrome = self.cmap.monochrome
            self.levels = np.asarray(levels, dtype='float64')
            self._x = self.levels
            self.levmax = self.levels.max()
            self.transformed_levels = np.linspace(0.0, self.levmax,
                 len(self.levels))
    
        def __call__(self, xi, alpha=1.0, **kw):
            yi = np.interp(xi, self._x, self.transformed_levels)
            return self.cmap(yi / self.levmax, alpha)
    
    tmax = max(t1.max(), t2.max())
    #the choice of the levels depends on the data:
    levels = np.concatenate((
        [0, tmax],
        np.linspace(t1mean - 4 * sigma1, t1mean + 4 * sigma1, 5),
        np.linspace(t2mean - 4 * sigma2, t2mean + 4 * sigma2, 5),
        ))
    
    levels = levels[levels <= tmax]
    levels.sort()
    
    cmap_nonlin = nlcmap(plt.cm.jet, levels)
    
    fig, (ax1, ax2) = plt.subplots(1, 2)
    
    ax1.scatter(x, y, edgecolors=cmap_nonlin(t1), s=15, linewidths=4)
    ax2.scatter(x, y, edgecolors=cmap_nonlin(t2), s=15, linewidths=4)
    
    fig.subplots_adjust(left=.25)
    cbar_ax = fig.add_axes([0.10, 0.15, 0.05, 0.7])
    
    #for the colorbar we map the original colormap, not the nonlinear one:
    sm = plt.cm.ScalarMappable(cmap=plt.cm.jet, 
                    norm=plt.Normalize(vmin=0, vmax=tmax))
    sm._A = []
    
    cbar = fig.colorbar(sm, cax=cbar_ax)
    #here we are relabel the linear colorbar ticks to match the nonlinear ticks
    cbar.set_ticks(cmap_nonlin.transformed_levels)
    cbar.set_ticklabels(["%.2f" % lev for lev in levels])
    
    plt.show()
    

    In the result, notice that the ticks of the colorbar are NOT equispaced:

    enter image description here

    0 讨论(0)
  • 2021-01-06 12:36

    You could use LinearSegmentedColormap:

    With this, you need to set up a color lookup table within a dictionary e.g. 'cdict' below.

    cdict = {'red':   [(0.0,  0.0, 0.0),
                       (0.15,  0.01, 0.01),
                       (0.35,  1.0, 1.0),
                       (1.0,  1.0, 1.0)],
    
             'green': [(0.0,  0.0, 0.0),
                       (1.0,  0.0, 1.0)],
    
             'blue':  [(0.0,  0.0, 1.0),
                       (0.9,  0.01, 0.01),
                       (1.0,  0.0, 1.0)]}
    

    This shows the transistions between values. I have set red to vary a lot around the values of t1/t2_max (0.15 to 0.35) and blue to vary a lot around the values of t2/t2_max (0.9 to 1.0). Green does nothing. I'd recommend reading the docs to see how this works. (Note this could be automated to automatically vary around your values). I then tweaked your code to show the graph:

    import matplotlib.colors as col
    
    my_cmap = col.LinearSegmentedColormap('my_colormap', cdict)
    
    plt.figure(figsize=(22.0, 15.50))
    
    p = plt.subplot(1,2,1)
    colors = my_cmap(t1/t2_max)
    
    p.scatter(x, y, edgecolors=colors, s=15, linewidths=4)
    
    p = plt.subplot(1,2,2)
    colors = my_cmap(t2/t2_max)
    
    p.scatter(x, y, edgecolors=colors, s=15, linewidths=4)
    
    plt.subplots_adjust(left=0.2)
    cbar_ax = plt.axes([0.10, 0.15, 0.05, 0.7])
    sm = plt.cm.ScalarMappable(cmap=my_cmap, norm=plt.Normalize(vmin=0, vmax=t2_max))
    sm._A = []
    cbar = plt.colorbar(sm,cax=cbar_ax)
    
    plt.show()
    

    enter image description here

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