#!/usr/bin/python
# -*- coding: utf-8 -*-
"""
FastPlotQt.py
ヒストグラムまたはスペクトルのプロット on Qt

History
181107 : Fix the issue that PeakLabel does not work with matplotlib 2.1.1 on Ubuntu 18.04
171225 : Update codes from wx version
         - add methods to choose Auto Scale mode on Y-axis
171110 : Update codes from wx version
         - fix problem for comarison between numpy.ndarray and None
         - fix that scales are not updated on adding data
170919 : Update Fitting function
         - merge latest FastPlot.py from github:master
         - add FitOnFastPlotQt class
         - add GUI to show errors and chi-sq of fitting results
         - improve error handling on fitting
170616 : merge latest FastPlot.py
   - merged rev 954-> 977 on subversion
   - merged latest FastPlot on git branch 0.3.5.1
[inamura 160408] - Bugfix of ticklabel's format on log scale
[inamura 160324] - Improve ticklabel's format : v < 0.0001 -> v = 1e-5
[inamura 160322] - Improve showing values in setting dialog
                 - Add new CUI for logx
[inamura 160126] - TextFile update to get Header info in other text format
[inamura 160122] - Enable to display Peak Label with vertical
                 - Improve numerical text format (%.2f -> %g)
[inamura 140307] - Enable log scale of X axis
[inamura 140220] - Deal with bug that auto scale does not work in matplotlib 1.2.0
[inamura 120513] - Enable change font size and font name
[inamura 120512] - Add marker face status "fill" or "none"
                 - fix that MASKVALUE is plotted.
[inamura 120511] - Enable double click on plotter to show dialog in main menu
[inamura 120131] - Add codes to keep paths in open/save dialog as default
[inamura 120128] - correct button label, keep previous path in Open/Save dialog
                 - update TextFile, can read text from ElementContainer
                 - correct a process to cahnge trace label
[inamura 110625] can use MatPlotLib ver0.92
[inamura 110620] can treat unit independent from title
[inamura 110303] Add calculation of d-value
[inamura 110223] save and load default attribute value
(2010.Oct.07)     added Auto Apply function by Y.I.
(2010.Jul.15)     added by Y.I.
(2010.Feb to Mar) added by KCS
"""
from __future__ import print_function
import six
import os
import sys
import codecs
import time
import tempfile
import matplotlib
# 先に指定されていなかったら、バックエンドを指定
from matplotlib.transforms import offset_copy
from matplotlib.ticker import MultipleLocator, FormatStrFormatter
#from pylab import setp, getp
from matplotlib.figure import Figure
from matplotlib import __version__ as mpl_version

import numpy as np
try:
    import numpy.ma as Ma
except ModuleNotFoundError:
    import numpy.core.ma as Ma
# For Fitting
from scipy import optimize as sp_optimize

from uGao import QtCom
from uGao.uGaoUtil import IFEvtProp, ChartToolBar, ImagesXpm, VerHandlePlotLib, TraceAtt, DefaultFastPlotAtt, PlotException, PlotMessage, MessageFile, TempFile
from uGao.uGaoUtil import MASKVALUE, NAVIGATIONTOOLBAR_CHANGED_VER, STRING_TO_REPLACE_SPACE, MATPLOTLIB_VER
if six.PY2:
    import cPickle as pickle
else:
    import pickle
PYSIDEVER = 1
try:
    from PySide6 import QtCore, QtGui, QtWidgets
    from PySide6.QtGui import QAction
    PYSIDEVER = 6
except ModuleNotFoundError:
    try:
        from PySide2 import QtCore, QtGui, QtWidgets
        from PySide2.QtWidgets import QAction
        PYSIDEVER = 2
    except ModuleNotFoundError:
        from PySide import QtCore, QtGui
        import PySide.QtGui as QtWidgets
        from PySide.QtGui import QAction

if QtCore.__version__ < '5.0.0':
    if not matplotlib.get_backend() == 'Qt4Agg':
        matplotlib.use('Qt4Agg')
        matplotlib.rcParams['backend.qt4'] = 'PySide'
    from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigCanvas
else:
    # For Jupyter mode (inline backend)
    if matplotlib.get_backend() == "inline":
        pass
    # For PySide2 or PySide6
    elif matplotlib.get_backend() == 'Qt5Agg':
        from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigCanvas
    else:
        # On environment with matplotlib '3.7.1' and PySide6 '6.5.2'
        # Import Error occurs on setting use('Qt5Agg') when X server (DISPLAY) is disabled.
        try:
            matplotlib.use('Qt5Agg')
            from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigCanvas
        except ImportError:
            # Change the backend to Agg at the error (without X-server-mode)
            matplotlib.use('Agg')

if QtCore.__version__ < '5.0.0':
    from uGao.ui_FastPlotQt import Ui_FastPlot, Ui_DgSetting, Ui_DgPlotPtn, Ui_FloatBox, Ui_DgScaleLabel, Ui_DgTitle, Ui_DgSaveAsText, Ui_DgFitting, Ui_DgGridSetting, Ui_DgTickStyleSetting, Ui_DgCalcDS
else:
    if PYSIDEVER == 2:
        from uGao.ui2_FastPlotQt import Ui_FastPlot, Ui_DgSetting, Ui_DgPlotPtn, Ui_FloatBox, Ui_DgScaleLabel, Ui_DgTitle, Ui_DgSaveAsText, Ui_DgFitting, Ui_DgGridSetting, Ui_DgTickStyleSetting, Ui_DgCalcDS
    elif PYSIDEVER == 6:
        from uGao.ui6_FastPlotQt import Ui_FastPlot, Ui_DgSetting, Ui_DgPlotPtn, Ui_FloatBox, Ui_DgScaleLabel, Ui_DgTitle, Ui_DgSaveAsText, Ui_DgFitting, Ui_DgGridSetting, Ui_DgTickStyleSetting, Ui_DgCalcDS

# On environment with matplotlib '3.7.1' and PySide6 '6.5.2'
# the import error does not occur on setting use('Qt5Agg').
# But 'from pylab import setp, getp' causes the ImportError when X server (DISPLAY) is disabled.
try:
    from pylab import setp, getp
except:
    # change the backend to Agg
    matplotlib.use('Agg')
    from pylab import setp, getp
# [inamura 160723]-->
#########################################
#       SetSaveAsTextDialog
#########################################


class SetSaveAsTextDialog(QtWidgets.QDialog):
    """
    SaveAsText 設定ダイアログクラス
    """
    ##########################################################
    # def __init__(self, parent, order, postfix, dataobj=None):

    def __init__(self, parent, isHist):
        """
        コンストラクタ
        @param  parent   親ウィンドウのID
        @param  order  プロッタの起動順序
        @param  postfix 画面タイトルに付ける親の識別子
        @param  dataobj
        @retval 無し
        """

        self.ifi = IFEvtProp(parent.order)
        self.parent = parent
        self.dataobj = parent.dataobj
        self.isHist = isHist

        # リソース取得
        super(SetSaveAsTextDialog, self).__init__(parent)
        self.dialog = Ui_DgSaveAsText()
        if self.dialog is None:
            return
        self.dialog.setupUi(self)

        # アイコンを設定
        # self.dialog.SetIcon(Images().GetMainIcon())

        # チェックボックス
        self.ckIgnoreMask = self.findChild(
            QtWidgets.QCheckBox, u'ckIgnoreMask')

        # チェックボックスのイベントハンドラ登録
        self.ckIgnoreMask.stateChanged.connect(self.OnIgnoreMask)

        # コンボボックス
        self.chMaskVal = self.findChild(QtWidgets.QComboBox, u'chMaskValue')

        # コンボボックスのイベントハンドラ登録
        self.chMaskVal.activated.connect(self.OnMaskVal)

        # テキストボックスのコントローラ取得
        self.txMaskVal = self.findChild(QtWidgets.QLineEdit, u'txMaskValue')

        # ボタンのイベントハンドラを登録
        self.btnSave = self.findChild(QtWidgets.QPushButton, u"btSave")
        self.btnCancel = self.findChild(QtWidgets.QPushButton, u"btCancel")
        self.btnSave.clicked.connect(self.OnSave)
        self.btnCancel.clicked.connect(self.OnCancel)

        # Set Values
        self.initialize()

        # ダイアログ表示
        self.show()

    ##########################################################
    def initialize(self):
        """
        """
        self.isIgnoreMask = True
        self.useGivenMaskVal = True
        self.ckIgnoreMask.setCheckState(QtCore.Qt.Checked)  # True
        self.chMaskVal.setEnabled(False)
        self.txMaskVal.setEnabled(False)

        return

    ##########################################################
    def OnIgnoreMask(self, event=None):
        """
        IgnoreMask チェックボックスイベント処理
        @param   event イベント情報
        @retval 無し
        """
        # チェックされたのか
        if self.ckIgnoreMask.checkState() == QtCore.Qt.Checked:
            self.isIgnoreMask = True
        else:
            self.isIgnoreMask = False

        if self.isIgnoreMask:
            # MaskValue テキストボックスを選択不可
            self.chMaskVal.setEnabled(False)
            self.txMaskVal.setEnabled(False)
        else:
            self.chMaskVal.setEnabled(True)
            self.txMaskVal.setEnabled(False)
            index = self.chMaskVal.currentIndex()
            if index == 0:
                self.txMaskVal.setEnabled(True)

    ##########################################################
    def OnMaskVal(self, event=None):
        """

        """
        self._CtrlParts(True)

    ##########################################################
    def OnSave(self, event=None):
        """
        """
        self._CtrlParts(False)
        maskval = 0.0
        if (not self.isIgnoreMask) and self.useGivenMaskVal:
            try:
                maskval = float(self.txMaskVal.text())
            except:
                msg = u"Given Mask Value is invalid (%s)" % (
                    self.txMaskVal.text())
                but = QtWidgets.QMessageBox().warning(
                    self, u"Warning", msg, QtWidgets.QMessageBox.Ok)
                self._CtrlParts(True)
                return

        maskInfo = None
        if self.isIgnoreMask:
            maskInfo = (True, 0)
        else:
            if self.useGivenMaskVal:
                maskInfo = (False, maskval)
            else:
                maskInfo = (False, MASKVALUE)

        tdir = self.parent.DefaultDialogPath["SAVE"]
        filepath, filt = QtWidgets.QFileDialog().getSaveFileName(
            self, u"Save data as text files", tdir, filter="Text Files (*.txt)")
        if filepath != "":
            TextFile(self.parent.order, self.isHist).WriteTo(
                filepath, self.dataobj, maskInfo)
            self.parent.DefaultDialogPath["SAVE"] = filepath[:filepath.rfind(
                "/")]
            self.OnCancel()

        self._CtrlParts(True)

    ##########################################################
    def _CtrlParts(self, isEnable=True):
        """
        """
        if not (isEnable in [True, False]):
            return

        if isEnable:
            self.btnSave.setEnabled(True)
            self.btnCancel.setEnabled(True)
            self.ckIgnoreMask.setEnabled(True)
            if self.isIgnoreMask:
                self.chMaskVal.setEnabled(False)
                self.txMaskVal.setEnabled(False)
            else:
                self.chMaskVal.setEnabled(True)
                self.txMaskVal.setEnabled(False)
                index = self.chMaskVal.currentIndex()
                self.useGivenMaskVal = True
                if index == 0:
                    self.txMaskVal.setEnabled(True)
                    pass
                elif index == 1:
                    self.txMaskVal.setText(str(0.0))
                elif index == 2:
                    self.txMaskVal.setText(str(-1.0))
                else:
                    self.useGivenMaskVal = False
                    self.txMaskVal.setText("")
        else:
            self.ckIgnoreMask.setEnabled(False)
            self.chMaskVal.setEnabled(False)
            self.txMaskVal.setEnabled(False)
            self.btnSave.setEnabled(False)
            self.btnCancel.setEnabled(False)

    ##########################################################

    def OnCancel(self, evt=None):
        """
        Cancel ボタンイベント処理
        @param  evt イベント情報
        @retval 無し
        """
        self.close()

#######################################
#  Fitting
#######################################


class FitOnFastPlotQt(object):
    class Parameter(object):
        def __init__(self, value):
            self.value = value
            self.init_value = value
            self.value_err = 0.0

        def set(self, value):
            self.value = value

        def __call__(self):
            return self.value

    def fit(self, function, parameters, y, x=None):
        def f(params):
            i = 0
            for p in parameters:
                p.set(params[i])
                i += 1

            return (y - function(x))

        if x is None:
            x = np.arange(y.shape[0])
        p = [param() for param in parameters]
        result = sp_optimize.leastsq(f, p, full_output=1)

        p = [param() for param in parameters]
        chisq = np.sum(f(p)**2)
        # err = sqrt( sp_diag(result[1]) )
        s_sq = chisq / float(len(y) - len(parameters))
        if isinstance(result[1], np.ndarray):
            err_sq = np.diag(result[1] * s_sq)
        else:
            err_sq = []
            for i in range(len(parameters)):
                err_sq.append(-1.0)

        return (chisq, err_sq)


class FittingDialog(QtWidgets.QDialog):
    """
    データ一覧表示ボックスクラス
    """
    ##########################################################

    def __init__(self, parent, postfix, traceNo):
        """
        Fitting
        @param  parent   親(PlotFrame)のインスタンス
        @param  postfix  画面タイトルに付ける親の識別子
        @param traceNo  trace
        @retval 無し
        """
        self.parent = parent
        # インターフェイスクラスのインスタンスを取得
        self.ifi = IFEvtProp(parent.order)
        # リソース取得
        super(FittingDialog, self).__init__(parent)
        self.dialog = Ui_DgFitting()
        if self.dialog is None:
            return
        self.dialog.setupUi(self)

        # アイコンを設定
        # self.frame.SetIcon(Images().GetMainIcon())
        # タイトル文字列を取得
        strT = self.windowTitle()
        # 順番を付してタイトル文字列を作成
        self.setWindowTitle(strT + postfix)

        # リソースからコントロールを取得
        # Choice
        self.cbTrace = self.findChild(QtWidgets.QComboBox, u'cbTrace')
        self.cbFunc = self.findChild(QtWidgets.QComboBox, u'cbFunctions')

        # choiceのイベントハンドラ登録
        self.cbTrace.activated.connect(self.OnChoiceTrace)
        self.cbFunc.activated.connect(self.OnChoiceFunc)

        self.RangeCtrl = []
        self.RangeCtrl.append(self.findChild(
            QtWidgets.QLineEdit, u'txRangeMin'))
        self.RangeCtrl.append(self.findChild(
            QtWidgets.QLineEdit, u'txRangeMax'))

        self.ArgsCtrl = []
        for i in range(8):
            ind = i + 1
            init_val = self.findChild(QtWidgets.QLineEdit, u'txA{:d}'.format(ind))
            fix_ck = self.findChild(QtWidgets.QCheckBox, u'ckA{:d}'.format(ind))
            ret_val = self.findChild(QtWidgets.QLabel, u'txA{:d}r'.format(ind))
            err_val = self.findChild(QtWidgets.QLabel, u'txA{:d}e'.format(ind))
            init_val.setText("0.0")
            ret_val.setText("0.0")
            err_val.setText("+- 0.0")
            self.ArgsCtrl.append((init_val, fix_ck, ret_val, err_val))

        self.txChisq = self.findChild(QtWidgets.QLabel, u'txChisq')
        self.txChisq.setText("0.0")
        self.btCheck = self.findChild(QtWidgets.QPushButton, u"btCheck")
        self.btFitting = self.findChild(QtWidgets.QPushButton, u"btFitting")
        self.btClose = self.findChild(QtWidgets.QPushButton, u"btClose")
        self.btLoadFunc = self.findChild(QtWidgets.QPushButton, u'btLoadFunc')

        # データがあれば
        if len(self.parent.dataobj.lstData) > 0:
            pass
        else:
            msg = u"There is no data."
            dial = QtWidgets.QMessageBox().critical(self, u"Error", msg)
            self.OnClose()

        # ボタンのイベントハンドラ登録
        self.btCheck.clicked.connect(self.OnCheck)
        self.btFitting.clicked.connect(self.OnFitting)
        self.btClose.clicked.connect(self.OnClose)
        self.btLoadFunc.clicked.connect(self.OnLoadFunc)

        # get labels of trace data
        self.UpdateTraceList(traceNo)

        # set function fig
        # self.cbFunc.setCurrentIndex(1)
        # self.SetFuncFig(1)

        # get trace data
        if len(self.parent.dataobj.lstData) > 0:
            self.data = self.parent.dataobj.lstData[traceNo]
            self.RangeCtrl[0].setText("%g" % (self.data[0][0]))
            self.RangeCtrl[1].setText("%g" % (self.data[0][-1]))
        else:
            self.data = None

        self.show()

        # to avoid parts in frame are shrinked
        # if sys.platform =="darwin":
        #    self.frame.SetSize( (310,600) )
        # if sys.platform =="win32":
        #    self.frame.SetSize( (320,620) )

        # Fitting Function Setting
        # stores tuple of ( <imported module>, <import path> )
        self.FitFuncModules = []
        self.FitFuncList = []       # stores function
        # [0]:title, [1]:function obj, [2]:num of param, [3]:png name, [4]:index of file

        # Load Base Fitting Functions
        try:
            fastPlotQt_path = os.path.abspath(__file__)
            func_path = os.path.dirname(fastPlotQt_path)
            # img_path = os.path.join( img_path,'img')
            sys.path.insert(0, func_path)
            self.FitFuncModules.append(
                (__import__("MPlotFittingBaseFuncs"), func_path))
        except:
            raise UserWarning("Failed to import MPlotFittingBaseFuncs.")

        # Load Fitting Functions for the instrument
        if "UTSUSEMI_BASE_DIR" in os.environ and "UTSUSEMI_SYS_NAME" in os.environ:
            facade_path = os.path.join(
                os.environ['UTSUSEMI_BASE_DIR'], os.environ['UTSUSEMI_SYS_NAME'], 'facade')
            if os.path.exists(os.path.join(facade_path, "MPlotFittingFuncs.py")):
                try:
                    self.FitFuncModules.append(
                        (__import__("MPlotFittingFuncs"), facade_path))
                except:
                    raise UserWarning("%s is invalid." % (
                        os.path.join(facade_path, "MPlotFittingFuncs.py")))
        # Load Fitting Functions for the instrument on Utsusemi4
        if "UTSUSEMI_BASE_DIR" in os.environ and "UTSUSEMI_INST_CODE" in os.environ:
            facade_path = os.path.join(
                os.environ['UTSUSEMI_BASE_DIR'], os.environ['UTSUSEMI_INST_CODE'], 'facade')
            fitfuncname = "MPlotFittingFuncs_{}".format(
                os.environ['UTSUSEMI_INST_CODE'])
            if os.path.exists(os.path.join(facade_path, fitfuncname + ".py")):
                try:
                    self.FitFuncModules.append(
                        (__import__(fitfuncname), facade_path))
                except:
                    raise UserWarning("%s is invalid." % (
                        os.path.join(facade_path, fitfuncname + ".py")))
            facade_path = os.path.join(
                os.environ['UTSUSEMI_USR_DIR'], 'facade')
            fitfuncname = "MPlotFittingFuncs_*"
            import glob
            fitfuncfiles = glob.glob(os.path.join(facade_path, fitfuncname))
            if len(fitfuncfiles) > 0:
                for a_file in fitfuncfiles:
                    mfile = os.path.basename(a_file)
                    mname = mfile[:-3]
                    try:
                        self.FitFuncModules.append(
                            (__import__(mname), facade_path))
                    except:
                        raise UserWarning("%s is invalid." %
                                          (os.path.join(facade_path, a_file)))

        # Make FitFucList
        for i, funcs in enumerate(self.FitFuncModules):
            for item in funcs[0].params:
                if (not isinstance(item, list)) or len(item) != 4:
                    raise UserWarning(
                        "%s params is invalid format" % (funcs[0].__name__))

                in_item = item[:]
                # [0]:title, [1]:function obj, [2]:num of param, [3]:png name, [4]:index of file
                in_item.append(i)
                self.FitFuncList.append(in_item)

        # Reconstruct Choice list
        self.cbFunc.clear()
        for item in (self.FitFuncList):
            self.cbFunc.addItem(item[0])
        # set function fig
        self.cbFunc.setCurrentIndex(0)
        self.SetFuncFig(0)
        self.SetArgsEnable(0)

    ##########################################################

    def OnClose(self, evt=None):
        """
        Close ボタンイベント処理
        @param  evt イベント情報
        @retval 無し
        """
        # [inamura 170712]-->
        for a_module, a_path in self.FitFuncModules:
            del a_module
            if a_path != "":
                sys.path.remove(a_path)
        # <--[inamura 170712]
        self.close()

    ##########################################################
    def SetArgsEnable(self, funcNo=0):
        """
        Change Enable setting for Arguments text controls
        @param  funcNo (int) fit_function number
        @retval None
        """
        for i in range(8):
            if i < (self.FitFuncList[funcNo][2]):
                self.ArgsCtrl[i][0].setEnabled(True)
                self.ArgsCtrl[i][1].setEnabled(True)
                self.ArgsCtrl[i][2].setEnabled(True)
            else:
                self.ArgsCtrl[i][0].setEnabled(False)
                self.ArgsCtrl[i][1].setEnabled(False)
                self.ArgsCtrl[i][2].setEnabled(False)

    ##########################################################
    def SetFuncFig(self, funcNo=0):
        """
        Set Fitting Function figure
        @param  evt イベント情報
        @retval 無し
        """
        fig_png = self.FitFuncList[funcNo][3]

        func_file_info = self.FitFuncModules[self.FitFuncList[funcNo][4]]
        splash_path = os.path.join(func_file_info[1], fig_png)
        splash_panel = self.findChild(QtWidgets.QFrame, u"pnlFunction")

        if os.path.exists(splash_path):
            splash_panel.setPixmap(QtGui.QPixmap(splash_path))
            splash_panel.setEnabled(True)
        else:
            splash_panel.setEnabled(False)

    ##########################################################
    def UpdateTraceList(self, traceNo=0):
        """
        """
        self.ldata = self.ifi.GetProperty('tracelabels')
        if self.cbTrace.count() != 0:
            for i in range(self.cbTrace.count()):
                self.cbTrace.removeItem(0)

        for a_trace in self.ldata:
            self.cbTrace.addItem(a_trace)

        if traceNo < self.cbTrace.count():
            self.cbTrace.setCurrentIndex(traceNo)

    ##########################################################
    def OnChoiceTrace(self, evt=None):
        """
        Combo Box
        @param  evt イベント情報
        @retval 無し
        """
        trace_no = self.cbTrace.currentIndex()
        self.UpdateTraceList(trace_no)
        # print "trace_no=",trace_no
        self.data = self.parent.dataobj.lstData[trace_no]
        self.RangeCtrl[0].setText("%g" % (self.data[0][0]))
        self.RangeCtrl[1].setText("%g" % (self.data[0][-1]))

    ##########################################################
    def OnChoiceFunc(self, evt=None):
        """
        Combo Box
        @param  evt イベント情報
        @retval 無し
        """
        func_id = self.cbFunc.currentIndex()
        # print "func_id=",func_id
        self.SetArgsEnable(func_id)  # [inamura 170712]

        self.SetFuncFig(funcNo=func_id)

    ##########################################################
    def OnLoadFunc(self, evt=None):
        """
        Load new fitting functions from given file
         [inamura 160726] added
        @param evt
        @retval None
        """
        # ファイルを開くダイアログを表示
        tdir = os.getcwd()
        filepath, filt = QtWidgets.QFileDialog.getOpenFileName(
            self, "Open Fitting Function file", tdir, filter='Python Script (*.py)')
        # dlg =wx.FileDialog(self.frame, "Open Fitting Function file", tdir, style=wx.OPEN, wildcard='python(*.py)|*.py')
        # OK であればファイルを開く
        if filepath != "":
            module_name = os.path.basename(filepath)
            module_name = module_name.split(".")[0]
            dir_name = os.path.dirname(filepath)

            sys.path.insert(0, dir_name)
            try:
                self.FitFuncModules.append((__import__(module_name), dir_name))
            except:
                raise UserWaring("FittingFunc params is invalid.")

            f_index = len(self.FitFuncModules) - 1
            for item in self.FitFuncModules[-1][0].params:
                in_item = item[:]
                in_item.append(f_index)
                self.FitFuncList.append(in_item)
                self.cbFunc.addItem(in_item[0])

    ##########################################################
    def OnCheck(self, evt=None):
        """
        Check initial parameters for fitting
        @param  evt イベント情報
        @retval 無し
        """
        xmin = float(self.RangeCtrl[0].text())
        xmax = float(self.RangeCtrl[1].text())
        if xmin >= xmax:
            msg = u"Fitting Range are invalid."
            dial = QtWidgets.QMessageBox().critical(self, u"Error", msg)
            return

        (xx, yy, ee, header, xunit, yunit, dam) = self.data

        if isinstance(xx, list):
            xmin_xx = min(xx)
            xmax_xx = max(xx)
        else:
            xmin_xx = xx.min()
            xmax_xx = xx.max()

        if xmin < xmin_xx:
            xmin = xmin_xx
        if xmax > xmax_xx:
            xmax = xmax_xx

        xxx = []
        yyy = []

        for i in range(len(xx)):
            if xx[i] > xmax:
                break
            if xx[i] >= xmin:
                if yy[i] < MASKVALUE:
                    xxx.append(xx[i])
                    yyy.append(yy[i])

        xxx = np.array(xxx)
        yyy = np.array(yyy)

        xx_fit = []
        if len(xxx) < 50:
            tmp_x = xmin
            tmp_dx = (xmax - xmin) / 50.0
            while(tmp_x < xmax):
                xx_fit.append(tmp_x)
                tmp_x += tmp_dx
        else:
            xx_fit = xxx.copy().tolist()

        func_id = self.cbFunc.currentIndex()

        # import ana.Reduction.UtilsOnChoppers as UOC
        # fit = UOC.FitOnChoppers()
        fit = FitOnFastPlotQt()
        A1 = fit.Parameter(float(self.ArgsCtrl[0][0].text()))
        A2 = fit.Parameter(float(self.ArgsCtrl[1][0].text()))
        A3 = fit.Parameter(float(self.ArgsCtrl[2][0].text()))
        A4 = fit.Parameter(float(self.ArgsCtrl[3][0].text()))
        A5 = fit.Parameter(float(self.ArgsCtrl[4][0].text()))
        A6 = fit.Parameter(float(self.ArgsCtrl[5][0].text()))
        A7 = fit.Parameter(float(self.ArgsCtrl[6][0].text()))
        A8 = fit.Parameter(float(self.ArgsCtrl[7][0].text()))

        f_index = self.FitFuncList[func_id][4]
        this_module = self.FitFuncModules[f_index][0]
        this_module.A1 = A1
        this_module.A1 = A1
        this_module.A2 = A2
        this_module.A3 = A3
        this_module.A4 = A4
        this_module.A5 = A5
        this_module.A6 = A6
        this_module.A7 = A7
        this_module.A8 = A8

        ret = 0
        yy_fit = []
        ee_fit = []

        fit_func = self.FitFuncList[func_id][1]
        for i in range(len(xx_fit)):
            yy_fit.append(fit_func(xx_fit[i]))
            ee_fit.append(0.0)

        header_fit = header.copy()
        header_fit["Label"] = "CheckInitialParams"
        fit_data = (xx_fit, yy_fit, ee_fit, header_fit, xunit, yunit, None)
        self.ifi.NotifyEvent(self, "add", [fit_data])
        # Change Line Style "-", No Maker, no Error bar
        dno = self.ifi.GetProperty('datanum')
        self.ifi.NotifyEvent(
            self, "plotparam", (dno, {"ls": "-", "mk": "", "eb": 0}))

    ##########################################################
    def OnFitting(self, evt=None):
        """
        Combo Box
        @param  evt イベント情報
        @retval 無し
        """

        xmin = float(self.RangeCtrl[0].text())
        xmax = float(self.RangeCtrl[1].text())
        if xmin >= xmax:
            msg = u"Fitting Range are invalid."
            dial = QtWidgets.QMessageBox().critical(self, u"Error", msg)
            return

        (xx, yy, ee, header, xunit, yunit, dam) = self.data

        if isinstance(xx, list):
            xmin_xx = min(xx)
            xmax_xx = max(xx)
        else:
            xmin_xx = xx.min()
            xmax_xx = xx.max()

        if xmin < xmin_xx:
            xmin = xmin_xx
        if xmax > xmax_xx:
            xmax = xmax_xx

        xxx = []
        yyy = []

        for i in range(len(xx)):
            if xx[i] > xmax:
                break
            if xx[i] >= xmin:
                if yy[i] < MASKVALUE:
                    xxx.append(xx[i])
                    yyy.append(yy[i])

        xxx = np.array(xxx)
        yyy = np.array(yyy)

        xx_fit = []
        if len(xxx) < 50:
            tmp_x = xmin
            tmp_dx = (xmax - xmin) / 50.0
            while(tmp_x < xmax):
                xx_fit.append(tmp_x)
                tmp_x += tmp_dx
        else:
            xx_fit = xxx.copy().tolist()

        func_id = self.cbFunc.currentIndex()

        # import ana.Reduction.UtilsOnChoppers as UOC
        # fit = UOC.FitOnChoppers()
        fit = FitOnFastPlotQt()
        A1 = fit.Parameter(float(self.ArgsCtrl[0][0].text()))
        A2 = fit.Parameter(float(self.ArgsCtrl[1][0].text()))
        A3 = fit.Parameter(float(self.ArgsCtrl[2][0].text()))
        A4 = fit.Parameter(float(self.ArgsCtrl[3][0].text()))
        A5 = fit.Parameter(float(self.ArgsCtrl[4][0].text()))
        A6 = fit.Parameter(float(self.ArgsCtrl[5][0].text()))
        A7 = fit.Parameter(float(self.ArgsCtrl[6][0].text()))
        A8 = fit.Parameter(float(self.ArgsCtrl[7][0].text()))

        Fixed_list = []
        for a_ctrl in self.ArgsCtrl:
            if a_ctrl[1].checkState() == QtCore.Qt.Checked:
                Fixed_list.append(False)  # Check Box info
            else:
                Fixed_list.append(True)  # Check Box info

        ret = 0
        yy_fit = []
        ee_fit = []

        fit_func = self.FitFuncList[func_id][1]
        f_index = self.FitFuncList[func_id][4]
        this_module = self.FitFuncModules[f_index][0]

        this_module.A1 = A1
        this_module.A2 = A2
        this_module.A3 = A3
        this_module.A4 = A4
        this_module.A5 = A5
        this_module.A6 = A6
        this_module.A7 = A7
        this_module.A8 = A8

        params = []
        param_num = self.FitFuncList[func_id][2]
        if Fixed_list[0] and param_num > 0:
            params.append(A1)
        if Fixed_list[1] and param_num > 1:
            params.append(A2)
        if Fixed_list[2] and param_num > 2:
            params.append(A3)
        if Fixed_list[3] and param_num > 3:
            params.append(A4)
        if Fixed_list[4] and param_num > 4:
            params.append(A5)
        if Fixed_list[5] and param_num > 5:
            params.append(A6)
        if Fixed_list[6] and param_num > 6:
            params.append(A7)
        if Fixed_list[7] and param_num > 7:
            params.append(A8)

        chisq, err_list = fit.fit(fit_func, params, yyy, xxx)
        for i in range(len(xx_fit)):
            yy_fit.append(fit_func(xx_fit[i]))
            ee_fit.append(0.0)

        header_fit = header.copy()
        header_fit["Label"] = "FittingResult"
        fit_data = (xx_fit, yy_fit, ee_fit, header_fit, xunit, yunit, None)
        self.ifi.NotifyEvent(self, "add", [fit_data])
        # Change Line Style "-", No Maker, no Error bar
        dno = self.ifi.GetProperty('datanum')
        self.ifi.NotifyEvent(
            self, "plotparam", (dno, {"ls": "-", "mk": "", "eb": 0}))

        self.ArgsCtrl[0][2].setText("%g" % (A1()))
        self.ArgsCtrl[1][2].setText("%g" % (A2()))
        self.ArgsCtrl[2][2].setText("%g" % (A3()))
        self.ArgsCtrl[3][2].setText("%g" % (A4()))
        self.ArgsCtrl[4][2].setText("%g" % (A5()))
        self.ArgsCtrl[5][2].setText("%g" % (A6()))
        self.ArgsCtrl[6][2].setText("%g" % (A7()))
        self.ArgsCtrl[7][2].setText("%g" % (A8()))

        ind_err = 0
        for i in range(len(Fixed_list)):
            if ind_err == len(err_list):
                break
            if Fixed_list[i]:
                if err_list[ind_err] >= 0.0:
                    self.ArgsCtrl[i][3].setText(
                        "+- %g" % (np.sqrt(err_list[ind_err])))
                else:
                    self.ArgsCtrl[i][3].setText("+- ERROR")
                ind_err = ind_err + 1
            else:
                self.ArgsCtrl[i][3].setText("+- ")

        self.txChisq.setText("%g" % (chisq))

        # Show results on terminal
        print(" ")
        print("------- MPlot Fitting results ---------")
        for i in range(param_num):
            if Fixed_list[i]:
                print("{} {}".format(
                    self.ArgsCtrl[i][2].text(), self.ArgsCtrl[i][3].text()))
            else:
                print("{} Fixed".format(self.ArgsCtrl[i][2].text()))
        """
        if func_id==0 or func_id==2:
            self.ArgsCtrl[4][2].setText("%g"%(A5()))
        else: ## id=1,3,4
            self.ArgsCtrl[4][2].setText("%g\n(%g)"%(A5(),2.0*math.sqrt(2.0*math.log(2))*A5() ))
        self.ArgsCtrl[5][2].setText("%g"%(A6()))
        self.ArgsCtrl[6][2].setText("%g"%(A7()))
        if func_id!=4:
            self.ArgsCtrl[7][2].setText("%g"%(A8()))
        else:
            self.ArgsCtrl[7][2].setText("%g\n(%g)"%(A8(),2.0*math.sqrt(2.0*math.log(2))*A8() ))
        """
        # <--[inamura 160726]
# <--[inamura 160723]
# [inamura 160726-2]-->
#########################################
#       SetAxisTickStyleDialog
#########################################


class SetAxisTickStyleDialog(QtWidgets.QDialog):
    """
    AxisTickStyle 設定ダイアログクラス
    """
    ##########################################################

    def __init__(self, parent, order, postfix):
        """
        コンストラクタ
        @param  parent   親ウィンドウのID
        @param  order  プロッタの起動順序
        @param  postfix 画面タイトルに付ける親の識別子
        @retval 無し
        """

        self.ifi = IFEvtProp(order)
        self.parent = parent

        # リソース取得
        super(SetAxisTickStyleDialog, self).__init__(parent)
        self.dialog = Ui_DgTickStyleSetting()
        if self.dialog is None:
            return
        self.dialog.setupUi(self)

        # アイコンを設定
        # self.dialog.SetIcon(Images().GetMainIcon())

        # ボタンのイベントハンドラを登録
        self.btApply = self.findChild(QtWidgets.QPushButton, u'btApply')
        self.btApply.clicked.connect(self.OnApply)
        self.btRevert = self.findChild(QtWidgets.QPushButton, u'btRevert')
        self.btRevert.clicked.connect(self.OnRevert)
        self.btClose = self.findChild(QtWidgets.QPushButton, u'btClose')
        self.btClose.clicked.connect(self.OnClose)

        # リソースよりコントロールを取得
        # テキストボックスのコントローラ取得
        self.txMajorLength = self.findChild(
            QtWidgets.QLineEdit, u'txMajorLength')
        self.txMajorWidth = self.findChild(
            QtWidgets.QLineEdit, u'txMajorWidth')
        self.txMinorLength = self.findChild(
            QtWidgets.QLineEdit, u'txMinorLength')
        self.txMinorWidth = self.findChild(
            QtWidgets.QLineEdit, u'txMinorWidth')

        # チェックボックス
        self.ckUseMinorTick = self.findChild(
            QtWidgets.QCheckBox, u'ckUseMinorTick')
        self.ckRightSideOn = self.findChild(
            QtWidgets.QCheckBox, u'ckRightSideOn')
        self.ckTopSideOn = self.findChild(QtWidgets.QCheckBox, u'ckTopSideOn')

        # チェックボックスのイベントハンドラ登録
        self.ckUseMinorTick.stateChanged.connect(self.OnUseMinorTick)
        self.ckRightSideOn.stateChanged.connect(self.OnRightSide)
        self.ckTopSideOn.stateChanged.connect(self.OnTopSide)

        # [X]ボタン押下時のイベントハンドラ登録
        # self.dialog.Bind(wx.EVT_CLOSE, self.OnClose)

        # ダイアログオープンイベント発行
        self.ifi.NotifyEvent(self, "setaxistickstyle2ddg", False)

        # Set Values
        self.initialize()

        pdict = self.ifi.GetProperty("tickstyledic")
        self.orgDict = pdict.copy()

        # to avoid parts in frame are shrinked
        if sys.platform == "darwin":
            self.resize(QtCore.QSize(310, 280))
        if sys.platform == "win32":
            self.resize(QtCore.QSize(320, 290))

        # ダイアログ表示
        self.show()

    ##########################################################
    def initialize(self, evt=None):
        """
        """
        pdict = self.ifi.GetProperty("tickstyledic")
        self.txMajorLength.setText(str(pdict["MajorLength"]))
        self.txMajorWidth.setText(str(pdict["MajorWidth"]))
        self.txMinorLength.setText(str(pdict["MinorLength"]))
        self.txMinorWidth.setText(str(pdict["MinorWidth"]))
        flag = pdict["Minor"]
        if flag:
            self.ckUseMinorTick.setCheckState(QtCore.Qt.Checked)
        else:
            self.ckUseMinorTick.setCheckState(QtCore.Qt.Unchecked)
        self.txMinorLength.setEnabled(flag)
        self.txMinorWidth.setEnabled(flag)
        if pdict["TopSide"]:
            self.ckTopSideOn.setCheckState(QtCore.Qt.Checked)
        else:
            self.ckTopSideOn.setCheckState(QtCore.Qt.Unchecked)
        if pdict["RightSide"]:
            self.ckRightSideOn.setCheckState(QtCore.Qt.Checked)
        else:
            self.ckRightSideOn.setCheckState(QtCore.Qt.Unchecked)

    ##########################################################
    def OnUseMinorTick(self, evt=None):
        """
        UseMinorTick Check Boxイベント処理
        @param  evt イベント情報
        @retval 無し
        """
        pdict = self.ifi.GetProperty("tickstyledic")
        if self.ckUseMinorTick.checkState() == QtCore.Qt.Checked:
            pdict["Minor"] = True
            self.txMinorLength.setEnabled(True)
            self.txMinorWidth.setEnabled(True)
        else:
            pdict["Minor"] = False
            self.txMinorLength.setEnabled(False)
            self.txMinorWidth.setEnabled(False)
        self.ifi.NotifyEvent(self, 'replot', None)

    ##########################################################
    def OnTopSide(self, evt=None):
        """
        TopSideOn Check Boxイベント処理
        @param  evt イベント情報
        @retval 無し
        """
        pdict = self.ifi.GetProperty("tickstyledic")
        if self.ckTopSideOn.checkState() == QtCore.Qt.Checked:
            pdict["TopSide"] = True
        else:
            pdict["TopSide"] = False
        self.ifi.NotifyEvent(self, 'replot', None)

    ##########################################################
    def OnRightSide(self, evt=None):
        """
        RightSideOn Check Boxイベント処理
        @param  evt イベント情報
        @retval 無し
        """
        pdict = self.ifi.GetProperty("tickstyledic")
        if self.ckRightSideOn.checkState() == QtCore.Qt.Checked:
            pdict["RightSide"] = True
        else:
            pdict["RightSide"] = False
        self.ifi.NotifyEvent(self, 'replot', None)

    ##########################################################
    def OnApply(self, evt=None):
        """
        Applyボタンイベント処理
        @param  evt イベント情報
        @retval 無し
        """
        pdict = self.ifi.GetProperty("tickstyledic")
        pdict["MajorLength"] = float(self.txMajorLength.text())
        pdict["MajorWidth"] = float(self.txMajorWidth.text())
        pdict["MinorLength"] = float(self.txMinorLength.text())
        pdict["MinorWidth"] = float(self.txMinorWidth.text())
        self.ifi.NotifyEvent(self, 'replot', None)

    ##########################################################
    def OnRevert(self, evt=None):
        """
        Revertボタンイベント処理
        @param  evt イベント情報
        @retval 無し
        """
        pdict = self.ifi.GetProperty("tickstyledic")
        for a_key in pdict:
            pdict[a_key] = self.orgDict[a_key]
        self.initialize()

        self.ifi.NotifyEvent(self, 'replot', None)

    ##########################################################
    def OnClose(self, evt=None):
        """
        Closeボタンイベント処理
        @param  evt イベント情報
        @retval 無し
        """
        # self.dialog.Destroy()
        self.close()
    ##########################################################

    def closeEvent(self, evt):
        """
        Catch close event ( by click close-box or self.close() )

        """
        self.ifi.NotifyEvent(self, "setaxistickstyle2ddg", True)
        evt.accept()

# <--[inamura 160726-2]
#######################################
#  ChartToolBar2
#######################################


class ChartToolBar2(ChartToolBar):
    """
    プロッタ用ツールバーの拡張クラス
    ピークラベル表示処理用のアイコン追加
    """

    def __init__(self, parent, order):
        """
        コンストラクタ
        @param order  イベントディスパッチャのID
        @param parent  親クラスのインスタンス
        @param order   イベントディスパッチャのID
        @retval 無
        """
        # self.parent = parent
        # イベント管理クラスのインスタンスを取得
        self.ifi = IFEvtProp(order)
        # 先にスーパークラスのコンストラクタを実行させる
        ChartToolBar.__init__(self, parent, order)
        self.init_toolbar()

    ##################################
#    def _init_toolbar(self):
    def init_toolbar(self):
        """
        ツールバーを作成
        @param 無し
        @retval 無し
        """
        # 先にスーパークラスのツールバーを作る
        # ChartToolBar._init_toolbar(self)

        # アイコンのサイズ指定
        self.setIconSize(QtCore.QSize(24, 24))
        # セパレータを入れる
        self.addSeparator()
        # アイコンをツールバーに追加
        self._PEN = QAction(QtGui.QIcon(ImagesXpm().GetQPixmap(
            "Pen")), "Peak Labeling Mode", self, checkable=True)
        self._LEFT = QAction(QtGui.QIcon(ImagesXpm().GetQPixmap(
            "Left")), "Shift Label Position to Left", self)
        self._RIGHT = QAction(QtGui.QIcon(ImagesXpm().GetQPixmap(
            "Right")), "Shift Label Position to Right", self)
        self._PIN = QAction(QtGui.QIcon(
            ImagesXpm().GetQPixmap("Pin")), "'Pinup a Label", self)
        self._LABEL = QAction(QtGui.QIcon(
            ImagesXpm().GetQPixmap("Xlabel")), "Change Label Type", self)
        self._DSPC = QAction(QtGui.QIcon(
            ImagesXpm().GetQPixmap("CalcD")), "CalcDspacing", self)
        self._GRIDON = QAction(QtGui.QIcon(ImagesXpm().GetQPixmap(
            "XYGrid")), "XY Grid", self, checkable=True)

        # 各アイコン押下時のイベントハンドラ作成
        self._PEN.triggered.connect(self.OnPen)
        self._LEFT.triggered.connect(self.OnLeft)
        self._RIGHT.triggered.connect(self.OnRight)
        self._PIN.triggered.connect(self.OnPin)
        self._LABEL.triggered.connect(self.OnLabel)
        self._DSPC.triggered.connect(self.OnCalcDS)
        self._GRIDON.triggered.connect(self.OnAxisGrid)

        self.addAction(self._GRIDON)
        self.addAction(self._PEN)
        self.addAction(self._LEFT)
        self.addAction(self._RIGHT)
        self.addAction(self._PIN)
        self.addAction(self._DSPC)
        self.addAction(self._LABEL)

        # ペンモードをオフ
        self.SetPenBtn(False)
        # ラベルタイプの初期値設定(X値表示モード)
        self.labeltype = 1
        # ログモードのリスナー登録
        self.ifi.AddListner('log', self.OnNotifyLog)
        # 公開プロパティを登録
        self.ifi.AddProperty('penmode', lambda: self.penMode)
        self.ifi.AddProperty('labeltype', lambda: self.labeltype)

    ##################################
    def OnPen(self, *args):
        """
        ピークラベルモード変更
        @param  *args    イベント情報
        @retval 無し
        """
        # ピークラベルモードの設定または解除
        self.SetPenBtn(self._PEN.isChecked())

    ##################################
    def OnLeft(self, *args):
        """
        レフトボタン押下イベント
        @param  *args イベント情報
        @retval 無し
        """
        # レフトボタン押下イベント通知
        self.ifi.NotifyEvent(self, "shift", "left")

    ##################################
    def OnRight(self, *args):
        """
        ライトボタン押下イベント
        @param  *args イベント情報
        @retval 無し
        """
        # ライトボタン押下イベント通知
        self.ifi.NotifyEvent(self, "shift", "right")

    ##################################
    def OnPin(self, *args):
        """
        ピンボタン押下イベント
        @param  *args イベント情報
        @retval 無し
        """
        # ピンボタン押下イベント通知
        self.ifi.NotifyEvent(self, "pinup")

    ##################################
    def OnLabel(self, *args):
        """
        ラベルタイプ変更ボタン押下イベント
        @param  *args イベント情報
        @retval 無し
        """
        # 前のラベルタイプアイコンを消す
        # ラベルタイプを変更し、該当するアイコンを追加する
        if self.labeltype == 1:
            self.labeltype = 2
            self._LABEL.setIcon(ImagesXpm().GetQPixmap("Ylabel"))
        elif self.labeltype == 2:
            self.labeltype = 3
            self._LABEL.setIcon(ImagesXpm().GetQPixmap("XYlabel"))
        elif self.labeltype == 3:
            self.labeltype = 4
            self._LABEL.setIcon(ImagesXpm().GetQPixmap("Xlabel"))
        elif self.labeltype == 4:
            self.labeltype = 5
            self._LABEL.setIcon(ImagesXpm().GetQPixmap("Ylabel"))
        elif self.labeltype == 5:
            self.labeltype = 6
            self._LABEL.setIcon(ImagesXpm().GetQPixmap("XYlabel"))
        elif self.labeltype == 6:
            self.labeltype = 1
            self._LABEL.setIcon(ImagesXpm().GetQPixmap("Ylabel"))
        # ツールバー再表示
        # ラベルタイプ変更イベント通知
        self.ifi.NotifyEvent(self, "labeltype", self.labeltype)

    ##################################
    def SetPenBtn(self, flag):
        """
        PEN ボタンオン/オフ処理
        @param  flag  True: On  False: Off
        @retval 無し
        """
        self.penMode = flag
        # ペンボタンの On/Off 変更
        self._PEN.setChecked(flag)
        # 各ボタンの選択可/不可状態変更
        self._LEFT.setEnabled(flag)
        self._RIGHT.setEnabled(flag)
        self._PIN.setEnabled(flag)
        self._LABEL.setEnabled(flag)
        self._DSPC.setEnabled(flag)
        # ペンモード変更イベント通知
        self.ifi.NotifyEvent(self, "penmode", flag)

    ###################################################
    def OnNotifyLog(self, wid, evtType, logflag):
        """
        Log モード変更イベント処理
        Log モード時、ペンモード不可
        @param  wid イベント発生元のインスタンス
        @param  evtType イベントタイプ
        @param  logflag 　Log モードフラグ
        @retval 無し
        """
        # ログモードか
        if logflag:
            # ペンモードであれば
            if self.penMode:
                # ペンモードをOff にする
                self.SetPenBtn(False)
            # ペンモードボタンを選択不可とする
            # self.EnableTool(self._PEN, False)
            self._PEN.setEnabled(False)
        else:
            # ペンモードボタンを選択可とする
            # self.EnableTool(self._PEN, True)
            self._PEN.setEnabled(True)

    def OnCalcDS(self, evt=None):
        """
        """
        self.ifi.NotifyEvent(self, "calcdspace")

    ##################################
    def OnAxisGrid(self, evt=None):
        """
        AxisGridモード変更
        @param  *args    イベント情報
        @retval 無し
        """
        # AxisGridモードの設定または解除
        ret = self._GRIDON.isChecked()
        ddic = self.ifi.GetProperty('gridstyledic')
        ddic["Show"] = ret
        # update D2Chart
        self.ifi.NotifyEvent(self, "replot")

#########################################
#       CalcDspclDialog
#########################################


class CalcDspcDialog(QtWidgets.QDialog):
    """
    Dialog class for calculation of D-spacing
    """
    ##########################################################

    def __init__(self, parent, order, postfix, tof, plangle, azangle, L2, L1=0.0):
        """
        Constructor
        @param  parent    the frame ID of parent
        @param  order     the order for plotting
        @param  postfix   the signature of this data
        @param  tof       Time of flight [micro sec]
        @param  plangle   Polar angle [deg]
        @param  azangle   Azimuthal angle [deg]
        @param  L2        L2 [m]
        @param  L1        L1 [m]
        @retval None
        """
        super(CalcDspcDialog, self).__init__(parent)

        # Set initial value
        self.ifi = IFEvtProp(order)
        self.tof = tof
        self.L2 = L2
        self.plangle = plangle
        self.azangle = azangle
        self.L1 = L1

        # Get resource
        self.dg = Ui_DgCalcDS()
        if self.dg is None:
            return
        self.dg.setupUi(self)

        # Make new title
        strT = self.windowTitle()
        self.setWindowTitle(strT + postfix)

        # Get control of objects
        self.txtResults = self.findChild(QtWidgets.QLabel, u'txtResults')
        self.txtResults.setText("Now Calculating")
        self.txtIndex = self.findChild(QtWidgets.QLabel, u'txtIndex')
        self.l1txt = self.findChild(QtWidgets.QLineEdit, u'L1txt')
        if L1 != 0.0:
            self.l1txt.setText(str(L1))
            self.OnApply(None)

        # Get event handler of buttons
        self.btApply = self.findChild(QtWidgets.QPushButton, u"btApply")
        self.btClose = self.findChild(QtWidgets.QPushButton, u"btClose")
        self.btApply.clicked.connect(self.OnApply)
        self.btClose.clicked.connect(self.OnClose)
        # Get event handler of 'close box'

        # Show this dialog
        self.show()

    ##########################################################
    def OnApply(self, evt=None):
        """
        Function driven by Apply button event
        @param  evt   information of event
        @retval None
        """

        # Get L1 value from text box
        L1 = float(self.l1txt.text())

        # Calculation
        velocity = (L1 + self.L2) / self.tof * 1e6
        WaveLength = 3956.0 / velocity
        Ei = 5.227e-6 * (velocity**2)
        Dspacing = WaveLength / 2.0 / np.sin(self.plangle / 180.0 * np.pi / 2.0)

        # Make format to show in this dialog
        res = "L2\n"
        res += "2theata\n"
        res += "Azim angle\n"
        res += "ToF\n"
        res += "Lambda\n"
        res += "Energy\n"
        res += "D-spacing"
        self.txtIndex.clear()
        self.txtIndex.setText(res)

        res = "= %10.4f (m)\n" % self.L2
        res += "= %10.4f (deg)\n" % (self.plangle)
        res += "= %10.4f (deg)\n" % (self.azangle)
        res += "= %10.1f (usec)\n" % (self.tof)
        res += "= %10.4f (Ang)\n" % (WaveLength)
        res += "= %10.4f (meV)\n" % (Ei)
        res += "= %10.4f (Ang)" % (Dspacing)

        self.txtResults.clear()
        self.txtResults.setText(res)

        # Update this dialog
        self.show()

    ##########################################################
    def OnClose(self, evt=None):
        """
        Function driven by Close event (just destroy)
        @param  evt  event info
        @retval None
        """
        self.close()

# <--[inamura 110303]
# [inamura 100715]-->
#######################################
#  MoniCursol
#######################################


class MoniCursor(object):
    """
    Class for control of cursor over plot
    """
    #######################################

    def __init__(self, parent, order):
        """
        Constructor
        @param parent instanse of pearent window
        @param order  plotter Id
        @retval None
        """
        self.parent = parent

        # get instans of class for event management
        self.ifi = IFEvtProp(order)

        self.axl = None        # plotter for cursor
        self.xval = 0          # cursor position
        self.IsActive = False  # On/Off

    ###################################################

    def NewPlot(self, fig, canvas):
        """
        Create New Cursor
        @param  fig      figure
        @param  canvas   canvas
        @retval None
        """
        self.fig = fig
        self.canvas = canvas
        if self.IsActive:
            self.CreateCursor()

    ###################################################
    def ClearCursor(self):
        """
        Delete cursor
        @param None
        @retval None
        """
        if self.axl is not None:
            if not isinstance(self.axl, list):
                self.axl.clear()
                setp(self.axl.get_xticklabels(), visible=False)
                setp(self.axl.get_yticklabels(), visible=False)
            else:
                for i in range(len(self.axl)):
                    self.axl[i].clear()
                    setp(self.axl[i].get_xticklabels(), visible=False)
                    setp(self.axl[i].get_yticklabels(), visible=False)

            self.canvas.draw()

    ###################################################
    def CreateCursor(self, xval=0):
        """
        Create cursor
        @param  xval the position of cursor on x-axis
        @retval None
        """
        if xval != 0:
            self.xval = xval

        # Overlay?
        if self.ifi.GetProperty('overlay'):

            # create plotter for cursor
            self.axl = self.fig.add_subplot(111, frameon=False)

            # draw cursor line
            self.axl.axvline(x=self.xval, color='k',
                             linewidth=2, linestyle=':')

            # set position of cursor plotter, same as base plot
            pos = VerHandlePlotLib().GetSubPlotPos(self.parent.ax)
            self.axl.set_position(pos)

            # set cursor plotter area same as base plot
            #self.axl.set_xlim(self.parent.ax.get_xlim())
            #self.axl.set_ylim(self.parent.ax.get_ylim())

            # set axes invisible
            setp(self.axl.get_xticklabels(), visible=False)
            setp(self.axl.get_yticklabels(), visible=False)

        # separeted plot
        else:
            self.axl = []
            # get the number of graphs on one plotter window
            tno = self.ifi.GetProperty('tracenum')

            # get graphs subplot information
            axgs = self.fig.get_axes()

            for i in range(len(axgs)):

                # create cursor plotter for each graphs subplot.
                ax = self.fig.add_subplot(tno, 1, (i + 1), frameon=False)

                # draw cursor line
                ax.axvline(x=self.xval, color='k', linewidth=2, linestyle=':')

                # set cursor plotter area same as base plot
                ax.sharex(axgs[i])
                ax.sharey(axgs[i])
                #ax.set_xlim(axgs[i].get_xlim())
                #ax.set_ylim(axgs[i].get_ylim())

                # set axes invisible
                setp(ax.get_xticklabels(), visible=False)
                setp(ax.get_yticklabels(), visible=False)

                self.axl.append(ax)

        self.canvas.draw()

    ###################################################
    def DispCursor(self, xval=0):
        """
        Show cursor
        @param xval the cursor position on x-axis
        @retval None
        """
        if not self.IsActive:
            return

        if xval != 0:
            self.xval = xval

        if self.ifi.GetProperty('overlay'):
            self.axl.clear()
            self.axl.axvline(x=self.xval, color='k',
                             linewidth=2, linestyle=':')
            self.axl.set_xlim(self.parent.ax.get_xlim())
            self.axl.set_ylim(self.parent.ax.get_ylim())
            setp(self.axl.get_xticklabels(), visible=False)
            setp(self.axl.get_yticklabels(), visible=False)
        else:
            num = self.ifi.GetProperty('tracenum')
            axgs = self.fig.get_axes()

            for i in range(len(self.axl)):
                ax = self.axl[i]
                ax.clear()
                ax.axvline(x=self.xval, color='k', linewidth=2, linestyle=':')
                #ax.set_xlim(axgs[i].get_xlim())
                #ax.set_ylim(axgs[i].get_ylim())
                #
                setp(ax.get_xticklabels(), visible=False)
                setp(ax.get_yticklabels(), visible=False)

        self.canvas.draw()

# <--[inamura 100715]
#######################################
#  PeakLabel
#######################################


class PeakLabel(object):
    """
    ピークラベル表示処理クラス
    """
    #######################################

    def __init__(self, parent, order):
        """
        コンストラクタ
        @param parent  親クラスのインスタンス
        @param order   プロッタID
        @retval 無
        """
        self.parent = parent
        self.do = parent.do
        self.plList = parent.peakLabels
        self.order = order  # [inamura 110303]
        # イベント管理クラスのインスタンスを取得
        self.ifi = IFEvtProp(order)
        # イベントのリスナー登録
        self.ifi.AddListner('penmode', self.OnNotifyPenMode)
        self.ifi.AddListner('labeltype', self.OnNotifyLabel)
        self.ifi.AddListner('pinup', self.OnNotifyPinup)
        self.ifi.AddListner('shift', self.OnNotifyKey)
        self.ifi.AddListner('changexy', self.OnNotifyChangeLim)
        self.ifi.AddListner('printfig', self.OnNotifyPrintFig)
        # [inamura 110303]
        self.ifi.AddListner('calcdspace', self.OnNotifyShowCalcDSpc)
        # 初期値設定
        self.pMode = False
        self.axl = None
        self.xdata = None
        self.datNum = -1
        self.index = -1
        self.xoffset = 0.0

    ###################################################
    def NewPlot(self, fig, canvas, flag):
        """
        サブプロット作成処理(フィギュア(再)作成時にコールされる)
        @param  fig     フィギュア
        @param  canvas  キャンバス
        @param  flag    カレントラベルのクリア指定　True 時クリア
        @retval 無し
        """
        self.fig = fig
        self.canvas = canvas

        # ペンモードなら
        if self.pMode:
            # ラベル描画用のサブプロットを作成
            self.CreatePlot()
            # カレントラベルのクリア指定か
            if flag:
                # カレントラベルをクリア
                self.xdata = None
                self.datNum = -1
                self.index = -1
                # ピンナップラベルの再表示
                self.DrawAllLabels()
                self.canvas.draw()
            else:
                # カレントラベルをアレンジ後、ラベルの再表示
                self.DispLabel(None, None, False)
        else:
            # ラベルアクシスクリア
            self.axl = None

    ###################################################
    def CreatePlot(self):
        """
        ラベル描画用のサブプロット作成
        @param  無し
        @retval 無し
        """

        # オーバレイモードか
        if self.ifi.GetProperty('overlay'):
            # ラベル表示用プロッタ作成(グラフ用のサブプロットと座標を共有)
            self.axl = self.fig.add_subplot(111, frameon=False)
            # 表示位置をグラフに合わせる
#            pos = self.parent.ax.get_position()  matplotlib 0.98.5 対応
            pos = VerHandlePlotLib().GetSubPlotPos(self.parent.ax)
            self.axl.set_position(pos)
            # 表示範囲をグラフ範囲に合わせる
            self.axl.sharex(self.parent.ax)
            self.axl.sharey(self.parent.ax)
            #self.axl.set_xlim(self.parent.ax.get_xlim())
            #self.axl.set_ylim(self.parent.ax.get_ylim())

            # 座標を不可視にする
            setp(self.axl.get_xticklabels(), visible=False)
            setp(self.axl.get_yticklabels(), visible=False)
        # 個別表示モード
        else:
            self.axl = []
            # 1ページ当たりのグラフ数取得
            tno = self.ifi.GetProperty('tracenum')
            # グラフ用のサブプロットを取得
            axgs = self.fig.get_axes()

            for i in range(len(axgs)):
                # ラベル表示用プロッタ作成(グラフ用のサブプロットと座標を共有)
                ax = self.fig.add_subplot(tno, 1, (i + 1), frameon=False)
                # 表示範囲をグラフ範囲に合わせる
                ax.sharex(axgs[i])
                ax.sharey(axgs[i])
                #ax.set_xlim(axgs[i].get_xlim())
                #ax.set_ylim(axgs[i].get_ylim())
                # 座標を不可視にする
                setp(ax.get_xticklabels(), visible=False)
                setp(ax.get_yticklabels(), visible=False)
                self.axl.append(ax)

    ###################################################

    def ClearPlot(self):
        """
        ラベル描画用のサブプロットクリア
        @param  無し
        @retval 無し
        """
        # サブプロットが未生成であれば
        if self.axl is None:
            return
        # オーバレイモードか
        if self.ifi.GetProperty('overlay'):
            # アクティブラベル表示用ザプロッタクリア
            self.axl.clear()
            # for matplotlib 2.1.1 on Ubuntu 18.04 [inamura 181107]-->
            pos = VerHandlePlotLib().GetSubPlotPos(self.parent.ax)
            self.axl.set_position(pos)
            # 表示範囲をグラフ範囲に合わせる
            self.axl.sharex(self.parent.ax)
            self.axl.sharey(self.parent.ax)
            #self.axl.set_xlim(self.parent.ax.get_xlim())
            #self.axl.set_ylim(self.parent.ax.get_ylim())
            # <--[inamura 181107]
            # 座標を不可視にする
            setp(self.axl.get_xticklabels(), visible=False)
            setp(self.axl.get_yticklabels(), visible=False)
        # 個別表示
        else:
            # 全サブプロットをクリア
            for ax in self.axl:
                # for matplotlib 2.1.1 on Ubuntu 18.04 [inamura 181107]-->
                tmp_xlim = ax.get_xlim()
                tmp_ylim = ax.get_ylim()
                ax.clear()
                # 表示範囲を元に戻す
                ax.set_xlim(tmp_xlim)
                ax.set_ylim(tmp_ylim)
                # <--[inamura 181107]
                # 座標を不可視にする
                setp(ax.get_xticklabels(), visible=False)
                setp(ax.get_yticklabels(), visible=False)

    ###################################################
    def DispSelectMark(self):
        """
        トレース選択マーク表示処理(オーバレイモードのみ)
        @param  無し
        @retval 無し
        """

        num = self.datNum % self.ifi.GetProperty('tracenum')
        # Y オフセットを計算
        offsety = self.ifi.GetProperty('offsety')
        if offsety < 10:
            offsety = 10
        else:
            offsety = offsety * \
                self.fig.get_size_inches()[1] / self.parent.orgsize
        gdpi = self.fig.get_dpi() * 1.0
        yoffset = offsety / gdpi * (num) - 0.03
        # オフセットを作成
        transOffset = offset_copy(self.axl.transData, fig=self.fig,
                                  x=0, y=yoffset, units='inches')
        # トレースラベルのX位置を計算
        xlim = self.axl.get_xlim()
        xx = xlim[1] + (xlim[1] - xlim[0]) * 0.005
        yy = self.axl.get_ylim()[0]
        # トレースラベルの前に選択マークを表示
        self.axl.text(xx, yy, '*', transform=transOffset)

    ###################################################

    def DispLabel(self, datNum, xdata, disp=True):
        """
        ラベル表示処理
        @param  datNum  データNo.
        @param  xdata   ラベル表示位置(X値)
        @param  disp    再表示実行フラグ
        @retval 無し
        """
        # データ番号が指定されているか
        if datNum is not None:
            self.datNum = datNum
        # データが指定されているか
        if xdata is not None:
            self.xdata = xdata
        else:
            # 一度もX値が指定されていなかったら
            if self.xdata is None:
                # オーバレイモードか
                if self.ifi.GetProperty('overlay'):
                    # トレースマークとピンナップされたラベルを描画
                    self.DrawAllLabels()
                    self.canvas.draw()
                return

        # 現在のデータ数より大きかったら(データ削除により)
        if self.datNum >= self.ifi.GetProperty('datanum'):
            # ページの最初のデータをデフォルトデータとする。
            self.datNum = self.ifi.GetProperty(
                'page') * self.ifi.GetProperty('tracenum')

        # 選択されたトレースのデータを取得
        dataX = self.do.GetDataX(self.datNum)

        # オーバレイモードか
        if self.ifi.GetProperty('overlay'):
            pos = VerHandlePlotLib().GetSubPlotPos(self.axl)   # matplotlib 0.98.5対応
            # X 値のオフセットを計算
            num = self.datNum % self.ifi.GetProperty('tracenum')
            xsize = self.fig.get_size_inches()[0] * self.fig.get_dpi() * pos[2]
            xrange = self.axl.get_xlim()[1] - self.axl.get_xlim()[0]
            self.xoffset = xrange * self.ifi.GetProperty('offsetx') * num / xsize
            # オフセット値を引いて、実際のデータ値を求める
            xx = self.xdata - self.xoffset
        else:
            xx = self.xdata
        # データ点のインデックスを探索
        self.SearchLabelPosi(dataX, xx)
        # ラベルを描画
        self.DrawAllLabels()
        # 再表示が指定されていたなら
        if disp:
            self.canvas.draw()

    ###################################################
    def SearchLabelPosi(self, dataX, xVal):
        """
        x の値より、データのインデックスを求める
        self.index に格納
        @param  dataX  Xデータ配列
        @param  xVal   Xの値
        @retval 無し
        """
        # データは昇順か
        if dataX[0] <= dataX[len(dataX) - 1]:
            # 最初のデータ点より大きいか
            if xVal > dataX[0]:
                # 最後のデータ点より大きいか
                if xVal > dataX[len(dataX) - 1]:
                    self.index = len(dataX) - 1
                else:
                    # クリック点に一番近いデータ点のインデックスを探索
                    for i in range(len(dataX)):
                        if xVal < dataX[i]:
                            # どちらが近いかを調べる
                            if xVal - dataX[i - 1] < dataX[i] - xVal:
                                i = i - 1
                            self.index = i
                            break
            else:
                # 最初のデータ点より小さい場合は、最初の点とする
                self.index = 0

        # 降順のデータ
        else:
            # 最初のデータ点より小さいか
            if xVal < dataX[0]:
                # 最後のデータ点より小さいか
                if xVal < dataX[len(dataX) - 1]:
                    self.index = len(dataX) - 1
                else:
                    # クリック点に一番近いデータ点のインデックスを探索
                    for i in range(len(dataX)):
                        if xVal > dataX[i]:
                            # どちらが近いかを調べる
                            if xVal - dataX[i] > dataX[i - 1] - xVal:
                                i = i - 1
                            self.index = i
                            break
            else:
                # 最初のデータ点より大きい場合は、最初の点とする
                self.index = 0

    ###################################################
    def DrawAllLabels(self, markflag=True):
        """
        全ラベル描画処理
        @param  markflag  トレース選択マーク表示指定
        @retval 無し
        """
        # データ数取得
        numData = self.ifi.GetProperty('datanum')
        # データがあるか
        if numData == 0:
            return
        # 現在のデータ数より大きかったら
        if self.datNum >= numData or self.datNum < 0:
            # ページの最初のデータをデフォルトデータとする。
            self.datNum = self.ifi.GetProperty(
                'page') * self.ifi.GetProperty('tracenum')

        # サブプロットをクリア
        self.ClearPlot()

        # オーバレイモードか
        if markflag and self.ifi.GetProperty('overlay'):
            # トレース選択マーク表示
            self.DispSelectMark()

        # 現在のページと1ページのデータ数を取得
        page = self.ifi.GetProperty('page')
        tno = self.ifi.GetProperty('tracenum')
        # ピンナップされたラベルを表示
        for i in range(numData):
            # 表示中のデータか
            if i >= (page * tno) and i < ((page + 1) * tno):
                for pindex in self.plList[i]:
                    self.DrawLabel(i, pindex, True)
        # カレントのラベルがあれば
        if self.index >= 0:
            self.DrawLabel(self.datNum, self.index, False)

    ###################################################
    def DrawLabel(self, datNum, index, pinup):
        """
        ラベル描画処理
        @param  datNum  トレースデータインデックス
        @param  index  データ中のX値-Y値のインデックス
        @param  pinup  固定ラベルフラグ
        @retval 無し
        """
        # トレースのデータを取得
        dataX = self.do.GetDataX(datNum)
        dataY = self.do.GetDataY(datNum)

        # ラベルタイプにより、ラベル文字列を作成
        # [inamura 160122]-->
        """
        if self.ifi.GetProperty('labeltype') == 1:
            # X値を表示
            strLabel = "%.2f" % dataX[index]
        elif self.ifi.GetProperty('labeltype') == 2:
            try:
                float(dataY[index])
            except:
                # Y値はマスク値
                strLabel = "--"
            else:
                # Y値を表示
                strLabel = "%.2f" % dataY[index]
        else:
            try:
                float(dataY[index])
            except:
                # Y値はマスク値
                strLabel = "%.2f , --" % dataX[index]
            else:
                # X値とY値を両方表示
                strLabel = "%.2f , %.2f" % (dataX[index], dataY[index])
        """
        label_type = self.ifi.GetProperty('labeltype')
        isTextVertical = False
        if label_type < 4:
            isTextVertical = True
        if label_type == 1 or label_type == 4:
            # X値を表示
            strLabel = "%g" % dataX[index]
        elif label_type == 2 or label_type == 5:
            try:
                float(dataY[index])
            except:
                # Y値はマスク値
                strLabel = "--"
            else:
                # Y値を表示
                strLabel = "%g" % dataY[index]
        else:
            try:
                float(dataY[index])
            except:
                # Y値はマスク値
                strLabel = "%g , --" % dataX[index]
            else:
                # X値とY値を両方表示
                strLabel = "%g , %g" % (dataX[index], dataY[index])
        # <--[inamura 160122]

        # 描画順を計算
        num = datNum % self.ifi.GetProperty('tracenum')

        # オーバレイモードか
        if self.ifi.GetProperty('overlay'):
            ax = self.axl
            # 描画色を取得
            ii = len(self.parent.laby) - 1 - num
            cl = self.parent.laby[ii][0]
            # オフセット計算
            offsety = self.ifi.GetProperty('offsety')
            # [inamura 160122]-->
            # yofs = offsety / (self.fig.get_dpi()*1.0) * num
            # xofs = self.ifi.GetProperty('offsetx') / (self.fig.get_dpi()*1.0) * num
            yofs = offsety * num
            xofs = self.ifi.GetProperty('offsetx') * num
            # <--[inamura 160122]

            pos = VerHandlePlotLib().GetSubPlotPos(self.axl)   # matplotlib 0.98.5対応
            # Y 値のオフセットを計算
            ysize = self.fig.get_size_inches()[1] * self.fig.get_dpi() * pos[3]
            # yoffset = (ax.get_ylim()[1]-ax.get_ylim()[0])*self.ifi.GetProperty('offsety')*num / ysize+0.02
            yoffset = (ax.get_ylim()[1] - ax.get_ylim()[0]) * self.ifi.GetProperty('offsety') * num / ysize  # [inamrua 160726]

        # 個別表示モード
        else:
            ax = self.axl[num]
            # 描画色を取得
            cl = self.parent.laby[num][0]
            # データオフセットは0
            yofs = 0.02
            xofs = 0.0
            yoffset = 0.0

        # マーク用オフセットを作成
        # [inamura 160122]-->
        transOffset0 = offset_copy(ax.transData, fig=self.fig,
                                   x=xofs, y=yofs, units='points')
        #                        x=xofs, y=yofs, units='inches')
        # 文字用オフセットを作成
        transOffset1 = None
        p_rotation = ''
        if isTextVertical:
            transOffset1 = offset_copy(ax.transData, fig=self.fig,
                                       x=(xofs - 1), y=(yofs + 10), units='points')
            #                    x=xofs-0.02, y=yofs+0.1, units='inches')
            p_rotation = 'vertical'
        else:
            transOffset1 = offset_copy(ax.transData, fig=self.fig,
                                       x=(xofs + 5), y=(yofs + 1), units='points')
            #                           x=xofs+0.02, y=yofs+0.02, units='inches')
            p_rotation = 'horizontal'
        # <--[inamura 160122]

        # 表示範囲を取得
        x0, x1 = ax.get_xlim()
        y0, y1 = ax.get_ylim()

        # X軸表示範囲内か
        if (dataX[index] + self.xoffset) < x0 or (dataX[index] + self.xoffset) > x1:
            return

        # Y軸下限値より下か
        if (dataY[index] + yoffset) < y0:
            # 下限位置にラベルを表示
            # ax.text(dataX[index], y0+(y1-y0)*0.01, strLabel, color=cl, fontsize = 7)
            ax.text(dataX[index], y0 + (y1 - y0) * 0.01, strLabel, color=cl, fontsize=7,
                    rotation=p_rotation, verticalalignment="bottom")  # [inamura 160122]
        #  Y軸上限値より上か
        elif (dataY[index] + yoffset) >= y1:
            # オフセット無しで、上限位置にラベルを表示
            # ax.text(dataX[index], y1+(y1-y0)*0.01, strLabel, color=cl, fontsize = 7)
            ax.text(dataX[index], y1 + (y1 - y0) * 0.01, strLabel, color=cl, fontsize=7,
                    rotation=p_rotation, verticalalignment="top")  # [inamura 160122]
        else:
            # オフセット付きで、データ値を表示
            # ax.text(dataX[index], dataY[index], strLabel, transform=transOffset1, \
            #              color=cl, fontsize = 7)
            ax.text(dataX[index], dataY[index], strLabel, transform=transOffset1,
                    color=cl, fontsize=7, rotation=p_rotation, verticalalignment="bottom")  # [inamura 160122]
            # データマーク(黒の十字形)で表示
            ax.plot((dataX[index],), (dataY[index],), transform=transOffset0,
                    linestyle='', marker='+', ms=8, mew=1.2, mec='k')
            # ピンナップされたラベルか
            if pinup:
                # 十字形の上にピンナップマーク(赤い小丸)を付ける
                ax.plot((dataX[index],), (dataY[index],), transform=transOffset0,
                        linestyle='', marker='o', ms=3, mfc='r', mec='k')
            # 表示範囲を元に戻す
            ax.set_xlim(x0, x1)
            ax.set_ylim(y0, y1)

    ###################################################

    def OnNotifyPenMode(self, wid, evt, flag):
        """
        ペンモード変更イベント処理
        @param  wid イベント発生元のインスタンス
        @param  evt イベントタイプ
        @param  flag  ペンモードフラグ
        @retval 無し
        """
        self.pMode = flag
        # ペンモードがOnに変わったのか
        if flag:
            # サブプロットが未作成なら
            if self.axl is None:
                # ラベル描画用のサブプロットを作成
                self.CreatePlot()
            # データがあれば
            if self.ifi.GetProperty('datanum') > 0:
                # ページの最初のデータをデフォルトデータとする。
                self.datNum = self.ifi.GetProperty(
                    'page') * self.ifi.GetProperty('tracenum')
                # オーバレイモードか
                if self.ifi.GetProperty('overlay'):
                    # 選択マークを表示
                    self.DispSelectMark()

        else:
            # ラベル描画用のサブプロットをクリア
            self.ClearPlot()

            # ピンナップされたラベルをクリア
            for i in range(len(self.plList)):
                self.plList[i] = []

            # 初期設定に戻す
            self.xdata = None
            self.datNum = -1
            self.index = -1

        # 再描画
        self.canvas.draw()

    ###################################################
    def OnNotifyLabel(self, wid, evt, typeno):
        """
        ラベルタイプ変更変更イベント処理
        @param  wid イベント発生元のインスタンス
        @param  evt イベントタイプ
        @param  typeno ラベルタイプ番号
        　　　　　　　　1: X 値 　2: Y値　3: X+Y値
        @retval 無し
        """
        # ラベルを描画
        self.DrawAllLabels()
        self.canvas.draw()

    ###################################################
    def OnNotifyPinup(self, *args):
        """
        ピンナップイベント処理
        @param  使用せず
        @retval 無し
        """
        # ラベルが指定されているか
        if self.datNum >= 0 and self.index >= 0:
            # 既に同じラベルが指定されているか
            if not (self.index in self.plList[self.datNum]):
                # 現在のラベルを保存
                self.plList[self.datNum].append(self.index)
            # 描画用にカレントラベルをクリア
            index = self.index
            self.index = -1
            # ピンマーク表示
            self.DrawAllLabels()
            # 再描画
            self.canvas.draw()
            self.index = index

    ###################################################
    def OnNotifyKey(self, wid, evt, keycode):
        """
        ラベル位置シフト処理
        @param  wid イベント発生元のインスタンス
        @param  evt イベントタイプ
        @param  keycode 矢印キー("right", "left", "up", "down")
        @retval 無し
        """
        # Pキーなら
        if keycode == 'p' or keycode == 'P':
            # ピンナップ処理
            self.OnNotifyPinup()
            return
        # 上下方向の移動か
        if keycode == "up" or keycode == "down":
            # 1ページ当たりのデータ数と現在のページを取得
            tnum = self.ifi.GetProperty('tracenum')
            page = self.ifi.GetProperty('page')
            # ページの最初と最後のデータNo.を求める
            d0 = tnum * page
            d1 = d0 + tnum - 1
            # データ数を超えたか
            if d1 >= self.ifi.GetProperty('datanum'):
                d1 = self.ifi.GetProperty('datanum') - 1

            # 個別表示モードか
            if not self.ifi.GetProperty('overlay'):
                # 先にラベルが選択されていないならば
                if self.index < 0:
                    # 何もしない
                    return

            # ↑キーなら
            if keycode == "up":
                # オーバレイモードか
                if self.ifi.GetProperty('overlay'):
                    dnum = self.datNum + 1
                else:
                    dnum = self.datNum - 1

            # ↓キーなら
            else:
                # オーバレイモードか
                if self.ifi.GetProperty('overlay'):
                    dnum = self.datNum - 1
                else:
                    dnum = self.datNum + 1
            # 表示中のデータの範囲内であれば
            if dnum >= d0 and dnum <= d1:
                # 選択中トレースを上または下に移動して再表示
                self.DispLabel(dnum, None)
                self.canvas.draw()
            return

        # 左右方向の移動か
        if keycode == "left" or keycode == "right":
            # 先にラベルが選択されていないならば
            if self.index < 0:
                # 何もしない
                return

            # データを取得
            dataX = self.do.GetDataX(self.datNum)
            # データは降順か
            if dataX[0] > dataX[len(dataX) - 1]:
                # keycode を逆にする
                if keycode == "left":
                    keycode = "right"
                else:
                    keycode = "left"

            # ←キーなら、インデックスが負とならないかをチェック
            if keycode == "left" and self.index > 0:
                self.index = self.index - 1

            # →キー、かつデータ数を超えないなら
            elif keycode == "right" and self.index < (len(dataX) - 1):
                self.index += 1

            # クリック点の入れ替え
            self.xdata = dataX[self.index] + self.xoffset
            # ラベルを描画
            self.DrawAllLabels()
            self.canvas.draw()

    ###################################################
    def OnNotifyChangeLim(self, wid, evt, value=None):
        """
        表示範囲変更イベント処理
        @param  wid イベント発生元のインスタンス
        @param  evt イベントタイプ
        @retval 無し
        """
        # ペンモードで無ければ
        if not self.pMode:
            return
            # オーバレイモードか
        if self.ifi.GetProperty('overlay'):
            # 表示範囲をグラフ範囲に合わせる
            #self.axl.set_xlim(self.parent.ax.get_xlim())
            #self.axl.set_ylim(self.parent.ax.get_ylim())
            pass
        # 個別モードか
        else:
            # グラフ用のサブプロットを取得
            axs = self.fig.get_axes()
            for i in range(len(self.axl)):
                # 各ラベル用サブプロットの表示範囲をグラフ範囲に合わせる
                #self.axl[i].set_xlim(axs[i].get_xlim())
                #self.axl[i].set_ylim(axs[i].get_ylim())
                pass

        # ラベルを消して、再表示
        self.DrawAllLabels()
        self.canvas.draw()

    ###################################################

    def OnNotifyPrintFig(self, wid, evt, markflag):
        """
        印刷・画像保存イベント処理
        (トレース選択マークを消去・再表示)
        @param  wid イベント発生元のインスタンス
        @param  evt イベントタイプ
        @param  markflag トレース選択フラグ表示フラグ
        　　　　　　　　True: 表示、　False: 非表示
        @retval 無し
        """
        # ペンモードかつオーバレイモードであれば
        if self.pMode and self.ifi.GetProperty('overlay'):
            # トレース選択マークの消去または再表示
            self.DrawAllLabels(markflag)

    # [inamura 110303]-->
    #######################################
    def OnNotifyShowCalcDSpc(self, wid, evt, arg):
        """
        Event-driven function to calculate d-space from plotter
        @param wid   instance of object producing event
        @param evt   type of event
        @param arg   other arguments
        """
        # Set Initial values
        L1 = L2 = pol = azm = 0.0

        # Analyse Header info.
        header = self.do.GetHeader(self.datNum)
        # TOF plot or not
        if "Xkey" in header:
            if header["Xkey"] != "TOF":
                print("This is not TOF data.")
                return
        else:
            print("Maybe this is not TOF data, be carefull")

        # Get PIXELID
        if "PIXELID" in header:
            pixel_id_str = "-%s" % (header["PIXELID"])
        else:
            pixel_id_str = "-%04d" % (self.datNum)

        # Get pixel position
        if "PixelPosition" in header:
            posi_str = header["PixelPosition"]
            str_list = posi_str.split(",")
            for item in str_list:
                L2 += float(item) * float(item)
            L2 = np.sqrt(L2) / 1000.0  # [m]
        else:
            print("No Header PixelPosition")
            return

        # Get polar angle
        if "PixelPolarAngle" in header:
            pol_str = header["PixelPolarAngle"]
            str_list = pol_str.split(",")
            pol = float(str_list[0])
        else:
            print("No Header PixelPolarAngle")
            return

        # Get azimuthal angle
        if "PixelAzimAngle" in header:
            azm_str = header["PixelAzimAngle"]
            str_list = azm_str.split(",")
            azm = float(str_list[0])
        else:
            print("No Header PixelAzimAngle")
            return

        # Get L1
        if "L1" in header:
            L1 = float(header["L1"]) / 1000.0  # [m]
        else:
            # If header has no L1
            sysname = ""
            if "UTSUSEMI_SYS_NAME" in os.environ:    # Utsusemi 0.3.7 or older
                sysname = os.environ["UTSUSEMI_SYS_NAME"]
            elif "UTSUSEMI_INST_CODE" in os.environ:  # Utsusemi 4.0 or later
                sysname = os.environ["UTSUSEMI_INST_CODE"]

            if sysname != "":
                if sysname == "SIK":
                    L1 = 18.03
                    print("Sys Name=", sysname)
                    print("L1=", L1)
                elif sysname == "AMR":
                    L1 = 30.00
                    print("Sys Name=", sysname)
                    print("L1=", L1)
                elif sysname == "HRC":
                    L1 = 15.00
                    print("Sys Name=", sysname)
                    print("L1=", L1)
                else:
                    L1 = 20.00
                    return
            else:
                print(
                    "Your Environment is not Utsusemi. Sorry you cannot use this function.")
                return

        # print "self.datNum,self.index=",self.datNum,self.index
        # Get X-axis from data
        dataX = self.do.GetDataX(self.datNum)

        # Show dialog
        dlg = CalcDspcDialog(self.parent.plot, self.parent.plot.order,
                             pixel_id_str, dataX[self.index],
                             pol, azm, L2, L1)
    # <--[inamura 110303]

#######################################
#  HeaderBox
#######################################


class HeaderBox(QtWidgets.QMainWindow):
    """
    ヒストグラムのヘッダー情報を表示
    """
    #########################################

    def __init__(self, parent, pos, header):
        """
        コンストラクタ
        @param  parent  親ウィンドウ(PlotFlame)のID
        @param  pos     ポップアップウィンドウの表示位置
        @param  header  表示するヘッダー
        @retval 無し
        """
        super(HeaderBox, self).__init__(
            parent, flags=QtCore.Qt.FramelessWindowHint)

        # リソースファイルを取得
        # res = ResourceFile()
        # ポップアップウィンドウを表示
        # self.hb = res.GetFrame(parent, 'PopFrame')
        # マウスのクリック点にウィンドウを表示
        self.move(pos[0], pos[1])
        # パネルコントロールを取得

        # ヘッダーテキストを作成し、サイザーに入れる
        fulltext = ""
        # for item in header.keys():
        for row, item in enumerate(header):
            # ヘッダーのキーを表示
            txt1 = "%s :" % item

            # キーが　ラベルなら
            if item == "Label":
                # 短縮表示処理
                psdID = header["Label"]
                strings = psdID.split('+')
                # 4個以上のID が連結されていたら
                if len(strings) > 3:
                    num = len(strings) - 1
                    # 中間部分を省略
                    psdID = strings[0] + " + ... + " + strings[num]
                txt2 = "%s  " % psdID
            else:
                # キーの値を表示
                txt2 = "%s  " % header[item]

            fulltext += (txt1 + txt2 + "\n")

        staticTxt1 = QtWidgets.QLabel(self)
        staticTxt1.setText(fulltext)
        self.setCentralWidget(staticTxt1)

        # ポップアップウィンドウを表示
        self.show()

    #########################
    def CloseHB(self):
        """
        ヘッダボックスクローズ
        @param  無し
        @retval 無し
        """
        self.close()

#########################################
#       ParamDialog
#########################################


class ParamDialog(QtWidgets.QDialog):
    """
    パラメータ設定ダイアログクラス
    """

    ##########################################################
    def __init__(self, parent, order, postfix="0"):
        """
        コンストラクタ
        @param  parent   親ウィンドウのID
        @param  order  プロッタの起動順序
        @param  postfix 画面タイトルに付ける親の識別子
        @retval 無し
        """
        super(ParamDialog, self).__init__(parent)

        # インターフェイスクラスのインスタンスを取得
        self.ifi = IFEvtProp(order)

        # リソースを取得
        self.dg = Ui_DgSetting()
        if self.dg is None:
            return
        self.dg.setupUi(self)

        # アイコンを設定
        # タイトル文字列を取得
        strT = self.windowTitle()
        # 順番を付してタイトル文字列を作成
        self.setWindowTitle(strT + postfix)
        # ボタンのイベントハンドラを登録
        self.btClose = self.findChild(QtWidgets.QPushButton, u"btClose")
        self.btXApply = self.findChild(QtWidgets.QPushButton, u"btXApply")
        self.btYApply = self.findChild(QtWidgets.QPushButton, u"btYApply")
        self.btClose.clicked.connect(self.close)
        self.btXApply.clicked.connect(self.OnApplyX)
        self.btYApply.clicked.connect(self.OnApplyY)
        # スピンボタン
        self.spinX = self.findChild(QtWidgets.QSpinBox, u'spX')
        self.spinY = self.findChild(QtWidgets.QSpinBox, u'spY')
        self.spinN = self.findChild(QtWidgets.QSpinBox, u'spN')
        self.spinFS = self.findChild(QtWidgets.QSpinBox, u'spFS')
        self.chFontName = self.findChild(QtWidgets.QComboBox, u'cbFontBox')

        # チェックボックス
        self.ckXAuto = self.findChild(QtWidgets.QCheckBox, u'ckXAuto')
        self.ckYAuto = self.findChild(QtWidgets.QCheckBox, u'ckYAuto')
        self.ckLog = self.findChild(QtWidgets.QCheckBox, u'ckLogY')
        self.ckLogX = self.findChild(QtWidgets.QCheckBox, u'ckLogX')
        self.ckOver = self.findChild(QtWidgets.QCheckBox, u'ckOver')

        # テキストボックス
        self.tx0 = self.findChild(QtWidgets.QLineEdit, u'x0')
        self.tx1 = self.findChild(QtWidgets.QLineEdit, u'x1')
        self.ty0 = self.findChild(QtWidgets.QLineEdit, u'y0')
        self.ty1 = self.findChild(QtWidgets.QLineEdit, u'y1')

        # プッシュボタン
        self.applyX = self.findChild(QtWidgets.QPushButton, u'btXApply')
        self.applyY = self.findChild(QtWidgets.QPushButton, u'btYApply')

        # 各部品に値を設定
        # Becase _SetValues method causes events
        # SetValues must be placed before setting event handler.
        self._SetValues()

        # スピンボタンのイベントハンドラ登録
        self.spinX.valueChanged[int].connect(self.OnSpinXY)
        self.spinY.valueChanged[int].connect(self.OnSpinXY)
        self.spinN.valueChanged[int].connect(self.OnSpinN)
        self.spinFS.valueChanged[int].connect(self.OnSetFont)
        self.chFontName.activated.connect(self.OnSetFont)

        # チェックボックスのイベントハンドラ登録
        self.ckXAuto.stateChanged.connect(self.OnAutoX)
        self.ckYAuto.stateChanged.connect(self.OnAutoY)
        self.ckOver.stateChanged.connect(self.OnOverlay)
        self.ckLog.stateChanged.connect(self.OnLog)
        self.ckLogX.stateChanged.connect(self.OnLogX)

        # パラメータ設定ダイアログオープンイベントを発行
        self.ifi.NotifyEvent(self, "paradg", False)
        # ダイアログ表示
        self.show()

    ##########################################################
    def _SetValues(self):
        """
        現在のパラメータを取得して画面に設定
        @param  無し
        @retval 無し
        """

        # 現在のスケールX範囲をテキストボックスにセット
        if self.ifi.GetProperty('autox'):
            self.ckXAuto.setCheckState(QtCore.Qt.Checked)
        else:
            self.ckXAuto.setCheckState(QtCore.Qt.Unchecked)

        self._SetEnableXRange()

        # 現在のスケールY範囲をテキストボックスにセット
        if self.ifi.GetProperty('autoy'):
            self.ckYAuto.setCheckState(QtCore.Qt.Checked)
        else:
            self.ckYAuto.setCheckState(QtCore.Qt.Unchecked)

        self._SetEnableYRange()

        # オフセットを設定
        x = self.ifi.GetProperty('offsetx')
        y = self.ifi.GetProperty('offsety')
        self.spinX.setValue(x)
        self.spinY.setValue(y)
        # グラフ数を設定
        self.spinN.setValue(self.ifi.GetProperty('tracenum'))
        # オーバレイモードを設定
        if self.ifi.GetProperty('overlay'):
            self.ckOver.setCheckState(QtCore.Qt.Checked)
        else:
            self.ckOver.setCheckState(QtCore.Qt.Unchecked)

        # オーバレイモードにより、スピンボタンの最大値を設定
        if self.ifi.GetProperty('overlay'):
            self.spinN.setRange(1, 50)
        else:
            self.spinN.setRange(1, 10)
        # ログモードを設定
        if self.ifi.GetProperty('log'):
            self.ckLog.setCheckState(QtCore.Qt.Checked)
        else:
            self.ckLog.setCheckState(QtCore.Qt.Unchecked)
        #   オーバレイモードであれば
        if self.ckOver.checkState() == QtCore.Qt.Checked:
            # オフセットを選択可
            self.spinX.setEnabled(True)
            self.spinY.setEnabled(True)
        else:
            # オフセットを選択不可
            self.spinX.setEnabled(False)
            self.spinY.setEnabled(False)
        # [inamura 120513]-->
        ifs = self.ifi.GetProperty('fontinfo')
        itx = self.ifi.GetProperty('textinfo')
        self.initFI = ifs[:]
        self.initTI = itx[:]
        # self.spinFS.SetValue( self.initFI[3][0] )

        fnl = self.ifi.GetProperty('fontnamelist')
        for it_fnl in fnl:
            self.chFontName.addItem(it_fnl)
        ind = self.chFontName.findText(self.initFI[3][1])
        self.chFontName.setCurrentIndex(ind)
        self.spinFS.setValue(self.initFI[3][0])
        # <--[inamura 120513]
    ##########################################################

    def OnSpinXY(self, evt=None):
        """
        オフセットスピンボックスイベント処理
        @param  evt イベント情報
        @retval 無し
        """
        x = self.spinX.value()
        y = self.spinY.value()
        # オフセット変更通知発行
        self.ifi.NotifyEvent(self, "offset", (x, y))

    ##########################################################
    def OnSpinN(self, evt=None):
        """
        グラフ数スピンボックスイベント処理
        @param  evt イベント情報
        @retval 無し
        """
        # グラフ数変更通知発行
        self.ifi.NotifyEvent(self, "tracenum", self.spinN.value())

    ##########################################################
    def OnSetFont(self, evt=None):
        """
        ##[inamura 120513]
        @param  evt
        @retval None
        """
        self.ifi.NotifyEvent(
            self, "setfontinfo", (3, [self.spinFS.value(), self.chFontName.currentText()]))

    ##########################################################
    def OnAutoX(self, evt=None):
        """
        AutoXチェックボックスイベント処理
        @param  evt イベント情報
        @retval 無し
        """
        self._SetEnableXRange()
        # スケール変更通知をリスナーへ送信
        # do auto scale when OFF -> ON
        if self.ckXAuto.checkState() == QtCore.Qt.Checked:
            self.ifi.NotifyEvent(self, "xscale", (True, None, None))

    ##########################################################
    def _SetEnableXRange(self):
        """
        X Range の選択可/不可を設定
        @param  evt イベント情報
        @retval 無し
        """

        # 自動モードであれば
        if self.ckXAuto.checkState() == QtCore.Qt.Checked:
            # テキストボックスを選択不可とする
            self.tx0.setEnabled(False)
            self.tx1.setEnabled(False)
            self.applyX.setEnabled(False)

        # マニュアルモードなら
        else:
            # 範囲プロパティを取得し文字列に変換
            strx0 = "%g" % self.ifi.GetProperty('x0')  # [inamura 160322]
            strx1 = "%g" % self.ifi.GetProperty('x1')  # [inamura 160322]
            # テキストボックスに値を設定
            self.tx0.setText(strx0)
            self.tx1.setText(strx1)
            # スケール入力テキストボックスを選択可とする
            self.tx0.setEnabled(True)
            self.tx1.setEnabled(True)
            # Apply ボタンを選択可とする
            self.applyX.setEnabled(True)

    ##########################################################

    def OnAutoY(self, evt=None):
        """
        AutoYチェックボックスイベント処理
        @param  evt イベント情報
        @retval 無し
        """
        self._SetEnableYRange()
        # スケール変更通知をリスナーへ送信
        # do auto scale when OFF -> ON
        if self.ckYAuto.checkState() == QtCore.Qt.Checked:
            self.ifi.NotifyEvent(self, "yscale", (True, None, None))

    ##########################################################
    def _SetEnableYRange(self):
        """
        X Range の選択可/不可を設定
        @param  evt イベント情報
        @retval 無し
        """
        # 自動モードであれば
        if self.ckYAuto.checkState() == QtCore.Qt.Checked:
            # テキストボックスを選択不可とする
            self.ty0.setEnabled(False)
            self.ty1.setEnabled(False)
            self.applyY.setEnabled(False)
        # マニュアルモードなら
        else:
            # 範囲プロパティを取得し文字列に変換
            stry0 = "%g" % self.ifi.GetProperty('y0')  # [inamura 160322]
            stry1 = "%g" % self.ifi.GetProperty('y1')  # [inamura 160322]
            # テキストボックスに値を設定
            self.ty0.setText(stry0)
            self.ty1.setText(stry1)
            # スケール入力テキストボックスを選択可とする
            self.ty0.setEnabled(True)
            self.ty1.setEnabled(True)
            # Apply ボタンを選択可とする
            self.applyY.setEnabled(True)

    ##########################################################
    def OnOverlay(self, evt=None):
        """
        Overlayチェックボックスイベント処理
        @param  evt イベント情報
        @retval 無し
        """
        # オーバレイモードであれば
        # if self.ckOver.GetValue():
        if self.ckOver.checkState() == QtCore.Qt.Checked:
            # オフセット選択可
            self.spinX.setEnabled(True)
            self.spinY.setEnabled(True)
            # グラフ数最大値は50
            self.spinN.setRange(1, 50)
            # グラフ数を設定
            self.spinN.setValue(20)
            tnum = 20
        else:
            # オフセット選択不可
            self.spinX.setEnabled(False)
            self.spinY.setEnabled(False)
            # グラフ数最大値は4
            # [inamura 100715]-->
            # Change the max number of graph to 10
            self.spinN.setRange(1, 10)
            # 現在のデータ数が 4 より大きければ
            if self.ifi.GetProperty('datanum') > 10:
                tnum = 10
            else:
                # データ数を、1ページ当たりのトレース数とする
                tnum = self.ifi.GetProperty('datanum')
            # <--[inamura 100715]
            # グラフ数を設定
            self.spinN.setValue(tnum)

        # オーバレイモード変更通知
        if self.ckOver.checkState() == QtCore.Qt.Checked:
            flag = True
        else:
            flag = False
        self.ifi.NotifyEvent(self, "overlay", flag)

    ##########################################################
    def OnLog(self, evt=None):
        """
        Log チェックボックスイベント処理
        @param  evt イベント情報
        @retval 無し
        """
        print("OnLog")
        if self.ckLog.checkState() == QtCore.Qt.Checked:
            flag = True
        else:
            flag = False
        self.ifi.NotifyEvent(self, "log", flag)

    # [inamura 140307]-->
    ##########################################################
    def OnLogX(self, evt=None):
        """
        LogX チェックボックスイベント処理
        @param  evt イベント情報
        @retval 無し
        """
        print("OnLogX")
        if self.ckLogX.checkState() == QtCore.Qt.Checked:
            flag = True
            print("flag=True")
        else:
            flag = False
            print("flag=False")
        self.ifi.NotifyEvent(self, "logx", flag)
    # <--[inamura 140307]

    ##########################################################
    def closeEvent(self, evt):
        """
        Catch close event ( by click close-box or self.close() )

        """
        self.ifi.NotifyEvent(self, "paradg", True)
        evt.accept()

    ##########################################################
    def OnClose(self, evt=None):
        """
        ダイアログクローズイベント処理
        @param  evt イベント情報
        @retval 無し
        """
        # パラメータ設定ダイアログクローズイベントを発行
        self.close()

    ##########################################################
    def OnApplyX(self, evt=None):
        """
        Applyボタンイベント処理
        @param  evt イベント情報
        @retval 無し
        """
        # テキストボックスより値を取得
        # 数値か
        try:
            x0 = float(self.tx0.text())
        except:
            x0 = 0.0
        try:
            x1 = float(self.tx1.text())
        except:
            x1 = 1.0
        # 同値か
        if x0 == x1:
            x1 = x0 + 1.0
        # 逆転していたら
        if x0 > x1:
            # 入れ替える
            tmp = x0
            x0 = x1
            x1 = tmp

        # 数値を再表示
        strX0 = "%g" % x0  # [inamura 160322]
        strX1 = "%g" % x1  # [inamura 160322]
        self.tx0.setText(strX0)
        self.tx1.setText(strX1)

        # スケール変更通知をリスナーへ送信
        self.ifi.NotifyEvent(self, "xscale", (False, x0, x1))

    ##########################################################
    def OnApplyY(self, evt=None):
        """
        Applyボタンイベント処理
        @param  evt イベント情報
        @retval 無し
        """
        # テキストボックスより値を取得
        # 数値か
        try:
            y0 = float(self.ty0.text())
        except:
            y0 = 0.0
        try:
            y1 = float(self.ty1.text())
        except:
            y1 = 1.0
        # 同値か
        if y0 == y1:
            y1 = y0 + 1.0
        # 逆転していたら
        if y0 > y1:
            # 入れ替える
            tmp = y0
            y0 = y1
            y1 = tmp

        # 数値を再表示
        strY0 = "%.5f" % y0
        strY1 = "%.5f" % y1
        self.ty0.setText(strY0)
        self.ty1.setText(strY1)
        # スケール変更通知をリスナーへ送信
        self.ifi.NotifyEvent(self, "yscale", (False, y0, y1))


#########################################
#       PlotDialog
#########################################
class PlotDialog(QtWidgets.QDialog):
    """
    プロット条件設定ダイアログクラス
    """

    ##########################################################
    def __init__(self, parent, order, select, postfix="0"):
        """
        コンストラクタ
        @param  parent   親ウィンドウのID
        @param  order    プロッタの起動順序
        @param  selects  選択中データのインデックスリスト
        @param  postfix 画面タイトルに付ける親の識別子
        @retval 無し
        """
        super(PlotDialog, self).__init__(parent)

        # インターフェイスクラスのインスタンスを取得
        self.ifi = IFEvtProp(order)
        self.select = select
        # リソースよりダイアログボックスを取得して作成
        self.dg = Ui_DgPlotPtn()
        if self.dg is None:
            return
        self.dg.setupUi(self)

        self.flagAutoApply = True  # [inamura 101007]
        # タイトル文字列を取得
        strT = self.windowTitle()
        # 順番を付してタイトル文字列を作成
        self.setWindowTitle(strT + postfix)

        # ボタンのイベントハンドラを登録
        self.btClose = self.findChild(QtWidgets.QPushButton, u"btClose")
        self.btApply = self.findChild(QtWidgets.QPushButton, u"btApply")
        self.btApplyThis = self.findChild(
            QtWidgets.QPushButton, u"btApplyThis")
        self.btSaveDefAtt = self.findChild(
            QtWidgets.QPushButton, u"btSaveDefAtt")
        self.btClose.clicked.connect(self.close)
        self.btApply.clicked.connect(self.OnApplyAll)
        self.btApplyThis.clicked.connect(self.OnApplyThis)
        self.btSaveDefAtt.clicked.connect(self.OnSaveDefAtt)

        # リソースよりコントロールを取得
        # コンボボックス
        self.cbLS = self.findChild(QtWidgets.QComboBox, u'cbLineStyle')
        self.cbLC = self.findChild(QtWidgets.QComboBox, u'cbLineColor')
        self.cbMK = self.findChild(QtWidgets.QComboBox, u'cbSymbolType')
        self.cbMC = self.findChild(QtWidgets.QComboBox, u'cbSymbolColor')
        self.cbEC = self.findChild(QtWidgets.QComboBox, u'cbErrorColor')

        # コンボボックスのイベントハンドラ登録
        self.cbLS.activated.connect(self.OnComboLS)
        self.cbLC.activated.connect(self.OnComboLC)
        self.cbMK.activated.connect(self.OnComboMK)
        self.cbMC.activated.connect(self.OnComboMC)
        self.cbEC.activated.connect(self.OnComboEC)

        # スピンボタン
        self.spinLW = self.findChild(QtWidgets.QSpinBox, u'spLineWidth')
        self.spinMS = self.findChild(QtWidgets.QSpinBox, u'spSymbolSize')
        self.spinCS = self.findChild(QtWidgets.QSpinBox, u'spCapSize')

        # スピンボタンのイベントハンドラ登録
        self.spinLW.valueChanged[int].connect(self.OnSpinLW)
        self.spinMS.valueChanged[int].connect(self.OnSpinMS)
        self.spinCS.valueChanged[int].connect(self.OnSpinCS)

        # チェックボックス
        self.ckAutoApply = self.findChild(QtWidgets.QCheckBox, u"ckAutoApply")
        self.ckAutoApply.setCheckState(QtCore.Qt.Checked)
        self.ckEB = self.findChild(QtWidgets.QCheckBox, u"ckErrorBar")
        self.ckHist = self.findChild(QtWidgets.QCheckBox, u"ckHist")
        self.ckFilledFace = self.findChild(
            QtWidgets.QCheckBox, u"ckFilledFace")

        # チェックボックスのイベントハンドラ登録
        self.ckAutoApply.stateChanged.connect(self.OnAutoApply)
        self.ckEB.stateChanged.connect(self.OnErrBar)
        self.ckHist.stateChanged.connect(self.OnHist)
        self.ckFilledFace.stateChanged.connect(self.OnFilledFace)

        # クローズイベント登録

        # ダイアログに、選択データの表示属性現在値を設定
        self._SetValues()

        # ダイアログを表示
        self.show()

    ##########################################################

    def _SetValues(self):
        """
        現在のパラメータを取得して画面に設定
        @param  無し
        @retval 無し
        """
        # トレース属性リストを取得
        attList = self.ifi.GetProperty('traceattrs')
        # 選択されているトレースの属性を取得
        attr = attList[self.select]

        # ラインスタイルの設定
        self.cbLS.setCurrentIndex(
            self._GetAttrNum(attr["ls"], TraceAtt.linestyle))
        # ヒストグラムスタイルを指定
        if attr["hs"] == 0:
            self.ckHist.setCheckState(QtCore.Qt.Unchecked)
        else:
            self.ckHist.setCheckState(QtCore.Qt.Checked)

        # ライン幅の設定
        self.spinLW.setValue(attr["lw"])
        # ラインカラーの設定
        self.cbLC.setCurrentIndex(self._GetAttrNum(attr["lc"], TraceAtt.color))

        # マークの設定
        self.cbMK.setCurrentIndex(
            self._GetAttrNum(attr["mk"], TraceAtt.marker))
        # マークサイズの設定
        self.spinMS.setValue(attr["ms"])
        # マークカラーの設定
        self.cbMC.setCurrentIndex(self._GetAttrNum(attr["mc"], TraceAtt.color))

        # [inamura 120512]-->
        if self._GetAttrNum(attr["mf"], TraceAtt.mface) == 0:
            self.ckFilledFace.setCheckState(QtCore.Qt.Checked)
        else:
            self.ckFilledFace.setCheckState(QtCore.Qt.Unchecked)
        # <--[inamura 120512]

        # エラーバー付きを指定
        if attr["eb"] == 0:
            self.ckEB.setCheckState(QtCore.Qt.Unchecked)
        else:
            self.ckEB.setCheckState(QtCore.Qt.Checked)

        # キャップサイズの設定
        self.spinCS.setValue(attr["es"])
        # エラーバーカラーの設定
        self.cbEC.setCurrentIndex(self._GetAttrNum(attr["ec"], TraceAtt.color))

    ##########################################################
    def _GetAttrNum(self, value, lst):
        """
        指定された値を検索しリストのインデックスに変換
        @param  value 値
        @param  lst 値
        @retval インデックス
        """
        # リストから指定された値を検索
        i = 0
        for item in lst:
            # 値と等しいか
            if item == value:
                # インデックスを返す
                return i
            i += 1
        # 検索できなかった場合
        return 0

    ##########################################################
    def ChangeSelect(self, select):
        """
        データ一覧で選択データが変更されたので
        表示中のプロット属性を変更
        @param  select 選択データのインデックス
        @retval 無し
        """
        # 選択インデックスを変更
        self.select = select
        # ダイアログの表示を変更
        self._SetValues()

    ##########################################################
    def OnComboLS(self, evt=None):
        """
        ラインスタイル変更イベント処理
        [inamura 101007: use self.flagAutoApply]
        @param  evt イベント情報
        @retval 無し
        """
        if self.flagAutoApply:
            # 線種を取得
            ls = TraceAtt.linestyle[self.cbLS.currentIndex()]
            # トレース属性変更要求をだす
            self.ifi.NotifyEvent(
                self, "plotparam", (self.select + 1, {"ls": ls}))

    ##########################################################
    def OnHist(self, evt=None):
        """
        ヒストグラムモスタイル変更イベント処理
        [inamura 101007: use self.flagAutoApply]
        @param  evt イベント情報
        @retval 無し
        """
        if self.flagAutoApply:
            # ヒストグラムモスタイル取得
            if self.ckHist.checkState() == QtCore.Qt.Unchecked:
                # ヒストグラムモスタイル変更要求をだす
                self.ifi.NotifyEvent(
                    self, "plotparam", (self.select + 1, {"hs": 0}))
            else:
                # ヒストグラムモスタイル変更要求をだす
                self.ifi.NotifyEvent(
                    self, "plotparam", (self.select + 1, {"hs": 1}))

    ##########################################################
    def OnComboLC(self, evt=None):
        """
        ラインカラー変更イベント処理
        [inamura 101007: use self.flagAutoApply]
        @param  evt イベント情報
        @retval 無し
        """
        if self.flagAutoApply:
            # 色を取得
            color = TraceAtt.color[self.cbLC.currentIndex()]
            # トレース属性変更要求をだす
            self.ifi.NotifyEvent(
                self, "plotparam", (self.select + 1, {"lc": color}))

    ##########################################################
    def OnComboMK(self, evt=None):
        """
        マークカラー変更イベント処理
        [inamura 101007: use self.flagAutoApply]
        @param  evt イベント情報
        @retval 無し
        """
        if self.flagAutoApply:
            # マーカーの種類を取得
            mk = TraceAtt.marker[self.cbMK.currentIndex()]
            # トレース属性変更要求をだす
            self.ifi.NotifyEvent(
                self, "plotparam", (self.select + 1, {"mk": mk}))

    ##########################################################
    def OnComboMC(self, evt=None):
        """
        マークカラー変更イベント処理
        [inamura 101007: use self.flagAutoApply]
        @param  evt イベント情報
        @retval 無し
        """
        if self.flagAutoApply:
            # 色を取得
            color = TraceAtt.color[self.cbMC.currentIndex()]
            # トレース属性変更要求をだす
            self.ifi.NotifyEvent(
                self, "plotparam", (self.select + 1, {"mc": color}))

    ##########################################################
    def OnComboEC(self, evt=None):
        """
        キャップカラー変更イベント処理
        [inamura 101007: use self.flagAutoApply]
        @param  evt イベント情報
        @retval 無し
        """
        if self.flagAutoApply:
            # 色を取得
            color = TraceAtt.color[self.cbEC.currentIndex()]
            # トレース属性変更要求をだす
            self.ifi.NotifyEvent(
                self, "plotparam", (self.select + 1, {"ec": color}))

    ##########################################################
    def OnSpinLW(self, evt=None):
        """
        ライン幅スピンボタンイベント処理
        [inamura 101007: use self.flagAutoApply]
        @param  evt イベント情報
        @retval 無し
        """
        if self.flagAutoApply:
            # 線幅を取得
            lw = self.spinLW.value()
            # トレース属性変更要求をだす
            self.ifi.NotifyEvent(
                self, "plotparam", (self.select + 1, {"lw": lw}))

    ##########################################################
    def OnSpinMS(self, evt=None):
        """
        マーカーサイズスピンボタンイベント処理
        [inamura 101007: use self.flagAutoApply]
        @param  evt イベント情報
        @retval 無し
        """
        if self.flagAutoApply:
            # マーカーサイズを取得
            ms = self.spinMS.value()
            # トレース属性変更要求をだす
            self.ifi.NotifyEvent(
                self, "plotparam", (self.select + 1, {"ms": ms}))

    ##########################################################
    def OnSpinCS(self, evt=None):
        """
        キャップサイズスピンボタンイベント処理
        [inamura 101007: use self.flagAutoApply]
        @param  evt イベント情報
        @retval 無し
        """
        if self.flagAutoApply:
            # キャップーサイズを取得
            es = self.spinCS.value()
            # トレース属性変更要求をだす
            self.ifi.NotifyEvent(
                self, "plotparam", (self.select + 1, {"es": es}))

    ##########################################################
    def OnErrBar(self, evt=None):
        """
        エラーバーチェックボックスイベント処理
        [inamura 101007: use self.flagAutoApply]
        @param  evt イベント情報
        @retval 無し
        """
        if self.flagAutoApply:
            # エラーバー付きを取得
            if self.ckEB.checkState() == QtCore.Qt.Unchecked:
                # トレース属性変更要求をだす
                self.ifi.NotifyEvent(
                    self, "plotparam", (self.select + 1, {"eb": 0}))
            else:
                # トレース属性変更要求をだす
                self.ifi.NotifyEvent(
                    self, "plotparam", (self.select + 1, {"eb": 1}))

    ##########################################################
    def OnFilledFace(self, evt=None):
        """
        [inamura 120512]
        @param  evt イベント情報
        @retval 無し
        """
        if self.flagAutoApply:
            if self.ckFilledFace.checkState() == QtCore.Qt.Checked:
                self.ifi.NotifyEvent(
                    self, "plotparam", (self.select + 1, {"mf": "fill"}))
            else:
                self.ifi.NotifyEvent(
                    self, "plotparam", (self.select + 1, {"mf": "none"}))

    ##########################################################
    def ShowDg(wid, evt, select):
        """
        選択データ変更イベント処理
        @param  evt イベント情報
        @retval 無し
        """
        # 選択データのインデックス
        self.select = select
        # ダイアログに値を設定
        self.SetValues()
        # ダイアログの表示
        self.show()

    ##########################################################
    def closeEvent(self, evt=None):
        """
        Catch close event ( by click close-box or self.close() )
        """
        self.ifi.NotifyEvent(self, "plotdg")
        evt.accept()

    ##########################################################
    def OnClose(self, evt=None):
        """
        ダイアログクローズイベント処理
        @param  evt イベント情報
        @retval 無し
        """
        # プロット条件設定ダイアログクローズイベント発行
        self.ifi.NotifyEvent(self, "plotdg")
        # self.dg.Destroy()
        self.close()

    ##########################################################
    def OnApplyAll(self, evt=None):
        """
        Applyボタンイベント処理
        [inamura 110223]
        @param  evt イベント情報
        @retval 無し
        """

        self.ifi.NotifyEvent(self, "plotparam", (0, self._GetAllAttr()))

    ##########################################################
    def OnAutoApply(self, evt=None):
        """
        AutoApplyチェックボックスイベント処理
        [inamura 101007]
        @param  evt イベント情報
        @retval 無し
        """
        # Get status of check box
        if self.ckAutoApply.checkState() == QtCore.Qt.Checked:
            # change flag and enable button
            self.flagAutoApply = True
            self.btApplyThis.setEnabled(False)
        else:
            # change flag and button disable
            self.flagAutoApply = False
            self.btApplyThis.setEnabled(True)

    ##########################################################
    def OnApplyThis(self, evt=None):
        """
        ApplyThisボタンイベント処理
        [inamura 110223]
        @param  evt イベント情報
        @retval 無し
        """
        self.ifi.NotifyEvent(
            self, "plotparam", (self.select + 1, self._GetAllAttr()))

    ##########################################################
    def OnSaveDefAtt(self, evt=None):
        """
        Save attributes as default
        [inamura 110223]
        @param evt event
        @retval None
        """
        def_att = DefaultFastPlotAtt()
        def_att.savePlotAtt(self._GetAllAttr())

    ##########################################################
    def _GetAllAttr(self):
        """
        Get all attributes of setting
        [inamura 110223][inamura 120512 add maker face]
        @param Noen
        @retval attribute dictionary
        """
        # get LineStyle
        ls = TraceAtt.linestyle[self.cbLS.currentIndex()]
        # get HistogramStyle
        if self.ckHist.checkState() == QtCore.Qt.Unchecked:
            hs = 0
        else:
            hs = 1
        # get LineWidth
        lw = self.spinLW.value()
        # get LineColor
        lc = TraceAtt.color[self.cbLC.currentIndex()]

        # get MarkerType
        mk = TraceAtt.marker[self.cbMK.currentIndex()]
        # get MarkerSize
        ms = self.spinMS.value()
        # get MarkerColor
        mc = TraceAtt.color[self.cbMC.currentIndex()]

        # get flag for marker face status [inamura 120512]
        if self.ckFilledFace.checkState() == QtCore.Qt.Checked:
            mf = "fill"
        else:
            mf = "none"

        # get flag to error bar
        if self.ckEB.checkState() == QtCore.Qt.Unchecked:
            eb = 0
        else:
            eb = 1
        # get size of cap of error bar
        es = self.spinCS.value()
        # get color of error bar
        ec = TraceAtt.color[self.cbEC.currentIndex()]

        return {"ls": ls, "hs": hs, "lw": lw, "lc": lc, "mk": mk, "ms": ms, "mc": mc, "eb": eb, "es": es, "ec": ec, "mf": mf}


#########################################
#       TitleDialog
#########################################
class TitleDialog(QtWidgets.QDialog):
    """
    タイトル設定ダイアログクラス
    """
    ##########################################################

    def __init__(self, parent, order, postfix):
        """
        コンストラクタ
        @param  parent   親ウィンドウのID
        @param  order  プロッタの起動順序
        @param  postfix 画面タイトルに付ける親の識別子
        @retval 無し
        """
        super(TitleDialog, self).__init__(parent)

        self.ifi = IFEvtProp(order)

        # リソース取得
        self.dg = Ui_DgTitle()
        if self.dg is None:
            return
        self.dg.setupUi(self)

        if order > 0:
            # タイトル文字列を取得
            strT = self.windowTitle()
            # 順番を付してタイトル文字列を作成
            self.setWindowTitle(strT + postfix)

        # テキストボックスのコントローラ取得
        self.text1 = self.findChild(QtWidgets.QLineEdit, u'tx1')
        self.text2 = self.findChild(QtWidgets.QPlainTextEdit, u'tx2')

        self.text1.setText(self.ifi.GetProperty('title1'))
        self.text2.appendPlainText(self.ifi.GetProperty("title2"))

        # ボタンのイベントハンドラ登録
        self.btOk = self.findChild(QtWidgets.QPushButton, u"btOK")
        self.btCancel = self.findChild(QtWidgets.QPushButton, u"btCancel")
        self.btOk.clicked.connect(self.OnOk)
        self.btCancel.clicked.connect(self.OnCancel)

        iff = self.ifi.GetProperty('fontinfo')
        ift = self.ifi.GetProperty('textinfo')
        self.initFI = iff[:]
        self.initTI = ift[:]

        self.spinFS = self.findChild(QtWidgets.QSpinBox, u"spFS")
        self.spinFS.setValue(self.initFI[0][0])

        self.chFontName = self.findChild(QtWidgets.QComboBox, u"cbFont")
        fnl = self.ifi.GetProperty('fontnamelist')
        ind = 0
        for i, it_fnl in enumerate(fnl):
            self.chFontName.addItem(it_fnl)
            if it_fnl == self.initFI[0][1]:
                ind = i
        self.chFontName.setCurrentIndex(ind)

        self.spinFS.valueChanged[int].connect(self.OnSetFont)
        self.chFontName.activated.connect(self.OnSetFont)

        # ダイアログオープンイベント発行
        self.ifi.NotifyEvent(self, "titledg", False)
        # ダイアログ表示
        self.show()

    ##########################################################
    def OnSetFont(self, evt=None):
        """
        [inamura 120513]
        @param  evt
        @retval None
        """
        font_size = int(self.spinFS.value())
        font_name = str(self.chFontName.currentText())
        self.ifi.NotifyEvent(self, "setfontinfo", (0, [font_size, font_name]))

    ##########################################################
    def OnOk(self, evt=None):
        """
        OK ボタンイベント処理
        @param  evt イベント情報
        @retval 無し
        """
        # テキストボックスから値を取得
        main = self.text1.text()
        sub = self.text2.toPlainText()

        try:
            # 日本語文字列が含まれているかどうかをチェック
            try:
                str(main)
            except:
                raise PlotException('Common', 'C025', ("Main Title",))
            try:
                str(sub)
            except:
                raise PlotException('Common', 'C025', ("Sub Title",))
        except PlotException as ex:
            PlotMessage(self.dialog, ex)

        else:
            # 前と変わらなかったら
            if self.ifi.GetProperty("title1") == main:
                # 変更無記号を送信(自動更新を解除しないため)
                # 注: 一度メインタイトル変更すると、自動更新モードを解除する
                # サブタイトルは、自動更新モードに影響しない
                main = '*'
            # タイトル変更要求送信
            self.ifi.NotifyEvent(self, "title", (main, sub))
            self.close()

    ##########################################################
    def OnCancel(self, evt=None):
        """
        Cancel ボタンイベント処理
        @param  evt イベント情報
        @retval 無し
        """
        self.ifi.NotifyEvent(self, "setfontinfo", (0, [
                             self.initFI[0][0], self.initFI[0][1]]))  # [inamura 120513]
        self.close()
    ##########################################################

    def closeEvent(self, event):
        """
        Catch close event ( by click close-box or self.close() )

        @param event
        @retval none
        """
        self.ifi.NotifyEvent(self, "titledg", True)
        event.accept()


#########################################
#       LabelDialog
#########################################
class LabelDialog(QtWidgets.QDialog):
    """
    スケールラベル設定ダイアログクラス
    """
    ##########################################################

    def __init__(self, parent, order, postfix):
        # def __init__(self, parent, order, postfix, dataobj):
        """
        コンストラクタ
        [inamura 110704] remove dataobj
        [inamura 110620] add dataobj
        @param  parent   親ウィンドウのID
        @param  order  プロッタの起動順序
        @param  postfix 画面タイトルに付ける親の識別子
        @param  dataobj
        @retval 無し
        """
        super(LabelDialog, self).__init__(parent)

        self.ifi = IFEvtProp(order)

        # リソース取得
        # res = ResourceFile()
        # self.dialog = res.GetDialog(parent, 'DgScaleLabel')
        self.dg = Ui_DgScaleLabel()
        if self.dg is None:
            return
        self.dg.setupUi(self)

        # タイトル文字列を取得
        strT = self.windowTitle()
        # 順番を付してタイトル文字列を作成
        self.setWindowTitle(strT + postfix)
        # テキストボックスのコントローラ取得
        self.xlabel = self.findChild(QtWidgets.QLineEdit, u'xlabel')
        self.ylabel = self.findChild(QtWidgets.QLineEdit, u'ylabel')

        self.xunit = self.findChild(QtWidgets.QLineEdit, u'xunit')
        self.xunit.setText(self.ifi.GetProperty("xunit"))
        self.yunit = self.findChild(QtWidgets.QLineEdit, u'yunit')
        self.yunit.setText(self.ifi.GetProperty("yunit"))

        iff = self.ifi.GetProperty('fontinfo')
        ift = self.ifi.GetProperty('textinfo')
        self.initFI = iff[:]
        self.initTI = ift[:]

        self.spinFS = self.findChild(QtWidgets.QSpinBox, u"spFS")
        self.spinFS.setValue(self.initFI[0][0])

        self.chFontName = self.findChild(QtWidgets.QComboBox, u"cbFont")
        fnl = self.ifi.GetProperty('fontnamelist')
        ind = 0
        for i, it_fnl in enumerate(fnl):
            self.chFontName.addItem(it_fnl)
            if it_fnl == self.initFI[1][1]:
                ind = i
        self.chFontName.setCurrentIndex(ind)

        self.spinFS.valueChanged[int].connect(self.OnSetFont)
        self.chFontName.activated.connect(self.OnSetFont)

        xl = self.ifi.GetProperty("xlabel")
        yl = self.ifi.GetProperty("ylabel")

        # プロパティが取得できたら、テキストボックスに設定
        self.xlabel.setText(xl)
        self.ylabel.setText(yl)

        # ボタンのイベントハンドラ登録
        self.btOk = self.findChild(QtWidgets.QPushButton, u"btOK")
        self.btCancel = self.findChild(QtWidgets.QPushButton, u"btCancel")
        self.btOk.clicked.connect(self.OnOk)
        self.btCancel.clicked.connect(self.OnCancel)

        # [X]ボタン押下時のイベントハンドラ登録
        # ダイアログオープンイベント発行
        self.ifi.NotifyEvent(self, "labeldg", False)
        # ダイアログ表示
        self.show()

    ##########################################################
    def OnSetFont(self, evt=None):
        """
        [inamura 120513]
        @param  evt
        @retval None
        """
        font_size = int(self.spinFS.value())
        font_name = str(self.chFontName.currentText())
        self.ifi.NotifyEvent(self, "setfontinfo", (1, [font_size, font_name]))
        self.ifi.NotifyEvent(self, "setfontinfo", (2, [font_size, font_name]))

    ##########################################################

    def OnOk(self, evt=None):
        """
        OK ボタンイベント処理
        @param  evt イベント情報
        @retval 無し
        """
        # テキストボックスから値を取得
        xlabel = self.xlabel.text()
        ylabel = self.ylabel.text()
        xunit = self.xunit.text()
        yunit = self.yunit.text()
        try:
            # 日本語文字列が含まれているかどうかをチェック
            try:
                str(xlabel)
            except:
                raise PlotException('Common', 'C025', ("X Label",))
            try:
                str(ylabel)
            except:
                raise PlotException('Common', 'C025', ("Y Label",))
        except PlotException as ex:
            PlotMessage(self, ex)
        else:
            self.ifi.NotifyEvent(self, "scalelabel", (xlabel, ylabel))
            # [inamura 110620]
            self.ifi.NotifyEvent(self, "setunits", (xunit, yunit))
            self.ifi.NotifyEvent(self, "labeldg", True)
            self.close()

    ##########################################################
    def OnCancel(self, evt=None):
        """
        Cancel ボタンイベント処理
        @param  evt イベント情報
        @retval 無し
        """
        self.ifi.NotifyEvent(self, "labeldg", True)

        font_size = int(self.spinFS.value())
        font_name = str(self.chFontName.currentText())
        self.ifi.NotifyEvent(self, "setfontinfo", (1, [font_size, font_name]))
        self.ifi.NotifyEvent(self, "setfontinfo", (2, [font_size, font_name]))
        self.close()
    ##########################################################

    def closeEvent(self, evt):
        """
        Catch close event ( by click close-box or self.close() )
        """
        self.ifi.NotifyEvent(self, "labeldg", True)
        evt.accept()


#######################################
#  DataList
#######################################
class DataList(QtWidgets.QMainWindow):
    """
    データ一覧表示ボックスクラス
    """
    ##########################################################

    def __init__(self, plot, order, postfix):
        """
        フローティングボックスのコンストラクタ
        作成のみで表示はしない
        @param  plot   親(PlotFrame)のインスタンス
        @param  order  プロッタの起動順序(タイトルバーに順番を表示)
        @param  postfix 画面タイトルに付ける親の識別子
        @retval 無し
        """

        # インターフェイスクラスのインスタンスを取得
        self.ifi = IFEvtProp(order)
        # 初期化
        self.order = order
        self.plot = plot
        self.pdg = None
        self.post = postfix
        # トレースラベルのリスト取得
        self.ldata = self.ifi.GetProperty('tracelabels')
        # リソース取得
        # フローティングボックスフレーム作成
        super(DataList, self).__init__(plot)
        self.fbFrame = Ui_FloatBox()
        if self.fbFrame is None:
            return
        self.fbFrame.setupUi(self)

        # タイトル文字列を取得
        strT = self.windowTitle()
        # 順番を付してタイトル文字列を作成
        self.setWindowTitle(strT + postfix)

        # リソースからコントロールを取得
        self.list = self.findChild(QtWidgets.QListWidget, u"specList")
        self.text = self.findChild(QtWidgets.QLineEdit, u"txEdit")
        self.spin = self.findChild(QtWidgets.QSpinBox, u"spNo")
        self.btPlot = self.findChild(QtWidgets.QPushButton, u"btPlot")
        self.btUp = self.findChild(QtWidgets.QPushButton, u"btUp")
        self.btDown = self.findChild(QtWidgets.QPushButton, u"btDown")
        self.btDelete = self.findChild(QtWidgets.QPushButton, u"btDelete")
        self.btChange = self.findChild(QtWidgets.QPushButton, u"btChange")
        self.btClose = self.findChild(QtWidgets.QPushButton, u"btClose")
        self.btDuplicate = self.findChild(
            QtWidgets.QPushButton, u"btDuplicate")  # [inamura 160723]
        self.txDupFactor = self.findChild(
            QtWidgets.QLineEdit, u"txDupFactor")  # [inamura 160723]

        # Set Icons
        btRemove_icon = self.btDelete.style().standardIcon(QtWidgets.QStyle.SP_TrashIcon)
        self.btDelete.setIcon(btRemove_icon)
        btUp_icon = self.btUp.style().standardIcon(QtWidgets.QStyle.SP_ArrowUp)
        self.btUp.setIcon(btUp_icon)
        btDown_icon = self.btDown.style().standardIcon(QtWidgets.QStyle.SP_ArrowDown)
        self.btDown.setIcon(btDown_icon)

        # データがあれば
        if len(self.ldata) > 0:
            # データ一覧リストを表示
            self.DispList()
            # データ数最大値をスピンに設定
            self.spin.setMaximum(len(self.ldata))
            self.spin.setMinimum(1)
            # 最初のトレースラベルをテキストボックスに設定
            self.text.setText(u"{0}".format(self.ldata[0]))
            # 最初のリストアイテムを選択状態とする
            self.list.setCurrentRow(0)
        else:
            # 各種ボタンを選択不可とする
            self.SetEnable(False)

        # ボタンのイベントハンドラ登録
        self.btPlot.clicked.connect(self.OnPlotParam)

        self.btUp.clicked.connect(self.OnUp)
        self.btDown.clicked.connect(self.OnDown)
        self.btDelete.clicked.connect(self.OnDelete)
        self.btChange.clicked.connect(self.OnChange)
        self.btClose.clicked.connect(self.OnClose)
        self.btDuplicate.clicked.connect(self.OnDuplicate)  # [inamura 160723]

        # リスト選択時のイベントハンドラ登録
        self.list.itemSelectionChanged.connect(self.OnSelect)

        # スピンボタンのイベントハンドラ登録
        self.spin.valueChanged[int].connect(self.OnSpin)

        # データ追加のリスナー登録
        self.ifi.AddListner('add', self.OnNotifyChangeData)
        # データ削除のリスナー登録
        self.ifi.AddListner('remove', self.OnNotifyChangeData)
        # データ順番変更のリスナー登録
        self.ifi.AddListner('shuffle', self.OnNotifyChangeData)

        # プロット条件設定ダイアログオープン・クローズのリスナー登録
        self.ifi.AddListner('plotdg', self.OnNotifyPlotDgClose)

    ##########################################################

    def DispList(self):
        """
        トレースリストを表示
        @param  無し
        @retval 無し
        """
        # リストをクリア
        self.list.clear()
        # 現在のデータを取得
        self.ldata = self.ifi.GetProperty('tracelabels')
        # No. 表示用カウンターを準備
        num = 1
        # 全データについてトレースラベルを取得
        for item in self.ldata:
            # No. の文字列作成
            strNum = "%3d : " % num
            # トレースラベルを付加
            self.list.addItem(strNum + item)
            num += 1
        # 現在のデータ数を更新
        self.num = num - 1

    ##########################################################
    def SetEnable(self, flag):
        """
        データ数各種コントロール選択可・不可を設定
        (データ数0時に選択不可)
        @param  flag   True  or False
        @retval 無し
        """
        self.btPlot.setEnabled(flag)
        self.text.setEnabled(flag)
        self.spin.setEnabled(flag)
        self.btUp.setEnabled(flag)
        self.btDown.setEnabled(flag)
        self.btDelete.setEnabled(flag)
        self.btChange.setEnabled(flag)
        self.btDuplicate.setEnabled(flag)
        # 選択不可とするの場合
        if not flag:
            # ラベル変更テキストボックスをクリア
            self.text.setText("")

    ##########################################################
    def DeselectAll(self):
        """
        全トレースを非選択状態にする
        @param  無し
        @retval 無し
        """
        for i in range(len(self.ldata)):
            self.list.Deselect(i)

    ##########################################################
    def OnUp(self, evt=None):
        """
        選択されているトレースの表示順番を上げる
        @param  evt イベント情報
        @retval 無し
        """
        # 選択中データのインデックスを取得
        select = self.list.currentRow()
        # 選択中のトレースが最初のトレースでないならば
        if select > 0:
            # データ順番変更要求イベント発行
            self.ifi.NotifyEvent(self, "shuffle", (select + 1, select))

    ##########################################################
    def OnDown(self, evt=None):
        """
        選択されているトレースの表示順番を下げる
        (選択されているトレースの一番上のみ)
        @param  evt イベント情報
        @retval 無し
        """
        # 選択中データのインデックスを取得
        select = self.list.currentRow()
        # 選択中のトレースが最後のトレースでないならば
        if select < (self.num - 1):
            # データ順番変更要求イベント発行
            self.ifi.NotifyEvent(self, "shuffle", (select + 1, select + 2))

    ##########################################################
    def OnDelete(self, evt=None):
        """
        選択されているトレースを、データオブジェクトから削除
        @param  evt イベント情報
        @retval 無し
        """
        # 選択されているトレースを取得
        select = self.list.currentRow()
        # データ削除要求イベント発行
        self.ifi.NotifyEvent(self, "remove", (select + 1))

    # [inamura 160723]-->
    ##########################################################
    def OnDuplicate(self, evt=None):
        """
        Copy selected trace with factor
        @param  evt イベント情報
        @retval 無し
        """
        # 選択されているトレースを取得
        select = self.list.currentRow()

        (xx_o, yy_o, ee_o, head_o, xunit_o, yunit_o,
         histx_o) = self.plot.dataobj.lstData[select]
        fact = float(self.txDupFactor.text())
        if fact <= 0.0:
            return

        size_of_data = len(xx_o)
        xx = np.zeros(size_of_data)
        yy = np.zeros(size_of_data)
        ee = np.zeros(size_of_data)

        for i in range(size_of_data):
            xx[i] = xx_o[i]
            if yy_o[i] < MASKVALUE:
                yy[i] = yy_o[i] * fact
                ee[i] = ee_o[i] * fact
            else:
                yy[i] = MASKVALUE
                ee[i] = 0.0

        head = head_o.copy()
        xunit = xunit_o
        yunit = yunit_o
        if histx_o is not None:
            if isinstance(histx_o, list):
                orgx = []
                for k in histx_o:
                    orgx.append(k)
            else:
                orgx = histx_o.copy()
        else:
            orgx = None

        newdata = (xx, yy, ee, head, xunit, yunit, orgx)
        self.ifi.NotifyEvent(self, "add", [newdata])
    # <--[inamura 160723]
    ##########################################################

    def OnSelect(self, evt=None):
        """
        リスト選択イベントハンドラ
        @param  evt イベント情報
        @retval 無し
        """
        # 選択されているインデックスを取得
        selNo = self.list.currentRow()
        # 選択消失イベントか
        if selNo < 0 or len(self.ldata) == 0:
            return
        # 現在プロット条件設定ダイアログが表示されているか
        if self.pdg:
            # プロット条件設定ダイアログの表示変更
            self.pdg.ChangeSelect(selNo)
        # スピンの値を設定
        self.spin.setValue(selNo + 1)
        # テキストボックスにトレースラベルを設定
        self.text.setText(self.ldata[selNo])
        # 一番上なら、Upボタンを選択不可
        if selNo == 0:
            self.btUp.setEnabled(False)
        else:
            self.btUp.setEnabled(True)
        # 一番下なら、Down ボタンを選択不可
        if selNo == len(self.ldata) - 1:
            self.btDown.setEnabled(False)
        else:
            self.btDown.setEnabled(True)

    ##########################################################
    def OnSpin(self, evt=None):
        """
        トレース変更(ラベル表示ボックス)
        @param  evt イベント情報
        @retval 無し
        """
        # データがあるなら
        if len(self.ldata) > 0:
            # スピンの値を取得
            selNo = int(self.spin.value())
            # 指定されたトレースを選択する
            try:
                self.list.setCurrentRow(selNo - 1)
            except:
                return
            # テキストボックスにトレースラベルを設定
            self.text.setText(self.ldata[selNo - 1])

    ##########################################################
    def OnChange(self, evt=None):
        """
        トレースラベル変更
        @param  evt イベント情報
        @retval 無し
        """
        # データがあるなら
        if len(self.ldata) > 0:
            # スピンボタンの値を取得
            selNo = int(self.spin.value())
            # テキストボックスの値を取得し
            tlabel = self.text.text()
            try:
                # 日本語文字列が含まれているかどうかをチェック
                try:
                    str(tlabel)
                except:
                    raise PlotException('Common', 'C025', ("Trace Label",))
            except PlotException as ex:
                PlotMessage(self.fbFrame, ex)

            else:
                # トレースラベルに設定
                self.ldata[selNo - 1] = tlabel
                self.ifi.NotifyEvent(self, "setlabeltodata", [selNo, tlabel])  # [inamura 120128]
                # リストの再表示
                self.DispList()
                # 変更したトレースを選択
                self.list.setCurrentRow(selNo - 1)
                # 当該データが表示されているページを計算
                tnum = self.ifi.GetProperty('tracenum')
                pnum = int(selNo / tnum)
                if selNo % tnum > 0:
                    pnum += 1

                # 現在のページと同じなら
                if self.ifi.GetProperty('page') == (pnum - 1):
                    # 表示範囲を変更せずにデータをプロット
                    self.ifi.NotifyEvent(self, "replot")

    ##########################################################
    def OnPlotParam(self, evt=None):
        """
        Plot Pattern ボタンイベント処理
        @param  evt イベント情報
        @retval 無し
        """
        try:
            # 選択されているデータのインデックスを取得
            select = self.list.currentRow()
        except:
            # 選択されているトレースがなかったら何もしない
            return

        # ボタンを選択不可とする
        self.btPlot.setEnabled(False)
        # ダイアログを表示
        # プロット条件設定ダイアログ表示
        self.pdg = PlotDialog(None, self.order, select, self.post)

    ##########################################################

    def HideFB(self):
        """
        フローティングボックス画面を非表示
        @param  無し
        @retval 無し
        """
        # プロットダイアログが表示されていたら
        if self.pdg is not None:
            # 消す
            self.pdg.close()
        # フローティングボックスを非表示
        self.hide()

    ##########################################################
    def ShowFB(self):
        """
        フローティングボックス画面を表示
        @param  無し
        @retval 無し
        """
        # self.fbFrame.Show()
        self.show()

    ##########################################################
    def OnNotifyChangeData(self, wid, evt, value):
        """
        データ追加またはデータ削除のイベント処理
        @param  wid イベント発生元のインスタンス
        @param  evt イベントタイプ
        @param  value イベントの値
        @retval 無し
        """
        # データ取得
        self.ldata = self.ifi.GetProperty('tracelabels')
        # データ数最大値をスピンに設定
        self.spin.setMaximum(len(self.ldata))
        self.spin.setMinimum(1)
        # リストの再表示
        self.DispList()

        # 変更がデータの追加によるものであれば
        if evt == "add":
            # 追加されたデータのインデックスを取得
            num = len(self.ldata) - len(value)
            # 変更されたデータを選択状態とする
            self.list.setCurrentRow(num)
            # 各種ボタンを選択可とする
            self.SetEnable(True)
        # 変更が削除によるもの
        elif evt == "remove":
            # 削除した結果データが無くなったのなら
            if len(self.ldata) == 0:
                # 現在プロット条件設定ダイアログが表示されているか
                if self.pdg:
                    # ロット条件設定ダイアログを閉じる
                    self.pdg.close()
                # 各種ボタンを選択不可とする
                self.SetEnable(False)
                return
            # 削除したデータが最後のデータでなかったら
            elif len(self.ldata) > value - 1:
                # 削除されたデータの次のインデックス
                num = value - 1
            # 最後のデータなら
            else:
                num = value - 2

        # 表示順番の変更
        else:
            num = value[1] - 1
        # 引数異常時
        if num > len(self.ldata) - 1:
            return
        # 変更されたデータを選択状態とする
        self.list.setCurrentRow(num)
        # 選択変更処理を実行
        self.OnSelect()
        # 現在プロット条件設定ダイアログが表示されているか
        if self.pdg:
            # プロット条件設定ダイアログの表示変更
            self.pdg.ChangeSelect(num)

    ##########################################################

    def OnNotifyPlotDgClose(self, wid, evt, value=None):
        """
        プロット条件設定画面クローズイベント処理
        Set Plotting Param ボタンを選択可設定
        @param  wid イベント発生元のインスタンス
        @param  evt イベントタイプ
        @param  value 無し
        @retval 無し
        """
        self.btPlot.setEnabled(True)
        self.pdg = None

    ##########################################################

    def OnClose(self, evt=None):
        """
        フローティングボックス画面クローズイベント処理
        画面を非表示にする。
        @param  evt イベント情報
        @retval 無し
        """
        # プロットダイアログが表示されていたら
        if self.pdg is not None:
            # 消す
            self.pdg.close()

        # フローティングボックスクローズイベント発行
        self.ifi.NotifyEvent(self, "fbclose")
        # フローティングボックスを非表示にする
        # self.fbFrame.Hide()
        self.hide()
    ##########################################################

    def closeEvent(self, event):
        """
        Ignore the click of close-box event to execute OnClose() (hide)

        @param event
        @retval none
        """
        event.ignore()
        self.OnClose()


#######################################
#  TextFile
#######################################

FILE_HEADER = "**  MPLOT FILE **"
XUNIT = "X unit"
YUNIT = "Y unit"
XLABEL = "X label"  # [inamrua 110620]
YLABEL = "Y label"  # [inamrua 110620]


class TextFile(object):
    """
    テキストファイル
    """

    ######################################################
    def __init__(self, order, histFlag=True):
        """
        コンストラクタ
        @param  order  プロッタ番号
        @param histFlag If True, output text with histogram format
        @retval 無し
        """

        # インターフェイスクラスのインスタンスを取得
        self.ifi = IFEvtProp(order)

        self.histFlag = histFlag  # [inamura 100819]
        self.mainTitle = ""
        self.subTitle = ""

    ######################################################

    def ReadFrom(self, path):
        """
        テキストファイルを開いて読み込む
        @param  path ファイルパス
        @retval 無し
        """
        # 拡張子を分離
        fbody, ext = os.path.splitext(path)
        # 拡張子がtxtでなければ
        if ext != "txt":
            path = "%s.txt" % fbody

        # 指定されたファイルを開く
        try:
            fp = codecs.open(path, 'r', "utf-8")
        except:
            raise PlotException('Common', 'C006', (path,))
            return
        # タイトル行を読み込む
        line = fp.readline().strip()
        # 正しいタイトル行か
        if line != FILE_HEADER:
            try:
                data = self._ReadOtherFile(fp, line)
            except:
                raise PlotException('Common', 'C015', (path,))
                return
        else:
            # データ読み込み
            data = self._ReadTextFile(fp)

        # Manyoコンテナのマスク処理に対応
        y = data[1]
        e = data[2]
        ny = []
        ne = []
        for ay, ae in zip(y, e):
            # エラー値がマイナスなら強度はMASKVALUE
            if ae < 0:
                ny.append(MASKVALUE)
                ne.append(0.0)
            else:
                ny.append(ay)
                ne.append(ae)
        if len(data) == 3: # _ReadOtherFile
            newdata = (data[0], ny, ne)
        elif len(data) == 6: # _ReadTextFile
            newdata = (data[0], ny, ne, data[3], data[4], data[5])

        # データ追加イベント発行
        self.ifi.NotifyEvent(self, "add", [newdata])

    ######################################################
    def _ReadTextFile(self, fp):
        """
        テキストファイルにデータを出力(1トレース)
        @param  fp ファイルポインタ
        @retval data (x, y, er, header, xunit, yunit)
        """

        stat = 0
        x = []
        y = []
        er = []
        header = {}
        xunit = ""
        yunit = ""
        xlabel = ""  # [inamura 110620]
        ylabel = ""  # [inamura 110620]
        isFirstTitle = True

        # データの終了まで
        while 1:
            # 読み込み終了
            if stat == 5:
                # return (x, y, er, header, xunit, yunit)
                fp.close
                return (x, y, er, header, (xlabel, xunit), (ylabel, yunit))

            line = fp.readline().strip()
            if "--------" in line:
                stat += 1
            elif stat == 1:
                if isFirstTitle:
                    self.mainTitle = line.strip()
                    isFirstTitle = False
                else:
                    self.subTitle = line.strip()
            elif stat == 2:
                # ヘッダー読み込み
                words = line.split(':')
                if len(words) == 2:
                    header[words[0]] = words[1]
            elif stat == 3:
                # 単位読み込み
                words = line.split(':')
                if len(words) == 2 and XUNIT in line:
                    xunit = words[1]
                elif len(words) == 2 and YUNIT in line:
                    yunit = words[1]
                # [inamura 110620]-->
                elif len(words) == 2 and XLABEL in line:
                    xlabel = words[1]
                elif len(words) == 2 and YLABEL in line:
                    ylabel = words[1]
                # <--[inamura 110620]
            elif stat == 4:
                # データ読み込み
                nums = line.split()
                if len(nums) == 3:
                    try:
                        xx = (float(nums[0]))
                        yy = (float(nums[1]))
                        err = (float(nums[2]))
                    except:
                        pass
                    else:
                        x.append(xx)
                        y.append(yy)
                        er.append(err)
                # 最後のXデータか
                # ヒストグラムデータの場合、Xデータの個数が1個多い
                elif len(nums) == 1:
                    try:
                        xx = (float(nums[0]))
                    except:
                        pass
                    else:
                        x.append(xx)
        fp.close

    ######################################################
    def _ReadOtherFile(self, fp, line):
        """
        テキストファイルにデータを出力(1トレース)
        FastPlot で出力したデータではないファイルの読み込み
        @param  fp ファイルポインタ
        @param  line 最初に読み込んだ行
        @retval data (x, y, er)
        """
        x = []
        y = []
        er = []
        # [inamura 120127]-->
        splitFlag = False
        if line.find(",") >= 0:
            splitFlag = True
        # <--[inamura 120127]
        # データの終了まで
        # [inamrua 160126]-->
        header = {}
        xunit = ""
        yunit = ""
        xlabel = ""
        ylabel = ""
        while True:
            if line[0] == "#":
                tmp = 0
                for i in range(1, len(line)):
                    if line[i] != "#":
                        tmp = i
                        break
                tmp_line = line[tmp:]
                words = tmp_line.split(':')
                if len(words) == 2:
                    if XUNIT in tmp_line:
                        xunit = words[1]
                    elif YUNIT in tmp_line:
                        yunit = words[1]
                    elif XLABEL in tmp_line:
                        xlabel = words[1]
                    elif YLABEL in tmp_line:
                        ylabel = words[1]
                    else:
                        header[words[0].strip()] = words[1].strip()
                line = fp.readline().strip()
            else:
                # [inamura 120127]-->
                if splitFlag:
                    line = line.replace(" ", "")
                    nums = line.split(",")
                else:
                    nums = line.split()
                # <--[inamura 120127]
                if len(nums) >= 2:
                    try:
                        xx = (float(nums[0]))
                    except:
                        fp.close
                        raise
                    x.append(xx)

                    try:
                        yy = (float(nums[1]))
                    except:
                        if (i + 1) < lnum:
                            raise
                    else:
                        y.append(yy)

                    try:
                        err = (float(nums[2]))
                    except:
                        # エラーが無い場合は、Yの平方根をエラーとする
                        if yy <= 0.0:
                            err = 0.0
                        else:
                            err = np.sqrt(yy)
                    er.append(err)
                # データ読み込み
                line = fp.readline().strip()
                if line == "":
                    break
                # [inamura 120127]-->
                splitFlag = False
                if line.find(",") >= 0:
                    splitFlag = True
                # <--[inamura 120127]

        fp.close

        ret = (x, y, er)
        if len(header) != 0 or xunit != "" or yunit != "" or xlabel != "" or ylabel != "":
            ret = (x, y, er, header, (xlabel, xunit), (ylabel, yunit))
        return ret
        # return (x,y,er)
        # <--[inamura 160126]

    ######################################################
    def WriteTo(self, path, dataobj, maskInfo=None):
        """
        テキストファイルにデータを出力(トレースの数だけ)
        @param  path ファイルパス
        @param  dataobj データクラスのインスタンス
        @retval 無し
        """

        # 拡張子を分離
        fbody, ext = os.path.splitext(path)

        num = 0
        for data in dataobj.lstData:
            #            label = data[3]["Label"]
            #            fname = "%s-%d %s.txt" % (fbody, num, label)
            # First file name is same as given path
            if num == 0:
                fname = "{}.txt".format(fbody)
            # Second or later file name are added numbering.
            else:
                fname = "%s-%d.txt" % (fbody, num)    # 2009.06.15 Minakawa 修正
            num += 1
            # 指定されたファイルを開く
            try:
                fp = codecs.open(fname, 'w', "utf-8")
            except:
                raise PlotException('Common', 'C006', (fname,))
            else:
                self._WriteTextFile(fp, data, maskInfo)

    ######################################################
    def _WriteTextFile(self, fp, data, maskInfo=None):
        """
        テキストファイルにデータを出力(1トレース)
        @param  fp ファイルポインタ
        @param  data データ
        @retval 無し
        """
        # ヘッダー書き込み
        fp.write(FILE_HEADER + "\n")
        fp.write("-------------------\n")
        # タイトル書き込み
        main = self.ifi.GetProperty("title1")
        sub = self.ifi.GetProperty("title2")
        fp.write(main + "\n")
        fp.write(sub + "\n")
        fp.write("-------------------\n")
        # ヘッダー書き込み
        header = data[3]
        for item in header:
            item = "%s: %s\n" % (item, header[item])
            fp.write(item)
        fp.write("-------------------\n")
        # [inamura 110620]-->
        # X unit 書き込み
        # xunit = "%s: %s\n" % (XUNIT, data[4])
        # fp.write(xunit)
        # Y unit 書き込み
        # yunit = "%s: %s\n" % (YUNIT, data[5])
        # fp.write(yunit)
        xlabel = self.ifi.GetProperty("xlabel")
        ylabel = self.ifi.GetProperty("ylabel")
        labels = "%s:%s\n" % (XLABEL, xlabel)
        labels += "%s:%s\n" % (XUNIT, data[4])
        labels += "%s:%s\n" % (YLABEL, ylabel)
        labels += "%s:%s\n" % (YUNIT, data[5])
        fp.write(labels)
        # <--[inamura110620]

        # データヘッダ書き込み
        # [inamura 110613]-->
        # dhead = "\n         X               Y               Error\n"
        dhead = "\n"
        if len(xlabel) <= 15:
            dhead += "%s " % xlabel.center(15)
        else:
            dhead += "%s " % xlabel
        if len(ylabel) <= 15:
            dhead += "%s " % ylabel.center(15)
        else:
            dhead += "%s " % ylabel
        dhead += "%15s\n" % ("     Error     ")
        fp.write(dhead)
        fp.write("-----------------------------------------------\n")
        # [inamura 100819]-->
        # X のオリジナルデータがあるか
        # if data[6] is None:
        #    xx = data[0]
        # else:
        #    # ヒストグラムデータのx値
        #    xx = data[6]
        # if existing histogram data AND Histogram output mode?
        # if (data[6] is not None) and self.histFlag:
        if data[6] is not None and self.histFlag:  # [inamura 171107]
            xx = data[6]
        else:
            xx = data[0]
        # <--[inamura 100819]

        # データ書き込み
        # for i in range(len(data[1])):
        #    dline = "%15e %15e %15e\n" % (xx[i],data[1][i],data[2][i] )
        #    fp.write(dline)
        if maskInfo is None:
            for i in range(len(data[1])):
                dline = "%15e %15e %15e\n" % (xx[i], data[1][i], data[2][i])
                fp.write(dline)
        else:
            if len(maskInfo) == 2:
                isIgnoreMaskVal = maskInfo[0]
                if isIgnoreMaskVal:
                    for i in range(len(data[1])):
                        if data[1][i] < MASKVALUE:
                            dline = "%15e %15e %15e\n" % (
                                xx[i], data[1][i], data[2][i])
                            fp.write(dline)
                else:
                    repVal = maskInfo[1]
                    for i in range(len(data[1])):
                        if data[1][i] < MASKVALUE:
                            dline = "%15e %15e %15e\n" % (
                                xx[i], data[1][i], data[2][i])
                        else:
                            dline = "%15e %15e %15e\n" % (
                                xx[i], repVal, data[2][i])
                        fp.write(dline)

        # ヒストグラムデータなら
        if len(xx) > len(data[1]):
            # 最後のX値を書き込む
            dline = "%15e \n" % xx[i + 1]
            fp.write(dline)

        # データ終了
        fp.write("-----------------------------------------------\n")
        # ファイルをクローズ
        fp.close


#########################################
#       SetAxisGridStyleDialog
#########################################
class SetAxisGridStyleDialog(QtWidgets.QDialog):
    """
    AxisGridStyle 設定ダイアログクラス
    """
    ##########################################################

    def __init__(self, parent, order, postfix):
        """
        コンストラクタ
        @param  parent   親ウィンドウのID
        @param  order  プロッタの起動順序
        @param  postfix 画面タイトルに付ける親の識別子
        @retval 無し
        """

        self.ifi = IFEvtProp(order)
        self.parent = parent

        # リソース取得
        super(SetAxisGridStyleDialog, self).__init__(parent)
        self.dialog = Ui_DgGridSetting()
        if self.dialog is None:
            return
        self.dialog.setupUi(self)

        # アイコンを設定
        # self.dialog.SetIcon(Images().GetMainIcon())

        # ボタンのイベントハンドラを登録
        self.btClose = self.findChild(QtWidgets.QPushButton, u"btClose")
        self.btClose.clicked.connect(self.OnClose)

        # リソースよりコントロールを取得
        # コンボボックス
        self.cbXLC = self.findChild(QtWidgets.QComboBox, u'cbXlineColor')
        self.cbXLS = self.findChild(QtWidgets.QComboBox, u'cbXlineStyle')
        self.cbYLC = self.findChild(QtWidgets.QComboBox, u'cbYlineColor')
        self.cbYLS = self.findChild(QtWidgets.QComboBox, u'cbYlineStyle')

        # コンボボックスのイベントハンドラ登録
        self.cbXLC.activated.connect(self.OnComboXLC)
        self.cbXLS.activated.connect(self.OnComboXLS)
        self.cbYLC.activated.connect(self.OnComboYLC)
        self.cbYLS.activated.connect(self.OnComboYLS)

        # スピンボタン
        self.spinXLW = self.findChild(QtWidgets.QSpinBox, u'spXlineWidth')
        self.spinYLW = self.findChild(QtWidgets.QSpinBox, u'spYlineWidth')

        # スピンボタンのイベントハンドラ登録
        self.spinXLW.valueChanged[int].connect(self.OnSpinXLW)
        self.spinYLW.valueChanged[int].connect(self.OnSpinYLW)

        # [X]ボタン押下時のイベントハンドラ登録
        # self.dialog.Bind(wx.EVT_CLOSE, self.OnClose)

        # ダイアログオープンイベント発行
        self.ifi.NotifyEvent(self, "setaxisgridstyledg", False)

        # Set Values
        self.initialize()

        # ダイアログ表示
        self.show()

    ##########################################################
    def initialize(self):
        """
        """
        ddic = self.ifi.GetProperty('gridstyledic')
        self.cbXLC.setCurrentIndex(self._GetAttrNum(ddic["XlineColor"], TraceAtt.color) - 1)
        self.cbYLC.setCurrentIndex(self._GetAttrNum(ddic["YlineColor"], TraceAtt.color) - 1)
        self.cbXLS.setCurrentIndex(self._GetAttrNum(ddic["XlineStyle"], TraceAtt.linestyle))
        self.cbYLS.setCurrentIndex(self._GetAttrNum(ddic["YlineStyle"], TraceAtt.linestyle))
        self.spinXLW.setValue(self._GetAttrNum(ddic["XlineWidth"], TraceAtt.linewidth))
        self.spinYLW.setValue(self._GetAttrNum(ddic["YlineWidth"], TraceAtt.linewidth))

    ##########################################################
    def _GetAttrNum(self, value, lst):
        """
        指定された値を検索しリストのインデックスに変換
        @param  value 値
        @param  lst 値
        @retval インデックス
        """
        # リストから指定された値を検索
        i = 0
        for item in lst:
            # 値と等しいか
            if item == value:
                # インデックスを返す
                return i
            i += 1
        # 検索できなかった場合
        return 0
    ##########################################################

    def OnComboXLC(self, evt=None):
        """
        ラインColor変更イベント処理
        @param  evt イベント情報
        @retval 無し
        """
        lc = TraceAtt.color[self.cbXLC.currentIndex() + 1]
        ddic = self.ifi.GetProperty('gridstyledic')
        ddic['XlineColor'] = lc
        self.ifi.NotifyEvent(self, 'replot', None)
    ##########################################################

    def OnComboXLS(self, evt=None):
        """
        ラインスタイル変更イベント処理
        @param  evt イベント情報
        @retval 無し
        """
        ls = TraceAtt.linestyle[self.cbXLS.currentIndex()]
        ddic = self.ifi.GetProperty('gridstyledic')
        ddic['XlineStyle'] = ls
        self.ifi.NotifyEvent(self, 'replot', None)
    ##########################################################

    def OnSpinXLW(self, evt=None):
        """
        """
        lw = TraceAtt.linewidth[int(self.spinXLW.value())]
        if lw == 0:
            lw = 0.5
        ddic = self.ifi.GetProperty('gridstyledic')
        ddic['XlineWidth'] = lw
        self.ifi.NotifyEvent(self, 'replot', None)

    ##########################################################
    def OnComboYLC(self, evt=None):
        """
        ラインスタイル変更イベント処理
        @param  evt イベント情報
        @retval 無し
        """
        lc = TraceAtt.color[self.cbYLC.currentIndex() + 1]
        ddic = self.ifi.GetProperty('gridstyledic')
        ddic['YlineColor'] = lc
        self.ifi.NotifyEvent(self, 'replot', None)

    ##########################################################
    def OnComboYLS(self, evt=None):
        """
        ラインスタイル変更イベント処理
        @param  evt イベント情報
        @retval 無し
        """
        ls = TraceAtt.linestyle[self.cbYLS.currentIndex()]
        ddic = self.ifi.GetProperty('gridstyledic')
        ddic['YlineStyle'] = ls
        self.ifi.NotifyEvent(self, 'replot', None)

    ##########################################################
    def OnSpinYLW(self, evt=None):
        """
        """
        lw = TraceAtt.linewidth[int(self.spinYLW.value())]
        if lw == 0:
            lw = 0.5
        ddic = self.ifi.GetProperty('gridstyledic')
        ddic['YlineWidth'] = lw
        self.ifi.NotifyEvent(self, 'replot', None)

    ##########################################################
    def OnClose(self, evt=None):
        """
        Closeボタンイベント処理
        @param  evt イベント情報
        @retval 無し
        """
        self.close()
    ##########################################################

    def closeEvent(self, evt):
        """
        """
        self.ifi.NotifyEvent(self, "setaxisgridstyle2ddg", True)
        evt.accept()


#######################################
#  PlotFrame
#######################################
class PlotFrame(QtWidgets.QMainWindow):
    """
    プロッタフレーム画面クラス
    プロッタの最上位クラス
    """
    #########################################################

    def __init__(self, parent, data=None, order=1, fTitle=None):
        """
        コンストラクタ
        @param  parent 親ウィンドウのID, None の場合はトップレベルウィンドウ
        @param  data 　ヒストグラムオブジェクト、またはヒストグラムのリスト
        @param  order  プロッタ番号(タイトルバーに順番を表示)
        @param  fTitle フレームタイトル
        @retval 無し
        """
        super(PlotFrame, self).__init__(parent)

        self.order = order
        self.frame = Ui_FastPlot()
        # リソースからフレームが取得できなかった
        if self.frame is None:
            return
        self.frame.setupUi(self)

        # アイコンの設定
        # self.frame.SetIcon(Images().GetMainIcon())
        # フレームのタイトルに番号を付ける
        strT = self.windowTitle()
        # フレームのタイトルが指定されているか
        if fTitle:
            self.post = " - %s" % fTitle
        else:
            # フレームのタイトルに番号を付ける
            self.post = " (%d)" % order

        self.setWindowTitle(strT + self.post)

        # データオブジェクトを設定
        self.dataobj = PlotData(self, data, order)

# -----------------[ work progress point]
        # panel = self.res.GetCtrl(self.frame, 'panel')

        # キャンバスを作成
        self.fig = Figure((8.0, 5.0), 90)

        self.canvas = FigCanvas(self.fig)
        # 垂直サイザーを作成
        layout = self.findChild(QtWidgets.QVBoxLayout, u"topLayout")
        # プロッタフレーム用ツールバー作成
        self.toolbar = ChartToolBar2(self, order)
        self.toolbar.canvas.draw_idle()
        layout.insertWidget(0, self.toolbar)
        # サイザーにキャンバスを追加
        layout.insertWidget(1, self.canvas)

        # サイザーにパネルを追加
        self.window = QtWidgets.QWidget()
        self.window.setLayout(layout)
        self.setCentralWidget(self.window)

        # マウス移動イベント登録(X-Y 表示用)
        self.canvas.mpl_connect('motion_notify_event', self.UpdateXY)
        # キー押下イベント登録
        self.canvas.mpl_connect('key_press_event', self.OnKeyPress)

        # メニューを表示
        self.SetMenus()

        # ボタンのコントロール取得
        # panel = self.res.GetCtrl(self.frame, 'panel')
        # self.btPrv=self.res.GetCtrl(panel, 'btPrev')
        # self.btNxt=self.res.GetCtrl(panel, 'btNxt')
        panel = self.findChild(QtWidgets.QFrame, u"ButtonFrame")
        self.btPrv = panel.findChild(QtWidgets.QPushButton, u"btPrev")
        self.btNxt = panel.findChild(QtWidgets.QPushButton, u"btNxt")

        # 表示テキストのコントロール取得
        # self.numtxt = self.res.GetCtrl(panel, 'strNum')
        # self.xytxt = self.res.GetCtrl(panel, 'strXY')
        self.numtxt = panel.findChild(QtWidgets.QLabel, u"strNum")
        self.xytxt = panel.findChild(QtWidgets.QLabel, u"strXY")

        # panel.Bind(wx.EVT_BUTTON, self.OnPrevious, id=self.res.GetId('btPrev'))
        # panel.Bind(wx.EVT_BUTTON, self.OnNext, id=self.res.GetId('btNxt'))
        self.btPrv.clicked.connect(self.OnPrevious)
        self.btNxt.clicked.connect(self.OnNext)
        # クローズイベント登録
        # self.frame.Bind(wx.EVT_CLOSE, self.OnClose)
        # アイコン化イベント登録
        # self.frame.Bind(wx.EVT_ICONIZE, self.OnIconize)
        # グラフを表示
        Chart(self, self.dataobj)

        # インターフェイスクラスのインスタンスを取得
        self.ifi = IFEvtProp(order)

        # フローティングボックスクローズのリスナー登録
        self.ifi.AddListner('fbclose', self.OnNotifyFBClose)

        # ダイアログオープン・クローズのリスナー登録
        self.ifi.AddListner('paradg', self.OnNotifyChildDg)
        self.ifi.AddListner('titledg', self.OnNotifyChildDg)
        self.ifi.AddListner('labeldg', self.OnNotifyChildDg)
        self.ifi.AddListner('setaxisgridstyle2ddg', self.OnNotifyChildDg)
        self.ifi.AddListner('setaxistickstyle2ddg', self.OnNotifyChildDg)

        # アイコン化処理のリスナー登録
        self.ifi.AddListner('doiconize', self.OnNotifyDoIconize)
        # プロッタ画面クローズ要求のリスナー登録
        self.ifi.AddListner('close', self.OnClose)
        # 印刷要求のリスナー登録
        self.ifi.AddListner('print', self.OnPrint)
        # 画像保存要求のリスナー登録
        self.ifi.AddListner('save', self.OnNotifySave)
        # ページ変更のリスナー登録
        self.ifi.AddListner('disppage', self.OnNotifyDisplayPage)
        # Load and Save data as text
        self.ifi.AddListner('loaddatafromtext', self.OnNotifyLoadDataFromText)
        self.ifi.AddListner('savedataastext', self.OnNotifySaveDataAsText)

        # データ数を表示
        self.OnNotifyDisplayPage(None, "page", 1)
        # プロッタフレームを表示
        # self.frame.Show(True)
        self.show()
        # データ一覧表示ボックスを作成(非表示のまま)
        self.fb = DataList(self, order, self.post)

        # [inamura 120131]-->
        def_att = DefaultFastPlotAtt()
        path_dic = def_att.loadPath()
        self.DefaultDialogPath = {}
        self.DefaultDialogPath["OPEN"] = path_dic["OPENPATH"]
        self.DefaultDialogPath["SAVE"] = path_dic["SAVEPATH"]
        # <--[inamura 120131]

    ######################################################
    def SetMenus(self):
        """
        メニューのイベントハンドラを登録
        矢印キーをメニューのアクセラレータとして登録
        (Windows では、'key_press_event'イベントで矢印キー押下
     　　　　イベントを取れなかったため、アクセラレータキーとして登録)
        @param  無し
        @retval 無し
        """
        # File メニューのイベントハンドラー登録
        # self.frame.Bind(wx.EVT_MENU, self.OnOpen, id=self.res.GetId('menu_open'))
        # self.frame.Bind(wx.EVT_MENU, self.OnSaveas, id=self.res.GetId('menu_saveas'))
        # self.frame.Bind(wx.EVT_MENU, self.OnSaveHistas, id=self.res.GetId('menu_saveas_hist')) ##[inamura 100819]
        # self.frame.Bind(wx.EVT_MENU, self.OnPrint, id=self.res.GetId('menu_print'))
        # self.frame.Bind(wx.EVT_MENU, self.OnClose , id=self.res.GetId('menu_exit'))
        self.MenuWidgets = {}
        self.menuBar = QtWidgets.QMenuBar(self)
        menu_FileMenu = QtWidgets.QMenu("File")
        menu_open = menu_FileMenu.addAction("Open ...")
        menu_saveas = menu_FileMenu.addAction("Save as ...")
        menu_savehistas = menu_FileMenu.addAction("Save Histogram as ...")
        menu_print = menu_FileMenu.addAction("Print ...")
        menu_exit = menu_FileMenu.addAction("Exit")

        menu_open.triggered.connect(self.OnOpen)
        menu_saveas.triggered.connect(self.OnSaveas)
        menu_savehistas.triggered.connect(self.OnSaveHistas)
        menu_print.triggered.connect(self.OnPrint)
        menu_exit.triggered.connect(self.OnClose)

        self.MenuWidgets["open"] = menu_open
        self.MenuWidgets["saveas"] = menu_saveas
        self.MenuWidgets["savehistas"] = menu_savehistas
        self.MenuWidgets["print"] = menu_print
        self.MenuWidgets["exit"] = menu_exit

        self.menuBar.addMenu(menu_FileMenu)

        # Display　メニューのイベントハンドラー登録
        # self.frame.Bind(wx.EVT_MENU, self.OnShow, id=self.res.GetId('menu_show'))
        # self.frame.Bind(wx.EVT_MENU, self.OnParam, id=self.res.GetId('menu_para'))
        # self.frame.Bind(wx.EVT_MENU, self.OnLabel, id=self.res.GetId('menu_label'))
        # self.frame.Bind(wx.EVT_MENU, self.OnTitle, id=self.res.GetId('menu_title'))
        # Making Display Menu
        menu_Display = QtWidgets.QMenu("Display")
        menu_showplot = menu_Display.addAction("Show Plotting Data...")
        menu_Display.addSeparator()
        menu_setgraph = menu_Display.addAction("Set Graph Parameter...")
        menu_settitle = menu_Display.addAction("Set Graph Title...")
        menu_scalelabel = menu_Display.addAction("Set Scale Label...")
        menu_gridon = menu_Display.addAction("Set XY Grid style...")
        menu_tickset = menu_Display.addAction("Set Ticks style...")
        self.menuBar.addMenu(menu_Display)

        menu_showplot.triggered.connect(self.OnShow)
        menu_setgraph.triggered.connect(self.OnParam)
        menu_settitle.triggered.connect(self.OnTitle)
        menu_scalelabel.triggered.connect(self.OnLabel)
        menu_gridon.triggered.connect(self.OnGrid)
        menu_tickset.triggered.connect(self.OnTicks)

        self.MenuWidgets["show"] = menu_showplot
        self.MenuWidgets["setgraph"] = menu_setgraph
        self.MenuWidgets["settitle"] = menu_settitle
        self.MenuWidgets["scalelabel"] = menu_scalelabel
        self.MenuWidgets["gridon"] = menu_gridon
        self.MenuWidgets["tickset"] = menu_tickset

        self.setMenuBar(self.menuBar)

        # Making Process Menu
        menu_Process = QtWidgets.QMenu("Process")
        menu_fitting = menu_Process.addAction("Fitting...")
        self.menuBar.addMenu(menu_Process)
        menu_fitting.triggered.connect(self.OnFitting)

        self.MenuWidgets["fitting"] = menu_fitting
        # Process メニューのイベントハンドラー登録
#        self.frame.Bind(wx.EVT_MENU, self.OnProcess,  id=xrc.XRCID('menu_process'))

        """
        # アクセラレータキーの、メニューIDを取得
        LEFT_ID = wx.NewId()
        RIGHT_ID = wx.NewId()
        UP_ID = wx.NewId()
        DOWN_ID = wx.NewId()
        # キーとコードのディクショナリを作成
        self.arrows = { LEFT_ID  : "left",
                        RIGHT_ID : "right",
                        UP_ID    : "up",
                        DOWN_ID  : "down" }
        # アクセラレータテーブルを作成
        aTable = wx.AcceleratorTable([(wx.ACCEL_NORMAL, wx.WXK_LEFT, LEFT_ID),
                              (wx.ACCEL_NORMAL, wx.WXK_RIGHT, RIGHT_ID),
                              (wx.ACCEL_NORMAL, wx.WXK_UP, UP_ID),
                              (wx.ACCEL_NORMAL, wx.WXK_DOWN, DOWN_ID)
                              ])
        # フレームにアクセラレータキーを割り付ける
        self.frame.SetAcceleratorTable(aTable)
        # アクセラレータキーのイベントハンドラを登録
        self.frame.Bind(wx.EVT_MENU, self.OnArrowKeys, id=LEFT_ID)
        self.frame.Bind(wx.EVT_MENU, self.OnArrowKeys, id=RIGHT_ID)
        self.frame.Bind(wx.EVT_MENU, self.OnArrowKeys, id=UP_ID)
        self.frame.Bind(wx.EVT_MENU, self.OnArrowKeys, id=DOWN_ID)
        """

    ######################################################
    def OnOpen(self, *args):
        """
        Open メニューイベント処理
        テキストファイルを開いて読み込む
        印刷ダイアログを表示
        @param  *args イベント情報
        @retval 無し
        """
        # Txtファイルのパスを取得
        # [inamura 120128]-->
        # path = AcqPath().GetHome()
        # tdir = os.path.join(path, "ana")
        tdir = self.DefaultDialogPath["OPEN"]
        # <--[inamura 120128]
        # ファイルを開くダイアログを表示
        filename, filt = QtWidgets.QFileDialog.getOpenFileName(
            self, "Open text file", tdir, filter='Text Files (*.txt)')

        # OK であればファイルを開く
        if filename != "":
            try:
                # TextFile(self.order).ReadFrom(filename)
                print("#[inamura 220627] OnOpen")
                TF = TextFile(self.order)
                TF.ReadFrom(filename)
                title1 = "*"
                title2 = "*"
                if TF.mainTitle != "":
                    title1 = TF.mainTitle
                if TF.subTitle != "":
                    title2 = TF.subTitle
                if title1 != "*" or title2 != "*":
                    print("#[inamura 220627] title1,title2={},{}".format(
                        title1, title2))
                    self.ifi.NotifyEvent(self, "title", (title1, title2))
                self.DefaultDialogPath["OPEN"] = filename[:filename.rfind("/")]
            except PlotException as ex:
                PlotMessage(self, ex)

    ######################################################

    def OnSaveas(self, *args):
        """
        Save as メニューイベント処理
        テキストファイルに出力(トレースの数だけ)
        印刷ダイアログを表示
        @param  *args イベント情報
        @retval 無し
        """
        # Txtファイルのパスを取得
        tdir = self.DefaultDialogPath["SAVE"]
        # ファイル保存ダイアログを表示
        dlg = SetSaveAsTextDialog(self, isHist=False)
        """
        filename,filt =QtWidgets.QFileDialog.getSaveFileName(self, "Save to text files",tdir, filter='Text Files (*.txt)' )
        # OK であればファイルを保存
        if filename!="":
            try:
                TextFile(self.order, False).WriteTo(filename, self.dataobj)
                self.DefaultDialogPath["SAVE"]=filename[:filename.rfind("/")]
            except PlotException, ex:
                PlotMessage(self, ex)
        """

    ######################################################
    def OnSaveHistas(self, *args):
        """
        Save as メニューイベント処理
        テキストファイルに出力(トレースの数だけ)
        印刷ダイアログを表示
        @param  *args イベント情報
        @retval 無し
        """
        # [inamura 160205]-->
        num_of_not_hist = 0
        for data in self.dataobj.lstData:
            if len(data[0]) != (len(data[1]) + 1) or data[6] is not None:
                num_of_not_hist += 1
        if num_of_not_hist != 0:
            if num_of_not_hist == 1:
                msg = u"One trace does not include histogram data. This trace are saved as same format as Save As... menu."
            else:
                msg = u"%d traces do not include histogram data. These traces are saved as same format as Save As... menu." % (
                    num_of_not_hist)
            QtWidgets.QMessageBox().warning(self, u"Warning", msg)

        dlg = SetSaveAsTextDialog(self, isHist=True)
        """
        # Txtファイルのパスを取得
        tdir = self.DefaultDialogPath["SAVE"]
        # ファイル保存ダイアログを表示
        filename,filt =QtWidgets.QFileDialog.getSaveFileName(self, "Save to text files",tdir, filter='Text Files (*.txt)' )
        # OK であればファイルを保存
        if filename!="":
            try:
                TextFile(self.order).WriteTo(filename, self.dataobj)
                self.DefaultDialogPath["SAVE"]=filename[:filename.rfind("/")]
            except PlotException, ex:
                PlotMessage(self, ex)
        """

    ######################################################
    def OnPrint(self, *args):
        """
        Print メニューイベント処理
        print コマンド処理        印刷ダイアログを表示
        @param  *args イベント情報
        @retval 無し
        """
        # トレース選択マークを消すためにprintfigイベントを発行
        self.ifi.NotifyEvent(self, "printfig", False)
        # プラットフォームを判定
        if os.name == "posix" or os.name == "mac":
            fname = "_plot%d.ps" % self.order
            # テンポラリファイルの絶対パスを作成(指定されたテンポラリディレクトリの下)
            tmpf = os.path.join(tempfile.gettempdir(), fname)
            # Linux または Mac OS なら
            try:
                try:
                    # ポストスクリプトファイルを作成
                    self.canvas.print_figure(
                        tmpf, dpi=600, orientation="landscape")
                except:
                    raise PlotException('Common', 'C018', (tmpf,))
                # スプーラにファイルを送信
                ret = os.system("lpr " + tmpf)
                # エラーがあったなら
                if ret > 0:
                    # エラーメッセージを表示
                    raise PlotException('Common', 'C023', ())

            except PlotException as ex:
                PlotMessage(self.frame, ex)
            time.sleep(2.0)
        # Linux または Mac OS 以外(Windowsを想定)
        # [inamura 210129] save figure file instead of use of printer because not sure about printing way on Windows...
        else:
            filepath, filt = QtWidgets.QFileDialog.getSaveFileName(
                self, u"Save the image ...", os.getcwd(), filter=u"(*.png *.eps)")
            filepath = str(filepath)
            if filepath == "":
                return
            file_name = os.path.basename(filepath)
            dir_name = os.path.dirname(filepath)
            base, extcode = os.path.splitext(file_name)
            print("#[inamura 210129] base, extcode=" + base + ", " + extcode)
            if extcode == ".png" or extcode == ".eps":
                try:
                    self.canvas.print_figure(filepath, dpi=300)
                except:
                    raise UserWarning(
                        "Failed to save file as {}".format(filepath))
            else:
                raise UserWarning("File name must be type of .png or .eps")
            """
            # 現在の解像度を取得
            dpi = self.canvas.figure.dpi.get()
            # 印刷用に解像度を高くする
            self.canvas.figure.dpi.set(180)
            #用紙をA4に設定
            self.canvas.printerData.SetPaperId(wx.PAPER_A4)
            # 用紙を横方向に設定
            self.canvas.printerData.SetOrientation(wx.LANDSCAPE)
            # マージンを設定
            self.canvas.printer_margin = 1.0
            # 印刷ダイアログを表示
            self.canvas.Printer_Print()
            # 解像度を元に戻す
            self.canvas.figure.dpi.set(dpi)
            """

        # トレース選択マークを再表示するためにprintfigイベントを発行
        self.ifi.NotifyEvent(self, "printfig", True)

        # 再描画
        self.canvas.draw()

    ######################################################
    def OnNotifySave(self, wid, evt, fname):
        """
        画像保存処理
        @param  wid イベント発生元のインスタンス
        @param  evt イベントタイプ
        @param  fname ファイル名
        @retval 無し
        """
        # トレース選択マークを消すためにprintfigイベントを発行
        self.ifi.NotifyEvent(self, "printfig", False)
        try:
            try:
                self.canvas.print_figure(fname, dpi=300)
            except:
                raise PlotException('Common', 'C018', (fname,))
        except PlotException as ex:
            PlotMessage(self.frame, ex)
        # トレース選択マークを再表示するためにprintfigイベントを発行
        self.ifi.NotifyEvent(self, "printfig", True)
        # 再描画
        self.canvas.draw()

    ######################################################
    def OnNotifySaveDataAsText(self, wid, evt, args):
        """
        Save plotting data as text file
        @param wid instance which published this event
        @param evt event type
        @param args tupple of filepath, isHist, useMask maskVal
        @retval None
        """
        fpath, isHist, useMask, maskVal = args
        maskInfo = None
        if useMask:
            if maskVal is None:
                maskInfo = (False, MASKVALUE)
            else:
                maskInfo = (False, float(maskval))
        else:
            maskInfo = (True, 0)

        TextFile(self.order, isHist).WriteTo(fpath, self.dataobj, maskInfo)
        self.DefaultDialogPath["SAVE"] = os.path.dirname(fpath)

    ######################################################
    def OnNotifyLoadDataFromText(self, wid, evt, fpath):
        """
        Load text file
        @param wid instance which published this event
        @param evt event type
        @param fpath path to file to be loaded
        @retval None
        """
        TF = TextFile(self.order)
        TF.ReadFrom(fpath)
        title1 = "*"
        title2 = "*"
        if TF.mainTitle != "":
            title1 = TF.mainTitle
        if TF.subTitle != "":
            title2 = TF.subTitle
        if title1 != "*" or title2 != "*":
            self.ifi.NotifyEvent(self, "title", (title1, title2))
        self.DefaultDialogPath["OPEN"] = os.path.dirname(fpath)

    ######################################################
    def OnShow(self):
        """
        Show Plotting data window メニューイベント処理
        データ一覧ボックスを表示
        @param  event イベント情報
        @retval 無し
        """
        # メニューを選択可とする
        # self.menuBar.setEnabled(self.res.GetId('menu_show'), False)
        self.MenuWidgets["show"].setEnabled(False)

        # フローティングボックスを表示
        self.fb.ShowFB()

    ######################################################
    def OnParam(self):
        """
        Set Potting Parameter メニューイベント処理
        パラメータ設定ダイアログを表示
        @param  event イベント情報
        @retval 無し
        """
        dg = ParamDialog(self, self.order, self.post)

    ######################################################
    def OnTitle(self):
        """
        Set Graph Title メニューイベント処理
        スケール設定ダイアログを表示
        @param  event イベント情報
        @retval 無し
        """
        dlg = TitleDialog(self, self.order, self.post)

    ######################################################

    def OnLabel(self):
        """
        Set Scale Label メニューイベント処理
        スケール設定ダイアログを表示
        @param  event イベント情報
        @retval 無し
        """
        # dlg = LabelDialog(self.frame, self.order, self.post)
        # dlg = LabelDialog(self.frame, self.order, self.post,self.dataobj) ##[inamura 110620]
        dlg = LabelDialog(self, self.order, self.post)

    ######################################################
    def OnGrid(self, event=None):
        """
        Set Graph Title メニューイベント処理
        スケール設定ダイアログを表示
        @param  event イベント情報
        @retval 無し
        """
        self.MenuWidgets["gridon"].setEnabled(False)
        dlg = SetAxisGridStyleDialog(self, self.order, self.post)
    # [inamura 160726-2]-->
    ######################################################

    def OnTicks(self, event=None):
        """
        Set Ticks Style メニューイベント処理
        スケール設定ダイアログを表示
        @param  event イベント情報
        @retval 無し
        """
        self.MenuWidgets["tickset"].setEnabled(False)
        dlg = SetAxisTickStyleDialog(self, self.order, self.post)

    # <--[inamura 160726-2]
    ######################################################
    def OnFitting(self, event=None):
        """
        """
        dlg = FittingDialog(self, self.post, 0)

    ######################################################
    def OnNotifyFBClose(self, wid, evt, value=None):
        """
        フローティングボックスクローズイベント処理
        Show Plotting Data ボタンを選択可とする
        @param  wid イベント発生元のインスタンス
        @param  evt イベントタイプ
        @param  value イベントの値、無し
        @retval 無し
        """
        # メニューを選択可とする
        # self.menuBar.Enable(self.res.GetId('menu_show'), True)
        self.MenuWidgets["show"].setEnabled(True)

    ######################################################
    def OnNotifyChildDg(self, wid, evt, flag):
        """
        ダイアログオープン・クローズイベント処理
        各ダイアログのメニューを選択可・不可とする
        @param  wid イベント発生元のインスタンス
        @param  evt イベントタイプ
        @param  flag True: クローズ、False:オープン
        @retval 無し
        """
        if evt == "paradg":
            # self.menuBar.Enable(self.res.GetId('menu_para'), flag)
            self.MenuWidgets["setgraph"].setEnabled(flag)
        elif evt == "titledg":
            # self.menuBar.Enable(self.res.GetId('menu_title'), flag)
            self.MenuWidgets["settitle"].setEnabled(flag)
        elif evt == "labeldg":
            # self.menuBar.Enable(self.res.GetId('menu_label'), flag)
            self.MenuWidgets["scalelabel"].setEnabled(flag)
        elif evt == "setaxisgridstyle2ddg":
            self.MenuWidgets["gridon"].setEnabled(flag)
        elif evt == "setaxistickstyle2ddg":
            self.MenuWidgets["tickset"].setEnabled(flag)

    ###################################################

    def UpdateXY(self, event):
        """
        マウス移動イベント処理
        マウス位置のプロットデータ情報を表示
        @param  event    イベント情報
        @retval 無し
        """
        # グラフ内かどうかをチェック
        if event.inaxes:
            # マウス位置のX値とY値をステータスバーに表示
            x, y = event.xdata, event.ydata
            # strTxt = "        X = %.2f    Y = %.2f" % (x, y)
            strTxt = "        X = %g    Y = %g" % (x, y)  # [inamura 160122]
            self.xytxt.setText(strTxt)

    ###################################################
    def OnNotifyDoIconize(self, wid, evtType, flag):
        """
        ウィンドウアイコン化または復元要求受信処理
        @param  wid ウィンドウID
        @param  evtType　イベントタイプ
        @param  flg    True: アイコン化　False: 元に戻す
        @retval 無し
        """
        # アイコン化する、または元に戻す
        # self.frame.Iconize(flag)

    ###################################################
    def OnPrevious(self):
        """
        Previousボタンクリックイベント処理関数
        (前のページを表示)
        @param  evt  イベント
        @retval 無し
        """
        # 現在のページを取得
        page = self.ifi.GetProperty('page') + 1
        # ページ変更要求イベント発行
        self.ifi.NotifyEvent(self, "page", page - 1)

    ###################################################
    def OnNext(self):
        """
        Nextボタンクリックイベント処理関数
        (次のページを表示)
        @param  evt  イベント
        @retval 無し
        """
        # 現在のページを取得
        page = self.ifi.GetProperty('page') + 1
        # ページ変更要求イベント発行
        self.ifi.NotifyEvent(self, "page", page + 1)

    ###################################################
    def OnNotifyDisplayPage(self, wid, evt, value=None):
        """
        パネルにページとデータ数を表示
        Next, Prev ボタンの選択可・不可コントロール
        @param wid   ウィンドウID
        @param  evt  イベント
        @retval 無し
        """
        # 1ページ当たりのグラフ数を取得
        gno = self.ifi.GetProperty('tracenum')
        # データ数を取得
        dno = self.ifi.GetProperty('datanum')
        # 現在のページを取得
        pno = self.ifi.GetProperty('page')
        if dno > 0:
            pno += 1

        # ページ数を計算
        maxp = int(dno / gno)
        if dno % gno > 0:
            maxp += 1

        if dno == 0:
            maxp = 0
        # 次ページがあれば
        if maxp > pno:
            # Next ボタンを選択可
            self.btNxt.setEnabled(True)
        else:
            # Next ボタンを選択不可
            self.btNxt.setEnabled(False)

        # 前のページがあれば
        if pno > 1:
            # Previus ボタンを選択可
            self.btPrv.setEnabled(True)
        else:
            # Previus ボタンを選択不可
            self.btPrv.setEnabled(False)
        # 現在ページの最後のデータ番号を計算
        dxno = pno * gno
        if dxno > dno:
            dxno = dno

        # ページと表示グラフ数を更新
        strNum = "Page: %d / %d    (%d / %d)" % (pno, maxp, dxno, dno)
        self.numtxt.setText(strNum)

    ###################################################
    def OnClose(self, *args):
        """
        ウィンドウクローズイベント処理
        クローズコマンド処理
        @param  *srgs    イベント情報
        @retval 無し
        """
        # [inamura 120131]-->
        def_att = DefaultFastPlotAtt()
        def_att.savePath("OPENPATH", self.DefaultDialogPath["OPEN"])
        def_att.savePath("SAVEPATH", self.DefaultDialogPath["SAVE"])
        # <--[inamura 120131]
        # プロッタフレームクローズイベント発行
        self.ifi.NotifyEvent(self, "plotclose")
        # フローティングボックスを終了
        # self.fb.fbFrame.Destroy()
        self.fb.close()
        # I/F をクリア
        self.ifi.InitIF()
        # 画面を閉じる
        # self.frame.Destroy()
        self.close()

    ##########################################################
    def closeEvent(self, event=None):
        """
        Catch window close event
        @event event
        """
        self.OnClose(event)
        if event is not None:
            event.accept()

    ###################################################
    def OnIconize(self, evt):
        """
        ウィンドウアイコン化イベント処理
        @param  evt    イベント情報
        @retval 無し
        """
        # プロッタフレームアイコン化イベント発行
        # self.ifi.NotifyEvent(self, "ploticonized", evt.Iconized())

    ###################################################
    def OnKeyPress(self, evt):
        """
        キー押下イベント処理
        (Windows では矢印キー押下イベントはここにこない)
        @param  evt    イベント情報
        @retval 無し
        """
        # ピークラベル表示モード中か
        if self.ifi.GetProperty('penmode'):
            # 押下されたキーが'p'なら
            if evt.key == 'p' or evt.key == 'P':
                # ピンボタン押下イベント通知
                self.ifi.NotifyEvent(self, "pinup")

    ###################################################
    def OnArrowKeys(self, evt):
        """
        矢印キー押下イベント処理
        @param  evt    イベント情報
        @retval 無し
        """
        # ピークラベル表示モード中か
        if self.ifi.GetProperty('penmode'):
            keycode = self.arrows[evt.GetId()]
            # キー押下イベント通知
            self.ifi.NotifyEvent(self, "shift", keycode)

#########################
#   Chart
#########################


class Chart(object):
    """
    グラフ描画クラス
    """

    title = "Run No.: "

    ###################################################
    def __init__(self, plot, dataobj):
        """
        コンストラクタ
        @param  plot     プロッタ画面(親)のインスタンス
        @param  dataobj ヒストグラムデータのインスタンス
        @retval 無し
        """

        self.do = dataobj
        self.plot = plot
        self.fig = plot.fig
        self.canvas = plot.canvas
        # ヘッダーフレームのインスタンスを初期化
        self.hb = None
        # リソースのインスタンスを取得
        # res = ResourceFile()

        # [inamura 110223]-->
        # default attribute
        self.DefAtt = DefaultFastPlotAtt()
        # <--[inamura 110223]
        # [inamura 120513]-->
        # Font size [Title1, bottom Axis label, left Axis label, ScaleLabel ]
        self.fontNameList = ["serif", "sans-serif", "monospace"]
        self.fontInfo = [[10, 'serif'], [10, 'serif'],
                         [10, 'serif'], [10, 'serif']]
        self.textInfo = [[0.13, 0.04], [0.04, 0.55], [0.45, 0.02], [0.0, 0.0]]
        # <--[inamura 120513]
        # [inamura 160722]-->
        self.GridStyleDic = {"Show": False,
                             "XlineWidth": 0.5,
                             "XlineColor": "b",
                             "XlineStyle": ":",
                             "YlineWidth": 0.5,
                             "YlineColor": "b",
                             "YlineStyle": ":"}
        # <--[inamura 160722]
        # [inamura 160726-2]-->
        self.TickStyleDic = {"Minor": False,
                             "MinorLength": 2,  # default=2
                             "MinorWidth": 0.5,  # default=0.5
                             "MajorLength": 5,  # default=5
                             "MajorWidth": 0.5,  # default=0.5
                             "TopSide": False,
                             "RightSide": False}
        # <--[inamura 160726-2]
        self.isAutoScaleY = False  # [inamura 171225]

        # トレースのラベルリストと属性リストを準備
        self._MakeLists()
        self.xunit = ""
        self.yunit = ""
        # 各ページの座標保存用リストを準備 2010.03.01 KCS Add
        self.pageax = []
        # プロパティセット
        self._SetInitialProperty()

        # マウスクリックイベント登録(データヘッダを表示するポップアップウィンドウ用)
        self.canvas.mpl_connect('button_press_event', self.OnMouseDown)
        self.canvas.mpl_connect('button_release_event', self.OnMouseUp)

        # ピークラベル表示クラスのインスタンスを取得
        self.pl = PeakLabel(self, plot.order)

        self.mc = MoniCursor(self, plot.order)  # [inamura 100715]

        # グラフを描画
        self.PlotOrgChart(True)
        # 最初の描画サイズを保存
        self.orgsize = self.fig.get_size_inches()[1]

        self.doubleClick_state1 = [0, 0.0]  # [inamura 120511]
        self.doubleClick_interval = 0.6  # [inamura 120511]

    ###################################################
    def _MakeLists(self):
        """
        トレースのラベルリストと属性リストを作成
        @param  無し
        @retval 無し
        """
        # トレースラベルのリストを準備
        self.traceLabels = []
        # トレースの属性リストを準備
        self.traceAttrs = []
        # 各トレース毎にピークラベルのリストを準備
        self.peakLabels = []
        # データ数取得
        num = self.do.GetDataNum()
        # データがあったら
        if num > 0:
            # データ数分のリストを作成
            for i in range(num):
                # デフォルトの属性を設定
                # [inamura 110223]-->
                # self.traceAttrs.append(TraceAtt.defaultTraceAttr.copy())
                def_att = self.DefAtt.loadPlotAtt()
                if def_att is None:
                    self.traceAttrs.append(TraceAtt.defaultTraceAttr.copy())
                else:
                    self.traceAttrs.append(self.DefAtt.loadPlotAtt())
                # <--[inamura 110223]
                # トレースラベルを取得
                psdId = self.do.GetTraceLabel(i)
                # トレースラベルを保存
                self.traceLabels.append(psdId)
                # ピークラベルに空のリストを格納
                self.peakLabels.append([])

    ###################################################
    def _SetInitialProperty(self):
        """
        プロパティの初期設定、リスナー登録、公開プロパティの登録
        @param  無し
        @retval 無し
        """

        # チャートのプロパティ管理クラスのインスタンスを取得
        self.ifi = IFEvtProp(self.plot.order)

        # デフォルトの初期値を設定
        self.page = 0
        self.autoXFlag = True
        self.autoYFlag = True
        self.overlayFlag = True
        self.xx0 = 0.0
        self.xx1 = 1000.0
        self.yy0 = 0.0
        self.yy1 = 1000.0
        self.offsetX = 0
        self.offsetY = 0  # [inamura 100205] change default 10 to 0
        self.logFlag = False
        self.logFlagX = False  # [inamura 140307]
        self.traceNum = 20
        self.xlabel = ""
        self.ylabel = ""
        self.title1 = ""
        self.title2 = ""

        # メインタイトル自動設定フラグを立てる
        self.autoTitle = True
        # ラベル自動設定フラグを立てる
        self.autoLabel = True
        self.autoUnitLabel = True  # [inamura 110620]

        # イベントのリスナー登録
        self.ifi.AddListner('title', self.OnNotifyTitle)
        self.ifi.AddListner('scalelabel', self.OnNotifyLabel)
        self.ifi.AddListner('plot', self.OnNotifyPlot)
        self.ifi.AddListner('xscale', self.OnNotifyXScale)
        self.ifi.AddListner('yscale', self.OnNotifyYScale)
        self.ifi.AddListner('log', self.OnNotifyLog)
        self.ifi.AddListner('logx', self.OnNotifyLogX)  # [inamura 140307]
        self.ifi.AddListner('overlay', self.OnNotifyOver)
        self.ifi.AddListner('offset', self.OnNotifyOffset)
        self.ifi.AddListner('tracenum', self.OnNotifyTraceNum)
        self.ifi.AddListner('plotparam', self.OnNotifyPlotParam)
        self.ifi.AddListner('add', self.OnNotifyAddData)
        self.ifi.AddListner('remove', self.OnNotifyRemoveData)
        self.ifi.AddListner('shuffle', self.OnNotifyShuffleData)
        self.ifi.AddListner('page', self.OnNotifyChangePage)
        self.ifi.AddListner('home', self.OnHome)
#        self.ifi.AddListner('changexy', self.OnChangeXY)
        self.ifi.AddListner('replot', self.RePlotChart)
        # [inamura 100715]
        self.ifi.AddListner('replace', self.OnNotifyReplaceData)
        # [inamura 110620]
        self.ifi.AddListner('setunits', self.OnNotifySetUnits)
        # [inamura 120513]
        self.ifi.AddListner('setfontinfo', self.OnNotifySetFontInfo)
        # [inamura 120513]
        self.ifi.AddListner('settextinfo', self.OnNotifySetTextInfo)
        # [inamura 171225]
        self.ifi.AddListner('setautoscaley', self.OnNotifySetAutoScaleY)

        # 公開プロパティを登録
        self.ifi.AddProperty('autox', lambda: self.autoXFlag)
        self.ifi.AddProperty('autoy', lambda: self.autoYFlag)
        self.ifi.AddProperty('x0', lambda: self.xx0)
        self.ifi.AddProperty('x1', lambda: self.xx1)
        self.ifi.AddProperty('y0', lambda: self.yy0)
        self.ifi.AddProperty('y1', lambda: self.yy1)
        self.ifi.AddProperty('overlay', lambda: self.overlayFlag)
        self.ifi.AddProperty('offsetx', lambda: self.offsetX)
        self.ifi.AddProperty('offsety', lambda: self.offsetY)
        self.ifi.AddProperty('log', lambda: self.logFlag)
        self.ifi.AddProperty('logx', lambda: self.logFlagX)  # [inamura 140307]
        self.ifi.AddProperty('tracenum', lambda: self.traceNum)
        self.ifi.AddProperty('page', lambda: self.page)
        self.ifi.AddProperty('title1', lambda: self.title1)
        self.ifi.AddProperty('title2', lambda: self.title2)
        self.ifi.AddProperty('xlabel', lambda: self.xlabel)
        self.ifi.AddProperty('ylabel', lambda: self.ylabel)
        self.ifi.AddProperty('tracelabels', lambda: self.traceLabels)
        self.ifi.AddProperty('traceattrs', lambda: self.traceAttrs)
        self.ifi.AddProperty('datanum', lambda: len(self.traceAttrs))
        self.ifi.AddProperty('xunit', lambda: self.xunit)  # [inamura 110704]
        self.ifi.AddProperty('yunit', lambda: self.yunit)  # [inamura 110704]
        # [inamura 120513]
        self.ifi.AddProperty('fontinfo', lambda: self.fontInfo)
        # [inamura 120513]
        self.ifi.AddProperty('textinfo', lambda: self.textInfo)
        # [inamura 120513]
        self.ifi.AddProperty('fontnamelist', lambda: self.fontNameList)
        # [inamura 100716]-->
        self.ifi.AddListner('moncursoron', self.OnNotifyMoniCursorOn)
        self.ifi.AddListner('moncursorpos', self.OnNotifyMoniCursorSet)
        # <--[inamura 100716]
        # [ianmrua 160722]
        self.ifi.AddProperty('gridstyledic', lambda: self.GridStyleDic)
        # [ianmrua 160726-2]
        self.ifi.AddProperty('tickstyledic', lambda: self.TickStyleDic)

    ###################################################
    def PlotOrgChart(self, flag):
        """
        オリジナルグラフ表示
        @param  flag 再描画指定フラグ
        @retval 無し
        """
        # グラフを描画
        self.PlotChart()
        # 再描画が指定されているか
        if flag:
            # ピークラベル表示クラスに、描画更新を通知、カレントラベルはクリア
            self.pl.NewPlot(self.fig, self.canvas, True)
            self.mc.NewPlot(self.fig, self.canvas)  # [inamura 100715]
            # グラフの再描画
            self.canvas.draw()
        # ホームポジション処理用に、X-Y範囲を保存
        self.ranges = []
        axs = self.fig.get_axes()

        # 現在のの、X-Y 範囲を保存
        for ax in axs:
            self.ranges.append((ax.get_xlim(), ax.get_ylim()))

    ###################################################

    def PlotChart(self):
        """
        グラフ表示
        @param  無し
        @retval 無し
        """

        # フィギュアをクリア
        self.fig.clf()

        # 表示情報保存用リストを準備
        self.laby = []

        # オーバレイモードか
        if self.overlayFlag:
            # オーバレイグラフを表示
            self._PlotOverlay()
        else:
            # 個別グラフを表示
            self._PlotIndividual()

    ###################################################
    def _SetLabels(self, ax):
        """
        """
        # ページ最初のデータ順番を計算
        iniNo = self.page * self.traceNum

        xlabel = self.xlabel
        ylabel = self.ylabel
        # データがあれば
        if len(self.traceLabels) > iniNo:
            # ページ最初の単位を取得
            if self.autoUnitLabel:
                xunit_in = self.do.GetXUnit(iniNo)
                yunit_in = self.do.GetYUnit(iniNo)
                setAutoLabel = False
                if isinstance(xunit_in, tuple) and (len(xunit_in) == 2):
                    if self.autoLabel:
                        self.xlabel, self.xunit = xunit_in
                        # self.autoLabel=False
                        setAutoLabel = True
                    else:
                        self.xunit = xunit_in[1]
                else:
                    self.xunit = xunit_in

                if isinstance(yunit_in, tuple) and (len(yunit_in) == 2):
                    if self.autoLabel:
                        self.ylabel, self.yunit = yunit_in
                        # self.autoLabel=False
                        setAutoLabel = True
                    else:
                        self.yunit = yunit_in[1]
                else:
                    self.yunit = yunit_in

                if setAutoLabel:
                    self.autoLabel = False

            # タイトル自動変更か
            if self.autoTitle:
                # 最初のデータより Run No. を取得してメインタイトルを作る
                self.title1 = self.title + self.do.GetRunNo(iniNo)
            # ラベル自動変更か(最初のデータより単位を取得)
            if self.autoLabel:
                self.xlabel = "X"
                self.ylabel = "Y"

        if self.xunit is None or self.xunit == "" or self.xunit == "None":
            xlabel = self.xlabel
        else:
            xlabel = "%s (%s)" % (self.xlabel, self.xunit)
        if self.yunit is None or self.yunit == "" or self.yunit == "None":
            ylabel = self.ylabel
        else:
            ylabel = "%s (%s)" % (self.ylabel, self.yunit)

        # スケールのラベルを表示
        ax.set_xlabel(xlabel)
        ax.set_ylabel(ylabel)
        finfo1 = self.fontInfo[1]
        finfo2 = self.fontInfo[2]
        ax.xaxis.label.set_fontsize(finfo2[0])
        ax.xaxis.label.set_fontname(finfo2[1])
        ax.yaxis.label.set_fontsize(finfo1[0])
        ax.yaxis.label.set_fontname(finfo1[1])

        # グラフのタイトルを表示
        fntinfo = self.fontInfo[0]
        txtinfo = self.textInfo[0]
        self.fig.text(txtinfo[0], (1.0 - txtinfo[1]), self.title1,
                      fontname=fntinfo[1], fontsize=fntinfo[0])
        self.fig.text(txtinfo[0], (1.0 - txtinfo[1] - 0.035),
                      self.title2, fontname=fntinfo[1], fontsize=fntinfo[0])

    ###################################################
    def _PlotOverlay(self):
        """
        重ね書きグラフ表示
        @param  無し
        @retval 無し
        """
        # ザプロッタ作成
        self.ax = self.fig.add_subplot(111)

        # スケールラベルの大きさ調整
        xlabels = getp(self.ax, 'xticklabels')
        ylabels = getp(self.ax, 'yticklabels')
        # [inamura 120513]-->
        setp(xlabels, size=self.fontInfo[3][0])
        setp(ylabels, size=self.fontInfo[3][0])
        setp(xlabels, fontname=self.fontInfo[3][1])
        setp(ylabels, fontname=self.fontInfo[3][1])
        # <--[inamura 120513]
        self._SetLabels(self.ax)  # [inamura 170615]
        # オフセットの初期値を設定
        xorg = 0.0
        yorg = 0.0
        gdpi = self.fig.get_dpi() * 1.0

        # グラフポジションを取得
#        pos = self.ax.get_position()   # matplotlib 0.98.5対応
        self.pos = VerHandlePlotLib().GetSubPlotPos(self.ax)
        aratio = self.fig.get_size_inches()[1] * gdpi
        # Y0点のピクセル値を求める
        y0dpi = aratio * self.pos[1]

        # 残りのデータ数が、トレース数より小さければ
        if (self.page + 1) * self.traceNum > self.do.GetDataNum():
            # 残りのデータ数を描画トレース数とする
            numT = self.do.GetDataNum() - self.page * self.traceNum
        else:
            # 指定されたトレース数だけ描画する
            numT = self.traceNum

        # Show grid lines
        # [inamura 160722]-->
        if (self.GridStyleDic["Show"]):
            # X-axis grid style
            # self.ax.xaxis.grid(True)
            # self.ax.yaxis.grid(True)
            self.ax.xaxis.grid(True, color=self.GridStyleDic["XlineColor"],
                               linestyle=self.GridStyleDic["XlineStyle"],
                               linewidth=self.GridStyleDic["XlineWidth"])
            # Y-axis grid style
            self.ax.yaxis.grid(True, color=self.GridStyleDic["YlineColor"],
                               linestyle=self.GridStyleDic["YlineStyle"],
                               linewidth=self.GridStyleDic["YlineWidth"])
        else:
            self.ax.xaxis.grid(False)
            self.ax.yaxis.grid(False)
        # <--[inamura 160722]
        # [inamura 160726-2]-->
        tick_t = self.TickStyleDic["TopSide"]
        tick_r = self.TickStyleDic["RightSide"]
        if mpl_version < '3.0.0':
            tick_side_dic = {True: "on", False: "off"}
            tick_t = tick_side_dic[tick_t]
            tick_r = tick_side_dic[tick_r]
        self.ax.xaxis.set_tick_params(
            which='major', length=self.TickStyleDic["MajorLength"], width=self.TickStyleDic["MajorWidth"], top=tick_t, direction="in")
        self.ax.yaxis.set_tick_params(
            which='major', length=self.TickStyleDic["MajorLength"], width=self.TickStyleDic["MajorWidth"], right=tick_r, direction="in")
        if (self.TickStyleDic["Minor"]):
            from matplotlib.ticker import AutoMinorLocator
            self.ax.xaxis.set_minor_locator(AutoMinorLocator(5))
            self.ax.yaxis.set_minor_locator(AutoMinorLocator(5))
            self.ax.xaxis.set_tick_params(
                which='minor', length=self.TickStyleDic["MinorLength"], width=self.TickStyleDic["MinorWidth"], top=self.TickStyleDic["TopSide"], direction="in")
            self.ax.yaxis.set_tick_params(
                which='minor', length=self.TickStyleDic["MinorLength"], width=self.TickStyleDic["MinorWidth"], right=self.TickStyleDic["RightSide"], direction="in")
        # <--[inamura 160726-2]

        # 1ページ分のトレースをプロット
        for i in range(numT):
            # 最初の(一番下)データを最後にプロットするため、逆順にプロット
            inum = numT - i - 1
            # オフセットを計算
            # [inamura 100205]-->
            # xoffset = xorg + self.offsetX / gdpi * inum
            # yoffset = yorg + self.offsetY / gdpi * inum
            xoffset = xorg + self.offsetX * inum
            yoffset = yorg + self.offsetY * inum
            # print "xoffset,yoffset = ",xoffset,yoffset
            # <--[inamura 100205]
            # オフセットを作成
            transOffset = offset_copy(self.ax.transData, fig=self.fig,
                                      # x=xoffset, y=yoffset, units='inches')
                                      x=xoffset, y=yoffset, units='points')
            # データの順番を求める
            ii = self.traceNum * self.page + inum
            # トレースをプロットする
            lc, firstx, firsty, lastx, lasty = self._PlotTrace(
                ii, self.ax, transOffset, inum)

            # Y軸のオフセットが10以下であれば
            if self.offsetY < 10:
                # オフセット10の位置にトレースラベルを表示(重なってラベルが見えなくなるため)
                yos = yorg + 10 / gdpi * inum
                yyoff = (y0dpi + yos * gdpi) / aratio
            else:
                # オフセットの位置にラベルを表示
                # [inamura 100205]-->
                # yyoff = (y0dpi+yoffset*gdpi)/aratio
                yyoff = (y0dpi + yoffset * 1.2) / aratio
                # print "yyoff = ",yyoff
                # <--[inamura 100205]

            # トレースラベル表示用データ保存
            self.laby.append((lc, yyoff))

        # トレースラベルを表示するために、横を少し縮める
        self.pos[2] = self.pos[2] * 0.9
        self.ax.set_position(self.pos)

        xx = self.pos[0] + self.pos[2]
        i = self.page * self.traceNum + numT - 1
        for lcyy in self.laby:
            # トレースラベルを取得して短縮形に変換
            label = self._AbbrbLabel(self.traceLabels[i])
            # トレースラベル表示
            self.fig.text(xx + 0.015, lcyy[1], label, color=lcyy[0],
                          verticalalignment='center', fontsize=7)
            i = i - 1

        # スケール範囲の設定
        self.SetScales(self.ax)

    ###################################################

    def _PlotIndividual(self):
        """
        グラフ個別表示
        @param  無し
        @retval 無し
        """
        # サブプロットを作成(グラフ間のマージンを最小)
        self.fig.subplots_adjust(hspace=0.001)

        minX = 1000000.0
        maxX = -1000000.0

        # 1ページ当たりのグラフ数分表示
        for i in range(self.traceNum):
            ii = self.traceNum * self.page + i
            # 選択データのプロットが終わったか?
            if ii > (len(self.traceLabels) - 1):
                break
            # 最初のトレースか
            if i == 0:
                # サブプロットを作成
                ax = self.fig.add_subplot(self.traceNum, 1, i + 1)
                ax0 = ax
            else:
                # x軸の共有を指定
                ax = self.fig.add_subplot(self.traceNum, 1, i + 1, sharex=ax0)

            # Show grid lines
            # [inamura 160722]-->
            if (self.GridStyleDic["Show"]):
                # X-axis grid style
                ax.xaxis.grid(True, color=self.GridStyleDic["XlineColor"],
                              linestyle=self.GridStyleDic["XlineStyle"],
                              linewidth=self.GridStyleDic["XlineWidth"])
                # Y-axis grid style
                ax.yaxis.grid(True, color=self.GridStyleDic["YlineColor"],
                              linestyle=self.GridStyleDic["YlineStyle"],
                              linewidth=self.GridStyleDic["YlineWidth"])
            else:
                ax.xaxis.grid(False)
                ax.yaxis.grid(False)
            # <--[inamura 160722]
            # [inamura 160726-2]-->
            ax.xaxis.set_tick_params(
                which='major', length=self.TickStyleDic["MajorLength"], width=self.TickStyleDic["MajorWidth"], top=self.TickStyleDic["TopSide"], direction="in")
            ax.yaxis.set_tick_params(
                which='major', length=self.TickStyleDic["MajorLength"], width=self.TickStyleDic["MajorWidth"], right=self.TickStyleDic["RightSide"], direction="in")
            if (self.TickStyleDic["Minor"]):
                from matplotlib.ticker import AutoMinorLocator
                ax.xaxis.set_minor_locator(AutoMinorLocator(5))
                ax.yaxis.set_minor_locator(AutoMinorLocator(5))
                ax.xaxis.set_tick_params(
                    which='minor', length=self.TickStyleDic["MinorLength"], width=self.TickStyleDic["MinorWidth"], top=self.TickStyleDic["TopSide"], direction="in")
                ax.yaxis.set_tick_params(
                    which='minor', length=self.TickStyleDic["MinorLength"], width=self.TickStyleDic["MinorWidth"], right=self.TickStyleDic["RightSide"], direction="in")
            # <--[inamura 160726-2]

            # オフセットを作成
            transOffset = offset_copy(ax.transData, fig=self.fig,
                                      x=0.0, y=0.0, units='inches')

            # トレースをプロットする
            lc, firstx, firsty, lastx, lasty = self._PlotTrace(
                ii, ax, transOffset)

            # 表示色を保存
            self.laby.append((lc, ))

            # 1ページに描画するデータの最小値を求める
            if firstx < minX:
                minX = firstx
            # 1ページに描画するデータの最大値を求める
            if lastx > maxX:
                maxX = lastx

            # Y軸スケールラベルの最初の数値を消す(数値が重ならないように)
            yy = ax.get_yticks()
            ax.set_yticks(yy[1:])
            # Y軸スケールラベルの文字を設定
            ylabels = getp(ax, 'yticklabels')
            setp(ylabels, size=8)

            # トレースラベルを取得
            strPSD = self.traceLabels[ii]
            # トレースのラベルを表示(黒で表示)
#            x0, y0, x1, y1 = ax.get_position()  matplotlib 0.98.5対応
            x0, y0, x1, y1 = VerHandlePlotLib().GetSubPlotPos(ax)
            self.fig.text(x0 + 0.03, y0 + y1 - 0.05, strPSD, fontsize=8)

            # スケール表示を消す
            xticklabel = ax.get_xticklabels()
            setp(xticklabel, visible=False)
            # スケール範囲の設定
            self.SetScales(ax)
            # [inamura 170615]-->
            if i == int(self.traceNum / 2.0):
                self._SetLabels(ax)
            # <--[inamura 170615]

        # 表示プロットがあれば
        if len(self.traceLabels) > 0:
            setp(xticklabel, visible=True)
            # 最後のグラフにのみスケールを表示
            xlabels = getp(ax, 'xticklabels')
            setp(xlabels, size=8)
            # 最後のグラフのポジションを設定
#            self.pos = ax.get_position()
            self.pos = VerHandlePlotLib().GetSubPlotPos(ax)

        # X自動スケールが指定されていたら
        if self.autoXFlag:
            # 1ページ中の全グラフの横軸を揃える
            axs = self.fig.get_axes()
            for ax in axs:
                ax.set_xlim(minX, maxX)

    ###################################################

    def _PlotTrace(self, i, ax, transOffset, tno=0):
        """
        グラフ個別表示
        @param  i        データの順番
        @param  ax       座標のインスタンス
        @param  transOffset  オフセット
        @param  tno      重ね書き時の描画順番
        @retval (線の描画色, 描画始点のX値、Y値、終点のX値、Y値)
        """
        # プロット属性を取得
        att = self.traceAttrs[i]
        # 線種を取得
        ls = att["ls"]
        # ヒストグラムスタイルを取得
        hflag = att["hs"]
        # 線幅を取得
        ns = att["lw"]
        lw = TraceAtt.linewidth[ns - 1]
        # 線色を取得
        lc = att["lc"]
        # マーカの種類を取得
        mk = att["mk"]
        # マーカサイズを取得
        ns = att["ms"]
        ms = TraceAtt.msize[ns - 1]
        # 線色を取得
        mc = att["mc"]
        # エラーバーモードを取得
        eb = att["eb"]
        # キャップサイズを取得
        es = float(att["es"]) / 2.0
        # ns = att["es"]
        # es = TraceAtt.csize[ns-1]
        # エラーバーの色を取得
        ec = att["ec"]

        # トレースの順番からカラー番号を計算
        cno = i % 7
        # 線の色が自動なら
        if lc == '*':
            # カラー番号から色を取得
            lc = TraceAtt.color[cno + 1]
        # マークの色が自動なら
        if mc == '*':
            # 線の色と同じ
            mc = lc
        # エラーバーのキャップの色が自動なら
        if ec == '*':
            # 線の色と同じ
            ec = lc

        # [inamura 120512]-->
        if att["mf"] == "fill":
            mfc_in = mc
        elif att["mf"] == "none":
            mfc_in = "none"
        # <--[inamura 120512]

        # データリストを取得
        xx = self.do.GetDataX(i)
        yy = self.do.GetDataY(i)

        # 最初と最後のデータを求める
        num = len(xx)
        lastx = xx[num - 1]
        lasty = yy[num - 1]
        firstx = xx[0]
        firsty = xx[0]

        # ヒストグラムモードか
        if hflag == 1:
            # ヒストグラムデータを取得
            xxh, yyh = self.do.GetHistXY(self.logFlag, i)
            # 最終 Xデータを求める
            lastx = xxh[len(xxh) - 1]
            firstx = xxh[0]

        # [inamura 140307]-->
        # ログモードか
        if self.logFlag:
            # ヒストグラムモードか
            if hflag == 1:
                if self.logFlagX:
                    ax.loglog(xxh, yyh, transform=transOffset,
                              linestyle=ls, linewidth=lw, color=lc)
                    ax.loglog(xx, yy, transform=transOffset,
                              linestyle="", marker=mk, markersize=ms, mfc=mfc_in, mec=mc, mew=1.0, linewidth=0)
                else:
                    # ヒストグラムの線をマーカ無しで描画
                    ax.semilogy(xxh, yyh, transform=transOffset,
                                linestyle=ls, linewidth=lw, color=lc)
                    # 線無しで、マーカのみをヒストグラムの中心に描画
                    ax.semilogy(xx, yy, transform=transOffset,
                                linestyle="", marker=mk, markersize=ms, mfc=mfc_in, mec=mc, mew=1.0, linewidth=0)
                if eb == 1:
                    ax.errorbar(xx, yy, yerr=self.do.GetDataEr(i), transform=transOffset,
                                linestyle=ls, linewidth=lw, color=lc,
                                marker=mk, markersize=ms, mfc=mfc_in, mec=mc, mew=1.0,
                                capsize=es, ecolor=ec, barsabove=True)
            else:
                if self.logFlagX:
                    ax.loglog(self.do.GetDataX(i), self.do.GetLogDataY(i), transform=transOffset,
                              linestyle=ls, linewidth=lw, color=lc,
                              marker=mk, markersize=ms, mfc=mfc_in, mec=mc, mew=1.0)
                else:
                    # Y軸ログスケール表示 (ログスケールでエラーバー付きは不可)
                    ax.semilogy(self.do.GetDataX(i), self.do.GetLogDataY(i), transform=transOffset,
                                linestyle=ls, linewidth=lw, color=lc,
                                marker=mk, markersize=ms, mfc=mfc_in, mec=mc, mew=1.0)
                if eb == 1:
                    ax.errorbar(self.do.GetDataX(i), self.do.GetLogDataY(i), yerr=self.do.GetDataEr(i), transform=transOffset,
                                linestyle=ls, linewidth=lw, color=lc,
                                marker=mk, markersize=ms, mfc=mfc_in, mec=mc, mew=1.0,
                                capsize=es, ecolor=ec, barsabove=True)

        # エラーバー付き指定時
        elif eb == 1:
            yye = self.do.GetNonMaskY(i)
            # ヒストグラムモードか
            if hflag == 1:
                if self.logFlagX:
                    ax.semilogx(xxh, yyh, linestyle=ls, linewidth=lw,
                                color=lc, transform=transOffset,)
                    ax.errorbar(xx, yye, yerr=self.do.GetDataEr(i), transform=transOffset,
                                linestyle="", marker=mk, markersize=ms, mfc=mfc_in, mec=mc, mew=1.0,
                                capsize=es, ecolor=ec, barsabove=True)
                else:
                    # ヒストグラムの線を、エラーバー無、マーカ無しで描画
                    ax.plot(xxh, yyh, linestyle=ls, linewidth=lw,
                            color=lc, transform=transOffset,)
                    # 線無しで、エラーバーとマーカのみをヒストグラムの中心に描画
                    ax.errorbar(xx, yye, yerr=self.do.GetDataEr(i), transform=transOffset,
                                linestyle="", marker=mk, markersize=ms, mfc=mfc_in, mec=mc, mew=1.0,
                                capsize=es, ecolor=ec, barsabove=True)
            else:
                if self.logFlagX:
                    ax.semilogx(xx, yye, linestyle=ls, linewidth=lw,
                                color=lc, transform=transOffset,)
                    ax.errorbar(xx, yye, yerr=self.do.GetDataEr(i), transform=transOffset,
                                linestyle=ls, linewidth=lw, color=lc,
                                marker=mk, markersize=ms, mfc=mfc_in, mec=mc, mew=1.0,
                                capsize=es, ecolor=ec, barsabove=True)
                else:
                    # リニアスケール、エラーバー付き
                    ax.errorbar(xx, yye, yerr=self.do.GetDataEr(i), transform=transOffset,
                                linestyle=ls, linewidth=lw, color=lc,
                                marker=mk, markersize=ms, mfc=mfc_in, mec=mc, mew=1.0,
                                capsize=es, ecolor=ec, barsabove=True)
        # リニアスケール、エラーバー無しのグラフ
        else:
            # ヒストグラムモードか
            if hflag == 1:
                if self.logFlagX:
                    # ヒストグラムの線をマーカ無しで描画
                    ax.semilogx(xxh, yyh, transform=transOffset,
                                linestyle=ls, linewidth=lw, color=lc)
                    # 線無しで、マーカのみをヒストグラムの中心に描画
                    ax.semilogx(xx, yy, transform=transOffset,
                                linestyle="", marker=mk, markersize=ms, mfc=mfc_in, mec=mc, mew=1.0)
                else:
                    # ヒストグラムの線をマーカ無しで描画
                    ax.plot(xxh, yyh, transform=transOffset,
                            linestyle=ls, linewidth=lw, color=lc)
                    # 線無しで、マーカのみをヒストグラムの中心に描画
                    ax.plot(xx, yy, transform=transOffset,
                            linestyle="", marker=mk, markersize=ms, mfc=mfc_in, mec=mc, mew=1.0)
            else:
                if self.logFlagX:
                    ax.semilogx(xx, yy, transform=transOffset,
                                linestyle=ls, linewidth=lw, color=lc,
                                marker=mk, markersize=ms, mfc=mfc_in, mec=mc, mew=1.0)
                else:
                    # 通常のグラフ
                    ax.plot(xx, yy, transform=transOffset,
                            linestyle=ls, linewidth=lw, color=lc,
                            marker=mk, markersize=ms, mfc=mfc_in, mec=mc, mew=1.0)
        # <--[inamura 140307]

        # [inamura 140220]-->
        # ax.relim()
        # ax.autoscale()
        # ax.autoscale_view()
        ax.set_xlim((firstx, lastx))
        if self.logFlag and yy.min() <= 0.0:
            yy_min = 1.0E-10
        else:
            yy_min = yy.min()
        ax.set_ylim((yy_min, yy.max()))
        # <--[inamura 140220]

        # 線を描画した色と最終点のデータを返す
        return (lc, firstx, firsty, lastx, lasty)

    ###################################################
    def _AbbrbLabel(self, label):
        """
        トレースラベルを短縮
        @param  label    ラベルの文字列
        @retval 短縮したラベル
        """

        # + で区切られている文字列を分解
        strings = label.split('+')
        # 文字列数が4以上なら
        if len(strings) > 3:
            # 中間部分を省略した文字列を作成
            num = len(strings) - 1
            label = strings[0] + " + ... + " + strings[num]

        return label

    ###################################################
    def OnMouseDown(self, evt):
        """
        マウス左ボタンダウンイベント処理関数
        @param  evt  イベント
        @retval 無し
        """
        # ヘッダー表示中は何もしない
        if self.hb is not None:
            return

        # パン処理中またはズーム処理中であり
        if MATPLOTLIB_VER < NAVIGATIONTOOLBAR_CHANGED_VER:
            if self.plot.toolbar._active == 'PAN' or self.plot.toolbar._active == 'ZOOM':
                # かつグラフ内ならば、以下の処理を実行しない
                if evt.inaxes:
                    return
        else:
            if self.plot.toolbar._actions['pan'].isChecked() or self.plot.toolbar._actions['zoom'].isChecked():
                if evt.inaxes:
                    return
        # if self.plot.toolbar._active == 'PAN' or self.plot.toolbar._active == 'ZOOM':
        #    # かつグラフ内ならば、以下の処理を実行しない
        #    if evt.inaxes:
        #        return
        # Y0点のピクセル値を求める
        y0dpi = self.pos[1] * self.fig.get_size_inches()[1] * self.fig.get_dpi()
        # Y1点のピクセル値を求める
        y1dpi = (self.pos[1] + self.pos[3]) * self.fig.get_size_inches()[1] * self.fig.get_dpi()

        # [inamura 120511]-->
        x0dpi = self.pos[0] * self.fig.get_size_inches()[0] * self.fig.get_dpi()
        x1dpi = (self.pos[0] + self.pos[2]) * self.fig.get_size_inches()[0] * self.fig.get_dpi()

        if (evt.y > y1dpi):
            # in Title area
            self.doubleClick_state1[0] = 3
        elif (evt.x < (x0dpi / 2.0) or (evt.y < (y0dpi / 2.0))):
            # in Label area
            self.doubleClick_state1[0] = 2
        elif (evt.x < x0dpi) or (evt.y < y0dpi):
            # in Param area (axis range)
            self.doubleClick_state1[0] = 1
        else:
            # in Show area ( chart area )
            self.doubleClick_state1[0] = 0

        # <--[inamura 120511]

        # グラフより下
        if evt.y < y0dpi:
            return

        # オーバレイグラフか
        if self.overlayFlag:
            # グラフ内か
            if evt.inaxes:
                # ピークラベル表示モードか
                if self.ifi.GetProperty('penmode'):
                    # クリック点のピークラベル表示
                    self.pl.DispLabel(None, evt.xdata)
                return

            # Yオフセットが10以下であれば
            if self.offsetY < 10:
                # Yオフセットを10 として、下から何番目のトレースかを求める
                yofs = 10
            else:
                yofs = self.offsetY * self.fig.get_size_inches()[1] / self.orgsize

            # 下から何番目のトレースかを求める
            dataNum = int((evt.y - y0dpi) / yofs)

            # 一番上のグラフより上
            if (self.traceNum - 1) < dataNum:
                return

        else:
            # 個別表示グラフ
            ydif = y1dpi - y0dpi

            # 最終頁のグラフか
            if (self.traceNum * (self.page + 1)) > (len(self.traceLabels) - 1):
                # 最終ページのグラフ数を求める
                noT = len(self.traceLabels) - self.traceNum * self.page

            else:
                # 最終ページでなければ、1ページあたりのグラフ数を使用
                noT = self.traceNum

            # 上から何番目のグラフかを求める
            dataNum = noT - int((evt.y - y0dpi) / ydif) - 1
            # グラフエリアより上であれば、ヘッダーを表示しない
            if dataNum < 0:
                return
            # 最終ページのY0点を仮想　0 点に入れ替える
            y0dpi = y0dpi - (self.traceNum - noT) * ydif

        # データの順番を算出
        num = self.traceNum * self.page + dataNum

        # 表示中のグラフ数を超えない
        if num > (len(self.traceLabels) - 1):
            return
        # ピークラベル表示モードか
        if self.ifi.GetProperty('penmode'):
            # オーバレイグラフか
            if self.overlayFlag:
                # トレース変更
                self.pl.DispLabel(num, None)
            else:
                # ラベル表示
                self.pl.DispLabel(num, evt.xdata)
            return

        # 該当ヒストグラムのヘッダーを取得
        header = self.do.GetHeader(num)
        # フレームの原点を取得
        # x0, y0 =  self.plot.frame.GetPosition()
        x0 = self.plot.x()
        y0 = self.plot.y()
        x0 = x0 + evt.x
        # フレームのサイズを取得
        # xx, yy =  self.plot.frame.GetSize()
        wsize = self.plot.size()
        xx = wsize.width()
        yy = wsize.height()
        # マウスクリック点の y 位置を求める
        y0 = y0 + yy - y0dpi - evt.y
        # ヘッダー表示ボックスを表示
        # self.hb = HeaderBox(self.plot.frame, (x0+5, y0+20), header)
        self.hb = HeaderBox(self.plot, (x0 + 5, y0 + 20), header)

    ###################################################
    def OnMouseUp(self, evt):
        """
        マウス左ボタンアップイベント処理関数
        @param  evt  イベント
        @retval 無し
        """
        # ヘッダー表示関数がでているか
        if self.hb is not None:
            # ボタンを離したら、ヘッダー表示ボックスを消す
            self.hb.CloseHB()

            self.hb = None

        # [inamura 120511]-->
        if (self.doubleClick_state1[1] != 0.0) and (self.doubleClick_state1[1] + self.doubleClick_interval) > time.time():
            if self.doubleClick_state1[0] == 0:
                self.plot.OnShow()
            if self.doubleClick_state1[0] == 1:
                self.plot.OnParam()
            if self.doubleClick_state1[0] == 2:
                self.plot.OnLabel()
            if self.doubleClick_state1[0] == 3:
                self.plot.OnTitle()
            self.doubleClick_state1[1] = 0.0
        else:
            self.doubleClick_state1[1] = time.time()
        # <--[inamura 120511]

    ###################################################
    def OnHome(self, wid, evt, data):
        """
        ホームポジション処理関数
        @param wid  ウィンドウID
        @param  evt　　イベント
        @param data　データ
        @retval 無し
        """
        axs = self.fig.get_axes()
        num = len(self.ranges)
        # X-Y 範囲を元に戻す
        i = 0
        for ax in axs:
            ax.set_xlim(self.ranges[i][0])
            ax.set_ylim(self.ranges[i][1])
            i += 1
            if i >= num:
                break

        # 表示範囲変更イベントを発行
        self.ifi.NotifyEvent(self, "changexy")
        # グラフを再描画
        self.canvas.draw()

    ###################################################
    def RePlotChart(self, *args):
        """
        (拡大した範囲を保存して)グラフを再描画
        @param  無し
        @retval 無し
        """
        ranges = []
        axs = self.fig.get_axes()

        # 再描画前の、X-Y 範囲を保存
        for ax in axs:
            ranges.append((ax.get_xlim(), ax.get_ylim()))

        # 新しい条件でグラフを描画(表示はしない)
        self.PlotOrgChart(False)
        # X-Y 範囲を元に戻す
        axs = self.fig.get_axes()
        for ax in axs:
            # 改ページによりグラフ数が変わることがあるため
            try:
                lims = ranges.pop(0)
                ax.set_xlim(lims[0])
                ax.set_ylim(lims[1])
            except:
                pass

        # ピークラベル表示クラスに、描画更新を通知、カレントラベルは保持
        self.pl.NewPlot(self.fig, self.canvas, False)
        self.mc.NewPlot(self.fig, self.canvas)  # [inamura 100715]
        # グラフを再描画
        self.canvas.draw()

    ###################################################
    def OnNotifyAddData(self, wid, evt, data):
        """
        ヒストグラムデータの追加イベント処理
        @param  wid イベント発生元のインスタンス
        @param  evt イベントタイプ
        @param  data 追加するデータのリスト
        @retval 無し
        """
        # 追加前のデータ数を取得
        preNum = len(self.traceLabels)
        # 追加されたデータ数分リストに追加
        for i in range(len(data)):
            # デフォルトの属性を設定
            # [inamura 110223]-->
            # self.traceAttrs.append(TraceAtt.defaultTraceAttr.copy())
            def_att = self.DefAtt.loadPlotAtt()
            if def_att is None:
                self.traceAttrs.append(TraceAtt.defaultTraceAttr.copy())
            else:
                self.traceAttrs.append(self.DefAtt.loadPlotAtt())
            # <--[inamura 110223]
            # 追加されたデータのヘッダーを取得
            header = self.do.GetHeader(i + preNum)
            # ヘッダー中の ラベルを取得し、トレースラベルリストに追加
            self.traceLabels.append(header["Label"])
            # ピークラベルに空のリストを追加
            self.peakLabels.append([])
        # 追加されたデータから表示
        pno = int(preNum / self.traceNum) + 1

        # 先にデータが表示されていなければ
        if preNum == 0:
            self.PlotOrgChart(False)

        # 現在のページと異なるなら
        if self.ifi.GetProperty('page') != (pno - 1):
            # 追加されたデータの最初のトレースが表示されるように、ページを変更して再表示
            self.ifi.NotifyEvent(self, "page", pno)
        else:
            # 表示範囲を変更せずにデータをプロット
            # [inamura 171225]-->
            if self.isAutoScaleY:
                self.PlotOrgChart(True)
            else:
                self.RePlotChart()
            # <--[inamura 171225]

        # ページ数・データ数表示更新要求
        self.ifi.NotifyEvent(self, "disppage")

    ###################################################
    def OnNotifyRemoveData(self, wid, evt, dnum):
        """
        ヒストグラムデータの削除イベント処理
        @param  wid イベント発生元のインスタンス
        @param  evt イベントタイプ
        @param  dnum 削除するデータの番号
        @retval 無し
        """
        # 全削除指定か
        if dnum == 0:
            del self.traceAttrs[:]
            del self.traceLabels[:]
            del self.peakLabels[:]
            self.page = 0
            # 再描画
            self.PlotOrgChart(True)
        # データがあれば
        elif dnum > 0 and dnum <= len(self.traceLabels):
            # 指定データの属性とトレースラベルを削除
            del self.traceAttrs[dnum - 1]
            del self.traceLabels[dnum - 1]
            del self.peakLabels[dnum - 1]
            # 該当データのページを計算
            pnum = int((dnum - 1) / self.traceNum) + 1

            # データ数を取得
            dno = self.ifi.GetProperty('datanum')
            # ページ数を計算
            maxp = int(dno / self.traceNum)
            if dno % self.traceNum > 0:
                maxp += 1
            # 最大ページを超えていたなら
            if pnum > maxp:
                pnum = maxp

            # 現在のページと異なるなら
            if self.ifi.GetProperty('page') != (pnum - 1):
                # 追加されたデータの最初のトレースが表示されるように、ページを変更して再表示
                self.ifi.NotifyEvent(self, "page", pnum)
            else:
                # 表示範囲を変更せずにデータをプロット
                self.RePlotChart()

        # ページ数・データ数表示更新要求
        self.ifi.NotifyEvent(self, "disppage")

    ###################################################
    def OnNotifyShuffleData(self, wid, evt, dnums):
        """
        ヒストグラムデータの削除イベント処理
        @param  wid イベント発生元のインスタンス
        @param  evt イベントタイプ
        @param  dnums 変更前のデータ番号と変更後のデータ番号のタプル
        @retval 無し
        """
        # データ番号がデータ数より小さいか
        if dnums[0] <= len(self.traceLabels) and dnums[1] <= len(self.traceLabels):
            # 変更前と変更後のデータを取得
            att1 = self.traceAttrs[dnums[0] - 1]
            att2 = self.traceAttrs[dnums[1] - 1]
            lbl1 = self.traceLabels[dnums[0] - 1]
            lbl2 = self.traceLabels[dnums[1] - 1]
            pkl1 = self.peakLabels[dnums[0] - 1]
            pkl2 = self.peakLabels[dnums[1] - 1]
            # データを入れ替え
            self.traceAttrs[dnums[0] - 1] = att2
            self.traceAttrs[dnums[1] - 1] = att1
            self.traceLabels[dnums[0] - 1] = lbl2
            self.traceLabels[dnums[1] - 1] = lbl1
            self.peakLabels[dnums[0] - 1] = pkl2
            self.peakLabels[dnums[1] - 1] = pkl1

        # 現在のページと異なるなら
        if self.ifi.GetProperty('page') != 0:
            # 最初のページを表示
            self.ifi.NotifyEvent(self, "page", 1)
        else:
            # 表示範囲を変更せずにデータをプロット
            self.RePlotChart()

    # [inamura 100715]-->
    ###################################################
    def OnNotifyReplaceData(self, wid, evt, data):
        """

        @param  wid イベント発生元のインスタンス
        @param  evt イベントタイプ
        @param  data
        @retval 無し
        """
        # データ番号がデータ数より小さいか
        if data[0] <= len(self.traceLabels) and data[0] >= 1:
            # not change TraceAttributes
            # データのヘッダーを取得
            header = self.do.GetHeader(data[0] - 1)
            # ヘッダー中の ラベルを取得し、トレースラベルリストに追加
            self.traceLabels[data[0] - 1] = header["Label"]
            # ピークラベルに空のリストを追加
            self.peakLabels[data[0] - 1] = []

        # 現在のページと異なるなら
        if self.ifi.GetProperty('page') != 0:
            # 最初のページを表示
            self.ifi.NotifyEvent(self, "page", 1)
        else:
            # 表示範囲を変更せずにデータをプロット
            self.RePlotChart()
    # <--[inamura 100715]
    ###################################################

    def OnNotifyTitle(self, wid, evtType, titles):
        """
        グラフタイトル変更イベント処理
        Set Plotting Param ボタンを選択可とする
        @param  wid イベント発生元のインスタンス
        @param  evt イベントタイプ
        @param  titles 1行目と2行目の文字列タプル
        @retval 無し
        """
        # グラフタイトルを取得
        title1, title2 = titles
        title1 = title1.replace(STRING_TO_REPLACE_SPACE, " ")
        title2 = title2.replace(STRING_TO_REPLACE_SPACE, " ")
        # メインタイトルが変更されたか
        if not title1 == '*':
            self.title1 = title1
            # タイトルを自動で変更しない
            self.autoTitle = False
        # サブタイトルが変更されたか
        if not title2 == '*':
            self.title2 = title2
        # グラフを再描画
        self.RePlotChart()

    ###################################################
    def OnNotifyLabel(self, wid, evtType, labels):
        """
        スケールラベル変更イベント処理
        Set Plotting Param ボタンを選択可とする
        @param  wid イベント発生元のインスタンス
        @param  evt イベントタイプ
        @param  labels X軸ラベルとY軸ラベル文字列タプル
        @retval 無し
        """
        # 縦軸、横軸のラベルを取得
        xlabel, ylabel = labels
        # 前と同じではなかったなら
        if not xlabel == '*':
            # 変更
            self.xlabel = xlabel
        # 前と同じではなかったなら
        if not ylabel == '*':
            self.ylabel = ylabel

        # ラベルを自動で変更しない
        self.autoLabel = False
        self.RePlotChart()

    # [inamura 110620]-->
    ###################################################
    def OnNotifySetUnits(self, wid, evtType, units):
        """
        For event to set units

        @param  wid      instance that make event occur
        @param  evtType  type of event
        @param  units    tupple of units for X and Y axes.
        @retval None
        """
        # Get units from argument
        self.xunit, self.yunit = units

        self.autoUnitLabel = False
        self.RePlotChart()
    # <--[inamura 110620]
    ###################################################

    def OnNotifySetFontInfo(self, wid, evtType, param):
        """
        [inamura 120513]
        @param  wid     instance of producing event
        @param  evtType type of event
        @param  param   tupple of index and value for fontInfo
        @retval None
        """
        self.fontInfo[param[0]] = param[1]
        self.RePlotChart()

    ###################################################
    def OnNotifySetTextInfo(self, wid, evtType, param):
        """
        [inamura 120513]
        @param  wid     instance of producing event
        @param  evtType type of event
        @param  param   tupple of index and value for textInfo
        @retval None
        """
        self.textInfo[param[0]] = param[1]
        self.RePlotChart()

    ###################################################
    def OnNotifyPlot(self, wid, evtType, value=None):
        """
        プロットデータ変更イベント処理
        @param  wid イベント発生元のインスタンス
        @param  evt イベントタイプ
        @param  value 使用せず
        @retval 無し
        """
        self.page = 0
        self.RePlotChart()

    ###################################################
    def OnNotifyXScale(self, wid, evtType, xscale):
        """
        プロットデータ変更イベント処理
        @param  wid イベント発生元のインスタンス
        @param  evt イベントタイプ
        @param  scale 　スケール範囲タプル
        @retval 無し
        """

        # 自動モードか
        if xscale[0]:
            self.autoXFlag = True
        else:
            # 範囲が指定されていたらマニュアル指定
            self.autoXFlag = False
            self.xx0 = xscale[1]
            self.xx1 = xscale[2]

        self.PlotOrgChart(True)

        ###################################################
    def OnNotifyYScale(self, wid, evtType, yscale):
        """
        プロットデータ変更イベント処理
        @param  wid イベント発生元のインスタンス
        @param  evt イベントタイプ
        @param  scale 　スケール範囲タプル
        @retval 無し
        """

        # 自動モードか
        if yscale[0]:
            self.autoYFlag = True
        else:
            # 範囲が指定されていたらマニュアル指定
            self.autoYFlag = False
            self.yy0 = yscale[1]
            self.yy1 = yscale[2]

        self.PlotOrgChart(True)

    ###################################################

    def OnNotifyLog(self, wid, evtType, value):
        """
        Log モード変更イベント処理
        @param  wid イベント発生元のインスタンス
        @param  evt イベントタイプ
        @param  value 　Log モードフラグ
        @retval 無し
        """

        # ログモード変更、再描画
        self.logFlag = value
        self.PlotOrgChart(True)

    # [inamura 140307]-->
    ###################################################

    def OnNotifyLogX(self, wid, evtType, value):
        """
        LogX モード変更イベント処理
        @param  wid イベント発生元のインスタンス
        @param  evt イベントタイプ
        @param  value 　Log モードフラグ
        @retval 無し
        """

        # ログモード変更、再描画
        self.logFlagX = value
        self.PlotOrgChart(True)

    # <--[inamura 140307]
    # [inamura 171225]-->
    ###################################################
    def OnNotifySetAutoScaleY(self, wid, evtType, flag):
        """

        """
        if isinstance(flag, bool):
            self.isAutoScaleY = flag
    # <--[inamura 171225]

    ###################################################
    def OnNotifyOver(self, wid, evtType, value):
        """
        Overlay モード変更イベント処理
        @param  wid イベント発生元のインスタンス
        @param  evt イベントタイプ
        @param  value 　Overlay モードフラグ
        @retval 無し
        """
        # オーバーレイチェックが変更された
        self.overlayFlag = value
        self.traceNum = len(self.traceLabels)
        # オーバレイモードなら
        if self.overlayFlag:
            # グラフ数を増やす
            self.traceNum = 20
        else:
            # グラフ数が 4 以上であれば
            # [inamura 100715]-->
            # Change the max number of graphs to 10
            if self.traceNum > 10:
                self.traceNum = 10
            # <--[inamura 100715]
        self.PlotOrgChart(True)
        # ページを1に変更
        self.ifi.NotifyEvent(self, "page", 1)

    ###################################################
    def OnNotifyOffset(self, wid, evtType, offsets):
        """
        オフセット変更イベント処理
        @param  wid イベント発生元のインスタンス
        @param  evt イベントタイプ
        @param  offsets 　XオフセットとYオフセットのタプル
        @retval 無し
        """

        # オーバレイ時のオフセットが変更された
        self.offsetX, self.offsetY = offsets
        self.RePlotChart()

    #################################################
    def OnNotifyTraceNum(self, wid, evtType, num):
        """
        グラフ数変更イベント処理
        @param  wid イベント発生元のインスタンス
        @param  evt イベントタイプ
        @param  num 　グラフ数
        @retval 無し
        """
        # グラフ数が変更された
        self.traceNum = num
        # ページを0に変更
        self.ifi.NotifyEvent(self, "page", 1)

    ##################################################
    def OnNotifyPlotParam(self, wid, evtType, param):
        """
        プロット条件変更イベント処理
        @param  wid イベント発生元のインスタンス
        @param  evtType イベントタイプ
        @param  param   トレース番号と属性ディクショナリのタプル
        　　　　　　　　トレース番号、0の場合は全トレースに適用
        @retval 無し
        """
        # 全トレースに適用か
        if param[0] == 0:
            # 全トレースの属性を変更
            for i in range(len(self.traceAttrs)):
                self._ChangeTraceAttr(i, param[1])
        else:
            # トレース番号は、現在のトレース数以内か
            if param[0] <= len(self.traceAttrs):
                # 指定されたトレースの属性を変更
                self._ChangeTraceAttr(param[0] - 1, param[1])
            else:
                try:
                    strEr = "Set Param data %d" % param[0]
                    raise PlotException(
                        'Common', 'C001', (strEr, "Chart:OnNotifyPlotParam"))
                except PlotException as ex:
                    PlotMessage(self.plot.frame, ex)

        # グラフを再描画
        self.RePlotChart()

    ##################################################
    def OnNotifyChangePage(self, wid, evtType, pageNo):
        """
        プロット条件変更イベント処理
        @param  wid イベント発生元のインスタンス
        @param  evtType イベントタイプ
        @param  param   トレース番号と属性ディクショナリのタプル
                        トレース番号、0の場合は全トレースに適用
        @retval 無し
        """
        # Start ---->  2010.03.01 KCS Add
        # 改ページ前のX-Y 範囲を取得
        ranges = []
        axs = self.fig.get_axes()
        for ax in axs:
            ranges.append((ax.get_xlim(), ax.get_ylim()))
        # 改ページ前の座標を保存
        if len(self.pageax) > self.page:
            self.pageax[self.page] = ranges
        else:
            self.pageax.append(ranges)
        # <----- End  2010.03.01 KCS Add

        if pageNo > 0:
            # ページを更新
            self.page = (pageNo - 1)
        else:
            self.page = 0

        # Start ---->  2010.03.01 KCS Change

        # グラフ表示範囲自動変更してグラフを再描画
        # self.PlotOrgChart(True)

        # 再描画せずにグラフを変更
        self.PlotOrgChart(False)
        # 変更したページの表示範囲が保存されていたなら
        if len(self.pageax) > self.page:
            # 先の表示範囲を取得
            ranges = self.pageax[self.page]
            # X-Y 範囲を元に戻す
            axs = self.fig.get_axes()
            for ax in axs:
                lims = ranges.pop(0)
                ax.set_xlim(lims[0])
                ax.set_ylim(lims[1])

        # グラフを描画
        self.mc.NewPlot(self.fig, self.canvas)  # [inamura 100715]
        self.canvas.draw()
        # <----- End  2010.03.01 KCS Change

        # ページ数・データ数表示更新要求
        self.ifi.NotifyEvent(self, "disppage")

    ##################################################
    def _ChangeTraceAttr(self, tno, attrs):
        """
        トレースの属性変更処理
        @param  tno トレース番号
        @param  attr トレース属性文字列(9桁)、'-' は変更無し
        @retval 無し
        """
        # トレースの属性ディクショナリを取得
        tattr = self.traceAttrs[tno]
        # キーを取得
        for key in attrs:

            # 属性があれば
            if key in tattr:
                # 属性を変更
                tattr[key] = attrs[key]
            else:
                # 内部処理エラー
                try:
                    strEr = "Set Param key %s" % key
                    raise PlotException(
                        'Common', 'C001', (strEr, "Chart:_ChangeTraceAttr"))
                except PlotException as ex:
                    PlotMessage(self.plot.frame, ex)

    ###################################################

    def SetScales(self, ax):
        """
        スケール範囲プロパティセット
        @param  ax : サブプロットの軸
        @retval 無し
        """
        if (not self.logFlag) and (not self.logFlagX):  # [inamura 160408]
            ax.ticklabel_format(style="sci", scilimits=(-5, 5))
        # X自動スケールが指定されていたら
        if self.autoXFlag:
            # 現在の範囲を取得してプロパティにセット
            self.xx0, self.xx1 = ax.get_xlim()
            isChangedScaleX = False
            for atrace in self.do.lstData:
                if isinstance(atrace[0], list):
                    xmin = min(atrace[0])
                    xmax = max(atrace[0])
                else:
                    xmin = atrace[0].min()
                    xmax = atrace[0].max()
                if self.xx0 > xmin:
                    self.xx0 = xmin
                    isChangedScaleX = True
                if self.xx1 < xmax:
                    self.xx1 = xmax
                    isChangedScaleX = True
            if isChangedScaleX:
                if self.logFlagX and self.xx0 <= 0.0:
                    self.xx0 = 1.0E-10
                ax.set_xlim((self.xx0, self.xx1))
        # マニュアル指定なら
        else:
            # プロパティをスケールにセット
            ax.set_xlim((self.xx0, self.xx1))

        # Y自動スケールが指定されていたら
        if self.autoYFlag:
            self.yy0, self.yy1 = ax.get_ylim()
            isChangedScaleY = False
            for atrace in self.do.lstData:
                if isinstance(atrace[1], list):
                    ymin = min(atrace[1])
                    # ymax = max(atrace[1])
                    ymax = -1.0 * MASKVALUE
                    for aval in atrace[1]:
                        if aval < MASKVALUE and aval > ymax:
                            ymax = aval
                else:
                    # treat numpy array
                    ymin = atrace[1].min()
                    # ymax = atrace[1][atrace[1]<MASKVALUE].max() ## MASK on MASKVALUE
                    under_mask = atrace[1][atrace[1] < MASKVALUE]
                    if len(under_mask) > 0:
                        ymax = under_mask.max()
                    else:
                        ymax = ymin
                if self.yy0 > ymin:
                    self.yy0 = ymin
                    isChangedScaleY = True
                if ymax < MASKVALUE and self.yy1 < ymax:
                    self.yy1 = ymax
                    isChangedScaleY = True
            if isChangedScaleY:
                if self.logFlag and self.yy0 <= 0.0:
                    self.yy0 = 1.0E-10
                ax.set_ylim((self.yy0, self.yy1))
        # マニュアル指定なら
        else:
            # ログモードでかつY軸始値が0以下であったなら
            if self.logFlag and self.yy0 <= 0.0:
                yy0 = 0.005
                if self.yy1 < yy0:
                    yy1 = 1.0
                else:
                    yy1 = self.yy1
                ax.set_ylim((0.005, yy1))
            else:
                # プロパティをスケールにセット
                ax.set_ylim((self.yy0, self.yy1))

    #############################
    def SetGNum(self, num):
        """
        グラフ数プロパティセット
        @param  num : グラフ数
        @retval 無し
        """
        self.traceNum = num
        self.page = 0
        self.PlotChart()
        # グラフを再描画
        self.canvas.draw()

    # [inamura 100716]-->
    ##################################################
    def OnNotifyMoniCursorOn(self, wid, evtType, flag):
        """
        Change status of cursor
        @param wid  windows ID
        @param evt  evnet
        @param flag True: cursor ON, Fasel: cursor OFF
        @retval None
        """
        if flag:
            self.PlotChart()
            self.mc.IsActive = True
            self.mc.NewPlot(self.fig, self.canvas)
        else:
            self.mc.IsActive = False
            self.mc.ClearCursor()

    #######################################
    def OnNotifyMoniCursorSet(self, wid, evt, xpos):
        """
        Set the cursor position
        @param wid  windows ID
        @param evt  evnet
        @param xpos  the position of cursor
        @retval None
        """
        if self.mc.IsActive:
            self.mc.DispCursor(xpos)

    # <--[inamura 100716]

################################
#  PlotData
################################


class PlotData(object):
    """
    ヒストグラムのデータクラス
    """

    ###################################################
    def __init__(self, parent, data, order):
        """
        コンストラクタ
        @param  parent  起動元インスタンス
        @param  data    ヒストグラムのエレメントアレイまたはそのリスト
                        (プロッタ起動時に引数が省略されていれば None )
        @param  order   プロッタの順番
        @retval 無し
        """

        self.parent = parent
        # 空のデータリストを作成
        self.lstData = []
        # データがあれば
        if data is not None:
            # リストか
            try:
                data[0][0][0]
            except:
                # 単独データであれば
                datTpl = self._ConvertData(data)
                if datTpl is not None:
                    # 1個のデータを変換して格納する
                    self.lstData.append(datTpl)
            # リストであれば
            else:
                # リスト中の各データに対し
                for datum in data:
                    # 変換して格納する
                    datTpl = self._ConvertData(datum)
                    if datTpl is not None:
                        # 1個のデータを変換して格納する
                        self.lstData.append(datTpl)

        # インターフェイスクラスのインスタンスを取得
        self.ifi = IFEvtProp(order)
        # データ追加イベントリスナー登録
        self.ifi.AddListner('add', self.OnNotifyAddData)
        # データ変更イベントリスナー登録    2010.02.17 KCS Add
        self.ifi.AddListner('change', self.OnNotifyChangeData)
        # データ削除イベントリスナー登録
        self.ifi.AddListner('remove', self.OnNotifyRemoveData)
        # データ順番変更イベントリスナー登録
        self.ifi.AddListner('shuffle', self.OnNotifyShuffleData)
        # [inamura 100715]-->
        # Listner to replace data
        self.ifi.AddListner('replace', self.OnNotifyReplaceData)
        # <--[inamura 100715]
        # [inamura 120128]
        self.ifi.AddListner('setlabeltodata', self.OnNotifySetLabel)

    ###################################################
    def _ConvertData(self, datum):
        """
        データ変換
        @param  datum  データタプル(Xデータ、Yデータ、ヘッダーディクショナリ、xunit, yunit )
        @retval x, y, er のリスト、ヘッダーディクショナリ、X軸単位、Y軸単位、のタプル
                xとyのみ必須、他は省略可
                len(x) = len(y)+1 : ヒストグラム、または len(x) = len(y) : スペクトルデータ
        """
        try:
            try:
                # データタプルの長さを取得
                lenTpl = len(datum)
            except:
                raise PlotException('FastVis', 'F000', ())

            # データタプルの長さを取得
            if len(datum[1]) < 2:

                raise PlotException('FastVis', 'F003', ())

            # X値リストを取得
            xl = datum[0]
            # Y値リストをアレイ化
            yy = np.array(datum[1])
            # X とY が同数のデータか
            if len(xl) == len(yy):
                xx = xl
                orgx = None
            # ヒストグラムデータか
            elif len(xl) == (len(yy) + 1):
                # Xデータ(bin の境界値)数 - 1 の array を作る
                xx = np.arange(0.0, (len(xl) - 1), 1.0)
                # 各bin の中央値を作る
                for i in range(len(xl) - 1):
                    xx[i] = (xl[i] + xl[i + 1]) / 2.0
                    # ヒストグラム表示用に、元のXリストを保存
                    orgx = xl
            else:
                # X の個数はYの個数と同じか、または1個だけ大きくなければならない
                raise PlotException('FastVis', 'F001', ())
        except PlotException as ex:
            PlotMessage(self.parent.frame, ex)
            return None

        # エラーリストがあるか
        if lenTpl > 2:
            if datum[2] is not None:
                er = np.array(datum[2])
            else:
                # エラー値がなければ、0値のアレイを作る
                er = np.zeros(len(yy))
        else:
            # エラー値がなければ、0値のアレイを作る
            er = np.zeros(len(yy))
        # ヘッダーディクショナリがあるか
        if lenTpl > 3:
            header = datum[3]
        else:
            # ヘッダーがなければ、空のディクショナリを作る
            header = {}
        # X軸単位文字列があるか
        if lenTpl > 4:
            xunit = datum[4]
        else:
            # X軸単位文字列が無ければNull 文字列
            xunit = ""
        # Y軸単位文字列があるか
        if lenTpl > 5:
            yunit = datum[5]
        else:
            # Y軸単位文字列が無ければNull 文字列
            yunit = ""

        # ヘッダー中にラベルがあるか
        try:
            header["Label"]
        except:
            # データの順番を文字列化してトレースラベルとする
            dataNum = len(self.lstData) + 1
            strLabel = "%d" % dataNum
            header["Label"] = strLabel

        return (xx, yy, er, header, xunit, yunit, orgx)

    ###################################################
    def OnNotifyAddData(self, wid, evt, data):
        """
        ヒストグラムデータの追加処理
        @param  wid イベント発生元のインスタンス
        @param  evt イベントタイプ
        @param  data 追加するデータのリスト
        @retval 無し        """
        # [inamura 100715]-->
        if not isinstance(data, list):
            self.lstData.append(self._ConvertData(data))
            return
        # <--[inamura 100715]
        # リスト中の各データに対し
        for datum in data:
            # 変換して格納する
            self.lstData.append(self._ConvertData(datum))

    ###################################################
    def OnNotifyChangeData(self, wid, evt, data):
        """
        ヒストグラムデータの変更処理  2010.02.17 KCS Add
        @param  wid イベント発生元のインスタンス
        @param  evt イベントタイプ
        @param  dnum 削除するデータの番号
        @retval 無し
        """
        # 全削除
        del self.lstData[:]
        # リスト中の各データに対し
        for datum in data:
            # 変換して格納する
            self.lstData.append(self._ConvertData(datum))
        # 描画範囲を変更せずに、データを描画
        self.ifi.NotifyEvent(self, "replot")

    ###################################################
    def OnNotifyRemoveData(self, wid, evt, dnum):
        """
        ヒストグラムデータの削除処理
        @param  wid イベント発生元のインスタンス
        @param  evt イベントタイプ
        @param  dnum 削除するデータの番号
        @retval 無し
        """
        # 全削除指定か
        if dnum == 0:
            del self.lstData[:]
        # 指定されたデータがあれば

        elif dnum > 0 and dnum <= len(self.lstData):
            # 指定データを削除
            del self.lstData[dnum - 1]
        else:
            try:
                strEr = "Delete data %d" % dnum
                raise PlotException(
                    'Common', 'C001', (strEr, "PlotData:OnNotifyRemoveData"))
            except PlotException as ex:
                PlotMessage(self.parent.frame, ex)

    ###################################################
    def OnNotifyShuffleData(self, wid, evt, dnums):
        """
        ヒストグラムデータ表示順変更処理
        @param  wid イベント発生元のインスタンス
        @param  evt イベントタイプ
        @param  dnums 変更前と変更後のデータ番号タプル
        @retval 無し
        """
        # データ番号がデータ数より小さいか
        if dnums[0] <= len(self.lstData) and dnums[1] <= len(self.lstData):
            # 変更前と変更後のデータを取得
            data1 = self.lstData[dnums[0] - 1]
            data2 = self.lstData[dnums[1] - 1]
            # データを入れ替え
            self.lstData[dnums[0] - 1] = data2
            self.lstData[dnums[1] - 1] = data1
        else:
            try:
                strEr = "Change data %d to %d" % (dnums[0], dnums[1])
                raise PlotException(
                    'Common', 'C001', (strEr, "PlotData:OnNotifyShuffleData"))
            except PlotException as ex:
                PlotMessage(self.parent.frame, ex)

    # [inamura 100715]-->
    ###################################################
    def OnNotifyReplaceData(self, wid, evt, data):
        """

        @param  wid イベント発生元のインスタンス
        @param  evt イベントタイプ
        @param  data
        @retval 無し
        """
        if data[0] <= len(self.lstData) and data[0] >= 1:
            self.lstData[data[0] - 1] = self._ConvertData(data[1])
        else:
            try:
                strEr = "Replace data %d " % (data[0])
                raise PlotException(
                    'Common', 'C001', (strEr, "PlotData:OnNotifyReplaceData"))
            except PlotException as ex:
                PlotMessage(self.parent.frame, ex)

    # <--[inamura 100715]
    # [inamura 120128]-->
    ###################################################
    def OnNotifySetLabel(self, wid, evt, data):
        """

        @param  wid イベント発生元のインスタンス
        @param  evt イベントタイプ
        @param  data   [ index, "New Label" ]
        @retval 無し
        """

        if data[0] <= len(self.lstData) and data[0] >= 1:
            if isinstance(data[1], str):
                self.lstData[data[0] - 1][3]["Label"] = data[1]

    # <--[inamura 120128]
    ###################################################

    def GetDataNum(self):
        """
        データ数取得
        @param 無し
        @retval データ数
        """
        return len(self.lstData)

    ###################################################
    def GetDataX(self, i):
        """
        ヒストグラムのXデータ取得
        @param  i       データの順番
        @retval Xデータ
        """
        return self.lstData[i][0]

    ###################################################
    def GetNonMaskY(self, i):
        """
        エラーバー表示用に、マスクデータを0で置き換える
        @param  i  データの順番
        @retval Yデータ
        """
        # Yデータ取得
        yy = self.lstData[i][1].copy()

        # マスクデータがあるか
        if yy.max() >= MASKVALUE:
            # マスクデータを、0.0に置き換える
            for ii in range(len(yy)):  # [inamura 120512]
                # マスクデータなら
                if yy[ii] >= MASKVALUE:
                    # 0 で置き換える
                    yy[ii] = 0.0

        return yy

    ###################################################
    def GetDataY(self, i):
        """
        ヒストグラムのYデータ(マスク付き)取得
        @param  i  データの順番
        @retval Yデータ
        """
        # マスクデータを作る
        yy = self.lstData[i][1]

        return Ma.masked_where(yy >= MASKVALUE, yy)

    ###################################################
    def GetLogDataY(self, i):
        """
        ヒストグラムのYデータ(マスク付き)取得
        ログ表示用にに、負値と0.0 を無くす
        @param  i  データの順番
        @retval Yデータ
        """
        # Yデータをコピー
        yy = self.lstData[i][1].copy()

        # [Inamura 100122]->
        # データ範囲の1/1000値を求める
        # logMin = (yy.max()  - yy.min()) / 10000.0
        # データの最小値は固定値とする（複数のデータプロット時の対策）
        logMin = 1.0E-20
        # <-[Inamura 100122]

        # 負値と0を logMin に置き換える
        for ii in range(len(yy)):
            # logMin より小さいなら
            if yy[ii] < logMin:
                # logMin で置き換える
                yy[ii] = logMin

        return Ma.masked_where(yy >= MASKVALUE, yy)

    ###################################################

    def GetDataEr(self, i):
        """
        ヒストグラムのエラーデータ取得
        @param  i       データの順番
        @retval エラーデータ
        """
        return self.lstData[i][2]

    ###################################################
    def GetHeader(self, i):
        """
        ヒストグラムのヘッダー取得
        @param  i       データの順番
        @retval ヘッダー情報(ディクショナリ)
        """

        return self.lstData[i][3]

    ###################################################
    def GetTraceLabel(self, i):
        """
        ヘッダーからトレースラベルを取得
        @param  i       データの順番
        @retval ラベル文字列
        """
        try:
            label = self.lstData[i][3]["Label"]
        except:
            label = ""
        return label

    ###################################################
    def GetRunNo(self, i):
        """
        ヘッダーからヒストグラムのRun No.取得
        @param  i       データの順番
        @retval Run No.(文字列)
        """
        try:
            # runno = self.lstData[i][3]["RunNo"]
            runno = self.lstData[i][3]["RUNNUMBER"]  # [inamura 100708]
        except:
            runno = ""
        return runno

    ###################################################
    def GetXUnit(self, i):
        """
        Xデータの単位文字列を取得
        @param  i       データの順番
        @retval 単位(文字列)
        """
        return self.lstData[i][4]

    ###################################################
    def GetYUnit(self, i):
        """
        Yデータの単位文字列を取得
        @param  i       データの順番
        @retval 単位(文字列)
        """
        return self.lstData[i][5]

    ###################################################

    def GetHistXY(self, logFlag, ix):
        """
        ヒストグラムバーグラフ用のデータ作成
        @param  logFlag  ログフラグ
        @param  i       データの順番
        @retval (X値リスト, Y値リスト)
        """

        # X値リストと Y値リストを準備
        lstX = []
        lstY = []
        # Yデータを取得
        ylst = self.lstData[ix][1]

        # ログモードか
        if logFlag:
            logMin = (ylst.max() - ylst.min()) / 10000.0
            edgeY = logMin
        else:
            edgeY = 0.0

        lstY.append(edgeY)

        # 中央値に変換前のXデータを取得
        xlst = self.lstData[ix][6]
        # ヒストグラムデータではなかたら、
        if xlst is None:
            # 元データのX をコピー
            xlst = self.lstData[ix][0][:]
            # 最終データをダミーで追加
            xx = xlst[len(xlst) - 1]
            xlst.append(xx)

        # バーデータX値とY値を作成
        for i in range(len(ylst)):
            lstX.append(xlst[i])
            lstX.append(xlst[i])
            # ログモードなら
            if logFlag:
                # ログ最小値以下か
                if ylst[i] < logMin:
                    lstY.append(logMin)
                    lstY.append(logMin)
                else:
                    lstY.append(ylst[i])
                    lstY.append(ylst[i])
            else:
                lstY.append(ylst[i])
                lstY.append(ylst[i])
        # 端点処理
        lstX.append(xlst[i + 1])
        lstX.append(xlst[i + 1])
        lstY.append(edgeY)

        # Yリストをアレイ化してマスクデータを作る
        yy = np.array(lstY)
        ym = Ma.masked_where(yy > MASKVALUE, yy)
        return (lstX, ym)


#######################################
#  CuiIF
#######################################
class CuiIF(object):
    """
    CUI からのコマンドを解析し、プロッタに対し
    イベントを発行する
    """
    ###################################################

    def StartPlot(self, plotNum, func):
        """
        コンストラクタ
        @param  sysarg 起動時の引数
        @param  func   起動した画面のクローズイベント発生時に実行する関数
        @retval 無し
        """
        self.func = func
        # テンポラリファイルクラスのインスタンス取得
        self.tp = TempFile()

        # プロッタ画面の起動
        self.plot = PlotFrame(None, None, plotNum)

        # プロッタが公開しているインターフェイスクラスのインスタンスを取得
        self.ifi = IFEvtProp(plotNum)

        # プロッタフレームクローズイベントのリスナー登録
        self.ifi.AddListner('plotclose', self.OnNotifyClose)

        # コマンドとその実行関数登録
        self.functions = {"add": self.AddData,
                          "remove": self.RemoveData,
                          "page": self.SetPage,
                          "tracenum": self.SetTraceNum,
                          "log": self.ChangeMode,
                          "logx": self.ChangeMode,
                          "overlay": self.ChangeMode,
                          "xscale": self.SetScale,
                          "yscale": self.SetScale,
                          "offset": self.SetIntegers,
                          "shuffle": self.ChangeData,
                          "doiconize": self.ChangeMode,
                          "plotparam": self.SetPlotAttr,
                          "save": self.SaveFile,
                          "loaddatafromtext": self.LoadDataFromText,
                          "savedataastext": self.SaveDataAsText,
                          "xlabel": self.SetXLabel,
                          "ylabel": self.SetYLabel,
                          "autoscaley": self.SetAutoScaleY,
                          "maintitle": self.SetMain,
                          "subtitle": self.SetSub,
                          "print": self.Exec,
                          "close": self.Exec,
                          "getattr": self.GetAttr}

    #####################################################

    def OnNotifyClose(self, wid, evt, value=None):
        """
        プロッタクローズイベント対応処理
        @param  wid 　 イベント発生元のインスタンス
        @param  evt 　イベントの種類
        @param  value  無し
        @retval 無し
        """
        # メッセージの解放
        MessageFile().CloseDoc()
        # 通信クラスの終了処理コールバック関数を実行
        self.func(*())

    ###################################################
    def TakeCommand(self, strCmd):
        """
        コマンドを解析し、プロッタ画面にイベントを発行
        @param  strCmd コマンド文字列
        @retval コマンドに対する応答
        """
        # 文字列を空白区切りで分解
        args = strCmd.split()
        # コマンド実行関数を取得
        try:
            function = self.functions[args[0]]
        except:
            print("Command error!!", args)
            return
        # 関数の実行
        return function(args)

    ###################################################
    def AddData(self, args):
        """
        データ追加イベント発行
        @param  args コマンドと引数のタプル
        @retval 無し
        """
        # テンポラリファイルを読んでデシリアライズ
        data = self.tp.ReadTempFile(args[1])
        if data is None:
            # 否定応答を返信
            return "NACK\n"
        # イベント発行
        self.ifi.NotifyEvent(self, args[0], data)

    ###################################################
    def RemoveData(self, args):
        """
        データ削除イベント発行
        @param  args コマンドと引数のタプル
        @retval 無し
        """
        # データ数取得
        dno = self.ifi.GetProperty("datanum")
        # 指定されたデータ数は、実際のデータ数以内か
        if dno >= int(args[1]):
            # データ削除イベント発行
            self.ifi.NotifyEvent(self, args[0], int(args[1]))
        else:
            # 否定応答を返信
            return "NACK\n"

    ###################################################
    def SetPage(self, args):
        """
        ページ設定イベント発行
        @param  args コマンドと引数のタプル
        @retval 無し
        """
        # データ数取得
        dno = self.ifi.GetProperty("datanum")
        # グラフ数取得
        gno = self.ifi.GetProperty("tracenum")
        # ページ数を計算
        maxp = int(dno / gno)
        if dno % gno > 0:
            maxp += 1
        # 指定されたページは、実際のページを超えないか
        if maxp >= int(args[1]):
            # ページ変更イベント発行
            self.ifi.NotifyEvent(self, args[0], int(args[1]))
        else:
            # 最後のページを指定
            self.ifi.NotifyEvent(self, args[0], maxp)

    ###################################################
    def SetTraceNum(self, args):
        """
        1ページ当たりのトレース数設定イベント発行
        @param  args コマンドと引数のタプル
        @retval 無し
        """
        # オーバーレイモード取得
        flag = self.ifi.GetProperty("overlay")
        tno = int(args[1])
        # 個別モードか
        if not flag:
            # 個別モードの場合、1ページ当たりの最大トレース数は4
            # [inamura 100715]-->
            # Change the max number of graphs to 10
            if tno > 10:
                # 否定応答を返信
                return "NACK\n"
            # <--[inamura 100715]

        # トレース数変更要求
        self.ifi.NotifyEvent(self, args[0], tno)

    ###################################################
    def ChangeData(self, args):
        """
        データ順番変更イベント発行
        @param  args コマンドと引数のタプル
        @retval 無し
        """
        # データ数取得
        dno = self.ifi.GetProperty("datanum")
        # 指定されたデータ数は、実際のデータ数以内か
        if dno >= int(args[1]) and dno >= int(args[2]):
            # データ順番変更イベント発行
            self.ifi.NotifyEvent(self, args[0], (int(args[1]), int(args[2])))
        else:
            # 否定応答を返信
            return "NACK\n"

    ###################################################
    def ChangeMode(self, args):
        """
        モード変更イベント発行(Boolean 型引数)
        ログモード変更、オーバレイモード変更、アイコン化
        @param  args コマンドと引数のタプル
        @retval 無し
        """
        # 変更フラグはFalse か
        if args[1] == "0":
            # モードイベント発行
            self.ifi.NotifyEvent(self, args[0], False)
        else:
            self.ifi.NotifyEvent(self, args[0], True)

    ###################################################

    def SetScale(self, args):
        """
        モード変更イベント発行
        @param  args コマンドと引数のタプル
        @retval 無し
        """
        # 引数無しであれば自動
        if len(args) == 1:
            # スケール変更(自動)イベント発行
            self.ifi.NotifyEvent(self, args[0], (True,))
        else:
            # マニュアルスケール範囲、X軸範囲または Y軸範囲
            self.ifi.NotifyEvent(
                self, args[0], (False, float(args[1]), float(args[2])))

    ###################################################
    def SetIntegers(self, args):
        """
        整数2個をデータとするコマンドを送信
        オフセット変更または順番変更イベント発行
        @param  args コマンドと引数のタプル
        @retval 無し
        """
        # オフセット変更イベント発行
        self.ifi.NotifyEvent(self, args[0], (int(args[1]), int(args[2])))

    ###################################################
    def SetPlotAttr(self, args):
        """
        プロット属性イベント発行
        @param  args コマンドと引数のタプル
        @retval 無し
        """
        # キーワード引き数の数を求める
        numKey = len(args) - 2
        # 属性ディクショナリを準備
        keydic = {}
        # キーワード引き数のディクショナリを作る
        for i in range(numKey):
            # 文字列を"="区切りで分解
            key, arg = args[i + 2].split('=')
            try:
                # 数値型
                keydic[key] = int(arg)
            except:
                # 文字列型
                keydic[key] = arg

        # データ数取得
        dno = self.ifi.GetProperty("datanum")
        # 指定されたデータ数は、実際のデータ数以内か
        if dno >= int(args[1]):
            # プロット属性変更イベント発行
            self.ifi.NotifyEvent(self, args[0], (int(args[1]), keydic))
        else:
            # 否定応答を返信
            return "NACK\n"

    ###################################################
    def SetAutoScaleY(self, args):
        """

        @param args
        @retval None
        """
        flag = False
        if args[1].upper() == "TRUE":
            flag = True
        self.ifi.NotifyEvent(self, "setautoscaley", flag)
    ###################################################

    def SaveFile(self, args):
        """
        画像保存コマンドを送信
        @param  args コマンドと引数のタプル
        @retval 無し
        """
        strArg = self._Rebuild(args)
        # 画像保存イベント発行
        self.ifi.NotifyEvent(self, args[0], strArg)

    ###################################################
    def _Rebuild(self, args):
        """
        文字列引数を復元(文字列に空白が含まれている場合)
        @param  args コマンドと引数のタプル
        @retval 復元後の文字列
        """
        strArg = ""
        # 引数文字列を連結
        for i in range(len(args) - 1):
            strArg = strArg + " " + args[i + 1]
        # 頭の余分な空白を消す
        ret = strArg[1:]
        # 復元後の文字列を返す
        return ret

    ###################################################
    def LoadDataFromText(self, args):
        """
        Load text data file
        @param args tupple of command and argument
        @retval None
        """
        strArg = self._Rebuild(args)
        self.ifi.NotifyEvent(self, args[0], strArg)

    ###################################################
    def SaveDataAsText(self, args):
        """
        Save plotting data as text file
        @param args tupple of command and arguments
        @retval None
        """
        fpath = ""
        isHist = False
        useMask = False
        maskVal = None
        if len(args) < 2:
            raise UserWarning("ERROR : SaveDataAsText")
        if len(args) >= 2:
            fpath = args[1]
        if len(args) >= 3:
            if args[2].upper() == "TRUE":
                isHist = True
        if len(args) >= 4:
            if args[3].upper() == "TRUE":
                useMask = True
            if len(args) >= 5:
                if args[4].upper() != "NONE":
                    maskVal = float(args[4])
        self.ifi.NotifyEvent(self, args[0], (fpath, isHist, useMask, maskVal))

    ###################################################
    def SetXLabel(self, args):
        """
        X軸ラベルコマンドを送信
        @param  args コマンドと引数のタプル
        @retval 無し
        """
        strArg = self._Rebuild(args)
        # スケールラベル設定コマンド送信
        self.ifi.NotifyEvent(self, "scalelabel", (strArg, "*"))

    ###################################################
    def SetYLabel(self, args):
        """
        Y軸ラベルコマンドを送信
        @param  args コマンドと引数のタプル
        @retval 無し
        """
        strArg = self._Rebuild(args)

        # スケールラベル設定コマンド送信
        self.ifi.NotifyEvent(self, "scalelabel", ("*", strArg))

    ###################################################
    def SetMain(self, args):
        """
        メインタイトルを送信
        @param  args コマンドと引数のタプル
        @retval 無し
        """
        strArg = self._Rebuild(args)

        # タイトル設定コマンド送信
        self.ifi.NotifyEvent(self, "title", (strArg, "*"))

    ###################################################
    def SetSub(self, args):
        """
        サブタイトルを送信
        @param  args コマンドと引数のタプル
        @retval 無し
        """
        strArg = self._Rebuild(args)

        # タイトル設定コマンド送信
        self.ifi.NotifyEvent(self, "title", ("*", strArg))

    ###################################################
    def Exec(self, args):
        """
        コマンド実行イベント発行(引数無)
        Close
        @param  args コマンドと引数のタプル
        @retval 無し
        """
        # コマンド実行要求イベント発行
        self.ifi.NotifyEvent(self, args[0])

    ###################################################
    def GetAttr(self, args):
        """
        属性の取得
        @param  args コマンドと引数のタプル
        @retval 無し
        """
        # 属性取得
        attr = self.ifi.GetProperty(args[1])

        # 属性が文字列か
        if args[2] == "0":
            return attr + '\n'
        # 整数か
        elif args[2] == "1":
            return "%d\n" % attr
        # 実数か
        elif args[2] == "2":
            return "%.5f\n" % attr
        # ブーリアンか
        elif args[2] == "3":
            if attr:
                return "True\n"
            else:
                return "False\n"
        # オブジェクトか
        elif args[2] == "4":
            # 現在の絶対時間(0.01秒単位)と、プロッタ番号よりテンポラリファイル名を作成
            tsec = int(time.time() * 100.0)
            tmpf = "attrs%d" % tsec
            # テンポラリファイルの絶対パスを作成(指定されたテンポラリディレクトリの下)
            tmppath = os.path.join(tempfile.gettempdir(), tmpf)
            try:
                # テンポラリファイルを開く
                fw = file(tmppath, "wb")
                # オブジェクトをバイナリモードでシリアライズ
                pickle.dump(attr, fw, True)
            except:
                print("\nError!! Cant create a temp file.")
            else:
                # テンポラリファイルをクローズ
                fw.close()
                # テンポラリファイル名を返信
                return tmppath + '\n'


if __name__ == '__main__':
    """
    CUI-GUI コミュニケータから、プロセスとして起動されるときに
    実行する処理
    """
    if PYSIDEVER == 2:
        # Hi-resolution Display for windows
        if hasattr(QtCore.Qt, 'AA_EnableHighDpiScaling'):
            QtWidgets.QApplication.setAttribute(
                QtCore.Qt.AA_EnableHighDpiScaling, True)

        # 他プロセスから起動されたか
    if len(sys.argv) > 2:
        # CUI-GUI コミュニケータのサーバアプリ(wxPython) 起動
        app = QtCom.QtApp(sys.argv)
        # Set Default Font Size to (default 14)
        deffont = app.font()
        if "UTSUSEMI_DEFAULT_FONTSIZE" in os.environ:
            deffontsize = int(os.environ["UTSUSEMI_DEFAULT_FONTSIZE"])
            deffont.setPointSize(deffontsize)
        else:
            deffont.setPointSize(10)
        app.setFont(deffont)
        # 汎用プロッタ(FastPlot)の CUI IF のインスタンス取得
        cuif = CuiIF()
        # 起動時引数より、通信ポート番号を取得
        portno = int(sys.argv[1])
        # 起動時引数より、プロッタ番号を取得
        pno = int(sys.argv[3])
        # プロッタ終了フラグが指定されているか
        if len(sys.argv) >= 5:
            if sys.argv[4] == "True":
                closeFlag = True
            else:
                closeFlag = False
        else:
            # 指定無しの場合は、True とする。
            closeFlag = True

        # プロッタを起動
        cuif.StartPlot(pno, app.OnGUIClose)
        # CUI との通信スタート(ポート番号と、コマンド処理関数を引数として渡す)
        app.OnStart(portno, closeFlag, cuif.TakeCommand)

    # 引数無しの場合は、テスト用のスクリプト
    else:

        """
        x =  [0, 3, 5, 6, 9, 11, 12, 13, 14, 16, 18, 21, 22, 23, 24, 38, 40]
        x1 =  [0, 3, 5, 6, 9, 11, 12, 13, 14, 16, 18, 21, 22, 23, 24, 38, 50]
        x2 =  [0, 3, 5, 6, 9, 11, 12, 13, 14, 16, 18, 21, 22, 23, 24, 25, 26]
        y1 =  [0, -0.1, 1.1, 5, 0, 0, 100, 250, 180.3, 90, 0, 0 , 2, 14, 0, 0]
        y2 =  [1, -1.8, 1.1, 5, 0, 0, 108.2, 290, 175.3, 95, 0, 0 , 2, 11, 0, 0]
        er = [1, 1, 1, 2, 1, 1, 6, 7.1, 5, 4, 2, 0, 2, 3, 2, 1]


        header = {'RunNo':'AMT00001',
                  'Label':'5-12(24)',
                  'Counts': "512",
                  '2Theater': "0.125",
                  'L2': "65.3215",
                  'Fai': "0.879"
                  }

        xunit = "micro-sec"
        xunit1 = "meV"
        yunit = "neutrons"

        dat1 = (x, y1, er, header, xunit, yunit)

        header2 = header.copy()
        header2["Label"]="11-32(120)"
        dat2 = (x1, y1, er, header2, xunit, yunit)

        header3 = header.copy()
        header3["Label"]="11-32(120)+11-32(121)+11-32(122)+11-32(123)"
        dat3 = (x, y2, er, header3, xunit1, yunit)

        header4 = header.copy()
        header4["Label"]="5-7(19)"
        dat4 = (x2, y1, er, header4, xunit, yunit)

        header5 = header.copy()
        header5["Label"]="5-7(20)+5-7(21)"
        header5["RunNo"]="AMT00003"
        dat5 = (x1, y1, er, header5, xunit, yunit)

        #app = wx.App()
        #PlotFrame(None, [dat1, dat2, dat3, dat4, dat5], 1)
        app=QtWidgets.QApplication(sys.argv)
        pw = PlotFrame(None,[dat1,dat2,dat3,dat4,dat5],1)
        """
        app = QtWidgets.QApplication(sys.argv)
        # Set Default Font Size to (default 14)
        deffont = app.font()
        if "UTSUSEMI_DEFAULT_FONTSIZE" in os.environ:
            deffontsize = int(os.environ["UTSUSEMI_DEFAULT_FONTSIZE"])
            deffont.setPointSize(deffontsize)
            print(
                "#[inamura 210830] FastPlotQt setPointSize(UTSUSEMI_DEFAULT_FONTSIZE)")
        else:
            print("#[inamura 210830] FastPlotQt setPointSize(10)")
            deffont.setPointSize(10)
        app.setFont(deffont)
        pw = PlotFrame(None, None, 1)
    # wxPython のメインループ開始
    # app.MainLoop()
    if PYSIDEVER == 6:
        sys.exit(app.exec())
    else:
        sys.exit(app.exec_())
