Festlegen einer anderen Farbe für jede Serie im Streudiagramm auf matplotlib

162

Angenommen, ich habe drei Datensätze:

X = [1,2,3,4]
Y1 = [4,8,12,16]
Y2 = [1,4,9,16]

Ich kann diese Handlung streuen:

from matplotlib import pyplot as plt
plt.scatter(X,Y1,color='red')
plt.scatter(X,Y2,color='blue')
plt.show()

Wie kann ich das mit 10 Sätzen machen?

Ich habe danach gesucht und konnte einen Hinweis auf das finden, was ich frage.

Edit: (hoffentlich) meine Frage klären

Wenn ich mehrmals Streuung aufrufe, kann ich nur für jede Streuung dieselbe Farbe einstellen. Ich weiß auch, dass ich ein Farbarray manuell einstellen kann, aber ich bin mir sicher, dass es einen besseren Weg gibt, dies zu tun. Meine Frage lautet dann: "Wie kann ich meine verschiedenen Datensätze mit jeweils unterschiedlichen Farben automatisch streuen und zeichnen?

Wenn das hilft, kann ich jedem Datensatz leicht eine eindeutige Nummer zuweisen.

Yotam
quelle
1
Was ist die Frage hier? Farbe kann auch ein Array sein, aber was können Sie nicht lösen, wenn Sie Scatter mehrmals aufrufen?
Seberg
1
Wenn ich mehrmals Scatter aufrufe, erhalte ich die gleichen Farben. Ich werde meine Frage aktualisieren.
Yotam

Antworten:

268

Ich weiß nicht, was Sie unter "manuell" verstehen. Sie können eine Farbkarte auswählen und ganz einfach ein Farbarray erstellen:

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.cm as cm

x = np.arange(10)
ys = [i+x+(i*x)**2 for i in range(10)]

colors = cm.rainbow(np.linspace(0, 1, len(ys)))
for y, c in zip(ys, colors):
    plt.scatter(x, y, color=c)

Matplotlib-Diagramm mit verschiedenen Farben

Oder Sie können Ihren eigenen Farbzyklus erstellen, itertools.cycleindem Sie die Farben verwenden und angeben, über die Sie eine Schleife ausführen möchten next, um die gewünschte Farbe zu erhalten. Zum Beispiel mit 3 Farben:

import itertools

colors = itertools.cycle(["r", "b", "g"])
for y in ys:
    plt.scatter(x, y, color=next(colors))

Matplotlib-Diagramm mit nur 3 Farben

Kommen Sie und denken Sie darüber nach, vielleicht ist es sauberer, es nicht zipmit dem ersten zu verwenden:

colors = iter(cm.rainbow(np.linspace(0, 1, len(ys))))
for y in ys:
    plt.scatter(x, y, color=next(colors))
DSM
quelle
1
+1. Ein itertools-Zyklus ist in dieser Situation wahrscheinlich keine gute Idee, da mehrere Datensätze dieselbe Farbe haben würden.
David Robinson
1
@ DavidRobinson: nicht, wenn Sie alle zehn angeben, obwohl ich damit einverstanden bin, dass Radfahren den Zweck dort irgendwie besiegt ..: ^)
DSM
Genau - dann ist es kein Zyklus :)
David Robinson
4
@ Macrocosme: funktioniert für mich. Wenn plt.legend(['c{}'.format(i) for i in range(len(ys))], loc=2, bbox_to_anchor=(1.05, 1), borderaxespad=0., fontsize=11)ich oben hinzufüge , erhalte ich eine Legende mit Farben.
DSM
Die itertools-Lösung eignet sich hervorragend, wenn Sie einige Farben vermeiden möchten. In meinem Fall möchte ich Schwarz vermeiden, da der Hintergrund schwarz ist.
Fabrizio
50

Die normale Methode zum Zeichnen von Plots mit Punkten in verschiedenen Farben in matplotlib besteht darin, eine Liste von Farben als Parameter zu übergeben.

Z.B:

import matplotlib.pyplot
matplotlib.pyplot.scatter([1,2,3],[4,5,6],color=['red','green','blue'])

3 Farben

Wenn Sie eine Liste mit Listen haben und diese pro Liste farbig gestalten möchten. Ich denke, der eleganteste Weg ist der, der von @DSM vorgeschlagen wird. Machen Sie einfach eine Schleife, in der mehrere Aufrufe zum Streuen ausgeführt werden.

Aber wenn Sie es aus irgendeinem Grund mit nur einem Aufruf tun wollten, können Sie eine große Liste von Farben erstellen, mit einem Listenverständnis und ein wenig Unterteilung in Bodenbeläge:

import matplotlib
import numpy as np

X = [1,2,3,4]
Ys = np.array([[4,8,12,16],
      [1,4,9,16],
      [17, 10, 13, 18],
      [9, 10, 18, 11],
      [4, 15, 17, 6],
      [7, 10, 8, 7],
      [9, 0, 10, 11],
      [14, 1, 15, 5],
      [8, 15, 9, 14],
       [20, 7, 1, 5]])
nCols = len(X)  
nRows = Ys.shape[0]

colors = matplotlib.cm.rainbow(np.linspace(0, 1, len(Ys)))

cs = [colors[i//len(X)] for i in range(len(Ys)*len(X))] #could be done with numpy's repmat
Xs=X*nRows #use list multiplication for repetition
matplotlib.pyplot.scatter(Xs,Ys.flatten(),color=cs)

Alles geplant

cs = [array([ 0.5,  0. ,  1. ,  1. ]),
 array([ 0.5,  0. ,  1. ,  1. ]),
 array([ 0.5,  0. ,  1. ,  1. ]),
 array([ 0.5,  0. ,  1. ,  1. ]),
 array([ 0.28039216,  0.33815827,  0.98516223,  1.        ]),
 array([ 0.28039216,  0.33815827,  0.98516223,  1.        ]),
 array([ 0.28039216,  0.33815827,  0.98516223,  1.        ]),
 array([ 0.28039216,  0.33815827,  0.98516223,  1.        ]),
 ...
 array([  1.00000000e+00,   1.22464680e-16,   6.12323400e-17,
          1.00000000e+00]),
 array([  1.00000000e+00,   1.22464680e-16,   6.12323400e-17,
          1.00000000e+00]),
 array([  1.00000000e+00,   1.22464680e-16,   6.12323400e-17,
          1.00000000e+00]),
 array([  1.00000000e+00,   1.22464680e-16,   6.12323400e-17,
          1.00000000e+00])]
Lyndon White
quelle
19

Eine einfache Lösung

Wenn Sie nur einen Sammlungstyp haben (z. B. Streuung ohne Fehlerbalken), können Sie die Farben auch ändern, nachdem Sie sie gezeichnet haben. Dies ist manchmal einfacher durchzuführen.

import matplotlib.pyplot as plt
from random import randint
import numpy as np

#Let's generate some random X, Y data X = [ [frst group],[second group] ...]
X = [ [randint(0,50) for i in range(0,5)] for i in range(0,24)]
Y = [ [randint(0,50) for i in range(0,5)] for i in range(0,24)]
labels = range(1,len(X)+1)

fig = plt.figure()
ax = fig.add_subplot(111)
for x,y,lab in zip(X,Y,labels):
        ax.scatter(x,y,label=lab)

Der einzige Code, den Sie benötigen:

#Now this is actually the code that you need, an easy fix your colors just cut and paste not you need ax.
colormap = plt.cm.gist_ncar #nipy_spectral, Set1,Paired  
colorst = [colormap(i) for i in np.linspace(0, 0.9,len(ax.collections))]       
for t,j1 in enumerate(ax.collections):
    j1.set_color(colorst[t])


ax.legend(fontsize='small')

Die Ausgabe gibt Ihnen unterschiedliche Farben, selbst wenn Sie viele verschiedene Streudiagramme im selben Unterplot haben.

Geben Sie hier die Bildbeschreibung ein

GM
quelle
Das ist großartig, aber wie würden Sie mit dieser Funktion beispielsweise Fehlerbalken mit derselben Farbe hinzufügen? @ GM
PEBKAC
1
Hallo @PEBKAC, danke für den Hinweis, ich habe mich heute Nachmittag bemüht, es auch in diesem Fall zum Laufen zu bringen, aber ich konnte keine Lösung finden, also habe ich die Frage bearbeitet und die anderen Benutzer gewarnt. Vielen Dank!
GM
Hallo @GM, sorry, ich habe ein paar Kommentare gepostet, bevor ich die Lösung fertiggestellt habe, die hier beschrieben wird: stackoverflow.com/q/51444364/7541421
PEBKAC
1
Ich habe eine andere Methode verwendet, um die Farben für jede Serie in einem Streudiagramm zuzuweisen. Jetzt funktioniert es, leider konnte ich mit Ihrer eleganten Lösung in Bezug auf Fehlerbalken nicht fortfahren, trotzdem bin ich sehr dankbar für Ihren super hilfreichen Beitrag! Prost!
PEBKAC
7

Sie können die plot()Funktion jederzeit wie folgt verwenden:

import matplotlib.pyplot as plt

import numpy as np

x = np.arange(10)
ys = [i+x+(i*x)**2 for i in range(10)]
plt.figure()
for y in ys:
    plt.plot(x, y, 'o')
plt.show()

Plot als Streuung, ändert aber die Farben

Ophir Carmi
quelle
6

Diese Frage ist vor Januar 2013 und matplotlib 1.3.1 (August 2013), der ältesten stabilen Version, die Sie auf der matpplotlib-Website finden, etwas knifflig. Aber danach ist es ziemlich trivial.

Weil aktuelle Version von matplotlib.pylab.scatter Unterstützung Folgendes zuweist: Array der Farbnamenzeichenfolge, Array der Gleitkommazahl mit Farbkarte, Array von RGB oder RGBA.

Diese Antwort ist der endlosen Leidenschaft von @ Oxinabox gewidmet, die 2013er Version von mir im Jahr 2015 zu korrigieren.


Sie haben zwei Möglichkeiten, den Scatter-Befehl mit mehreren Farben in einem einzigen Aufruf zu verwenden.

  1. pylab.scatterVerwenden Sie als Befehlsunterstützung das RGBA-Array, um die gewünschte Farbe zu erstellen.

  2. Anfang 2013 gibt es keine Möglichkeit dazu, da der Befehl nur eine einzige Farbe für die gesamte Streupunktsammlung unterstützt. Als ich mein 10000-Zeilen-Projekt durchführte, fand ich eine allgemeine Lösung, um es zu umgehen. es ist also sehr klebrig, aber ich kann es in jeder Form, Farbe, Größe und Transparenz machen. Dieser Trick kann auch zum Zeichnen von Pfaden, zum Sammeln von Linien usw. angewendet werden.

Der Code ist auch vom Quellcode von inspiriert pyplot.scatter Ich habe nur dupliziert, was Scatter macht, ohne ihn zum Zeichnen auszulösen.

Der Befehl gibt pyplot.scatterein PatchCollectionObjekt zurück, in der Datei "matplotlib / collection.py" eine private Variable _facecolorsin der CollectionKlasse und eine Methode set_facecolors.

Wenn Sie also Streupunkte zeichnen müssen, können Sie Folgendes tun:

# rgbaArr is a N*4 array of float numbers you know what I mean
# X is a N*2 array of coordinates
# axx is the axes object that current draw, you get it from
# axx = fig.gca()

# also import these, to recreate the within env of scatter command 
import matplotlib.markers as mmarkers
import matplotlib.transforms as mtransforms
from matplotlib.collections import PatchCollection
import matplotlib.markers as mmarkers
import matplotlib.patches as mpatches


# define this function
# m is a string of scatter marker, it could be 'o', 's' etc..
# s is the size of the point, use 1.0
# dpi, get it from axx.figure.dpi
def addPatch_point(m, s, dpi):
    marker_obj = mmarkers.MarkerStyle(m)
    path = marker_obj.get_path()
    trans = mtransforms.Affine2D().scale(np.sqrt(s*5)*dpi/72.0)
    ptch = mpatches.PathPatch(path, fill = True, transform = trans)
    return ptch

patches = []
# markerArr is an array of maker string, ['o', 's'. 'o'...]
# sizeArr is an array of size float, [1.0, 1.0. 0.5...]

for m, s in zip(markerArr, sizeArr):
    patches.append(addPatch_point(m, s, axx.figure.dpi))

pclt = PatchCollection(
                patches,
                offsets = zip(X[:,0], X[:,1]),
                transOffset = axx.transData)

pclt.set_transform(mtransforms.IdentityTransform())
pclt.set_edgecolors('none') # it's up to you
pclt._facecolors = rgbaArr

# in the end, when you decide to draw
axx.add_collection(pclt)
# and call axx's parent to draw_idle()
Hualin
quelle
Das Lesen ist etwas kompliziert und 2013 habe ich 1 Jahr lang Python verwendet. Warum sollten die Leute wissen wollen, wie es geht? Nachdem es funktioniert hat, mache ich mir nie wieder die Mühe, es mir anzusehen. Mein Projekt bestand darin, viel Visualisierung zu zeichnen. Mit dem obigen Code wurde der Arbeitsablauf optimiert.
Hualin
1

Das funktioniert bei mir:

Verwenden Sie für jede Serie einen zufälligen RGB-Farbgenerator

c = color[np.random.random_sample(), np.random.random_sample(), np.random.random_sample()]
Bracoo
quelle
Ich weiß nicht, was Ihre Farbvariable ist, aber mit Ihrem Ansatz ist es möglich, etwas zu tun wie : plt.scatter(your values to the graph, color= (np.random.random_sample(), np.random.random_sample(), np.random.random_sample()) ). Sie haben einen RGB-Generator erwähnt und eine RGB-Liste deklariert. Generatoren werden zwischen '()'
Joel Carneiro am
0

Eine VIEL schnellere Lösung für große Datenmengen und eine begrenzte Anzahl von Farben ist die Verwendung von Pandas und der Groupby-Funktion:

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import time


# a generic set of data with associated colors
nsamples=1000
x=np.random.uniform(0,10,nsamples)
y=np.random.uniform(0,10,nsamples)
colors={0:'r',1:'g',2:'b',3:'k'}
c=[colors[i] for i in np.round(np.random.uniform(0,3,nsamples),0)]

plt.close('all')

# "Fast" Scatter plotting
starttime=time.time()
# 1) make a dataframe
df=pd.DataFrame()
df['x']=x
df['y']=y
df['c']=c
plt.figure()
# 2) group the dataframe by color and loop
for g,b in df.groupby(by='c'):
    plt.scatter(b['x'],b['y'],color=g)
print('Fast execution time:', time.time()-starttime)

# "Slow" Scatter plotting
starttime=time.time()
plt.figure()
# 2) group the dataframe by color and loop
for i in range(len(x)):
    plt.scatter(x[i],y[i],color=c[i])
print('Slow execution time:', time.time()-starttime)

plt.show()
MdM
quelle