【matplotlib】グラフ軸のスケールを変更する(対数、対称対数)
通常、グラフを描画するとき、軸のスケールは線形スケールだが、たまに線形スケールだと見にくいデータがある。
データのスケールが100倍や1000倍の差がある場合などは大きい方の数字に軸の値が合わせられるため、値の小さい範囲がどうなっているのかが分かりにくくなる。
そういう時は軸のスケールを対数に変換する。また対数は負の値を扱えず、0付近では無限大になるため、負の値を扱えるようにした対照対数というスケールもある。
対数スケールでのグラフ作成
線形スケールでのグラフ
通常の線形スケールでのグラフ作成。
1import matplotlib.pyplot as plt
2import numpy as np
3
4# データ生成
5x = np.linspace(0.1, 15, 100)
6y = x ** 3
7
8fig, ax = plt.subplots(figsize=(8, 4.5), facecolor="w")
9
10# データをプロット
11ax.plot(x, y)
12
13ax.set_title('A linear scale plot')
14ax.set_xlabel('X-axis')
15ax.set_ylabel('Y-axis (Log scale)')
16fig.tight_layout()
17plt.show()
y=x^3のグラフ。x<4ぐらいまでは0付近にいるように見える。
対数スケールでのグラフ作成
yscaleにlogを設定することで、y軸のスケールが対数になる。
1import matplotlib.pyplot as plt
2import numpy as np
3
4# データ生成
5x = np.linspace(0.1, 15, 100)
6y = x ** 3
7
8fig, ax = plt.subplots(figsize=(8, 4.5), facecolor="w")
9# y軸を対数スケールに設定
10ax.set_yscale('log')
11
12# データをプロット
13ax.plot(x, y)
14
15ax.set_title('A log scale plot')
16ax.set_xlabel('X-axis')
17ax.set_ylabel('Y-axis (Log scale)')
18fig.tight_layout()
19plt.show()
軸を対数にすることで、x<2ぐらいの範囲ではyの値が急激に増えていることが分かる。(10^-3ぐらいの値から一気に10^1ぐらいまで増えている、1万倍)
一方、x>10ぐらいの範囲では、値は増えていっているが、桁数が増えるような変化はしていないことが分かる。
この辺りは、グラフから絶対値がどれだけ大きく増えているのか、もしくは値が何倍に増えているのかなど、何を主張したいかによって選択するグラフは変わってくるが、選択肢として、対数スケールもあることを知っておくと便利。
Axesオブジェクトを使わない場合のコード
fig, ax = plt.subplots()
としてAxesオブジェクトを使わずに直接pltからグラフを書く場合、以下のようなコードになる。
1x = np.linspace(0.1, 15, 100)
2y = x ** 3
3
4plt.figure(figsize=(8, 4.5), facecolor="w")
5plt.yscale("log")
6plt.plot(x, y)
7plt.title('A log scale plot')
8plt.xlabel('X-axis')
9plt.ylabel('Y-axis (Log scale)')
10plt.tight_layout()
11plt.show()
グラフを単独で表示できればOKな場合などは、この書き方で十分。
yの値を対数に変換してから線形スケールでグラフ作成
yの値をnp.log()で対数に変換してから、スケールは対数にせずに線形スケールのままグラフを描画しても、スケールを対数スケールに変換した場合と同じ形状になる。
1import matplotlib.pyplot as plt
2import numpy as np
3
4# データ生成
5x = np.linspace(0.1, 15, 100)
6y = x ** 3
7
8fig, ax = plt.subplots(figsize=(8, 4.5), facecolor="w")
9# yを対数に変換
10y_log = np.log(y)
11
12# データをプロット
13ax.plot(x, y_log)
14
15ax.set_title('A log-transformed plot')
16ax.set_xlabel('X-axis')
17ax.set_ylabel('Y-axis (Log scale)')
18fig.tight_layout()
19plt.show()
y軸の2や-2が10の2乗、10の-2乗を表している。
これを理解してグラフを見れるのであれば、この形でも良いかもしれないが、個人的にはスケールの方を対数にした方が分かりやすい気がする。(yの値をわざわざ対数に変換する手間も省ける)
xに負の値を含む場合の対数スケールのグラフ
xに負の値を含むグラフの場合、x <= 0の部分では対数が定義されないため、x < 0の範囲のグラフはプロットされなくなる。
1import matplotlib.pyplot as plt
2import numpy as np
3
4# データ生成
5x = np.linspace(-10, 10, 100)
6y = x ** 3
7
8fig, ax = plt.subplots(figsize=(8, 4.5), facecolor="w")
9
10# スケールを対数に変更
11ax.set_yscale("log")
12
13# データをプロット
14# x<0の部分は値が存在しないためプロットされない。
15ax.plot(x, y)
16
17ax.set_title('A log plot')
18ax.set_xlabel('X-axis')
19ax.set_ylabel('Y-axis')
20fig.tight_layout()
21plt.show()
xに負の値を含む場合の対数のグラフ
スケールではなくyの値を対数に変換してからプロットしようとする場合も、x < 0の範囲では対数が定義されないため、値がなく、プロットされない。
1import matplotlib.pyplot as plt
2import numpy as np
3
4# データ生成
5x = np.linspace(-10, 10, 100)
6y = x ** 3
7
8fig, ax = plt.subplots(figsize=(8, 4.5), facecolor="w")
9
10# yの対数を取る。
11# 対数は負の値を取れないため、x<=0の部分は値がNaNになり、ワーニングが出力される。
12y_log = np.log(y)
13# RuntimeWarning: invalid value encountered in log
14# y_log = np.log(y)
15
16# データをプロット
17# x<0の部分は値が存在しないためプロットされない。
18ax.plot(x, y_log)
19
20ax.set_title('A log plot')
21ax.set_xlabel('X-axis')
22ax.set_ylabel('Y-axis')
23fig.tight_layout()
24plt.show()
yをy_logに変換した際にx < 0の部分はNaNとしてデータがなくなるため、 x<0の部分はx軸自体がなくなる。
対照対数スケールでのグラフ作成
xが負の値も取る場合、対照対数スケールを使う。
これは、0付近では線形スケールでの描画となり、設定した閾値を超える範囲では対数スケールとなる。
xに負数を含む場合の対照対数スケールのグラフ
yscaleにsymlogを設定することで対照対数スケールになる。
1import matplotlib.pyplot as plt
2import numpy as np
3
4# データ生成
5x = np.linspace(-10, 10, 100)
6y = x ** 3
7
8fig, ax = plt.subplots(figsize=(8, 4.5), facecolor="w")
9
10# データをプロット
11ax.plot(x, y)
12
13# 対称対数スケールに設定
14# データの正負を問わず、0近傍では線形スケールになり、線形スケールの閾値よりも大きい範囲は対数スケールとなる。
15# デフォルトでは閾値は1となっており、絶対値が1未満の範囲は線形スケール、絶対値が1以上の範囲は対数スケールで表示する
16ax.set_yscale('symlog')
17
18ax.set_title('A symlog plot')
19ax.set_xlabel('X-axis')
20ax.set_ylabel('Y-axis')
21fig.tight_layout()
22plt.show()
線形スケールの閾値を変更する
yscaleにsymlogを設定する際に、linthreshを設定することで、線形スケールとなる範囲を指定できる。
1import matplotlib.pyplot as plt
2import numpy as np
3
4# データ生成
5x = np.linspace(-10, 10, 100)
6y = x ** 3
7
8fig, ax = plt.subplots(figsize=(8, 4.5), facecolor="w")
9
10# データをプロット
11ax.plot(x, y)
12
13# 対称対数スケールに設定
14# 線形スケールの閾値を絶対値が3未満の範囲に変更。絶対値が3以上の範囲が対数スケールとなる。
15ax.set_yscale('symlog', linthresh=3)
16
17ax.set_title('A symlog plot linthresh3')
18ax.set_xlabel('X-axis')
19ax.set_ylabel('Y-axis')
20fig.tight_layout()
21plt.show()
今回の例の場合、linthresh=1
でもlinthresh=3
でも形状はほとんど変わらないが、y軸の目盛りが少し変化していることが分かる。
まとめ
xが負数を含むかどうかで対数スケールにするか対照対数スケールにするかが変わる。
1# xに負数を含まない場合
2# データ生成
3x = np.linspace(0.1, 15, 100)
4y = x ** 3
5fig, ax = plt.subplots(figsize=(8, 4.5), facecolor="w")
6# y軸を対数スケールに設定
7ax.set_yscale('log')
8# データをプロット
9ax.plot(x, y)
10
11# xに負数を含む場合
12# データ生成
13x = np.linspace(-10, 10, 100)
14y = x ** 3
15fig, ax = plt.subplots(figsize=(8, 4.5), facecolor="w")
16# 対称対数スケールに設定
17ax.set_yscale('symlog', linthresh=3)
18# データをプロット
19ax.plot(x, y)