web-dev-qa-db-ja.com

matplotlib-白黒のカラーマップ(ダッシュ、ドットなどを含む)

Matplotlibを使用して2Dラインプロットを作成しています。出版の目的で、私はそれらのプロットを白黒(notグレースケール)にしたいのですが、そのための邪魔にならない解決策を見つけるのに苦労しています。

Gnuplotは異なる線の破線パターンを自動的に変更しますが、matplotlibでも同様のことが可能ですか?

34
eudoxos

以下に、色付きの線を独自のスタイルで黒い線に変換する関数を示します。私の簡単なテストでは、7行後に色が繰り返されることが示されました。そうでない場合(そして私が間違えた場合)、提供されたルーチンの「定数」COLORMAPを微調整する必要があります。

ルーチンと例は次のとおりです。

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

これにより、次の2つのプロットが提供されます。 enter image description here 次に、白黒で: enter image description here

各色をスタイルに変換する方法を調整できます。ダッシュスタイル(-。vs.-vs。任意のパターン)のみでプレイしたい場合は、COLORMAP対応する 'マーカー'値をNoneに設定し、 'を調整します。ダッシュパターン、またはその逆。

たとえば、辞書の最後の色は「k」(黒の場合)です。もともと私は破線のパターンしかありませんでした[1,2,1,10]、表示されている1つのピクセル、表示されていない2つ、表示されていない1つ、表示されていない10に対応します。これは、ドット-ドット-スペースパターンです。次に、ダッシュを(None、None)に設定してコメントしました。これは、実線の非常に正式な言い方であり、円のマーカー「o」を追加しました。

また、デフォルトのサイズが少し大きいことがわかったため、各マーカーのサイズを設定する「定数」MARKERSIZEも設定しました。

これは明らかに、行にダッシュまたはマーカーパターンがすでにある場合には対処しませんが、これらのルーチンを開始点として使用して、より高度なコンバーターを構築できます。たとえば、元のプロットに赤い実線と赤い点線がある場合、これらのルーチンを使用すると、両方が黒い一点鎖線に変わります。それらを使用するときに覚えておくべきこと。

48
Yann

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

拡張回答

新しいmatplotlibリリースでは、新しいrcParams、つまり_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'])
_

plt.style.use(...)またはwith plt.style.context(...):で使用できる事前に用意されたスタイルの場合、_prop_cycle_は従来のと同等であり、非推奨_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']
_

しかし、cyclerオブジェクトにはさらに多くの可能性があります。特に、複雑なcyclerは、_+_と_*_を使用して、さまざまなプロパティを参照し、より単純なオブジェクトから構成できます。それぞれzippingとデカルト積。

ここでは、cyclerヘルパー関数をインポートし、さまざまなプロパティを参照する3つの単純なcyclerを定義し、最後にデカルト積を使用してそれらを構成します。

_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
_

ここに2つの異なる(?)複合体cyclerがあり、はい、この操作は非可換であるため、これらは異なります。

_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
_

変化の速い要素サイクルは製品の最後などです。これは、線のスタイリングに特定の順序が必要な場合に重要です。

cyclersの合成を使用するにはどうすればよいですか? _plt.rc_、またはrcParamsmatplotlibを変更する同等の方法を使用します。例えば。、

_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

もちろん、これは単なる例であり、OPはさまざまなプロパティを組み合わせて、最も満足のいくビジュアル出力を実現できます。

PSこのアプローチでは、凡例ボックスの行サンプルが自動的に処理されることを忘れました enter image description here

8
gboffi

私はYannのコードを多用しましたが、今日は matplotlibで線のスタイルを循環できますか からの回答を読みました。次に、この方法でBWプロットを作成します。

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
Jānis Erdmanis

plot(x,y,'k-.')のようなものは、黒('k')一点鎖線('-.')行。それはあなたが探しているものではありませんか?

1
ev-br