Create own colormap using matplotlib and plot color scale

前端 未结 4 448
清歌不尽
清歌不尽 2020-11-22 14:18

I have the following problem, I want to create my own colormap (red-mix-violet-mix-blue) that maps to values between -2 and +2 and want to use it to color points in my plot.

相关标签:
4条回答
  • 2020-11-22 14:36

    This seems to work for me.

    def make_Ramp( ramp_colors ): 
        from colour import Color
        from matplotlib.colors import LinearSegmentedColormap
    
        color_ramp = LinearSegmentedColormap.from_list( 'my_list', [ Color( c1 ).rgb for c1 in ramp_colors ] )
        plt.figure( figsize = (15,3))
        plt.imshow( [list(np.arange(0, len( ramp_colors ) , 0.1)) ] , interpolation='nearest', origin='lower', cmap= color_ramp )
        plt.xticks([])
        plt.yticks([])
        return color_ramp
    
    custom_ramp = make_Ramp( ['#754a28','#893584','#68ad45','#0080a5' ] ) 
    

    0 讨论(0)
  • If you want to automate the creating of a custom divergent colormap commonly used for surface plots, this module combined with @unutbu method worked well for me.

    def diverge_map(high=(0.565, 0.392, 0.173), low=(0.094, 0.310, 0.635)):
        '''
        low and high are colors that will be used for the two
        ends of the spectrum. they can be either color strings
        or rgb color tuples
        '''
        c = mcolors.ColorConverter().to_rgb
        if isinstance(low, basestring): low = c(low)
        if isinstance(high, basestring): high = c(high)
        return make_colormap([low, c('white'), 0.5, c('white'), high])
    

    The high and low values can be either string color names or rgb tuples. This is the result using the surface plot demo: enter image description here

    0 讨论(0)
  • 2020-11-22 14:50

    Since the methods used in other answers seems quite complicated for such easy task, here is a new answer:

    Instead of a ListedColormap, which produces a discrete colormap, you may use a LinearSegmentedColormap. This can easily be created from a list using the from_list method.

    import numpy as np
    import matplotlib.pyplot as plt
    import matplotlib.colors
    
    x,y,c = zip(*np.random.rand(30,3)*4-2)
    
    norm=plt.Normalize(-2,2)
    cmap = matplotlib.colors.LinearSegmentedColormap.from_list("", ["red","violet","blue"])
    
    plt.scatter(x,y,c=c, cmap=cmap, norm=norm)
    plt.colorbar()
    plt.show()
    


    More generally, if you have a list of values (e.g. [-2., -1, 2]) and corresponding colors, (e.g. ["red","violet","blue"]), such that the nth value should correspond to the nth color, you can normalize the values and supply them as tuples to the from_list method.

    import numpy as np
    import matplotlib.pyplot as plt
    import matplotlib.colors
    
    x,y,c = zip(*np.random.rand(30,3)*4-2)
    
    cvals  = [-2., -1, 2]
    colors = ["red","violet","blue"]
    
    norm=plt.Normalize(min(cvals),max(cvals))
    tuples = list(zip(map(norm,cvals), colors))
    cmap = matplotlib.colors.LinearSegmentedColormap.from_list("", tuples)
    
    plt.scatter(x,y,c=c, cmap=cmap, norm=norm)
    plt.colorbar()
    plt.show()
    

    0 讨论(0)
  • 2020-11-22 15:00

    There is an illustrative example of how to create custom colormaps here. The docstring is essential for understanding the meaning of cdict. Once you get that under your belt, you might use a cdict like this:

    cdict = {'red':   ((0.0, 1.0, 1.0), 
                       (0.1, 1.0, 1.0),  # red 
                       (0.4, 1.0, 1.0),  # violet
                       (1.0, 0.0, 0.0)), # blue
    
             'green': ((0.0, 0.0, 0.0),
                       (1.0, 0.0, 0.0)),
    
             'blue':  ((0.0, 0.0, 0.0),
                       (0.1, 0.0, 0.0),  # red
                       (0.4, 1.0, 1.0),  # violet
                       (1.0, 1.0, 0.0))  # blue
              }
    

    Although the cdict format gives you a lot of flexibility, I find for simple gradients its format is rather unintuitive. Here is a utility function to help generate simple LinearSegmentedColormaps:

    import numpy as np
    import matplotlib.pyplot as plt
    import matplotlib.colors as mcolors
    
    
    def make_colormap(seq):
        """Return a LinearSegmentedColormap
        seq: a sequence of floats and RGB-tuples. The floats should be increasing
        and in the interval (0,1).
        """
        seq = [(None,) * 3, 0.0] + list(seq) + [1.0, (None,) * 3]
        cdict = {'red': [], 'green': [], 'blue': []}
        for i, item in enumerate(seq):
            if isinstance(item, float):
                r1, g1, b1 = seq[i - 1]
                r2, g2, b2 = seq[i + 1]
                cdict['red'].append([item, r1, r2])
                cdict['green'].append([item, g1, g2])
                cdict['blue'].append([item, b1, b2])
        return mcolors.LinearSegmentedColormap('CustomMap', cdict)
    
    
    c = mcolors.ColorConverter().to_rgb
    rvb = make_colormap(
        [c('red'), c('violet'), 0.33, c('violet'), c('blue'), 0.66, c('blue')])
    N = 1000
    array_dg = np.random.uniform(0, 10, size=(N, 2))
    colors = np.random.uniform(-2, 2, size=(N,))
    plt.scatter(array_dg[:, 0], array_dg[:, 1], c=colors, cmap=rvb)
    plt.colorbar()
    plt.show()
    

    enter image description here


    By the way, the for-loop

    for i in range(0, len(array_dg)):
      plt.plot(array_dg[i], markers.next(),alpha=alpha[i], c=colors.next())
    

    plots one point for every call to plt.plot. This will work for a small number of points, but will become extremely slow for many points. plt.plot can only draw in one color, but plt.scatter can assign a different color to each dot. Thus, plt.scatter is the way to go.

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