Matplotlib - colormap noir et blanc (avec des tirets, points, etc.)
-
28-10-2019 - |
Question
J'utilise matplotlib pour créer une ligne-parcelles 2d. Aux fins de la publication, je voudrais avoir ces parcelles en noir et blanc ( pas en niveaux de gris), et je me bats pour trouver une solution non intrusive pour cela.
Gnuplot automatiquement modifie fringant modèles pour des lignes différentes, est quelque chose de similaire possible avec matplotlib?
La solution
Ci-dessous je fournir des fonctions pour convertir une ligne de couleur à une ligne noire avec un style unique. Mon test rapide a montré que, après 7 lignes, les couleurs répétées. Si ce n'est pas le cas (et je fait une erreur), puis un ajustement mineur est nécessaire pour la COLORMAP
« constante » dans la routine prévue.
Voici la routine et par exemple:
import matplotlib.pyplot as plt
import numpy as np
def setAxLinesBW(ax):
"""
Take each Line2D in the axes, ax, and convert the line style to be
suitable for black and white viewing.
"""
MARKERSIZE = 3
COLORMAP = {
'b': {'marker': None, 'dash': (None,None)},
'g': {'marker': None, 'dash': [5,5]},
'r': {'marker': None, 'dash': [5,3,1,3]},
'c': {'marker': None, 'dash': [1,3]},
'm': {'marker': None, 'dash': [5,2,5,2,5,10]},
'y': {'marker': None, 'dash': [5,3,1,2,1,10]},
'k': {'marker': 'o', 'dash': (None,None)} #[1,2,1,10]}
}
lines_to_adjust = ax.get_lines()
try:
lines_to_adjust += ax.get_legend().get_lines()
except AttributeError:
pass
for line in lines_to_adjust:
origColor = line.get_color()
line.set_color('black')
line.set_dashes(COLORMAP[origColor]['dash'])
line.set_marker(COLORMAP[origColor]['marker'])
line.set_markersize(MARKERSIZE)
def setFigLinesBW(fig):
"""
Take each axes in the figure, and for each line in the axes, make the
line viewable in black and white.
"""
for ax in fig.get_axes():
setAxLinesBW(ax)
xval = np.arange(100)*.01
fig = plt.figure()
ax = fig.add_subplot(211)
ax.plot(xval,np.cos(2*np.pi*xval))
ax.plot(xval,np.cos(3*np.pi*xval))
ax.plot(xval,np.cos(4*np.pi*xval))
ax.plot(xval,np.cos(5*np.pi*xval))
ax.plot(xval,np.cos(6*np.pi*xval))
ax.plot(xval,np.cos(7*np.pi*xval))
ax.plot(xval,np.cos(8*np.pi*xval))
ax = fig.add_subplot(212)
ax.plot(xval,np.cos(2*np.pi*xval))
ax.plot(xval,np.cos(3*np.pi*xval))
ax.plot(xval,np.cos(4*np.pi*xval))
ax.plot(xval,np.cos(5*np.pi*xval))
ax.plot(xval,np.cos(6*np.pi*xval))
ax.plot(xval,np.cos(7*np.pi*xval))
ax.plot(xval,np.cos(8*np.pi*xval))
fig.savefig("colorDemo.png")
setFigLinesBW(fig)
fig.savefig("bwDemo.png")
Cela donne les deux parcelles suivantes: Tout d'abord en couleur: Puis, en noir et blanc:
Vous pouvez régler la façon dont chaque couleur est converti en un style. Si vous voulez juste jouer uniquement avec le style de tiret (-. Contre - par rapport à ce que modèle que vous voulez), définissez la valeur COLORMAP
« marqueur » correspondant à None
et ajusté le modèle « tableau de bord », ou vice versa.
Par exemple, la dernière couleur dans le dictionnaire est « k » (pour le noir); l'origine I eu seulement un motif en pointillé [1,2,1,10]
, correspondant à un pixel représenté, deux pas, un seul est représenté, 10 pas, qui est un modèle d'espace de point-point. Ensuite, je commentais que sur, le réglage du tableau de bord à (None, None), d'une manière très formelle de dire la ligne solide, et a ajouté le marqueur « o », pour le cercle.
J'ai aussi mis une « constante » MARKERSIZE, qui fixera la taille de chaque marqueur, parce que je trouvais la taille par défaut d'être un peu grand.
Cela ne signifie évidemment pas manipuler le cas lorsque vos lignes ont déjà un boniment tableau de bord ou d'un marqueur, mais vous pouvez utiliser ces routines comme point de départ pour construire un convertisseur plus sophistiqué. Par exemple, si vous intrigue originale avait une ligne rouge solide et une ligne en pointillé rouge, ils ont tous deux se transformer en lignes au tableau de bord points noirs avec ces routines. Quelque chose à garder à l'esprit lorsque vous les utilisez.
Autres conseils
TL; DR
import matplotlib.pyplot as plt
from cycler import cycler
monochrome = (cycler('color', ['k']) * cycler('marker', ['', '.']) *
cycler('linestyle', ['-', '--', ':', '=.']))
plt.rc('axes', prop_cycle=monochrome)
réponse prolongée
Les nouvelles versions de matplotlib
a introduit une nouvelle rcParams
, à savoir axes.prop_cycle
In [1]: import matplotlib.pyplot as plt
In [2]: plt.rcParams['axes.prop_cycle']
Out[2]: cycler('color', ['b', 'g', 'r', 'c', 'm', 'y', 'k'])
Pour les styles prédéfinis, disponibles par plt.style.use(...)
ou with plt.style.context(...):
, l'prop_cycle
est équivalente à la traditionnelle et désapprouvée axes.color_cycle
In [3]: plt.rcParams['axes.color_cycle']
/.../__init__.py:892: UserWarning: axes.color_cycle is deprecated and replaced with axes.prop_cycle; please use the latter.
warnings.warn(self.msg_depr % (key, alt_key))
Out[3]: ['b', 'g', 'r', 'c', 'm', 'y', 'k']
mais l'objet cycler
a beaucoup plus de possibilités, notamment un cycler
complexe peut être composé de plus simples, se référant à des propriétés différentes, en utilisant +
et *
, ce qui signifie respectivement passer comme un éclair et produit cartésien.
Ici, nous importons la fonction d'aide de cycler
, nous définissons 3 cycler
simple qui se réfèrent à des propriétés différentes et enfin les composent en utilisant le produit cartésien
In [4]: from cycler import cycler
In [5]: color_c = cycler('color', ['k'])
In [6]: style_c = cycler('linestyle', ['-', '--', ':', '-.'])
In [7]: markr_c = cycler('marker', ['', '.', 'o'])
In [8]: c_cms = color_c * markr_c * style_c
In [9]: c_csm = color_c * style_c * markr_c
Ici, nous avons deux différents (?) cycler
complexe et oui, ils sont différents parce que cette opération est non-commutative, consultez
In [10]: for d in c_csm: print('\t'.join(d[k] for k in d))
- k
- . k
- o k
-- k
-- . k
-- o k
: k
: . k
: o k
-. k
-. . k
-. o k
In [11]: for d in c_cms: print('\t'.join(d[k] for k in d))
- k
-- k
: k
-. k
- . k
-- . k
: . k
-. . k
- o k
-- o k
: o k
-. o k
Le cycle élémentaire que des changements plus rapides est le dernier dans le produit, etc., ce qui est important si nous voulons un certain ordre dans le style des lignes.
Comment utiliser la composition de cycler
s? A l'aide d'plt.rc
, ou un moyen équivalent pour modifier la rcParams
de matplotlib
. Par exemple.
In [12]: %matplotlib
Using matplotlib backend: Qt4Agg
In [13]: import numpy as np
In [14]: x = np.linspace(0, 8, 101)
In [15]: y = np.cos(np.arange(7)+x[:,None])
In [16]: plt.rc('axes', prop_cycle=c_cms)
In [17]: plt.plot(x, y);
In [18]: plt.grid();
Bien sûr, cela est juste un exemple, et l'OP peut mélanger et faire correspondre des propriétés différentes pour atteindre le plus agréable sortie visuelle.
PS j'ai oublié de mentionner que cette approche prend automatiquement en charge des échantillons de ligne dans la zone de légende,
Je fortement fait le code d'utilisation Yann, mais aujourd'hui je l'ai lu une réponse de Puis-je faire défiler les styles de ligne dans matplotlib Alors maintenant, je vais faire mes parcelles BW ainsi:
import pylab as plt
from itertools import cycle
lines = ["k-","k--","k-.","k:"]
linecycler = cycle(lines)
plt.figure()
for i in range(4):
x = range(i,i+10)
plt.plot(range(10),x,next(linecycler))
plt.show()
Des choses comme plot(x,y,'k-.')
produira la ligne de points-tirets noirs ('k'
) ('-.'
). Est-ce pas ce que vous une recherche?