2017-12-17 6 views
1

カーブを1つの色で開始し、最後まで別の色に段階的にブレンドしたいとします。私のMCVEの次の機能は動作しますが、確かに、私がまだ知りませんでしたが、より良い方法が必要です。matplotlib/pyplotで線の色を混ぜ合わせたプロットカー

import numpy as np 
import matplotlib.pyplot as plt 

def colorlist(color1, color2, num): 
    """Generate list of num colors blending from color1 to color2""" 
    result = [np.array(color1), np.array(color2)] 
    while len(result) < num: 
     temp = [result[0]] 
     for i in range(len(result)-1): 
      temp.append(np.sqrt((result[i]**2+result[i+1]**2)/2)) 
      temp.append(result[i+1]) 
     result = temp 
    indices = np.linspace(0, len(result)-1, num).round().astype(int) 
    return [result[i] for i in indices] 

x = np.linspace(0, 2*np.pi, 100) 
y = np.sin(x) 
colors = colorlist((1, 0, 0), (0, 0, 1), len(x)) 

for i in range(len(x)-1): 
    xi = x[i:i+1+1] 
    yi = y[i:i+1+1] 
    ci = colors[i] 
    plt.plot(xi, yi, color=ci, linestyle='solid', linewidth='10') 

plt.show() 

1

答えて

2

ない "より良い方法は、" 何を参照するか確認してください。より高速に描画できるコードの少ないソリューションは、LineCollectionとカラーマップの併用です。

カラーマップは2色で定義でき、その間の色は自動的に補間されます。

cmap = matplotlib.colors.LinearSegmentedColormap.from_list("", [(1, 0, 0), (0, 0, 1)]) 

LineCollectionを使用すると、多数の行を同時にプロットすることができます。 ScalarMappableであるため、カラーマップを使用して、各行をある配列に従って色分けすることができます。この場合、その目的のためにx値を使用することができます。

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

x = np.linspace(0, 2*np.pi, 100) 
y = np.sin(x) 

cmap = LinearSegmentedColormap.from_list("", [(1, 0, 0), (0, 0, 1)]) 

points = np.array([x, y]).T.reshape(-1,1,2) 
segments = np.concatenate([points[:-1],points[1:]], axis=1) 

lc = LineCollection(segments, cmap=cmap, linewidth=10) 
lc.set_array(x) 
plt.gca().add_collection(lc) 
plt.gca().autoscale() 
plt.show() 

enter image description here

画像で見ることができるように、この解決策の欠点は、個々の線がうまく接続されていないことです。

そこでこれを回避するために、一つの色を直線二つの与えられた色の間で補間される上記において

segments = np.concatenate([points[:-2],points[1:-1], points[2:]], axis=1) 

enter image description here


を使用して、重複これらの点をプロットしてもよいです。したがって、プロットは、いくつかのカスタム補間を使用して質問からのものと異なって見えます。

enter image description here

問題になっていると同じ色を得るために、あなたはLineCollectionのためのカラーマップで使用する色を作成するために、同じ機能を使用することができます。この機能を単純化することを目的としている場合は、チャネルの色差の平方根として値を直接計算することができます。

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

x = np.linspace(0, 2*np.pi, 100) 
y = np.sin(x) 

def colorlist2(c1, c2, num): 
    l = np.linspace(0,1,num) 
    a = np.abs(np.array(c1)-np.array(c2)) 
    m = np.min([c1,c2], axis=0) 
    s = np.sign(np.array(c2)-np.array(c1)).astype(int) 
    s[s==0] =1 
    r = np.sqrt(np.c_[(l*a[0]+m[0])[::s[0]],(l*a[1]+m[1])[::s[1]],(l*a[2]+m[2])[::s[2]]]) 
    return r 

cmap = LinearSegmentedColormap.from_list("", colorlist2((1, 0, 0), (0, 0, 1),100)) 

points = np.array([x, y]).T.reshape(-1,1,2) 
segments = np.concatenate([points[:-2],points[1:-1], points[2:]], axis=1) 

lc = LineCollection(segments, cmap=cmap, linewidth=10) 
lc.set_array(x) 
plt.gca().add_collection(lc) 
plt.gca().autoscale() 
plt.show() 

enter image description here

関連する問題