20180128

matplotlib plotの色を、値によって変える。

plotに、値によるグラデーションをつける。

imshow(二次元、画像)で作図したとき、一次元の線にも、値によって色を着けたいと思った。
必ずしも必要ないし、むしろ分かりにくくなる場合の方が多い。しかし、やってみた。

最終目標はコレ。

007.png

今のところ、欠点として、2点間プロットのどちらかの値で着色するので、同じ高さの線が、違う色で着色されている。。。
二つの値の平均をとるべきでしたね。すいません。

2つのやり方を見つけた。

  1. colorcycleの設定を行う。
  2. plot時に、colorを指定する。

両方とも手間は同じくらい。
両方とも、cmapを使う事になる。

clorcycleとは、

線の色を変えるだけなら、プロットの度に自動で切り替わる。

000.png
このサイクルが、colorcycle

import matplotlib.pyplot as plt
import math
import matplotlib

N=128f = 8
omg = [i*f*2*math.pi/N for i in range(N)]
sig = [math.sin(i) for i in omg]

fig,(ax) = plt.subplots(1,1)

for j in range(len(sig)-1):
ax.plot(omg[j:j+2], sig[j:j+2])

plt.show()

このプロットの度に色が変わるサイクルが、colorcycleで設定できる。これを手動で設定するのが「1」のやり方。
colorcycleの次の色は、下記で見れる。

ax._get_lines.get_next_color()

colorcycleを設定するやり方

色は、colorcycleによって変更できる。

RGBA=[1,0,0,1]
ax.set_color_cycle(RGBA)

こんな感じで。

使ってみると、こんな感じになる。

import matplotlib.pyplot as plt
import math
import matplotlib


N=128
f = 8
omg = [i*f*2*math.pi/N for i in range(N)]
sig = [math.sin(i) for i in omg]

fig,(ax) = plt.subplots(1,1)
colormap = plt.get_cmap('jet')

ax.set_color_cycle([colormap(k) for k in sig])

for j in range(len(sig)-1):
ax.plot(omg[j:j+2], sig[j:j+2])

plt.show()

0以下が、同じ色になってしまっているのは、なんか変ですね。

003.png

各cmapは、データ→[R,G,B,A]に変える関数としても使える。

すでに上でも使ったが、カラーマップというのがある。
imshowを使う際は、画像の着色の仕方を指定したりする「何か」と認識していた。
実は、このcmapは、RGBAを返す関数としても使える。
これを使って、「2」のやり方を実現する。

とりあえずRGBAに変える関数としてcmapを使ってみる。

-1から1までの数値を、cmapに入れたら、どうなるのか。

import matplotlib.pyplot as plt

cm = plt.get_cmap("jet")#jetの色を返す関数
print cm([i/100. for i in range(101)])

こうなりました。

[[ 0.00000000e+00 0.00000000e+00 5.00000000e-01 1.00000000e+00]
[ 0.00000000e+00 0.00000000e+00 5.35650624e-01 1.00000000e+00]
(省略)
[ 5.35650624e-01 0.00000000e+00 0.00000000e+00 1.00000000e+00]
[ 5.00000000e-01 0.00000000e+00 0.00000000e+00 1.00000000e+00]]

ちゃんと、RGBAのリストが返ってきた。
これを、plotの関数の、引数colorのなかにいれるだけ。

import matplotlib.pyplot as plt
import math
import matplotlib


N=128f = 8
omg = [i*f*2*math.pi/N for i in range(N)]
sig = [math.sin(i) for i in omg]

fig,(ax) = plt.subplots(1,1)
colormap = plt.get_cmap('jet')
cm = colormap(sig)

for j in range(len(sig)-1):
ax.plot(omg[j:j+2], sig[j:j+2],color=cm[j])

plt.show()

003.png

やっぱり0以下が変ですね。
0以下、1以上が、同じ色になる。

正規化が必要。

0以下が表示されないのは、cmapは0から1までで正規化された値にしか対応していないから。
範囲がmin. -1, max. 1のデータを、min. 0,max 1のデータに書き直す(0~1のデータに正規化する)必要がある。

ここに、使用できる正規化の一覧があるのと、
ここで、具体例がある。

  1. プロットする変数を用意する。
  2. cmapを用意する。
  3. 変数を正規化する。
  4. cmapに3の変数を入れる。

カラーマップのほうを変えるのではなく、入力データの方を変える。
データが変わっちゃうじゃん。なんか気持ち悪い。

import matplotlib.pyplot as plt
import matplotlib as mt

data = [i/10.0 -1 for i in range(21)]
cm = plt.get_cmap("jet")
norm = mt.colors.Normalize(vmin=-1, vmax=1)#正規化 これに入れたデータは、cmapのリミットは-1to1になる。

print data#-1 から 1までのデータ。
print cm(data)#データをカラーマップで
print cm(norm(data))

>>> print data#-1 から 1までのデータ。
[-1.0, -0.9, -0.8, -0.7, -0.6, -0.5, -0.4, -0.30000000000000004, -0.19999999999999996, -0.09999999999999998, 0.0, 0.10000000000000009, 0.19999999999999996, 0.30000000000000004, 0.3999999999999999, 0.5, 0.6000000000000001, 0.7, 0.8, 0.8999999999999999, 1.0]
>>> print cm(data)#データをカラーマップで
[[ 0. 0. 0.5 1. ]
[ 0. 0. 0.5 1. ]
[ 0. 0. 0.5 1. ]
[ 0. 0. 0.5 1. ]
[ 0. 0. 0.5 1. ]
[ 0. 0. 0.5 1. ]
[ 0. 0. 0.5 1. ]
[ 0. 0. 0.5 1. ]
[ 0. 0. 0.5 1. ]
[ 0. 0. 0.5 1. ]
[ 0. 0. 0.5 1. ]
[ 0. 0. 0.9456328 1. ]
[ 0. 0.3 1. 1. ]
[ 0. 0.69215686 1. 1. ]
[ 0.16129032 1. 0.80645161 1. ]
[ 0.49019608 1. 0.47754586 1. ]
[ 0.80645161 1. 0.16129032 1. ]
[ 1. 0.77051561 0. 1. ]
[ 1. 0.40740741 0. 1. ]
[ 0.9456328 0.02977487 0. 1. ]
[ 0.5 0. 0. 1. ]]
>>> print cm(norm(data))
[[ 0. 0. 0.5 1. ]
[ 0. 0. 0.71390374 1. ]
[ 0. 0. 0.9456328 1. ]
[ 0. 0.09607843 1. 1. ]
[ 0. 0.3 1. 1. ]
[ 0. 0.50392157 1. 1. ]
[ 0. 0.69215686 1. 1. ]
[ 0. 0.89607843 0.97090449 1. ]
[ 0.16129032 1. 0.80645161 1. ]
[ 0.3257432 1. 0.64199873 1. ]
[ 0.49019608 1. 0.47754586 1. ]
[ 0.64199873 1. 0.3257432 1. ]
[ 0.80645161 1. 0.16129032 1. ]
[ 0.97090449 0.95933188 0. 1. ]
[ 1. 0.77051561 0. 1. ]
[ 1. 0.58169935 0. 1. ]
[ 1. 0.40740741 0. 1. ]
[ 1. 0.21859114 0. 1. ]
[ 0.9456328 0.02977487 0. 1. ]
[ 0.71390374 0. 0. 1. ]
[ 0.5 0. 0. 1. ]]
>>>

とすれば、normによって、cmap全域のRGBAが得られているのは見える。
normが、-1から+1のdataを、0から+1のデータに変形させた。
normは、0から1までのデータに置き換えるときの、やり方を指定している。

import matplotlib as mt

data = [i/10.0 -1 for i in range(21)]
norm = mt.colors.Normalize(vmin=-1, vmax=1)#正規化 これに入れたデータは、cmapのリミットは-1to1になる。
print dataprint norm(data)

>>> print data
[-1.0, -0.9, -0.8, -0.7, -0.6, -0.5, -0.4, -0.30000000000000004, -0.19999999999999996, -0.09999999999999998, 0.0, 0.10000000000000009, 0.19999999999999996, 0.30000000000000004, 0.3999999999999999, 0.5, 0.6000000000000001, 0.7, 0.8, 0.8999999999999999, 1.0]
>>> print norm(data)
[ 0. 0.05 0.1 0.15 0.2 0.25 0.3 0.35 0.4 0.45 0.5 0.55
0.6 0.65 0.7 0.75 0.8 0.85 0.9 0.95 1. ]
>>>

引数のvmin,vmaxは、imshowの時にも使う。
あれは、normalizeの関連の引数だったんだ…

ややこしい。

  • プロット時は、生データを使いたい。
  • cmapは、0to1のデータしか受け付けない。
  • 入力データの形を正規化してしまうと、カラーバーの表示と、表示したいデータとの整合性が取れなくなる。
  • imshowは自動的にnormalizeしてくれる(ことが多い。)

不都合は…特にないか。?もし、カラーバーを表示しようとなると、ちょっと大変なのかもしれない…
ごちゃごちゃしてよく分からない。

設定できるのは、最大値、最小値だけではない。
値の増え方、色の変わり方の関係を非線形にできる。

ここで線形っていうのは、直線だから、線形。直線じゃないと、非線形。

20180127210724.png

先ほどのnormは線形。線形なら、二点vminとvmaxが決まれば、値の移り変わり-色の移り変わりが決まる。


非線形っていうのは例えばlogとかだろうよ。
対数グラフであれば、こちらも2点が決まれば、形が決まる事が分かる。

20180127230253.png


とりあえず、colorcycleを修正

import matplotlib.pyplot as plt
import mathimport matplotlib

N=128
f = 8
omg = [i*f*2*math.pi/N for i in range(N)]
sig = [math.sin(i) for i in omg]

fig,(ax) = plt.subplots(1,1)
colormap = plt.get_cmap('jet')
norm = matplotlib.colors.Normalize(vmin=min(sig), vmax=max(sig))
ax.set_color_cycle([colormap(norm(k)) for k in sig])

for j in range(len(sig)-1):
ax.plot(omg[j:j+2], sig[j:j+2])

plt.show()

007.png

plotの引数color版も修正。

plotに入れるか、set_color_cycleに入れるかの違いでしかありませんが、

import matplotlib.pyplot as plt
import math
import matplotlib

N=128
f = 8
omg = [i*f*2*math.pi/N for i in range(N)]
sig = [math.sin(i) for i in omg]

fig,(ax) = plt.subplots(1,1)
colormap = plt.get_cmap('jet')
norm = matplotlib.colors.Normalize(vmin=min(sig), vmax=max(sig))
c = colormap(norm(sig))

for j in range(len(sig)-1):
ax.plot(omg[j:j+2], sig[j:j+2], color=c[j+1])

plt.show()

トップに載せたのは、上記コードの画像。


いちいち、normするのが面倒。cmapの引数でvminvmaxが選べればいいのに。

この機能は、次の次の動画くらいで使った。

posted by yuchan at 07:00 | Comment(0) | python
この記事へのコメント
コメントを書く
お名前:

メールアドレス:

ホームページアドレス:

コメント: