'''
測定データとそのフィッティング結果を表示する．
'''
import matplotlib.pyplot as plt
from matplotlib.backends.backend_pdf import PdfPages
import numpy as np
from scipy import interpolate
import scipy.optimize as optimize


# =================================================================
# クラス: データを読み込んでフィッティングパラメーターを決める．
# =================================================================
class Fit_Fuction():
    '''
    データからフィッティング関数を決めるクラス．
    '''
    def __init__(self, data_file, x_column=0, y_column=1):
        '''初期化を実行する．'''
        print('data file: {0:s}'.format(data_file))
        self.data = np.genfromtxt(data_file)
        self.x, self.y = self.data[:,x_column], self.data[:,y_column]
        print(self.x)
        print('\n\n')
        print(self.y)
        # フィッティングの実行．sol[0]がパラメーターリスト
        self.sol = optimize.curve_fit(self.f, self.x, self.y)

    def f(self, x, a, s, x0):
        '''関数の定義: 関数の値を返す．'''
        return a*np.exp(-(x-x0)**2/(2*s**2))

    def fitted_f(self, x):
        '''フィッティング結果関数の値を返す．'''
        return self.f(x, *self.sol[0])

    def get_data(self):
        '''フィッティングの元データを返す．'''
        return self.x, self.y

    def get_fit_results(self):
        '''フィッティングのパラメーターを返す．'''
        return self.sol    # sol[0] がフィッティング結果


# =================================================================
# クラス: データをフィッティング関数をプロット
# =================================================================
class Plot_Data():
    '''
    データとフィッティング関数をプロットするクラス．
    '''
    def __init__(self, fit_class):
        '''プロットのクラスの初期化をおこなう．'''
        self.x, self.y = fit_class.get_data()
        self.xmin, self.xmax = 0, 1.0
        self.ymin, self.ymax = 0, 1.2
        self.fit_x = np.linspace(self.xmin, self.xmax, 512)
        self.fit_y = fit_class.fitted_f(self.fit_x)
        title_fn = '$f(x) = a_0\exp[-x^2/(2\sigma^2)]$\n'
        title_res = '  $a_0={0:g}$\n  $\sigma={1:g}$\n  $x_0={2:g}$'.\
                        format(*fit_class.get_fit_results()[0])
        self.title = title_fn + title_res   # プロット中のタイトル
        self.xl, self.yl = 0.05, 0.8        # タイトルの座標

    def mk_plot(self):
        '''元データとフィッティング結果をプロットする'''
        pp = PdfPages('plot_data.pdf')
        fig = plt.figure()
        ax1 = fig.add_subplot(2,2,1)
        ax1.text(self.xl, self.yl, self.title, color='red', fontsize=10)
        ax1.set_xlabel("x", fontsize=12, fontname='serif')
        ax1.set_ylabel("y", fontsize=12, fontname='serif')
        ax1.tick_params(direction='in', axis='both', length=10, which='major',
                        bottom=True, top=True, left=True, right=True)
        ax1.tick_params(direction='in', axis='both', length=5, which='minor',
                        bottom=True, top=True, left=True, right=True)
        ax1.set_xlim([self.xmin, self.xmax])
        ax1.set_ylim([self.ymin, self.ymax])
        ax1.minorticks_on()
        ax1.plot(self.fit_x, self.fit_y, color='red', linestyle='solid', linewidth=1.0)
        ax1.scatter(self.x, self.y, color='blue', marker='o', s=20)

        plt.tight_layout()
        plt.subplots_adjust(top=0.9)
        plt.draw()
        plt.show()
        fig.savefig(pp, format='pdf', orientation='portrait', \
                    transparent=False, bbox_inches=None, frameon=None)
        fig.clf()
        pp.close()


# =================================================================
# メインルーチン
# =================================================================
if __name__ == '__main__':
    fit_func = Fit_Fuction('sample.dat', x_column=0, y_column=1)
    plot = Plot_Data(fit_func)
    plot.mk_plot()
