matplotlib - Black & white colormap (z kreskami, kropkami itp)

Używam matplotlib do tworzenia wykresów liniowych 2d. Na potrzeby publikacji chciałbym mieć te wykresy w czerni i bieli (a nie w skali szarości) i staram się znaleźć na to nieinwazyjne rozwiązanie.

Gnuplot automatycznie zmienia wzory wykrojów dla różnych linii, czy możliwe jest coś podobnego z matplotlib?

Author: eudoxos, 2011-09-09

4 answers

Poniżej przedstawiam funkcje do konwersji kolorowej linii do czarnej linii o unikalnym stylu. Mój szybki test pokazał, że po 7 liniach Kolory się powtarzały. Jeśli tak nie jest (i popełniłem błąd), to potrzebna jest niewielka korekta dla "stałej" COLORMAP w dostarczonej rutynie.

Oto schemat i przykład:

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

Daje to następujące dwie działki: Pierwszy w Kolorze: Tutaj wpisz opis obrazka Potem w czerni i bieli: Tutaj wpisz opis obrazka

Możesz dostosować sposób konwersji każdego koloru za styl. Jeśli chcesz grać tylko w stylu dash ( -. vs. -- vs. dowolny wzorzec), ustawić COLORMAP odpowiadającą wartość 'marker' na None i skorygować wzorzec 'dash' lub odwrotnie.

Na przykład ostatni kolor w słowniku to " k " (dla czerni); początkowo miałem tylko przerywany wzór [1,2,1,10], odpowiadający jednemu pokazanemu pikselowi, dwóm nie, jednemu pokazanemu, 10 Nie, który jest wzorcem kropka-kropka-przestrzeń. Potem to skomentowałem, ustawiając kreskę na (brak, brak), bardzo formalną sposób wymawiania stałej linii i dodawanie znacznika "o", dla okręgu.

Ustawiłem również' stałą ' MARKERSIZE, która ustawi rozmiar każdego znacznika, ponieważ domyślna wielkość jest trochę duża.

To oczywiście nie obsługuje przypadku, gdy twoje linie mają już wzorzec myślnika lub znacznika, ale możesz użyć tych procedur jako punktu wyjścia do zbudowania bardziej zaawansowanego konwertera. Na przykład, jeśli oryginalny Wykres miał czerwoną linię ciągłą i czerwoną linię przerywaną, oba będą zmieniaj się w czarne kreski z kropkami za pomocą tych procedur. Coś, o czym należy pamiętać, gdy ich używasz.

 48
Author: Yann,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
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)

Odpowiedź Rozszerzona

Nowsze matplotlib wydania wprowadziły nowe rcParams, a mianowicie 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'])

Dla wstępnie przeskanowanych stylów, dostępnych przez plt.style.use(...) lub with plt.style.context(...):, {[11] } jest odpowiednikiem tradycyjnego i przestarzałego 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']

Ale cycler obiekt ma o wiele więcej możliwości, w szczególności złożony cycler może być złożony z prostszych, odwołujących się do różnych właściwości, używając odpowiednio + i *, czyli zipping i produkt kartezjański.

Tutaj importujemy cycler funkcję pomocniczą, definiujemy 3 proste cycler, które odnoszą się do różnych właściwości i ostatecznie komponujemy je za pomocą iloczynu kartezjańskiego

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

Tutaj mamy dwa różne(?) złożone cycler i tak, są różne, ponieważ ta operacja nie jest przemienna, spójrz

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

Cykl elementarny, który zmienia się szybciej, jest ostatnim w produkcie itp., jest to ważne, jeśli chcemy mieć określony porządek w stylizacja linii.

Jak wykorzystać skład cyclers? Za pomocą plt.rc lub równoważnego sposobu modyfikacji rcParams z matplotlib. Np.,

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

Tutaj wpisz opis obrazka

Oczywiście jest to tylko przykład, A OP może mieszać i dopasowywać różne właściwości, aby uzyskać jak najbardziej przyjemny efekt wizualny.

PS zapomniałem wspomnieć, że takie podejście automatycznie zajmuje się próbkami linii w polu legendy, Tutaj wpisz opis obrazka

 6
Author: gboffi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-30 10:11:31

Mocno użyłem kodu Yanna, ale dzisiaj przeczytałem odpowiedź z Czy Mogę przechodzić przez style liniowe w matplotlib więc teraz zrobię moje BW działy w ten sposób:

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

Tutaj wpisz opis obrazka

 2
Author: Jānis Erdmanis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:02:39

Rzeczy takie jakplot(x,y,'k-.') będą produkować czarną ('k') linię z kropkami ('-.'). Nie tego szukasz?

 1
Author: ev-br,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-09-09 14:21:58