matplotlibで軸の値が小数になったりオフセット表現になったりするのを止める方法


このエントリーをはてなブックマークに追加

問題

pythonのmatplotlibで、年ごとの値の変化を表す折れ線グラフを書こうとして以下のコードを書きました。

import numpy as np
import matplotlib.pyplot as plt

x = np.array([2006, 2007, 2008])
y = np.array([35.2, 27.4, 41.2])

plt.plot(x, y)
plt.show()

すると、以下のような期待に反したグラフが表示されてしまいます。 f:id:minus9d:20160421214605p:plain

期待に反しているのは以下の2点です。

  • 横軸の値に小数が出現している
  • 横軸の値からそれぞれオフセット分が引かれている
    • +2.006e3, つまり2006がオフセットとなっています

これを期待通りにするには以下の2種類の方法があるようです。

解決法1 - set_useOffset()とMaxNLocator()を使う方法

Matlabスタイルで書いているとき

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker

# X軸の数字をオフセットを使わずに表現する
plt.gca().get_xaxis().get_major_formatter().set_useOffset(False)

# X軸の数字が必ず整数になるようにする
plt.gca().get_xaxis().set_major_locator(ticker.MaxNLocator(integer=True))

x = np.array([2006, 2007, 2008])
y = np.array([35.2, 27.4, 41.2])

plt.plot(x, y)
plt.show()

オブジェクト指向で書いているとき

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker

x = np.array([2006, 2007, 2008])
y = np.array([35.2, 27.4, 41.2])

fig, ax = plt.subplots()
ax.get_xaxis().get_major_formatter().set_useOffset(False)
ax.get_xaxis().set_major_locator(ticker.MaxNLocator(integer=True))
ax.plot(x, y)

plt.plot()
plt.show()

結果

期待通りのグラフが描画できました。 f:id:minus9d:20160421215819p:plain

解決法2 - xticks()を使う方法

コメント欄で id:kochory さんに教えていただいた方法です。データの量によってはこの方法で済むこともあります。

Matlabスタイルで書いているとき

plt.xticks()という関数を使うと、X軸のラベルに任意の文字列を表示させることができます。例えば

x = np.array([2006, 2007, 2008])
y = np.array([35.2, 27.4, 41.2])

plt.plot(x, y)
plt.xticks(x, ["year1", "year2", "year3"])
plt.show()

とすると f:id:minus9d:20160422201916p:plain のようにX軸のラベルを変更できます。この関数を利用して

plt.plot(x, y)
plt.xticks(x, x)
plt.show()

と書くと f:id:minus9d:20160422202454p:plain と、意図通りの表示になりました。ここではxticks()の第二引数に数字のリストを与えていますが、このリストの各要素が文字列として評価されてラベルとなっているように見えます。

オブジェクト指向で書いているとき

set_xticks()とset_xticklabels()に分けて呼ぶ必要があるそうです。

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker

x = np.array([2006, 2007, 2008])
y = np.array([35.2, 27.4, 41.2])

fig, ax = plt.subplots()
ax.plot(x, y)
ax.set_xticks(x)
ax.set_xticklabels(x)

plt.plot()
plt.show()

結果は同じなので省略します。

解決法2の補足

解決法2の場合、以下のようにデータ数が多いと

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker

x = np.arange(10000,10016,1)
y = np.arange(0,16,1)
plt.plot(x, y)
plt.show()

下図のようにX軸のラベルが混雑して破綻します。 f:id:minus9d:20160423210539p:plain

コメント欄での指摘通り、ラベルを手調整するのが一案です。

x = np.arange(10000,10016,1)
y = np.arange(0,16,1)
plt.plot(x, y)
xlabels = [10000,10005,10010,10015]
plt.xticks(xlabels, xlabels)
plt.show()

とラベルの場所とその値を明示的に指定することで f:id:minus9d:20160423210758p:plain となります。

参考URLs