how to extract a subset of a colormap as a new colormap in matplotlib?

后端 未结 3 1483
攒了一身酷
攒了一身酷 2020-11-27 03:35

I would like to use a colormap from matplotlib e.g. CMRmap. But I don\'t want to use the \"black\" color at the beginning and the \"white\" color at the end. I\'m interested

相关标签:
3条回答
  • 2020-11-27 04:02

    I was just recently struggling with this on my own. Here are some possible solutions:


    Try using vmin, vmax keyword arguments in your plotting function. For example, say you had data between 0 and 1 but didn't like the colors used at the extremes of the colormap for 0 and 1.

    import matplotlib.pyplot as plt
    import matplotlib.cm as cm
    
    my_cmap = cm.spectral_r
    my_cmap.set_over('c')
    my_cmap.set_under('m')
    plt.pcolor(data, vmin=0.01, vmax=0.99, cmap=my_cmap)
    

    This will force the entire colormap to be used for values between 0.01 and 0.99 and values above and below will be cyan and magenta respectively. This may not solve your problem exactly, but it could be useful if you like a particular colormap and wish it had additional colors at both ends.


    If you really want to change the colormap, look at the documentation here and for LinearSegmentedColormap here.

    First,

    import matplotlib.cm as cm
    cdict = cm.get_cmap('spectral_r')._segmentdata
    

    This returns a dictionary of all the colors that make up the colormap. However, it's pretty tricky figuring out exactly how to alter this dictionary. This dict has three keys, red, green, blue. cdict[key] returns a list of values of the form (x, y0, y1). Let's take a look at two consecutive elements of cdict['red']:

    ((0.0, 0.0, 0.0)
     (0.5, 1.0, 1.0),...
    

    What this means is that data with z (assuming we're doing a pcolor or imshow) between 0.0 and 0.5 will have the red component of the rgb color associated with that data will increase from 0.0 (no red) to 1.0 (maximum red). This means that to change the color of the colormap, you have to examine how each of the three components of rgb are interpolated in the region of the colormap that you are interested in. Just make sure that for each color, the first and the last entry start with x=0 and x=1 respectively; you must cover the whole spectrum of [0, 1].

    If you want to change the beginning and end colors, try

    import matplotlib.cm as cm
    from matplotlib.colors import LinearSegmentedColormap
    cdict = cm.get_cmap('spectral_r')._segmentdata
    
    cdict['red'][0] = (0, 0.5, 0.5) # x=0 for bottom color in colormap
    cdict['blue'][0] = (0, 0.5, 0.5) # y=0.5 gray
    cdict['green'][0] = (0, 0.5, 0.5) # y1=y for simple interpolation
    cdict['red'][-1] = (1, 0.5, 0.5) # x=1 for top color in colormap
    cdict['blue'][-1] = (1, 0.5, 0.5)
    cdict['green'][-1] = (1, 0.5, 0.5)
    
    my_cmap = LinearSegmentedColormap('name', cdict)
    

    Then use this cmap in your plotting function.


    What I wanted to do was change the gray at the end of the spectral_r colormap to pure white. This was achieved using

    # Using imports from above
    cdict = matplotlib.cm.get_cmap('spectral_r')._segmentdata
    cdict['red'][0] = (0, 1, 1)
    cdict['green'][0] = (0, 1, 1)
    cdict['blue'][0] = (0, 1, 1)
    my_cmap = LinearSegmentedColormap('my_cmap', cdict)
    
    0 讨论(0)
  • 2020-11-27 04:09

    The staticmethod colors.LinearSegmentedColormap.from_list can be used to create new LinearSegmentedColormaps. Below, I sample the original colormap at 100 points between 0.2 and 0.8:

    cmap(np.linspace(0.2, 0.8, 100))
    

    and use these colors to generate a new colormap:

    import matplotlib.pyplot as plt
    import matplotlib.colors as colors
    import numpy as np
    
    def truncate_colormap(cmap, minval=0.0, maxval=1.0, n=100):
        new_cmap = colors.LinearSegmentedColormap.from_list(
            'trunc({n},{a:.2f},{b:.2f})'.format(n=cmap.name, a=minval, b=maxval),
            cmap(np.linspace(minval, maxval, n)))
        return new_cmap
    
    arr = np.linspace(0, 50, 100).reshape((10, 10))
    fig, ax = plt.subplots(ncols=2)
    
    cmap = plt.get_cmap('jet')
    new_cmap = truncate_colormap(cmap, 0.2, 0.8)
    ax[0].imshow(arr, interpolation='nearest', cmap=cmap)
    ax[1].imshow(arr, interpolation='nearest', cmap=new_cmap)
    plt.show()
    

    enter image description here

    The plot on the left shows the image using the original colormap (in this example, jet). The plot on the right shows the same image using new_cmap.

    0 讨论(0)
  • 2020-11-27 04:23

    Here is an adaptation of a previous answer which embeds the plotting function:

    import matplotlib.pyplot as plt
    import matplotlib.colors as colors
    import numpy as np
    
    ################### Function to truncate color map ###################
    def truncate_colormap(cmapIn='jet', minval=0.0, maxval=1.0, n=100):
        '''truncate_colormap(cmapIn='jet', minval=0.0, maxval=1.0, n=100)'''    
        cmapIn = plt.get_cmap(cmapIn)
    
        new_cmap = colors.LinearSegmentedColormap.from_list(
            'trunc({n},{a:.2f},{b:.2f})'.format(n=cmapIn.name, a=minval, b=maxval),
            cmapIn(np.linspace(minval, maxval, n)))
    
        arr = np.linspace(0, 50, 100).reshape((10, 10))
        fig, ax = plt.subplots(ncols=2)
        ax[0].imshow(arr, interpolation='nearest', cmap=cmapIn)
        ax[1].imshow(arr, interpolation='nearest', cmap=new_cmap)
        plt.show()
    
        return new_cmap
    
    cmap_mod = truncate_colormap(minval=.2, maxval=.8)  # calls function to truncate colormap
    

    visual of output from truncate_colormap():

    Having a compact function with the plotting embedded is helpful if you need to call the function more than once.

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