211 votes

Définition d'une couleur différente pour chaque série dans un nuage de points sur matplotlib

Supposons que j'ai trois ensembles de données :

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

Je peux faire un diagramme de dispersion :

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

Comment puis-je faire ça avec 10 séries ?

J'ai fait des recherches à ce sujet et je n'ai trouvé aucune référence à ce que je demande.

Edit : clarifiant (j'espère) ma question

Si j'appelle scatter plusieurs fois, je ne peux définir que la même couleur sur chaque scatter. Je sais aussi que je peux définir un tableau de couleurs manuellement, mais je suis sûr qu'il existe un meilleur moyen de le faire. Ma question est donc la suivante : "Comment puis-je faire automatiquement un nuage de points pour mes différents ensembles de données, chacun avec une couleur différente ?

Si cela peut aider, je peux facilement attribuer un numéro unique à chaque ensemble de données.

1 votes

Quelle est la question ici ? La couleur peut aussi être un tableau, mais qu'est-ce que vous ne pouvez pas résoudre en appelant scatter plusieurs fois ?

1 votes

Si j'appelle scatter plusieurs fois, j'obtiens les mêmes couleurs. Je vais mettre à jour ma question.

331voto

DSM Points 71975

Je ne sais pas ce que vous entendez par "manuellement". Vous pouvez choisir une carte de couleurs et créer un tableau de couleurs assez facilement :

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 graph with different colors

Ou vous pouvez fabriquer votre propre cycleur de couleurs en utilisant itertools.cycle et en spécifiant les couleurs sur lesquelles vous voulez boucler, en utilisant next pour obtenir celui que vous voulez. Par exemple, avec 3 couleurs :

import itertools

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

Matplotlib graph with only 3 colors

En y réfléchissant, c'est peut-être plus propre de ne pas utiliser zip avec le premier non plus :

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

3 votes

+1. Un cycle itertools n'est probablement pas une bonne idée dans cette situation, car il aboutirait à ce que plusieurs ensembles de données aient la même couleur.

1 votes

@DavidRobinson : pas si vous spécifiez les dix, bien que je sois d'accord pour dire que le cyclisme va à l'encontre du but recherché :^)

0 votes

Précisément - alors ce n'est pas un cycle :)

65voto

Oxinabox Points 3930

La façon normale de tracer des graphiques avec des points de différentes couleurs dans matplotlib est de passer une liste de couleurs comme paramètre.

Par exemple :

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

3 colors

Lorsque vous avez une liste de listes et que vous voulez les colorer par liste. Je pense que la manière la plus élégante est celle suggérée par @DSM, il suffit de faire une boucle faisant de multiples appels à scatter.

Mais si, pour une raison quelconque, vous vouliez le faire en un seul appel, vous pouvez faire une grande liste de couleurs, avec une compréhension de liste et un peu de division de plancher :

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)

All plotted

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

0 votes

C'est vraiment génial pour un diagramme de dispersion où j'ai des données quotidiennes sur la taille d'un fichier texte, et si j'ai ajouté moins de, disons, 200 octets, je fais un point rouge, mais sinon il est vert.

25voto

G M Points 508

Une solution facile

Si vous n'avez qu'un seul type de collecte (par exemple, une dispersion sans barres d'erreur), vous pouvez également modifier les couleurs après les avoir tracées, ce qui est parfois plus facile à réaliser.

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)

Le seul morceau de code dont vous avez besoin :

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

La sortie vous donne des couleurs différentes même si vous avez plusieurs diagrammes de dispersion différents dans le même sous-plot.

enter image description here

0 votes

C'est génial mais comment ajouter par exemple des barres d'erreur de la même couleur avec cette fonction ? @G M

1 votes

Bonjour @PEBKAC, merci de l'avoir signalé, j'ai essayé cet après-midi de le faire fonctionner également dans ce cas mais je n'ai pas trouvé de solution donc j'ai édité la question et prévenu les autres utilisateurs. Merci !

0 votes

Bonjour @G M, désolé j'ai posté quelques commentaires avant d'avoir finalisé la solution, qui est décrite ici : stackoverflow.com/q/51444364/7541421

10voto

Ophir Carmi Points 1457

Vous pouvez toujours utiliser le plot() comme suit :

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 as scatter but changes colors

6voto

Hualin Points 16

Cette question est un peu délicate avant janvier 2013 et matplotlib 1.3.1 (août 2013), qui est la plus ancienne version stable que vous pouvez trouver sur le site web de matpplotlib. Mais après cela, c'est assez trivial.

Parce que la version actuelle de matplotlib.pylab.scatter permet d'assigner : un tableau de chaînes de noms de couleurs, un tableau de nombres flottants avec carte de couleurs, un tableau de RGB ou RGBA.

cette réponse est dédiée à la passion sans fin de @Oxinabox pour corriger la version 2013 de moi-même en 2015.


vous avez deux possibilités d'utiliser la commande scatter avec plusieurs couleurs en un seul appel.

  1. comme pylab.scatter permet d'utiliser un tableau RGBA pour obtenir la couleur que vous souhaitez ;

  2. au début de 2013, il n'y a aucun moyen de le faire, puisque la commande ne prend en charge qu'une seule couleur pour toute la collection de points de diffusion. Lorsque je faisais mon projet de 10000 lignes, j'ai trouvé une solution générale pour contourner ce problème. C'est donc très collant, mais je peux le faire dans n'importe quelle forme, couleur, taille et transparence. Cette astuce pourrait également s'appliquer à la collection de chemins, la collection de lignes.....

le code est également inspiré par le code source de pyplot.scatter j'ai juste dupliqué ce que scatter fait sans le déclencher pour dessiner.

le commandement pyplot.scatter retourner un PatchCollection Objet, dans le fichier "matplotlib/collections.py" une variable privée _facecolors en Collection et une méthode set_facecolors .

donc quand vous avez un point de dispersion à dessiner, vous pouvez le faire :

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

0 votes

C'est un peu compliqué à lire et en 2013 j'ai utilisé python pendant 1 an. alors pourquoi les gens voudraient-ils savoir comment le faire ? après l'avoir fait fonctionner, je n'ai jamais pris la peine de le regarder à nouveau. mon projet était de dessiner beaucoup de visualisation, avec le code ci-dessus, le flux de travail a été simplifié.

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