J'ai le problème suivant, je veux créer ma propre palette de couleurs (rouge-mélange-violet-mélange-bleu) qui mappe sur des valeurs comprises entre -2 et +2 et je veux l'utiliser pour colorer des points dans mon tracé. L'intrigue devrait alors avoir les couleurs à droite.
C’est ainsi que j’ai créé la carte jusqu’à présent. Mais je ne suis pas vraiment sûr que ça mélange les couleurs.
cmap = matplotlib.colors.ListedColormap(["red","Violet","blue"], name='from_list', N=None)
m = cm.ScalarMappable(norm=norm, cmap=cmap)
Ainsi, je mappe les couleurs sur les valeurs.
colors = itertools.cycle([m.to_rgba(1.22), ..])
Puis je fais le tracé:
for i in range(0, len(array_dg)):
plt.plot(array_dg[i], markers.next(),alpha=alpha[i], c=colors.next())
Mes problèmes sont:
1. Je ne peux pas tracer l'échelle de couleur.
2. Je ne suis pas tout à fait sûr que mon échelle crée une échelle de couleurs continue (lisse).
Il existe un exemple illustratif de comment créer des tables de couleurs personnalisées ici . La docstring est essentielle pour comprendre le sens de cdict
. Une fois que vous obtenez cela sous votre ceinture, vous pouvez utiliser un cdict
comme ceci:
cdict = {'red': ((0.0, 1.0, 1.0),
(0.1, 1.0, 1.0), # red
(0.4, 1.0, 1.0), # Violet
(1.0, 0.0, 0.0)), # blue
'green': ((0.0, 0.0, 0.0),
(1.0, 0.0, 0.0)),
'blue': ((0.0, 0.0, 0.0),
(0.1, 0.0, 0.0), # red
(0.4, 1.0, 1.0), # Violet
(1.0, 1.0, 0.0)) # blue
}
Bien que le format cdict
vous apporte beaucoup de souplesse, je trouve que son format est plutôt peu intuitif pour les gradients simples. Voici une fonction utilitaire permettant de générer des LinearSegmentedColormaps simples:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors as mcolors
def make_colormap(seq):
"""Return a LinearSegmentedColormap
seq: a sequence of floats and RGB-tuples. The floats should be increasing
and in the interval (0,1).
"""
seq = [(None,) * 3, 0.0] + list(seq) + [1.0, (None,) * 3]
cdict = {'red': [], 'green': [], 'blue': []}
for i, item in enumerate(seq):
if isinstance(item, float):
r1, g1, b1 = seq[i - 1]
r2, g2, b2 = seq[i + 1]
cdict['red'].append([item, r1, r2])
cdict['green'].append([item, g1, g2])
cdict['blue'].append([item, b1, b2])
return mcolors.LinearSegmentedColormap('CustomMap', cdict)
c = mcolors.ColorConverter().to_rgb
rvb = make_colormap(
[c('red'), c('Violet'), 0.33, c('Violet'), c('blue'), 0.66, c('blue')])
N = 1000
array_dg = np.random.uniform(0, 10, size=(N, 2))
colors = np.random.uniform(-2, 2, size=(N,))
plt.scatter(array_dg[:, 0], array_dg[:, 1], c=colors, cmap=rvb)
plt.colorbar()
plt.show()
Au fait, le for-loop
for i in range(0, len(array_dg)):
plt.plot(array_dg[i], markers.next(),alpha=alpha[i], c=colors.next())
trace un point pour chaque appel à plt.plot
. Cela fonctionnera pour un petit nombre de points, mais deviendra extrêmement lent pour de nombreux points. plt.plot
ne peut dessiner qu’en une couleur, mais plt.scatter
peut attribuer une couleur différente à chaque point. Ainsi, plt.scatter
est la voie à suivre.
Puisque les méthodes utilisées dans les autres réponses semblent assez compliquées pour une tâche aussi facile, voici une nouvelle réponse:
Au lieu d'un ListedColormap
, qui produit une palette de couleurs discrète, vous pouvez utiliser un LinearSegmentedColormap
. Ceci peut facilement être créé à partir d'une liste en utilisant le from_list
méthode.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors
x,y,c = Zip(*np.random.Rand(30,3)*4-2)
norm=plt.Normalize(-2,2)
cmap = matplotlib.colors.LinearSegmentedColormap.from_list("", ["red","Violet","blue"])
plt.scatter(x,y,c=c, cmap=cmap, norm=norm)
plt.colorbar()
plt.show()
Plus généralement, si vous avez une liste de valeurs (par exemple, [-2., -1, 2]
) et les couleurs correspondantes (par exemple ["red","Violet","blue"]
), de sorte que la valeur n
e corresponde à la couleur n
, vous pouvez normaliser les valeurs et les fournir sous forme de n-uplets à la commande from_list
méthode.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors
x,y,c = Zip(*np.random.Rand(30,3)*4-2)
cvals = [-2., -1, 2]
colors = ["red","Violet","blue"]
norm=plt.Normalize(min(cvals),max(cvals))
tuples = list(Zip(map(norm,cvals), colors))
cmap = matplotlib.colors.LinearSegmentedColormap.from_list("", tuples)
plt.scatter(x,y,c=c, cmap=cmap, norm=norm)
plt.colorbar()
plt.show()
Si vous souhaitez automatiser la création d'une palette de couleurs divergente personnalisée couramment utilisée pour tracés de surface , ce module associé à la méthode @unutbu a bien fonctionné pour moi.
def diverge_map(high=(0.565, 0.392, 0.173), low=(0.094, 0.310, 0.635)):
'''
low and high are colors that will be used for the two
ends of the spectrum. they can be either color strings
or rgb color tuples
'''
c = mcolors.ColorConverter().to_rgb
if isinstance(low, basestring): low = c(low)
if isinstance(high, basestring): high = c(high)
return make_colormap([low, c('white'), 0.5, c('white'), high])
Les valeurs hautes et basses peuvent être des noms de couleur de chaîne ou des nuplets rgb. C’est le résultat obtenu avec le démo de surface :