How to generate random colors in matplotlib?

前端 未结 11 2220
长情又很酷
长情又很酷 2020-12-12 16:13

What\'s the trivial example of how to generate random colors for passing to plotting functions?

I\'m calling scatter inside a loop and want each plot a different col

相关标签:
11条回答
  • 2020-12-12 16:28

    For some time I was really annoyed by the fact that matplotlib doesn't generate colormaps with random colors, as this is a common need for segmentation and clustering tasks.

    By just generating random colors we may end with some that are too bright or too dark, making visualization difficult. Also, usually we need the first or last color to be black, representing the background or outliers. So I've wrote a small function for my everyday work

    Here's the behavior of it:

    new_cmap = rand_cmap(100, type='bright', first_color_black=True, last_color_black=False, verbose=True)
    

    Than you just use new_cmap as your colormap on matplotlib:

    ax.scatter(X,Y, c=label, cmap=new_cmap, vmin=0, vmax=num_labels)
    

    The code is here:

    def rand_cmap(nlabels, type='bright', first_color_black=True, last_color_black=False, verbose=True):
        """
        Creates a random colormap to be used together with matplotlib. Useful for segmentation tasks
        :param nlabels: Number of labels (size of colormap)
        :param type: 'bright' for strong colors, 'soft' for pastel colors
        :param first_color_black: Option to use first color as black, True or False
        :param last_color_black: Option to use last color as black, True or False
        :param verbose: Prints the number of labels and shows the colormap. True or False
        :return: colormap for matplotlib
        """
        from matplotlib.colors import LinearSegmentedColormap
        import colorsys
        import numpy as np
    
    
        if type not in ('bright', 'soft'):
            print ('Please choose "bright" or "soft" for type')
            return
    
        if verbose:
            print('Number of labels: ' + str(nlabels))
    
        # Generate color map for bright colors, based on hsv
        if type == 'bright':
            randHSVcolors = [(np.random.uniform(low=0.0, high=1),
                              np.random.uniform(low=0.2, high=1),
                              np.random.uniform(low=0.9, high=1)) for i in xrange(nlabels)]
    
            # Convert HSV list to RGB
            randRGBcolors = []
            for HSVcolor in randHSVcolors:
                randRGBcolors.append(colorsys.hsv_to_rgb(HSVcolor[0], HSVcolor[1], HSVcolor[2]))
    
            if first_color_black:
                randRGBcolors[0] = [0, 0, 0]
    
            if last_color_black:
                randRGBcolors[-1] = [0, 0, 0]
    
            random_colormap = LinearSegmentedColormap.from_list('new_map', randRGBcolors, N=nlabels)
    
        # Generate soft pastel colors, by limiting the RGB spectrum
        if type == 'soft':
            low = 0.6
            high = 0.95
            randRGBcolors = [(np.random.uniform(low=low, high=high),
                              np.random.uniform(low=low, high=high),
                              np.random.uniform(low=low, high=high)) for i in xrange(nlabels)]
    
            if first_color_black:
                randRGBcolors[0] = [0, 0, 0]
    
            if last_color_black:
                randRGBcolors[-1] = [0, 0, 0]
            random_colormap = LinearSegmentedColormap.from_list('new_map', randRGBcolors, N=nlabels)
    
        # Display colorbar
        if verbose:
            from matplotlib import colors, colorbar
            from matplotlib import pyplot as plt
            fig, ax = plt.subplots(1, 1, figsize=(15, 0.5))
    
            bounds = np.linspace(0, nlabels, nlabels + 1)
            norm = colors.BoundaryNorm(bounds, nlabels)
    
            cb = colorbar.ColorbarBase(ax, cmap=random_colormap, norm=norm, spacing='proportional', ticks=None,
                                       boundaries=bounds, format='%1i', orientation=u'horizontal')
    
        return random_colormap
    

    It's also on github: https://github.com/delestro/rand_cmap

    0 讨论(0)
  • 2020-12-12 16:29

    I'm calling scatter inside a loop and want each plot in a different color.

    Based on that, and on your answer: It seems to me that you actually want n distinct colors for your datasets; you want to map the integer indices 0, 1, ..., n-1 to distinct RGB colors. Something like:

    mapping index to color

    Here is the function to do it:

    import matplotlib.pyplot as plt
    
    def get_cmap(n, name='hsv'):
        '''Returns a function that maps each index in 0, 1, ..., n-1 to a distinct 
        RGB color; the keyword argument name must be a standard mpl colormap name.'''
        return plt.cm.get_cmap(name, n)
    

    Usage in your pseudo-code snippet in the question:

    cmap = get_cmap(len(data))
    for i, (X, Y) in enumerate(data):
       scatter(X, Y, c=cmap(i))
    

    I generated the figure in my answer with the following code:

    import matplotlib.pyplot as plt
    
    def get_cmap(n, name='hsv'):
        '''Returns a function that maps each index in 0, 1, ..., n-1 to a distinct 
        RGB color; the keyword argument name must be a standard mpl colormap name.'''
        return plt.cm.get_cmap(name, n)
    
    def main():
        N = 30
        fig=plt.figure()
        ax=fig.add_subplot(111)   
        plt.axis('scaled')
        ax.set_xlim([ 0, N])
        ax.set_ylim([-0.5, 0.5])
        cmap = get_cmap(N)
        for i in range(N):
            rect = plt.Rectangle((i, -0.5), 1, 1, facecolor=cmap(i))
            ax.add_artist(rect)
        ax.set_yticks([])
        plt.show()
    
    if __name__=='__main__':
        main()
    

    Tested with both Python 2.7 & matplotlib 1.5, and with Python 3.5 & matplotlib 2.0. It works as expected.

    0 讨论(0)
  • 2020-12-12 16:34

    When less than 9 datasets:

    colors = "bgrcmykw"
    color_index = 0
    
    for X,Y in data:
        scatter(X,Y, c=colors[color_index])
        color_index += 1
    
    0 讨论(0)
  • 2020-12-12 16:42

    Improving the answer https://stackoverflow.com/a/14720445/6654512 to work with Python3. That piece of code would sometimes generate numbers greater than 1 and matplotlib would throw an error.

    for X,Y in data:
       scatter(X, Y, c=numpy.random.random(3))
    
    0 讨论(0)
  • 2020-12-12 16:43
    enter code here
    
    import numpy as np
    
    clrs = np.linspace( 0, 1, 18 )  # It will generate 
    # color only for 18 for more change the number
    np.random.shuffle(clrs)
    colors = []
    for i in range(0, 72, 4):
        idx = np.arange( 0, 18, 1 )
        np.random.shuffle(idx)
        r = clrs[idx[0]]
        g = clrs[idx[1]]
        b = clrs[idx[2]]
        a = clrs[idx[3]]
        colors.append([r, g, b, a])
    
    0 讨论(0)
提交回复
热议问题