なまもの備忘録

気になったことをつらつらと書いていきます

scipyによる3次スプライン補完

未知の関数に出会った時3次スプライン補完をしたいと思うのは人類の普遍的欲求です。 普遍的欲求はだいたいpythonのライブラリが満たしてくれるもので、今回のケースではscipyがその役割を担ってくれます。

scipyの3次スプライン補完についてはいくつか日本語解説ページがあるのですが、

qiita.com

ここで使われているkind='cubic'interp1d関数だと、スプライン補完の係数取得に少々非自明な処理をする必要が出てきます。 人間が3次スプライン補完をするときって、欲しいものは大抵関数そのものではなく係数なので、これは困りますね。

さて、scipyではinterp1d以外にもCubicSpline関数で3次スプライン補完を実行することができ、こちらを使えばこの問題は解決します。 使い方は以下

import numpy
from scipy import interpolate
import matplotlib.pyplot as plt

if __name__ == '__main__':

    x_coordinates = []
    y_coordinates = []
    for line in open('test.txt', 'r'):
        point = [float(coord.split()[0]) for coord in line.split(',')]
        x_coordinates.append(point[0])
        y_coordinates.append(point[1])
        
    spline_func = interpolate.CubicSpline(x_coordinates, y_coordinates)
    print(spline_func.c) # ここで係数を取得しています
    
    x_res = numpy.linspace(1, 5, 200)
    y_res = spline_func(x_res)
   
    plt.plot(x_coordinates, y_coordinates, 'o', x_res, y_res)
    plt.show()

CubicSplineの返り値であるPPolyオブジェクトのcを呼び出すことで、係数にアクセスしています。

テストデータとしては下記を使用しました。

1.5, 1.65
1.677, 5.64
2.3, 5.53
3.0, 4.354
3.8, 3.555

出力グラフ

f:id:purple-apple:20180226130144p:plain

標準出力(コメント部分は後から追記)

[[ 25.17215028  25.17215028  -3.16687764  -3.16687764] # 3次の係数
 [-52.99186318 -39.62545138   7.42129748   0.77085443] # 2次の係数
 [ 31.13331437  14.74004969  -5.32313819   0.41136815]    # 1次の係数 
 [  1.65         5.64         5.53         4.354     ]]    # 定数項

バージョン情報

$ python -V
Python 3.5.2
>>> import scipy as sp
>>> sp.version.full_version
'0.18.1'

参考

https://docs.scipy.org/doc/scipy/reference/generated/scipy.interpolate.CubicSpline.html

https://docs.scipy.org/doc/scipy/reference/generated/scipy.interpolate.PPoly.html#scipy.interpolate.PPoly

matplotlibでのオブジェクト指向的な描画

matplotlibには主にpyplotの関数を用いてオブジェクトを明示的に操作せず簡単に描画する方法と、オブジェクトを明示的に操作する方法がある。以下後者の方法について。

matplotlibではグラフは一度FigureCanvasに描画され、それがバックエンドのmatplotlib.backend_bases.FigureCanvasBaseを継承した出力フォーマット依存のクラスによって出力されるという仕組みをとっている(はず、要出典)。
FigureCanvasに描画されるFigureは部品ごとに管理されており、すべての部品はmatplotlib.artist.Artistという抽象基底クラスを継承している。Figure自身もArtistの派生クラス。部品というのは例えば、軸(Axisというクラスで管理される)や目盛り、グリッド線(Tickというクラスに管理される)などのことを指す。また、これらはこちらもまたArtistの派生クラスであるmatplotlin.axes.Axesによってまとめられ、管理されている。

オブジェクト指向でのプロットは以下のようになる(例として2つの行列から2つのカラーマップを描く場合を取り上げる)。

import matplotlib.pyplot as pet
import matplotlib.cm as cm

#データを用意する
arr1 = [[1,0,0],[0,1,0],[0,0,1]]
arr2 = [[0,0,1],[0,1,0],[1,0,0]]
data = [arr1,arr2]

#Figure全体を管理するオブジェクトfigを生成する
fig = plt.figure()

#Figureの構成要素である2つの図それぞれを管理するAxesオブジェクトax1とax2を生成する
ax1 = fig.add_subplot(1,2,1)#1行2列のグラフの1つめを描く
ax2 = fig.add_subplot(1,2,2)#1行2列のグラフの2つめを描く

ax1.imshow(data[0], cmap = cm.Greys, interpolation = 'nearest')#オブジェクトにカラーマップの情報をもたせるAxesのimshowメソッドを呼び出す
ax1.set_axis_off()#軸を表示しない設定にするset_axis_off()メソッドを呼び出す
ax2.imshow(data[1], cmap = cm.Greys_r, interpolation = 'nearest')
ax2.set_axis_off()

#描画する
plt.show()

f:id:purple-apple:20170206221130p:plain

上記コードのうちcm.binaryは色を指定している。指定できる色は(http://matplotlib.org/examples/color/colormaps_reference.html)にある。”Greys_r”の”_r”は、グラデーションを反転させている。ここにない色も指定できたりする(例えば”binary”)。また、interpolationの’nearest’は描画をタイル状にしており、無指定だとグラフはグラデーションになる。
図の詳細な設定をいじる場合は図を管理しているAxesオブジェクトのメソッドを使う、というような事になる。Axes.get_xaxisなどのメソッドを使ってX軸の情報のみを管理するXAxisオブジェクトを生成し、更に細かく設定を行うことも(多分)できる。このようなAxesクラスのメソッドは(http://matplotlib.org/api/axes_api.html#axis-limits)に書いてある。

matplotlib version2.0.0をインストールした作業記録[Ubuntu 16.04]

Ubuntu 16.04に何も考えずaptでmatplotlibを入れたらversionが1.5.1だった。バージョンの確認は

$ python
>>> import matplotlib
>>> matplotlib.__version__

でできる。
最新版は2.0.0なのでこちらに更新したい。また、今まではpythonで使っていたが折角なのでpython3で使いたい。以下作業ログ。

$ apt search python3-matplotlib

の結果aptで入れられるのは1.5.1までらしい。apt-get updateしても変わらなかった。
少し調べてみるとどうもpythonのパッケージ管理システムpipで入れることができるらしい。そういうわけで、まずはpipを入れる(aptとpipが後々衝突したりしないかとても不安だけれど取り敢えず気にせず入れてみる)。

$ apt search python3-matplotlib

の結果python3-pipがヒットしたのでインストールする。

$ sudo apt-get install python3-pip

pipが入ったので以下でmatplotlibを探そうとしたらpipがまだ入っていないと怒られた。

$ pip search matplotlib

pipという名前では入っていないようなので名前を特定する。/usr/bin内を探したところ、pipというファイルはなかったが代わりにpip3というファイルがあった。おそらくこれだと思われるのでpip3で呼べば良い。
さてmatplotlibのインストールといきたいところだが、念の為以前入れていたmatplotlibを削除しておく必要がある。

$ sudo apt-get purge python-matplotlib

で以前のmatplotlibを削除した。purgeだと設定ファイルごと削除してくれるらしい。
pip3でmatplotlibを検索する。

$ pip3 search matplotlib

matplotlib (2.0.0)がヒットしてくれたのでこれをインストールする。

$ pip3 install matplotlib  

ちゃんとpython3のmatplotlib(2.0.0)が入っているかどうか確認する。

$ python3
>>> import matplotlib as mpl
>>> mpl.__version__

と打ったら

'2.0.0'

と帰ってきたので無事完了したか?と思ったのだけど、その後

$ python3 (実行ファイル名).py

pythonスクリプトを実行しようとしたら

ImportError: No module named '_tkinter', please install the python3-tk package

と怒られてしまった。python3-tkパッケージがないということなのでpip3でsearchをかけたがそれらしきものがない。

$ apt search python3-tk

としたらヒットしたのでaptで入れることにする。

$ sudo apt-get install python3-tk

こうしたら実行ファイルもちゃんと動くようになった。めでたしめでたし。