web-dev-qa-db-ja.com

matplotlibを使用して20を超える独自の凡例色を作成する

Matplotlibを使用して、1つのプロットに20の異なるラインをプロットしています。 forループを使用してプロットし、すべての行にそのキーでラベルを付けてから、凡例関数を使用します

for key in dict.keys():
    plot(x,dict[key], label = key)
graph.legend()

しかし、この方法を使用すると、グラフは凡例で多くの色を繰り返します。 matplotlibと20行以上を使用して各行に一意の色を割り当てる方法はありますか?

ありがとう

44
msohail

あなたの質問に対する答えは、他の2つのSOの質問に関連しています。

matplotlibのFigure内のプロットされた各ラインの新しい色を選択する方法 への答えは、プロットする次の色を選択するために循環するデフォルトの色のリストを定義する方法を説明します。これは_Axes.set_color_cycle_ method で行われます。

正しい色のリストを取得したいのですが、この質問に対する答えで説明されているように、これはカラーマップを使用して最も簡単に実行できます。 matplotlibの指定されたカラーマップからカラージェネレーターを作成 。そこでは、カラーマップは0〜1の値を取り、色を返します。

したがって、20行の場合、1/20のステップで0から1に循環させます。具体的には、1が0にマップされるため、フォーム0から19/20を循環させます。

これはこの例で行われます:

_import matplotlib.pyplot as plt
import numpy as np

NUM_COLORS = 20

cm = plt.get_cmap('Gist_Rainbow')
fig = plt.figure()
ax = fig.add_subplot(111)
ax.set_color_cycle([cm(1.*i/NUM_COLORS) for i in range(NUM_COLORS)])
for i in range(NUM_COLORS):
    ax.plot(np.arange(10)*(i+1))

fig.savefig('moreColors.png')
plt.show()
_

これは結果の図です:

Yosemitebear Mountain Giant Double Rainbow 1-8-10

代替案、より良い(議論の余地のある)解決策

ScalarMappableオブジェクトを使用して値の範囲を色に変換する別の方法があります。この方法の利点は、非線形Normalizationを使用して、ラインインデックスから実際の色に変換できることです。次のコードは、まったく同じ結果を生成します。

_import matplotlib.pyplot as plt
import matplotlib.cm as mplcm
import matplotlib.colors as colors
import numpy as np

NUM_COLORS = 20

cm = plt.get_cmap('Gist_Rainbow')
cNorm  = colors.Normalize(vmin=0, vmax=NUM_COLORS-1)
scalarMap = mplcm.ScalarMappable(norm=cNorm, cmap=cm)
fig = plt.figure()
ax = fig.add_subplot(111)
# old way:
#ax.set_color_cycle([cm(1.*i/NUM_COLORS) for i in range(NUM_COLORS)])
# new way:
ax.set_color_cycle([scalarMap.to_rgba(i) for i in range(NUM_COLORS)])
for i in range(NUM_COLORS):
    ax.plot(np.arange(10)*(i+1))

fig.savefig('moreColors.png')
plt.show()
_

廃止予定ノート
mplib(1.5+)の最近のバージョンでは、ax.set_prop_cycle(color=[...])を支持して_set_color_cycle_関数は廃止されました。

95
Yann

12行のプロットがありましたが、 Yannの手法 を試してみると、同じような色の行を区別するのが難しいことがわかりました。私のラインもペアで表示されるため、各ペアの2つのラインに同じ色を使用し、2つの異なるライン幅を使用しました。線のスタイルを変更して、より多くの組み合わせを取得することもできます。

set_prop_cycle() を使用できますが、plot()を呼び出した後にlineオブジェクトを変更しました。

次に、3つの異なる線幅を使用したYannの例を示します。

import matplotlib.pyplot as plt
import numpy as np

NUM_COLORS = 20

cm = plt.get_cmap('Gist_Rainbow')
fig = plt.figure()
ax = fig.add_subplot(111)
for i in range(NUM_COLORS):
    lines = ax.plot(np.arange(10)*(i+1))
    lines[0].set_color(cm(i//3*3.0/NUM_COLORS))
    lines[0].set_linewidth(i%3 + 1)

fig.savefig('moreColors.png')
plt.show()

Example plot with line widths

異なる線種の同じ例です。もちろん、必要に応じて2つを組み合わせることができます。

import matplotlib.pyplot as plt
import numpy as np

NUM_COLORS = 20
LINE_STYLES = ['solid', 'dashed', 'dashdot', 'dotted']
NUM_STYLES = len(LINE_STYLES)

cm = plt.get_cmap('Gist_Rainbow')
fig = plt.figure()
ax = fig.add_subplot(111)
for i in range(NUM_COLORS):
    lines = ax.plot(np.arange(10)*(i+1))
    lines[0].set_color(cm(i//NUM_STYLES*float(NUM_STYLES)/NUM_COLORS))
    lines[0].set_linestyle(LINE_STYLES[i%NUM_STYLES])

fig.savefig('moreColors.png')
plt.show()

Example plot with line styles

17
Don Kirkby

Don Kirkby's answer を構築するために、 seaborn をインストール/使用する場合は、色を計算できます:

import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np

NUM_COLORS = 20
LINE_STYLES = ['solid', 'dashed', 'dashdot', 'dotted']
NUM_STYLES = len(LINE_STYLES)

sns.reset_orig()  # get default matplotlib styles back
clrs = sns.color_palette('husl', n_colors=NUM_COLORS)  # a list of RGB tuples
fig, ax = plt.subplots(1)
for i in range(NUM_COLORS):
    lines = ax.plot(np.arange(10)*(i+1))
    lines[0].set_color(clrs[i])
    lines[0].set_linestyle(LINE_STYLES[i%NUM_STYLES])

fig.savefig('moreColors.png')
plt.show()

Seabornのさまざまなカラーパレットを使用できるほかに、必要に応じて後で使用/操作できるRGBタプルのリストを取得できます。明らかに、matplotlibのカラーマップを使用して同様の何かを計算できますが、これは便利だと思います。 seaborn husl color map with 20 colors

10