web-dev-qa-db-fra.com

Utilisation de couleurs pour définir la couleur de la ligne dans matplotlib

Comment définir la couleur d'une ligne dans matplotlib avec des valeurs scalaires fournies lors de l'exécution à l'aide d'une palette de couleurs (disons jet)? J'ai essayé différentes approches ici et je pense que je suis perplexe. values[] est un tableau altéré de scalaires. les courbes sont un ensemble de tableaux unidimensionnels et les étiquettes sont un tableau de chaînes de texte. Chaque tableau a la même longueur.

fig = plt.figure()
ax = fig.add_subplot(111)
jet = colors.Colormap('jet')
cNorm  = colors.Normalize(vmin=0, vmax=values[-1])
scalarMap = cmx.ScalarMappable(norm=cNorm, cmap=jet)
lines = []
for idx in range(len(curves)):
    line = curves[idx]
    colorVal = scalarMap.to_rgba(values[idx])
    retLine, = ax.plot(line, color=colorVal)
    #retLine.set_color()
    lines.append(retLine)
ax.legend(lines, labels, loc='upper right')
ax.grid()
plt.show()
63
fodon

L'erreur que vous recevez est due à la façon dont vous définissez jet. Vous créez la classe de base Colormap avec le nom 'jet', mais cela est très différent d'obtenir la définition par défaut de la palette de couleurs 'jet'. Cette classe de base ne doit jamais être créée directement et seules les sous-classes doivent être instanciées.

Ce que vous avez trouvé avec votre exemple est un comportement buggy dans Matplotlib. Un message d'erreur plus clair doit être généré lorsque ce code est exécuté.

Ceci est une version mise à jour de votre exemple:

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

# define some random data that emulates your indeded code:
NCURVES = 10
np.random.seed(101)
curves = [np.random.random(20) for i in range(NCURVES)]
values = range(NCURVES)

fig = plt.figure()
ax = fig.add_subplot(111)
# replace the next line 
#jet = colors.Colormap('jet')
# with
jet = cm = plt.get_cmap('jet') 
cNorm  = colors.Normalize(vmin=0, vmax=values[-1])
scalarMap = cmx.ScalarMappable(norm=cNorm, cmap=jet)
print scalarMap.get_clim()

lines = []
for idx in range(len(curves)):
    line = curves[idx]
    colorVal = scalarMap.to_rgba(values[idx])
    colorText = (
        'color: (%4.2f,%4.2f,%4.2f)'%(colorVal[0],colorVal[1],colorVal[2])
        )
    retLine, = ax.plot(line,
                       color=colorVal,
                       label=colorText)
    lines.append(retLine)
#added this to get the legend to work
handles,labels = ax.get_legend_handles_labels()
ax.legend(handles, labels, loc='upper right')
ax.grid()
plt.show()

Résultant en:

enter image description here

L'utilisation de ScalarMappable constitue une amélioration par rapport à l'approche présentée dans ma réponse: création de plus de 20 couleurs de légende uniques à l'aide de matplotlib

79
Yann

J'ai pensé qu'il serait avantageux d'inclure ce que je considère être une méthode plus simple en utilisant le linspace de numpy couplé à l'objet de type cm de matplotlib. Il est possible que la solution ci-dessus concerne une version plus ancienne. J'utilise le python 3.4.3, matplotlib 1.4.3 et numpy 1.9.3., Et ma solution est la suivante.

import matplotlib.pyplot as plt

from matplotlib import cm
from numpy import linspace

start = 0.0
stop = 1.0
number_of_lines= 1000
cm_subsection = linspace(start, stop, number_of_lines) 

colors = [ cm.jet(x) for x in cm_subsection ]

for i, color in enumerate(colors):
    plt.axhline(i, color=color)

plt.ylabel('Line Number')
plt.show()

Il en résulte 1 000 lignes de couleurs uniques qui couvrent la palette de couleurs cm.jet complète, comme illustré ci-dessous. Si vous exécutez ce script, vous constaterez que vous pouvez effectuer un zoom avant sur les lignes individuelles.

cm.jet between 0.0 and 1.0 with 1000 graduations

Maintenant, disons que je veux que mes 1000 couleurs de trait s'étendent juste sur la partie verdâtre entre les lignes 400 à 600. Je change simplement mes valeurs de départ et d'arrêt à 0.4 et 0.6, ce qui n'utilise que 20% de la palette de couleurs cm.jet entre 0.4 et 0,6.

enter image description here

Ainsi, dans un résumé d'une ligne, vous pouvez créer une liste de couleurs rgba à partir d'une palette de couleurs matplotlib.cm:

colors = [ cm.jet(x) for x in linspace(start, stop, number_of_lines) ]

Dans ce cas, j'utilise la carte couramment appelée nommée jet, mais vous pouvez trouver la liste complète des cartes de couleurs disponibles dans votre version de matplotlib en appelant:

>>> from matplotlib import cm
>>> dir(cm)
53
blahreport

Une combinaison de styles de ligne, de marqueurs et de couleurs qualitatives de matplotlib:

import itertools
import matplotlib as mpl
import matplotlib.pyplot as plt
N = 8*4+10
l_styles = ['-','--','-.',':']
m_styles = ['','.','o','^','*']
colormap = mpl.cm.Dark2.colors   # Qualitative colormap
for i,(marker,linestyle,color) in Zip(range(N),itertools.product(m_styles,l_styles, colormap)):
    plt.plot([0,1,2],[0,2*i,2*i], color=color, linestyle=linestyle,marker=marker,label=i)
plt.legend(bbox_to_anchor=(1.05, 1), loc=2, borderaxespad=0.,ncol=4);

enter image description here

UPDATE: Prise en charge non seulement de ListedColormap, mais également de LinearSegmentedColormap

import itertools
import matplotlib.pyplot as plt
Ncolors = 8
#colormap = plt.cm.Dark2# ListedColormap
colormap = plt.cm.viridis# LinearSegmentedColormap
Ncolors = min(colormap.N,Ncolors)
mapcolors = [colormap(int(x*colormap.N/Ncolors)) for x in range(Ncolors)]
N = Ncolors*4+10
l_styles = ['-','--','-.',':']
m_styles = ['','.','o','^','*']
fig,ax = plt.subplots(gridspec_kw=dict(right=0.6))
for i,(marker,linestyle,color) in Zip(range(N),itertools.product(m_styles,l_styles, mapcolors)):
    ax.plot([0,1,2],[0,2*i,2*i], color=color, linestyle=linestyle,marker=marker,label=i)
ax.legend(bbox_to_anchor=(1.05, 1), loc=2, borderaxespad=0.,ncol=3,prop={'size': 8})

enter image description here

8
Pablo Reyes

Vous pouvez faire ce que j'ai écrit à partir de mon compte supprimé (interdiction pour les nouveaux messages: (il y en avait)). C'est plutôt simple et agréable à regarder.

En utilisant le 3-ème de ces 3 uns habituellement, je vérifiais également les versions 1 et 2.

from matplotlib.pyplot import cm
import numpy as np

#variable n should be number of curves to plot (I skipped this earlier thinking that it is obvious when looking at picture - sorry my bad mistake xD): n=len(array_of_curves_to_plot)
#version 1:

color=cm.Rainbow(np.linspace(0,1,n))
for i,c in Zip(range(n),color):
   ax1.plot(x, y,c=c)

#or version 2: - faster and better:

color=iter(cm.Rainbow(np.linspace(0,1,n)))
c=next(color)
plt.plot(x,y,c=c)

#or version 3:

color=iter(cm.Rainbow(np.linspace(0,1,n)))
for i in range(n):
   c=next(color)
   ax1.plot(x, y,c=c)

exemple de 3:

Amortissement RAO du bateau vs Ikeda en fonction de l'amplitude du roulis A44

1
Robert GRZELKA