matplotlib-colormap noir et blanc (avec des tirets, des points, etc.)

j'utilise matplotlib pour créer des tracés de ligne 2d. Pour les besoins de la publication, je voudrais avoir ces parcelles en noir et blanc ( et non ), et je me bats pour trouver une solution non-intrusive pour cela.

gnuplot modifie automatiquement les motifs fringants pour différentes lignes, est-ce que quelque chose de similaire est possible avec matplotlib?

32
demandé sur eudoxos 2011-09-09 10:52:48

4 réponses

ci-dessous je fournis des fonctions pour convertir une ligne de couleur à une ligne noire avec un style unique. Mon test rapide a montré qu'après 7 lignes, les couleurs répétées. Si ce n'est pas le cas (et j'ai fait une erreur), puis un ajustement mineur est nécessaire pour la "constante COLORMAP dans la routine.

Voici la routine et l'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 fournit les deux parcelles suivantes: D'abord en couleur: enter image description here Puis dans noir et blanc: enter image description here

vous pouvez ajuster la façon dont chaque couleur est convertie en un style. Si vous voulez seulement jouer avec le style dash ( -. vs. -- vs. whatever pattern you want), définissez la valeur COLORMAP correspondant au "marqueur" à None et ajustez le "dash" pattern, ou vice versa.

par exemple , la dernière couleur du dictionnaire est "k" (pour le noir); à l'origine je n'avais qu'un motif en tirets [1,2,1,10] , correspondant à un pixel montré, deux pas, un montré, 10 pas, qui est un motif point-point-Espace. Puis j'ai commenté que dehors, mettant le tiret à (Aucun, Aucun), une manière très formelle de dire ligne solide, et ai ajouté le marqueur 'o', pour cercle.

j'ai aussi défini un MARKERSIZE 'constant', qui définira la taille de chaque marqueur, parce que j'ai trouvé que la taille par défaut est un peu grande.

cela ne gère évidemment pas le cas lorsque vos lignes ont déjà un tiret ou un marqueur patter, mais vous pouvez utiliser ces routines comme point de départ pour construire un convertisseur plus sophistiqué. Par exemple, si votre parcelle d'origine avait une ligne pleine rouge et une ligne pointillée rouge, les deux se transformeraient en lignes noires de points de tableau de bord avec ces routines. Quelque chose à garder à l'esprit lorsque vous les utilisez.

48
répondu Yann 2016-02-02 13:08:51

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

le plus Récent matplotlib versions introduit un nouveau 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 modèles précannés, disponibles par plt.style.use(...) ou with plt.style.context(...): , le prop_cycle est équivalent au traditionnel et déprécié 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, en particulier un complexe cycler peut être composé de plus simples, se référant à des propriétés différentes, en utilisant + et * , signification respectivement fermeture éclair et produit cartésien.

ici nous importons la fonction d'aide cycler , nous définissons 3 simple cycler qui se réfèrent à des propriétés différentes et finalement 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(?) complexe cycler et oui, ils sont différents parce que cette opération n'est pas commutative, avoir un look

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 qui change plus vite est le dernier dans le produit, etc. ceci est important si nous voulons un certain ordre dans le style de lignes.

comment utiliser la composition de cycler s? Au moyen de plt.rc , ou d'une manière équivalente pour modifier le rcParams de matplotlib . E. g.,

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

enter image description here

bien sûr, ce n'est qu'un exemple, et L'OP peut mélanger et assortir différentes propriétés pour obtenir le résultat visuel le plus agréable.

PS j'ai oublié de mentionner que cette approche s'occupe automatiquement des échantillons de ligne dans la boîte de légende, enter image description here

6
répondu gboffi 2016-06-30 10:11:31

j'ai beaucoup utilisé le code de Yann, mais aujourd'hui, j'ai lu une réponse de puis-je cycle à travers les styles de ligne dans matplotlib donc maintenant, je vais faire mes parcelles de BW de cette façon:

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

enter image description here

2
répondu Jānis Erdmanis 2017-05-23 12:02:39

des choses comme plot(x,y,'k-.') produiront la ligne noire ( 'k' ) pointillée ( '-.' ). N'est-ce pas ce que vous cherchez?

1
répondu ev-br 2011-09-09 14:21:58