81 votes

Utilisation de Colormaps pour définir la couleur d'une ligne dans matplotlib

Comment définir la couleur d'une ligne dans matplotlib avec des valeurs scalaires fournies au moment de l'exécution à l'aide d'une carte de couleurs (par exemple, une carte de couleurs) ? jet ) ? J'ai essayé plusieurs approches différentes et je crois que je suis dans l'impasse. values[] est un tableau de scalaires. Les courbes sont un ensemble de tableaux 1-d, et les étiquettes sont un tableau de chaînes de texte. Tous les tableaux ont 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()

92voto

Yann Points 6909

L'erreur que vous rencontrez est due à la façon dont vous définissez l'option jet . Vous créez la classe de base Colormap avec le nom 'jet', mais c'est très différent d'obtenir la définition par défaut de la carte 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 bogué dans Matplotlib. Un message d'erreur plus clair devrait être généré lorsque ce code est exécuté.

Il s'agit d'une version actualisée 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

Utilisation d'un ScalarMappable est une amélioration par rapport à l'approche présentée dans ma réponse connexe : création de plus de 20 couleurs de légende uniques à l'aide de matplotlib

85voto

blahreport Points 890

J'ai pensé qu'il serait bénéfique d'inclure ce que je considère comme une méthode plus simple utilisant l'espace linéaire de numpy couplé à l'objet cm-type de matplotlib. Il est possible que la solution ci-dessus soit pour une ancienne version. J'utilise 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 1000 lignes de couleur unique qui couvrent la totalité de la carte des couleurs de cm.jet, comme illustré ci-dessous. Si vous exécutez ce script, vous constaterez que vous pouvez zoomer sur les lignes individuelles.

cm.jet between 0.0 and 1.0 with 1000 graduations

Supposons maintenant que je souhaite que les couleurs de mes 1000 lignes couvrent uniquement la partie verdâtre entre les lignes 400 et 600. Je modifie simplement mes valeurs de départ et d'arrivée à 0,4 et 0,6, ce qui permet d'utiliser seulement 20 % de la carte de couleurs cm.jet entre 0,4 et 0,6.

enter image description here

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

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

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

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

19voto

Pablo Reyes Points 2017

Une combinaison de styles de lignes, de marqueurs, et de couleurs qualitatives provenant 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 : Soutenir non seulement ListedColormap mais aussi 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

8voto

Robert GRZELKA Points 79

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

J'utilise la troisième de ces trois versions habituellement, et je n'ai jamais vérifié 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 :

RAO de roulis du navire par rapport à l'amortissement d'Ikeda en fonction de l'amplitude du roulis A44

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