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.


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.


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

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.


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


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

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


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

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



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

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.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.