Wie generiere ich zufällige Farben in matplotlib?

83

Was ist das triviale Beispiel dafür, wie zufällige Farben für die Übergabe an Plotfunktionen generiert werden?

Ich rufe Scatter innerhalb einer Schleife auf und möchte, dass jeder Plot eine andere Farbe hat.

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

c: eine Farbe. c kann eine einzelne Farbformatzeichenfolge oder eine Folge von Farbspezifikationen der Länge N oder eine Folge von N Zahlen sein, die mithilfe der über kwargs angegebenen cmap und Norm auf Farben abgebildet werden sollen (siehe unten). Beachten Sie, dass c keine einzelne numerische RGB- oder RGBA-Sequenz sein sollte, da dies nicht von einem Array von Werten zu unterscheiden ist, die farblich zugeordnet werden sollen. c kann jedoch ein 2D-Array sein, in dem die Zeilen RGB oder RGBA sind.

John Mee
quelle
1
Aus was zufällig ausgewählt? Wenn Sie zufällig aus allen verfügbaren Farben auswählen, erhalten Sie möglicherweise eine seltsame Mischung aus einigen sehr unterschiedlichen Farben und einigen, die so ähnlich sind, dass sie schwer zu unterscheiden sind.
BrenBarn

Antworten:

138

Ich rufe Scatter innerhalb einer Schleife auf und möchte, dass jeder Plot eine andere Farbe hat.

Basierend darauf und auf Ihrer Antwort: Es scheint mir, dass Sie tatsächlich n unterschiedliche Farben für Ihre Datensätze wünschen ; Sie möchten die Ganzzahlindizes 0, 1, ..., n-1unterschiedlichen RGB-Farben zuordnen. Etwas wie:

Zuordnungsindex zur Farbe

Hier ist die Funktion, um es zu tun:

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)

Verwendung in Ihrem Pseudo- Code-Snippet in der Frage:

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

Ich habe die Zahl in meiner Antwort mit dem folgenden Code generiert:

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

Getestet mit Python 2.7 und Matplotlib 1.5 sowie mit Python 3.5 und Matplotlib 2.0. Es funktioniert wie erwartet.

Ali
quelle
1
@ user1941407 Danke! :) Ich wünschte, ich wüsste, warum jemand die Antwort anonym abgelehnt hat.
Ali
7
Vielleicht ist es kompliziert
Ingrid
1
scheint nicht zu funktionieren? scheint überhaupt nicht in die Python-Konsole zu stecken.
mjwrazor
@mjwrazor Sorry, ich folge nicht. Könnten Sie näher erläutern, was "nicht funktioniert"?
Ali
Ich habe versucht, die Methode in der Python-Konsole zu platzieren. Die Konsole liest sie nie ein. Auch die Logik am Ende Ihrer Methode macht keinen Sinn. Warum eine Methode zurückgeben, die eine andere Methode aufruft, die eine Ausführungsmethode zurückgibt? Warum nicht einfach die ausgeführte Methode zurückgeben?
mjwrazor
76
for X,Y in data:
   scatter(X, Y, c=numpy.random.rand(3,))
Charles Brunet
quelle
1
Was ist, wenn drei Werte geplottet werden müssen?
Panda-34
1
Steht die 3 für 3 Werte von R-, G- und B-Komponenten?
Kshitij Bajracharya
ohne numpy können Sie verwendencolor=(random.uniform(0, 1), random.uniform(0, 1), random.uniform(0, 1))
azzamsa
1
Effizienter und weniger tippend:scatter(X,Y, c=numpy.random.rand(len(X),3)
Qualia
31

Ausarbeitung der Antwort von @ john-mee, wenn Sie beliebig lange Daten haben, aber keine streng eindeutigen Farben benötigen:

für Python 2:

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

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

für Python 3:

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

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

Dies hat den Vorteil, dass die Farben leicht zu kontrollieren sind und kurz sind.

user3240588
quelle
27

Für einige Zeit war ich wirklich verärgert darüber, dass matplotlib keine Farbkarten mit zufälligen Farben generiert, da dies ein häufiger Bedarf für Segmentierungs- und Clustering-Aufgaben ist.

Indem wir nur zufällige Farben erzeugen, können wir mit einigen enden, die zu hell oder zu dunkel sind, was die Visualisierung schwierig macht. Außerdem muss die erste oder letzte Farbe normalerweise schwarz sein und den Hintergrund oder die Ausreißer darstellen. Also habe ich eine kleine Funktion für meine tägliche Arbeit geschrieben

Hier ist das Verhalten davon:

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

Generierte Farbkarte

Dann verwenden Sie einfach new_cmap als Farbkarte auf matplotlib:

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

Der Code ist hier:

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

Es ist auch auf Github: https://github.com/delestro/rand_cmap

Delestro
quelle
2
Vielen Dank. Es war sehr nützlich.
Ash
14

Bei weniger als 9 Datensätzen:

colors = "bgrcmykw"
color_index = 0

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

Da die Frage ist How to generate random colors in matplotlib?und ich nach einer Antwort bezüglich gesucht habe pie plots, denke ich, dass es sich lohnt, hier eine Antwort zu geben (für pies)

import numpy as np
from random import sample
import matplotlib.pyplot as plt
import matplotlib.colors as pltc
all_colors = [k for k,v in pltc.cnames.items()]

fracs = np.array([600, 179, 154, 139, 126, 1185])
labels = ["label1", "label2", "label3", "label4", "label5", "label6"]
explode = ((fracs == max(fracs)).astype(int) / 20).tolist()

for val in range(2):
    colors = sample(all_colors, len(fracs))
    plt.figure(figsize=(8,8))
    plt.pie(fracs, labels=labels, autopct='%1.1f%%', 
            shadow=True, explode=explode, colors=colors)
    plt.legend(labels, loc=(1.05, 0.7), shadow=True)
    plt.show()

Ausgabe

Geben Sie hier die Bildbeschreibung ein

Geben Sie hier die Bildbeschreibung ein

J. Doe
quelle
1
Hey, genau das suche ich. In Ihrem zweiten Bild (das passiert mir auch) erhalten Sie jedoch fast die gleichen Farben (beige / weiß). Ist es möglich, diesen Ansatz zu verwenden, aber auf eine Weise zu probieren, die deutlichere Farben hervorhebt?
Armara
9

Hier ist eine präzisere Version von Alis Antwort, die eine bestimmte Farbe pro Handlung angibt:

import matplotlib.pyplot as plt

N = len(data)
cmap = plt.cm.get_cmap("hsv", N+1)
for i in range(N):
    X,Y = data[i]
    plt.scatter(X, Y, c=cmap(i))
Champitoad
quelle
4

Basierend auf Alis und Champitoads Antwort:

Wenn Sie verschiedene Paletten für dieselbe ausprobieren möchten, können Sie dies in wenigen Zeilen tun:

cmap=plt.cm.get_cmap(plt.cm.viridis,143)

^ 143 ist die Anzahl der Farben, die Sie abtasten

Ich habe 143 ausgewählt, weil hier die gesamte Farbpalette auf der Farbkarte ins Spiel kommt. Sie können bei jeder Iteration die n-te Farbe abtasten, um den Farbkarteneffekt zu erzielen.

n=20 for i,(x,y) in enumerate(points): plt.scatter(x,y,c=cmap(n*i))

ai-shwarya
quelle
1

Verbesserung der Antwort https://stackoverflow.com/a/14720445/6654512 für die Arbeit mit Python3. Dieser Code erzeugte manchmal Zahlen größer als 1 und matplotlib warf einen Fehler aus.

for X,Y in data:
   scatter(X, Y, c=numpy.random.random(3))
Ale Solano
quelle
1
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])
Santosh Magadum
quelle
Weisen Sie diese
Farbliste
1

Wenn Sie sicherstellen möchten, dass die Farben unterschiedlich sind, aber nicht wissen, wie viele Farben benötigt werden. Versuchen Sie so etwas. Es wählt Farben von gegenüberliegenden Seiten des Spektrums aus und erhöht systematisch die Granularität.

import math

def calc(val, max = 16):
    if val < 1:
        return 0
    if val == 1:
        return max

    l = math.floor(math.log2(val-1))    #level 
    d = max/2**(l+1)                    #devision
    n = val-2**l                        #node
    return d*(2*n-1)
import matplotlib.pyplot as plt

N = 16
cmap = cmap = plt.cm.get_cmap('gist_rainbow', N)

fig, axs = plt.subplots(2)
for ax in axs:
    ax.set_xlim([ 0, N])
    ax.set_ylim([-0.5, 0.5])
    ax.set_yticks([])

for i in range(0,N+1):
    v = int(calc(i, max = N))
    rect0 = plt.Rectangle((i, -0.5), 1, 1, facecolor=cmap(i))
    rect1 = plt.Rectangle((i, -0.5), 1, 1, facecolor=cmap(v))
    axs[0].add_artist(rect0)
    axs[1].add_artist(rect1)

plt.xticks(range(0, N), [int(calc(i, N)) for i in range(0, N)])
plt.show()

Ausgabe

Vielen Dank an @Ali für die Bereitstellung der Basisimplementierung.

Johan
quelle