web-dev-qa-db-ja.com

カラーマップを使用した色付きのMatplotlibプロットライン

1つのプロットに複数の線をプロットし、同じ6色または7色だけでなく、カラーマップのスペクトル全体を通過させたい。コードはこれに似ています:

for i in range(20):
     for k in range(100):
          y[k] = i*x[i]
     plt.plot(x,y)
plt.show()

カラーマップ「ジェット」とシーボーンからインポートした別のものの両方で、同じ7色が同じ順序で繰り返されます。最大60までの異なる線を、すべて異なる色でプロットできるようにしたいと思います。

19
Scott

Matplotlibカラーマップは引数(0..1、スカラーまたは配列)を使用して、カラーマップから色を取得します。例えば:

col = pl.cm.jet([0.25,0.75])    

(2つの)RGBA色の配列を提供します。

array([[0.、0.50392157、1.、1.]、[1.、0.58169935、0.、1.]])

これを使用して、N異なる色を作成できます。

import numpy as np
import matplotlib.pylab as pl

x = np.linspace(0, 2*np.pi, 64)
y = np.cos(x) 

pl.figure()
pl.plot(x,y)

n = 20
colors = pl.cm.jet(np.linspace(0,1,n))

for i in range(n):
    pl.plot(x, i*y, color=colors[i])

enter image description here

38
Bart

バートのソリューションは素晴らしくシンプルですが、2つの欠点があります。

  1. plt.colorbar()は、ラインプロットが(たとえば、画像と比較して)マップできないため、適切に機能しません。

  2. Forループが原因で、行数が多い場合は遅くなる可能性があります(これはほとんどのアプリケーションでは問題にならないかもしれませんが?)

これらの問題は LineCollection を使用して解決できます。ただし、これは私の(控えめな)意見ではユーザーフレンドリーではありません。 plt.scatter(...)関数と同様に、マルチカラーラインプロット関数を追加するためのオープンな GitHubに関する提案 があります。

これは私が一緒にハッキングすることができた実用的な例です

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.collections import LineCollection

def multiline(xs, ys, c, ax=None, **kwargs):
    """Plot lines with different colorings

    Parameters
    ----------
    xs : iterable container of x coordinates
    ys : iterable container of y coordinates
    c : iterable container of numbers mapped to colormap
    ax (optional): Axes to plot on.
    kwargs (optional): passed to LineCollection

    Notes:
        len(xs) == len(ys) == len(c) is the number of line segments
        len(xs[i]) == len(ys[i]) is the number of points for each line (indexed by i)

    Returns
    -------
    lc : LineCollection instance.
    """

    # find axes
    ax = plt.gca() if ax is None else ax

    # create LineCollection
    segments = [np.column_stack([x, y]) for x, y in Zip(xs, ys)]
    lc = LineCollection(segments, **kwargs)

    # set coloring of line segments
    #    Note: I get an error if I pass c as a list here... not sure why.
    lc.set_array(np.asarray(c))

    # add lines to axes and rescale 
    #    Note: adding a collection doesn't autoscalee xlim/ylim
    ax.add_collection(lc)
    ax.autoscale()
    return lc

これは非常に簡単な例です:

xs = [[0, 1],
      [0, 1, 2]]
ys = [[0, 0],
      [1, 2, 1]]
c = [0, 1]

lc = multiline(xs, ys, c, cmap='bwr', lw=2)

生成する:

Example 1

そしてもう少し洗練されたもの:

n_lines = 30
x = np.arange(100)

yint = np.arange(0, n_lines*10, 10)
ys = np.array([x + b for b in yint])
xs = np.array([x for i in range(n_lines)]) # could also use np.tile

colors = np.arange(n_lines)

fig, ax = plt.subplots()
lc = multiline(xs, ys, yint, cmap='bwr', lw=2)

axcb = fig.colorbar(lc)
axcb.set_label('Y-intercept')
ax.set_title('Line Collection with mapped colors')

生成する:

enter image description here

お役に立てれば!

16
Alex Williams

plt.plotへの各呼び出しで色を指定しないBartの回答の代替案は、set_prop_cycleで新しいカラーサイクルを定義することです。彼の例は次のコードに変換できます(matplotlibのインポートも推奨スタイルに変更しました)。

import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(0, 2*np.pi, 64)
y = np.cos(x) 

n = 20
ax = plt.axes()
ax.set_prop_cycle('color',[plt.cm.jet(i) for i in np.linspace(0, 1, n)])

for i in range(n):
    plt.plot(x, i*y)
6
Ramon Crehuet

Brg、hsv、jet、またはデフォルトのパレットなどの連続カラーパレットを使用している場合は、次のようにすることができます。

color = plt.cm.hsv(r) # r is 0 to 1 inclusive

これで、この色の値を次のような任意のAPIに渡すことができます。

line = matplotlib.lines.Line2D(xdata, ydata, color=color)
1
Shital Shah