123 votes

Comment générer des couleurs aléatoires dans matplotlib ?

Quel est l'exemple trivial permettant de générer des couleurs aléatoires à transmettre aux fonctions de traçage ?

J'appelle scatter dans une boucle et je veux que chaque graphique ait une couleur différente.

for X,Y in data:
   scatter(X, Y, c=??)

c : une couleur. c peut être une simple chaîne de format de couleur, ou une séquence de spécifications de couleur de longueur N, ou une séquence de N nombres à mettre en correspondance avec des couleurs en utilisant cmap et la norme spécifiée via kwargs (voir ci-dessous). Notez que c ne doit pas être une séquence numérique unique RVB ou RGBA, car il est impossible de la distinguer d'un tableau de valeurs à mettre en correspondance. c peut cependant être un tableau 2-D dont les lignes sont RVB ou RGBA.

197voto

Ali Points 18740

J'appelle scatter dans une boucle et je veux que chaque graphique ait une couleur différente.

Basé sur ça, et sur votre réponse : Il me semble que vous voulez en fait n distinct couleurs pour vos ensembles de données ; vous voulez mettre en correspondance les indices entiers 0, 1, ..., n-1 à des couleurs RVB distinctes. Quelque chose comme :

mapping index to color

Voici la fonction pour le faire :

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)

Utilisation dans votre pseudo -dans la question :

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

J'ai généré la figure dans ma réponse avec le code suivant :

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()

Testé à la fois avec Python 2.7 & matplotlib 1.5, et avec Python 3.5 & matplotlib 2.0. Il fonctionne comme prévu.

108voto

Charles Brunet Points 5730
for X,Y in data:
   scatter(X, Y, c=numpy.random.rand(3,))

44voto

user3240588 Points 65

En élaborant la réponse de @john-mee, si vous avez des données arbitrairement longues mais n'avez pas besoin de couleurs strictement uniques :

pour python 2 :

from itertools import cycle
cycol = cycle('bgrcmk')

for X,Y in data:
    scatter(X, Y, c=cycol.next())

pour python 3 :

from itertools import cycle
cycol = cycle('bgrcmk')

for X,Y in data:
    scatter(X, Y, c=next(cycol))

Elle a l'avantage de permettre un contrôle facile des couleurs et d'être courte.

40voto

Delestro Points 531

Pendant un certain temps, j'ai été vraiment ennuyé par le fait que matplotlib ne génère pas de cartes de couleurs avec des couleurs aléatoires, car c'est un besoin courant pour les tâches de segmentation et de regroupement.

En générant simplement des couleurs aléatoires, nous risquons de nous retrouver avec des couleurs trop claires ou trop sombres, ce qui rend la visualisation difficile. De plus, il faut généralement que la première ou la dernière couleur soit noire, pour représenter le fond ou les valeurs aberrantes. J'ai donc écrit une petite fonction pour mon travail quotidien

Voici le comportement de celui-ci :

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

Generated colormap

Il suffit alors d'utiliser nouveau_cmap comme votre carte de couleur sur matplotlib :

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

Le code est ici :

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

Il est également sur github : https://github.com/delestro/rand_cmap

24voto

John Mee Points 12004

Lorsque moins de 9 ensembles de données :

colors = "bgrcmykw"
color_index = 0

for X,Y in data:
    scatter(X,Y, c=colors[color_index])
    color_index += 1

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X