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

History
[inamura 181107] - fixed the issue that PeakLabel does not work with matplotlib 2.1.1 on Ubuntu 18.04
[inamura 171110] - fixed that scales are not updated on adding data
[inamura 170919] - add FitOnFastPlot class from ana.Reduction.UtilOnChoppers::FitOnChoppers
                 - add GUI to show errors and chi-sq of fitting results
                 - improve error handling on fitting
[inamura 170712] - Improve Fitting to import function from given file
[inamura 160726-2] - added Tick Setting
[inamura 160726] - Improve Fitting Function and parameters
[inamura 160722] - Add grid on plotter
[inamura 160714] - Add trace duplication
                 - Improve SaveAsText to treat MASKVALUE 
                 - Improve autoscale
                 - Add Fitting 
[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
"""
import wx
from wx import xrc
import os
import sys

import matplotlib
# 先に指定されていなかったら、バックエンドを指定
if not matplotlib.get_backend() == 'WXAgg':
    matplotlib.use('WXAgg')
import cPickle as pickle
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigCanvas
from pylab import *
from matplotlib.figure import Figure

#import matplotlib.numerix as numpy
#import matplotlib.numerix.ma as Ma
import numpy
try:
    import numpy.ma as Ma
except:
    import numpy.core.ma as Ma
from matplotlib.transforms import offset_copy
import time
import tempfile
from matplotlib.ticker import MultipleLocator, FormatStrFormatter

from vis.UtilPlot import *
from vis.ChartToolBar import *
import vis.WxCom as WxCom

##[inamura 120513]-->
v=matplotlib.__version__
vs = v.split(".")
MATPLOTLIB98 = False
if int(vs[0])==1 or int(vs[1])>92:
    MATPLOTLIB98 = True
##<--[inamura 120513]
##[inamura 160324]-->
MATPLOTLIB110 = False
if int(vs[0])==1 and int(vs[1])>=1:
    MATPLOTLIB110 = True
##<--[inamura 160324]

##[inamura 160714]-->
#########################################
#       SetSaveAsTextDialog
#########################################
class SetSaveAsTextDialog(wx.Dialog):
    """
    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
        
        # リソース取得      
        self.res = ResourceFile()
                
        self.dialog = self.res.GetDialog(parent.frame, 'DgSaveAsText')
        # アイコンを設定
        self.dialog.SetIcon(Images().GetMainIcon())
        
        # チェックボックス
        self.ckIgnoreMask = self.res.GetCtrl(self.dialog, 'ckIgnoreMask')
        
        # チェックボックスのイベントハンドラ登録
        self.ckIgnoreMask.Bind(wx.EVT_CHECKBOX, self.OnIgnoreMask, self.ckIgnoreMask)
        
        # コンボボックス
        self.chMaskVal = self.res.GetCtrl(self.dialog, 'chMaskValue')
        
        # コンボボックスのイベントハンドラ登録
        self.chMaskVal.Bind(wx.EVT_CHOICE, self.OnMaskVal, self.chMaskVal)
        
        # テキストボックスのコントローラ取得        
        self.txMaskVal = self.res.GetCtrl(self.dialog, 'txMaskValue')
        
        # ボタンのイベントハンドラを登録
        self.btnSave = self.res.GetCtrl( self.dialog, 'btSave' )
        self.btnCancel = self.res.GetCtrl( self.dialog, 'btCancel' )
        self.btnSave.Bind(wx.EVT_BUTTON, self.OnSave, self.btnSave )
        self.btnCancel.Bind(wx.EVT_BUTTON, self.OnCancel, self.btnCancel )
        #self.dialog.Bind(wx.EVT_BUTTON, self.OnSave, id=self.res.GetId('btSave'))
        #self.dialog.Bind(wx.EVT_BUTTON, self.OnCancel, id=self.res.GetId('btCancel'))
        
        #[X]ボタン押下時のイベントハンドラ登録
        self.dialog.Bind(wx.EVT_CLOSE, self.OnCancel)
        
        # Set Values
        self.initialize()
        
        # ダイアログ表示
        self.dialog.Show()
        
    ##########################################################
    def initialize(self):
        """
        """
        self.isIgnoreMask = True
        self.useGivenMaskVal = True
        self.ckIgnoreMask.SetValue(True)
        self.chMaskVal.Enable(False)
        self.txMaskVal.Enable(False)

        return
        
    ##########################################################
    def OnIgnoreMask(self, event=None):
        """
        IgnoreMask チェックボックスイベント処理
        @param   event イベント情報   
        @retval 無し
        """ 
        # チェックされたのか
        self.isIgnoreMask = self.ckIgnoreMask.GetValue()
        if self.isIgnoreMask:
            # MaskValue テキストボックスを選択不可
            self.chMaskVal.Enable(False)
            self.txMaskVal.Enable(False)
        else:  
            self.chMaskVal.Enable(True)
            self.txMaskVal.Enable(False)
            index = self.chMaskVal.GetSelection()
            if index==0:
                self.txMaskVal.Enable(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.GetValue() )
            except:
                msg = "Given Mask Value is invalid (%s)"%(self.txMaskVal.GetValue())
                dial = wx.MessageDialog(None, msg, "Warning", wx.OK | wx.ICON_EXCLAMATION )
                dial.ShowModal()
                self._CtrlParts(True)
                return
                
        maskInfo = None
        if self.isIgnoreMask:
            maskInfo = (True,0)
        else:
            if self.useGivenMaskVal:
                maskInfo=(False, maskval )
            else:
                maskInfo=(False, MASKVALUE )

        dlg =wx.FileDialog(self.parent.frame, "Save data as text files", style=wx.SAVE, wildcard='Text(*.*)|*.*')
        if dlg.ShowModal() == wx.ID_OK:
            TextFile(self.parent.order, self.isHist).WriteTo(dlg.GetPath(),self.dataobj,maskInfo)
            flp = dlg.GetPath()
            self.parent.DefaultDialogPath["SAVE"]=flp[:flp.rfind("/")]
            self.OnCancel()
            
        self._CtrlParts(True)

    ##########################################################
    def _CtrlParts(self, isEnable=True):
        """
        """
        if not isEnable in [True,False]:
            return
            
        if isEnable:
            self.btnSave.Enable(True)
            self.btnCancel.Enable(True)
            self.ckIgnoreMask.Enable(True)
            if self.isIgnoreMask:
                self.chMaskVal.Enable(False)
                self.txMaskVal.Enable(False)
            else:
                self.chMaskVal.Enable(True)
                self.txMaskVal.Enable(False)
                index = self.chMaskVal.GetSelection()
                self.useGivenMaskVal = True
                if index==0:
                    self.txMaskVal.Enable(True)
                    pass
                elif index==1:
                    self.txMaskVal.SetValue( str(0.0) )
                elif index==2:
                    self.txMaskVal.SetValue( str(-1.0) )
                else:
                    self.useGivenMaskVal = False
                    self.txMaskVal.SetValue( "" )
        else:
            self.ckIgnoreMask.Enable(False)
            self.chMaskVal.Enable(False)
            self.txMaskVal.Enable(False)
            self.btnSave.Enable(False)
            self.btnCancel.Enable(False)
            
            
    ##########################################################
    def OnCancel(self, evt=None):
        """
        Cancel ボタンイベント処理
        @param  evt イベント情報
        @retval 無し
        """ 
        
        self.dialog.Destroy()        
        
#######################################
#  Fitting
#######################################
from scipy import optimize
from scipy import sum,sqrt,diag
class FitOnFastPlot(object):
    class Parameter:
        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 = arange(y.shape[0])
        p=[param() for param in parameters]
        result = optimize.leastsq(f, p, full_output=1)

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

class FittingFrame(wx.Frame):
    """
    データ一覧表示ボックスクラス
    """
    ##########################################################
    def __init__(self, parent,postfix,traceNo):
        """
        Fitting
        @param  parent   親(PlotFrame)のインスタンス
        @param  postfix  画面タイトルに付ける親の識別子  
        @param traceNo  trace
        @retval 無し
        """ 
        self.parent = parent
        # インターフェイスクラスのインスタンスを取得
        self.ifi = IFEvtProp(parent.order)
        # リソース取得      
        self.res = ResourceFile()
        # フローティングボックスフレーム作成
        self.frame = self.res.GetFrame(parent.frame, 'FittingFrame')
        # アイコンを設定
        self.frame.SetIcon(Images().GetMainIcon())
        # タイトル文字列を取得
        strT = self.frame.GetTitle()
        # 順番を付してタイトル文字列を作成
        self.frame.SetTitle(strT + postfix)
        
        # リソースからコントロールを取得
        # Choice
        self.cbTrace = self.res.GetCtrl(self.frame, 'cbTrace')
        self.cbFunc = self.res.GetCtrl(self.frame, 'cbFunctions')
        
        # choiceのイベントハンドラ登録
        self.cbTrace.Bind(wx.EVT_CHOICE, self.OnChoiceTrace, self.cbTrace)
        self.cbFunc.Bind(wx.EVT_CHOICE, self.OnChoiceFunc, self.cbFunc)
        
        self.RangeCtrl = []
        self.RangeCtrl.append( self.res.GetCtrl(self.frame, "txRangeMin"))
        self.RangeCtrl.append( self.res.GetCtrl(self.frame, "txRangeMax"))
        
        self.ArgsCtrl = []
        for i in range(8):
            init_val = self.res.GetCtrl(self.frame, "txA%d"%(i+1) )
            fix_ck = self.res.GetCtrl(self.frame, "ckA%d"%(i+1) )
            ret_val = self.res.GetCtrl(self.frame, "txA%dr"%(i+1) )
            err_val = self.res.GetCtrl(self.frame, "txA%de"%(i+1) )
            self.ArgsCtrl.append( (init_val, fix_ck, ret_val, err_val) )
        
        self.btCheck = self.res.GetCtrl(self.frame, 'btCheck')
        self.btFitting = self.res.GetCtrl(self.frame, 'btFitting')
        self.btClose = self.res.GetCtrl(self.frame, 'btClose')
        self.btLoadFunc = self.res.GetCtrl(self.frame, 'btLoadFunc') ##[inamura 170712]
        self.txChisq = self.res.GetCtrl(self.frame, 'txChisq') ##[inamura 170919]
        
        # データがあれば
        if len(self.parent.dataobj.lstData) > 0:
            pass
        else:
            msg = "There is no data."
            dial = wx.MessageDialog(None, msg, "Error", wx.OK | wx.ICON_EXCLAMATION )
            dial.ShowModal()
            self.OnClose()
              
        # ボタンのイベントハンドラ登録
        self.frame.Bind(wx.EVT_BUTTON, self.OnCheck, id=self.res.GetId('btCheck'))
        self.frame.Bind(wx.EVT_BUTTON, self.OnFitting, id=self.res.GetId('btFitting'))
        self.frame.Bind(wx.EVT_BUTTON, self.OnClose, id=self.res.GetId('btClose'))
        self.frame.Bind(wx.EVT_BUTTON, self.OnLoadFunc, id=self.res.GetId('btLoadFunc')) ##[inamura 170712]

        #[X]ボタン押下時のイベントハンドラ登録
        self.frame.Bind(wx.EVT_CLOSE, self.OnClose)
        
        # get labels of trace data
        self.UpdateTraceList(traceNo)
        
        # get trace data
        if len(self.parent.dataobj.lstData)>0:
            self.data = self.parent.dataobj.lstData[traceNo]
            self.RangeCtrl[0].SetValue("%g"%(self.data[0][0]))
            self.RangeCtrl[1].SetValue("%g"%(self.data[0][-1]))
        else:
            self.data=None
        
        self.frame.Show()
        
        # to avoid parts in frame are shrinked
        if sys.platform =="darwin":
            self.frame.SetSize( (380,600) )
        if sys.platform =="win32":
            self.frame.SetSize( (390,620) )

        ##[inamura 170712]-->
        # Fitting Function Setting
        self.FitFuncModules = []    # stores tuple of ( <imported module>, <import path> )
        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:
            vis_path = os.path.join( os.environ['UTSUSEMI_BASE_DIR'],'vis')
            sys.path.insert(0, vis_path )
            self.FitFuncModules.append( (__import__( "MPlotBaseFittingFuncs" ), vis_path) )
        except:
            raise UserWarning, "Failed to import MPlotBaseFittingFuncs."

        # Load Fitting Functions for the instrument
        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" ))


        # Make FitFucList
        for i,funcs in enumerate(self.FitFuncModules):
            for item in funcs[0].params:
                if type(item)!=type([]) or len(item)!=4:
                    raise UserWarning, "%s params is invalid format"%(funcs[0].__name__)
                
                in_item = item[:]
                in_item.append(i) # [0]:title, [1]:function obj, [2]:num of param, [3]:png name, [4]:index of file
                self.FitFuncList.append(in_item)

        # Reconstruct Choice list
        self.cbFunc.Clear()
        for item in (self.FitFuncList):
            self.cbFunc.Append( item[0] )
        # set function fig
        self.cbFunc.SetSelection(0)
        self.FuncFig = None
        self.SetFuncFig(0)
        self.SetArgsEnable(0)

        #<--[inamura 170712]
            
    ##########################################################
    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.frame.Destroy()

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

    ##########################################################
    def SetFuncFig(self, funcNo=0):
        """
        Set Fitting Function figure [inamura 170712] changed
        @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 )
        if os.path.exists( splash_path ):
            if self.FuncFig!=None:
                self.FuncFig.Destroy()
            splash_panel = self.res.GetCtrl(self.frame, 'pnlFunction' )
            splash_bmp = wx.Image(splash_path).ConvertToBitmap()
            self.FuncFig = wx.StaticBitmap(splash_panel, -1, splash_bmp, (2,0),(400,50))
            splash_panel.Show()
        else:
            splash_panel = self.res.GetCtrl(self.frame, 'pnlFunction' )
            splash_panel.Hide()

    ##########################################################
    def UpdateTraceList(self,traceNo=0):
        """
        """
        self.ldata = self.ifi.GetProperty('tracelabels')
        if self.cbTrace.GetCount()!=0:
            for i in range(self.cbTrace.GetCount()):
                self.cbTrace.Delete(0)
        
        for a_trace in self.ldata:
            self.cbTrace.Append( a_trace )
        
        if traceNo<self.cbTrace.GetCount():
            self.cbTrace.SetSelection(traceNo)
        
    ##########################################################
    def OnChoiceTrace(self, evt=None):
        """
        Combo Box
        @param  evt イベント情報
        @retval 無し
        """ 
        trace_no = self.cbTrace.GetSelection()
        self.UpdateTraceList(trace_no)
        #print "trace_no=",trace_no
        self.data = self.parent.dataobj.lstData[trace_no]
        self.RangeCtrl[0].SetValue("%g"%(self.data[0][0]))
        self.RangeCtrl[1].SetValue("%g"%(self.data[0][-1]))

    ##########################################################
    def OnChoiceFunc(self, evt=None):
        """
        Combo Box
        @param  evt イベント情報
        @retval 無し
        """ 
        func_id = self.cbFunc.GetSelection()
        #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()
        dlg =wx.FileDialog(self.frame, "Open Fitting Function file", tdir, style=wx.OPEN, wildcard='python(*.py)|*.py')
        # OK であればファイルを開く
        if dlg.ShowModal() == wx.ID_OK:
            path_file = dlg.GetPath()
            module_name = os.path.basename( path_file )
            module_name = module_name.split(".")[0]
            dir_name = os.path.dirname( path_file )

            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.Append( in_item[0] )

        
    ##########################################################
    def OnCheck(self, evt=None):
        """
        Check initial parameters for fitting
        @param  evt イベント情報
        @retval 無し
        """ 
        from scipy import exp
        xmin = float( self.RangeCtrl[0].GetValue() )
        xmax = float( self.RangeCtrl[1].GetValue() )
        if xmin>=xmax:
            msg = "Fitting Range are invalid."
            dial = wx.MessageDialog(None, msg, "Error", wx.OK | wx.ICON_EXCLAMATION )
            dial.ShowModal()
            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 = numpy.array(xxx)
        yyy = numpy.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.GetSelection()
        
        fit = FitOnFastPlot()
        A1 = fit.Parameter( float( self.ArgsCtrl[0][0].GetValue() ) )
        A2 = fit.Parameter( float( self.ArgsCtrl[1][0].GetValue() ) )
        A3 = fit.Parameter( float( self.ArgsCtrl[2][0].GetValue() ) )
        A4 = fit.Parameter( float( self.ArgsCtrl[3][0].GetValue() ) )
        A5 = fit.Parameter( float( self.ArgsCtrl[4][0].GetValue() ) )
        A6 = fit.Parameter( float( self.ArgsCtrl[5][0].GetValue() ) )
        A7 = fit.Parameter( float( self.ArgsCtrl[6][0].GetValue() ) )
        A8 = fit.Parameter( float( self.ArgsCtrl[7][0].GetValue() ) )

        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])
                
    ##########################################################
    def OnFitting(self, evt=None):
        """
        Combo Box
        @param  evt イベント情報
        @retval 無し
        """ 
        
        xmin = float( self.RangeCtrl[0].GetValue() )
        xmax = float( self.RangeCtrl[1].GetValue() )
        if xmin>=xmax:
            msg = "Fitting Range are invalid."
            dial = wx.MessageDialog(None, msg, "Error", wx.OK | wx.ICON_EXCLAMATION )
            dial.ShowModal()
            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 = numpy.array(xxx)
        yyy = numpy.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.GetSelection()

        fit = FitOnFastPlot()
        A1 = fit.Parameter( float( self.ArgsCtrl[0][0].GetValue() ) )
        A2 = fit.Parameter( float( self.ArgsCtrl[1][0].GetValue() ) )
        A3 = fit.Parameter( float( self.ArgsCtrl[2][0].GetValue() ) )
        A4 = fit.Parameter( float( self.ArgsCtrl[3][0].GetValue() ) )
        A5 = fit.Parameter( float( self.ArgsCtrl[4][0].GetValue() ) )
        A6 = fit.Parameter( float( self.ArgsCtrl[5][0].GetValue() ) )
        A7 = fit.Parameter( float( self.ArgsCtrl[6][0].GetValue() ) )
        A8 = fit.Parameter( float( self.ArgsCtrl[7][0].GetValue() ) )
        
        Fixed_list =[]
        for a_ctrl in self.ArgsCtrl:
            Fixed_list.append( not a_ctrl[1].GetValue() ) # 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])
        
        self.ArgsCtrl[0][2].SetLabel("%g"%(A1()))
        self.ArgsCtrl[1][2].SetLabel("%g"%(A2()))
        self.ArgsCtrl[2][2].SetLabel("%g"%(A3()))
        self.ArgsCtrl[3][2].SetLabel("%g"%(A4()))
        #[inamura 160726]-->
        self.ArgsCtrl[4][2].SetLabel("%g"%(A5()))
        self.ArgsCtrl[5][2].SetLabel("%g"%(A6()))
        self.ArgsCtrl[6][2].SetLabel("%g"%(A7()))
        self.ArgsCtrl[7][2].SetLabel("%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].SetLabel("+- %g"%(sqrt(err_list[ind_err])))
                else:
                    self.ArgsCtrl[i][3].SetLabel("+- ERROR")
                ind_err = ind_err + 1
            else:
                self.ArgsCtrl[i][3].SetLabel("+- ")

        self.txChisq.SetLabel("%g"%(chisq))
        """
        if func_id==0 or func_id==2:
            self.ArgsCtrl[4][2].SetLabel("%g"%(A5()))
        else: ## id=1,3,4
            self.ArgsCtrl[4][2].SetLabel("%g\n(%g)"%(A5(),2.0*math.sqrt(2.0*math.log(2))*A5() ))
        self.ArgsCtrl[5][2].SetLabel("%g"%(A6()))
        self.ArgsCtrl[6][2].SetLabel("%g"%(A7()))
        if func_id!=4:
            self.ArgsCtrl[7][2].SetLabel("%g"%(A8()))
        else:
            self.ArgsCtrl[7][2].SetLabel("%g\n(%g)"%(A8(),2.0*math.sqrt(2.0*math.log(2))*A8() ))
        """
        #<--[inamura 160726]
#<--[inamura 160714]
##[inamura 160726-2]-->
#########################################
#       SetAxisTickStyleDialog
#########################################
class SetAxisTickStyleDialog(wx.Dialog):
    """
    AxisTickStyle 設定ダイアログクラス
    """
    ##########################################################
    def __init__(self, parent, order, postfix):
        """
        コンストラクタ
        @param  parent   親ウィンドウのID
        @param  order  プロッタの起動順序
        @param  postfix 画面タイトルに付ける親の識別子    
        @retval 無し
        """ 
        
        self.ifi = IFEvtProp(order)
        self.parent = parent
        
        # リソース取得      
        self.res = ResourceFile()
        self.dialog = self.res.GetDialog(parent, 'DgTickStyleSetting')
        # アイコンを設定
        self.dialog.SetIcon(Images().GetMainIcon())
        
        # ボタンのイベントハンドラを登録
        self.dialog.Bind(wx.EVT_BUTTON, self.OnApply, id=self.res.GetId('btApply'))
        self.dialog.Bind(wx.EVT_BUTTON, self.OnRevert, id=self.res.GetId('btRevert'))
        self.dialog.Bind(wx.EVT_BUTTON, self.OnClose, id=self.res.GetId('btClose'))
        
        # リソースよりコントロールを取得
        # テキストボックスのコントローラ取得        
        self.txMajorLength = self.res.GetCtrl(self.dialog, 'txMajorLength')
        self.txMajorWidth = self.res.GetCtrl(self.dialog, 'txMajorWidth')
        self.txMinorLength = self.res.GetCtrl(self.dialog, 'txMinorLength')
        self.txMinorWidth = self.res.GetCtrl(self.dialog, 'txMinorWidth')
        
        # チェックボックス
        self.ckUseMinorTick = self.res.GetCtrl(self.dialog, 'ckUseMinorTick')
        self.ckRightSideOn = self.res.GetCtrl(self.dialog, 'ckRightSideOn')
        self.ckTopSideOn = self.res.GetCtrl(self.dialog, 'ckTopSideOn')
        
        # チェックボックスのイベントハンドラ登録
        self.ckUseMinorTick.Bind(wx.EVT_CHECKBOX, self.OnUseMinorTick, self.ckUseMinorTick)
        self.ckRightSideOn.Bind(wx.EVT_CHECKBOX, self.OnRightSide, self.ckRightSideOn)
        self.ckTopSideOn.Bind(wx.EVT_CHECKBOX, self.OnTopSide, self.ckTopSideOn)

        #[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()
        
        # ダイアログ表示
        self.dialog.Show()
        
        # to avoid parts in frame are shrinked
        if sys.platform =="darwin":
            self.dialog.SetSize( (310,280) )
        if sys.platform =="win32":
            self.dialog.SetSize( (320,290) )

    ##########################################################
    def initialize(self, evt=None):
        """
        """
        pdict = self.ifi.GetProperty("tickstyledic")
        self.txMajorLength.SetValue( str(pdict["MajorLength"]) )
        self.txMajorWidth.SetValue( str(pdict["MajorWidth"]) )
        self.txMinorLength.SetValue( str(pdict["MinorLength"]) )
        self.txMinorWidth.SetValue( str(pdict["MinorWidth"]) )
        flag = pdict["Minor"]
        self.ckUseMinorTick.SetValue( flag )
        self.txMinorLength.Enable(flag)
        self.txMinorWidth.Enable(flag)
        if pdict["TopSide"]=="on":
            self.ckTopSideOn.SetValue(True)
        else:
            self.ckTopSideOn.SetValue(False)
        if pdict["RightSide"]=="on":
            self.ckRightSideOn.SetValue(True)
        else:
            self.ckRightSideOn.SetValue(False)
        
    ##########################################################
    def OnUseMinorTick(self, evt=None):
        """
        UseMinorTick Check Boxイベント処理
        @param  evt イベント情報
        @retval 無し
        """
        pdict = self.ifi.GetProperty("tickstyledic")
        flag = self.ckUseMinorTick.GetValue()
        pdict["Minor"] = flag
        self.txMinorLength.Enable(flag)
        self.txMinorWidth.Enable(flag)
        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.GetValue():
            pdict["TopSide"] = "on"
        else:
            pdict["TopSide"] = "off"
        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.GetValue():
            pdict["RightSide"] = "on"
        else:
            pdict["RightSide"] = "off"
        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.GetValue() )
        pdict["MajorWidth"]  = float( self.txMajorWidth.GetValue() )
        pdict["MinorLength"] = float( self.txMinorLength.GetValue() )
        pdict["MinorWidth"]  = float( self.txMinorWidth.GetValue() )
        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.keys():
            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.ifi.NotifyEvent(self, "setaxistickstyle2ddg", True) 
        self.dialog.Destroy()
        
##<--[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)

    ##################################    
    def _init_toolbar(self):
        """
        ツールバーを作成
        @param 無し
        @retval 無し
        """
        #先にスーパークラスのツールバーを作る
        ChartToolBar._init_toolbar(self)
        
        self._parent = self.parent.canvas.GetParent()
        # アイコンのIDを生成
        self._PEN    =wx.NewId()
        self._LEFT    =wx.NewId()
        self._RIGHT    =wx.NewId()
        self._PIN    =wx.NewId()
        self._LABEL    =wx.NewId()
        self._DSPC   =wx.NewId() ##[inamura 110303]
        self._GRIDON = wx.NewId() ##[inamura 160722]
        # アイコンのサイズ指定
        self.SetToolBitmapSize(wx.Size(24, 24))
        
        # セパレータを入れる
        self.AddSeparator()
        #アイコンをツールバーに追加
        self.AddCheckTool(self._GRIDON, self.GetAxisGridIconData(), shortHelp='Axis Grid On/Off')##[inamura 160722]
        self.AddCheckTool(self._PEN, Images().GetBmp("Pen"), shortHelp='Peak Labeling Mode')
        self.AddSimpleTool(self._LEFT, Images().GetBmp("Left"), 'Shift Label Position to Left')
        self.AddSimpleTool(self._RIGHT, Images().GetBmp("Right"), 'Shift Label Position to Right')
        self.AddSimpleTool(self._PIN, Images().GetBmp("Pin"), 'Pinup a Label')
        self.AddSimpleTool(self._DSPC, self.GetCursorIconData(), 'CalcDspacing') ##[inamura 110303]
        self.AddSimpleTool(self._LABEL, Images().GetBmp("Xlabel"), 'Change Label Type')

        #　各アイコン押下時のイベントハンドラ作成 
        if wx.VERSION_STRING >= '2.5':
            self.Bind(wx.EVT_TOOL, self.OnPen, id=self._PEN)
            self.Bind(wx.EVT_TOOL, self.OnLeft, id=self._LEFT)
            self.Bind(wx.EVT_TOOL, self.OnRight, id=self._RIGHT)
            self.Bind(wx.EVT_TOOL, self.OnPin, id=self._PIN)
            self.Bind(wx.EVT_TOOL, self.OnLabel, id=self._LABEL)
            self.Bind(wx.EVT_TOOL, self.OnCalcDS, id=self._DSPC) ##[inamura 110303]
            self.Bind(wx.EVT_TOOL, self.OnAxisGrid, id=self._GRIDON) ##[inamura 160722]
        else:
            wx.EVT_TOOL(self, self._PEN, self.OnPen)
            wx.EVT_TOOL(self, self._LEFT, self.OnLeft)
            wx.EVT_TOOL(self, self._RIGHT, self.OnRight)
            wx.EVT_TOOL(self, self._PIN, self.OnPin)
            wx.EVT_TOOL(self, self._LABEL, self.OnLabel)
            wx.EVT_TOOL(self, self._DSPC, self.OnCalcDS) ##[inamura 110303]
            wx.EVT_TOOL(self, self._GRIDON, self.OnAxisGrid) ##[inamura 160722]
            
        # ペンモードをオフ   
        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)
        # ツールバーの再表示
        self.Realize()

    ##################################    
    def OnPen(self, *args):
        """
        ピークラベルモード変更
        @param  *args    イベント情報
        @retval 無し
        """
        # ピークラベルモードの設定または解除 
        self.SetPenBtn(self.GetToolState(self._PEN))
 
    ##################################    
    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 無し
        """ 
        # 前のラベルタイプアイコンを消す        
        self.DeleteTool(self._LABEL)
        # ラベルタイプを変更し、該当するアイコンを追加する
        if self.labeltype == 1:
            self.labeltype = 2
            self.AddSimpleTool(self._LABEL, Images().GetBmp("Ylabel"), 'Change Label Type')
        elif self.labeltype == 2:
            self.labeltype = 3
            self.AddSimpleTool(self._LABEL, Images().GetBmp("XYlabel"), 'Change Label Type')
        ## [inamura 160122]-->
        elif self.labeltype == 3:
            self.labeltype = 4
            self.AddSimpleTool(self._LABEL, Images().GetBmp("Xlabel"), 'Change Label Type')
        elif self.labeltype == 4:
            self.labeltype = 5
            self.AddSimpleTool(self._LABEL, Images().GetBmp("Ylabel"), 'Change Label Type')
        elif self.labeltype == 5:
            self.labeltype = 6
            self.AddSimpleTool(self._LABEL, Images().GetBmp("XYlabel"), 'Change Label Type')
        ##<--[inamura 160122]
        else:
            self.labeltype = 1
            self.AddSimpleTool(self._LABEL, Images().GetBmp("Xlabel"), 'Change Label Type')
        
        # ツールバー再表示
        self.Realize()
        # ラベルタイプ変更イベント通知
        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.ToggleTool(self._PEN, flag)
        # 各ボタンの選択可/不可状態変更
        self.EnableTool(self._LEFT, flag)  
        self.EnableTool(self._RIGHT, flag)  
        self.EnableTool(self._PIN, flag)
        self.EnableTool(self._LABEL, flag)
        self.EnableTool(self._DSPC, flag) ##[inamura 110303]
        # ペンモード変更イベント通知
        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)
        else:
            # ペンモードボタンを選択可とする
            self.EnableTool(self._PEN, True)  

##[inamura 110303]-->
    ###################################################
    def GetCursorIconData(self):
        """
        Return Icom picture data as Bitmap
        Image text data is XPM format.
        @param None
        @retval wx.Bitmap
        """
        xpm_icon_data = [
            "24 24 5 1",
            " 	c None",
            ".	c #999999",
            "+	c #FFFFFF",
            "@	c #FF0000",
            "#	c #07C5FB",
            "........................",
            ".++++++++++++++++++++++.",
            ".++++++++++++++++++++++.",
            ".++@@@@++++++++@+++++++.",
            ".+@@+++@+++++++@+++++++.",
            ".+@++++++@@@+++@+++@@@+.",
            ".+@+++++++++@++@++@++++.",
            ".+@++++++@@@@++@++@++++.",
            ".+@@+++@+@++@++@++@++++.",
            ".++@@@@++@@@@++@+++@@@+.",
            ".++++++#+++++++++++++++.",
            ".+++++#+#++++++++++++++.",
            ".+++++#+#++++++++++++++.",
            ".++++##+#++++++++++++++.",
            ".++++#+++#+++++++++++++.",
            ".++++#+++#+++++++++++++.",
            ".++++#+++#+++++++++++++.",
            ".+++##+++#+++++++++++++.",
            ".+++#+++++#++++++++++++.",
            ".+++#++++++#+++++++++++.",
            ".+++#+++++++##+++++++++.",
            ".++##+++++++++###++++++.",
            ".++++++++++++++++++++++.",
            "........................"]
        
        return wx.BitmapFromXPMData(xpm_icon_data)

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

    ##[inamura 160722]-->
    ##################################    
    def OnAxisGrid(self, *args):
        """
        AxisGridモード変更
        @param  *args    イベント情報
        @retval 無し
        """
        # AxisGridモードの設定または解除 
        ret = self.SetAxisGridBtn(self.GetToolState(self._GRIDON))
        
        ddic = self.ifi.GetProperty('gridstyledic')
        ddic["Show"]=ret
        # update D2Chart
        self.ifi.NotifyEvent(self, "replot" )
        
    ##################################    
    def SetAxisGridBtn(self, flag): 
        """
        CURSOR ボタンオン/オフ処理
        @param  flag  True: On  False: Off
        @retval 無し
        """ 
        self.AxisGrid = flag 
        # Turn on/off Cursor button
        self.ToggleTool(self._GRIDON, flag)
        return flag

    ###################################################
    def GetAxisGridIconData(self):
        """
        Return Icom picture data as Bitmap
        Image text data is XPM format.
        @param None
        @retval wx.Bitmap
        """
        xpm_icon_data = [
            "24 24 4 1",
            " 	c None",
            ".	c #BACDF3",
            "+	c #000000",
            "@	c #8896B2",
            "                        ",
            " ...................... ",
            " ....+.....+.....+..... ",
            " ....+@....+@....+@.... ",
            " ....+@....+@....+@.... ",
            " ....+@....+@....+@.... ",
            " +++++++++++++++++++++. ",
            " .@@@+@@@@@+@@@@@+@@@@@ ",
            " ....+@....+@....+@.... ",
            " ....+@....+@....+@.... ",
            " ....+@....+@....+@.... ",
            " ....+@....+@....+@.... ",
            " .++++++++++++++++++++. ",
            " ..@@+@@@@@+@@@@+@@@@@@ ",
            " ....+@....+@....+@.... ",
            " ....+@....+@....+@.... ",
            " ....+@....+@....+@.... ",
            " ....+@....+@....+@.... ",
            " +++++++++++++++++++++. ",
            " .@@@+@@@@@+@@@@@+@@@@@ ",
            " ....+@....+@....+@.... ",
            " ....+@....+@....+@.... ",
            " .....@.....@.....@.... ",
            "                        "]
        
        return wx.BitmapFromXPMData(xpm_icon_data)
        ##<--[inamura 160722]

#########################################
#       CalcDspclDialog
#########################################
class CalcDspcDialog(wx.Dialog):
    """
    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
        """ 
        # Set initial value
        self.ifi = IFEvtProp(order)
        self.tof = tof
        self.L2 = L2
        self.plangle = plangle
        self.azangle = azangle
        self.L1 = L1
        
        # Get resource
        res = ResourceFile()
        self.dialog = res.GetDialog(parent, 'DgCalcDS')
        
        # Make new title
        strT = self.dialog.GetTitle()
        self.dialog.SetTitle(strT + postfix)
        
        # Get control of objects
        self.txtResults = res.GetCtrl(self.dialog, 'txtResults')
        self.txtResults.SetLabel("Now Calculating")
        self.txtIndex = res.GetCtrl(self.dialog, 'txtIndex')
        self.l1txt = res.GetCtrl(self.dialog, 'L1txt')
        if L1!=0.0:
            self.l1txt.SetValue(str(L1))
            self.OnApply(None)
        
        # Get event handler of buttons
        self.dialog.Bind(wx.EVT_BUTTON, self.OnApply, id=res.GetId('btApply'))
        self.dialog.Bind(wx.EVT_BUTTON, self.OnClose, id=res.GetId('btClose'))
        # Get event handler of 'close box'
        self.dialog.Bind(wx.EVT_CLOSE, self.OnClose)

        # Show this dialog
        self.dialog.Show()

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

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

        # Calculation 
        velocity = (L1+self.L2)/self.tof*1e6
        WaveLength = 3956./velocity
        Ei = 5.227e-6*velocity**2
        Dspacing = WaveLength/2./numpy.sin(self.plangle/180.*numpy.pi/2.)

        # 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.SetLabel(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.SetLabel(res)

        # Update this dialog
        self.dialog.Show()
        
    ##########################################################
    def OnClose(self, evt):
        """
        Function driven by Close event (just destroy)
        @param  evt  event info
        @retval None
        """ 
        self.dialog.Destroy()

##<--[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!=None:
            if type(self.axl)!=type([]):
                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.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)
        self.ifi.AddListner('calcdspace', self.OnNotifyShowCalcDSpc ) ##[inamura 110303]
        # 初期値設定        
        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.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.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 == 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.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 != None:
            self.datNum = datNum
        # データが指定されているか
        if xdata != None:
            self.xdata = xdata
        else:
            # 一度もX値が指定されていなかったら
            if self.xdata == 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 == 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())
        # 個別モードか
        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()) 
                
        # ラベルを消して、再表示
        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 header.has_key("Xkey"):
            if header["Xkey"]!="TOF":
                print "This is not TOF data."
                return
        else:
            print "Maybe this is not TOF data, be carefull"

        ### Get PIXELID
        if header.has_key("PIXELID"):
            pixel_id_str = "-%s" % (header["PIXELID"])
        else:
            pixel_id_str = "-%04d" % (self.datNum)
        
        ### Get pixel position
        if header.has_key("PixelPosition"):
            posi_str = header["PixelPosition"]
            str_list = posi_str.split(",")
            for item in str_list:
                L2 += float(item)*float(item)
            L2 = numpy.sqrt(L2)/1000.0 #[m]
        else:
            print "No Header PixelPosition"
            return

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

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

        ### Get L1
        if header.has_key("L1"):
            L1 = float( header["L1"] )/1000.0 #[m]
        else:
            ### If header has no L1
            if os.environ.has_key("UTSUSEMI_SYS_NAME"):
                sysname=os.environ["UTSUSEMI_SYS_NAME"]
                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:
                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.frame, self.parent.plot.order,
                             pixel_id_str, dataX[self.index],
                             pol,azm,L2,L1)
    ##<--[inamura 110303]

#######################################
#  HeaderBox
#######################################     
class HeaderBox(wx.Frame):
    """
    ヒストグラムのヘッダー情報を表示
    """
    #########################################
    def __init__(self, parent, pos, header):
        """
        コンストラクタ
        @param  parent  親ウィンドウ(PlotFlame)のID
        @param  pos     ポップアップウィンドウの表示位置
        @param  header  表示するヘッダー
        @retval 無し
        """ 
        # リソースファイルを取得
        res = ResourceFile()
        # ポップアップウィンドウを表示
        self.hb = res.GetFrame(parent, 'PopFrame')
        # マウスのクリック点にウィンドウを表示
        self.hb.SetPosition(pos)
        # パネルコントロールを取得
        panel = res.GetCtrl(self.hb, 'panel')
        
        # 垂直サイザーを作成
        sizer = wx.FlexGridSizer(rows=20, cols=2, hgap=5, vgap=0)
        # ヘッダーテキストを作成し、サイザーに入れる
        for item in header.keys():
            # ヘッダーのキーを表示
            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]
            
            # キーとその値を、サイザーにいれる    
            staticTxt1 = wx.StaticText(panel, -1, txt1)
            #sizer.Add(staticTxt1, 0, wx.LEFT|wx.TOP|wx.GROW, border=10)
            sizer.Add(staticTxt1, 0, wx.LEFT|wx.TOP|wx.GROW, border=0) ##[inamura 110303]
            staticTxt2 = wx.StaticText(panel, -1, txt2, size=(220, 20))
            #sizer.Add(staticTxt2, 0, wx.LEFT|wx.TOP|wx.GROW, border=10) 
            sizer.Add(staticTxt2, 0, wx.LEFT|wx.TOP|wx.GROW, border=0) ##[inamura 110303]
        # 最後に空白行を入れる    
        staticTxt1 = wx.StaticText(panel, -1, str("   "))
        sizer.Add(staticTxt1, 0, wx.LEFT|wx.GROW, border=10)
        self.hb.SetSizer(sizer)
        self.hb.Fit()
        
        # ポップアップウィンドウを表示
        self.hb.Show()
        
    #########################    
    def CloseHB(self):
        """
        ヘッダボックスクローズ
        @param  無し
        @retval 無し
        """ 
        self.hb.Destroy()    
        
#########################################
#       ParamDialog
#########################################        
class ParamDialog(wx.Dialog):
    """
    パラメータ設定ダイアログクラス
    """
    
    ##########################################################
    def __init__(self, parent, order, postfix):
        """
        コンストラクタ
        @param  parent   親ウィンドウのID
        @param  order  プロッタの起動順序
        @param  postfix 画面タイトルに付ける親の識別子    
        @retval 無し
        """ 
        # インターフェイスクラスのインスタンスを取得
        self.ifi = IFEvtProp(order)
        
        # リソースを取得
        res = ResourceFile()
        self.dg = res.GetDialog(parent, 'DgSetting')
        # アイコンを設定
        self.dg.SetIcon(Images().GetMainIcon())
        # タイトル文字列を取得
        strT = self.dg.GetTitle()
        # 順番を付してタイトル文字列を作成
        self.dg.SetTitle(strT + postfix)
        # ボタンのイベントハンドラを登録
        self.dg.Bind(wx.EVT_BUTTON, self.OnClose, id=res.GetId('btClose'))
        self.dg.Bind(wx.EVT_BUTTON, self.OnApplyX, id=res.GetId('btXApply'))
        self.dg.Bind(wx.EVT_BUTTON, self.OnApplyY, id=res.GetId('btYApply'))
        
        # リソースよりコントロールを取得
        panel1 = res.GetCtrl(self.dg, 'scpanel')
        panel2 = res.GetCtrl(self.dg, 'stpanel')
        panel3 = res.GetCtrl(self.dg, 'fspanel') ##[inamura 120513]
        # スピンボタン
        self.spinX = res.GetCtrl(panel2, 'spX')
        self.spinY = res.GetCtrl(panel2, 'spY')
        self.spinN = res.GetCtrl(panel2, 'spN')
        self.spinFS= res.GetCtrl(panel3, 'spFS') ##[inamura 120513]
        self.chFontName= res.GetCtrl(panel3, 'chFontName') ##[inamura 120513]
        
        # チェックボックス
        self.ckXAuto = res.GetCtrl(panel1, 'ckXAuto')
        self.ckYAuto = res.GetCtrl(panel1, 'ckYAuto')
        self.ckLog = res.GetCtrl(panel1, 'ckLog')
        self.ckLogX = res.GetCtrl(panel1, 'ckLogX' ) ##[inamura 140307]
        self.ckOver = res.GetCtrl(panel2, 'ckOver')
 
        # テキストボックス
        self.tx0 = res.GetCtrl(panel1, 'x0')
        self.tx1 = res.GetCtrl(panel1, 'x1')
        self.ty0 = res.GetCtrl(panel1, 'y0')
        self.ty1 = res.GetCtrl(panel1, 'y1')
        # プッシュボタン
        self.applyX = res.GetCtrl(self.dg, 'btXApply')
        self.applyY = res.GetCtrl(self.dg, 'btYApply')
        
        # スピンボタンのイベントハンドラ登録
        self.spinX.Bind(wx.EVT_SPINCTRL, self.OnSpinXY, self.spinX)
        self.spinY.Bind(wx.EVT_SPINCTRL, self.OnSpinXY, self.spinY)
        self.spinN.Bind(wx.EVT_SPINCTRL, self.OnSpinN, self.spinN)
        self.spinFS.Bind(wx.EVT_SPINCTRL, self.OnSetFont, self.spinFS) ##[inamura 120513]
        self.chFontName.Bind(wx.EVT_CHOICE, self.OnSetFont, self.chFontName) ##[inamura 120513]
        
        #[X]ボタン押下時のイベントハンドラ登録
        self.dg.Bind(wx.EVT_CLOSE, self.OnClose)
        # チェックボックスのイベントハンドラ登録
        self.ckXAuto.Bind(wx.EVT_CHECKBOX, self.OnAutoX, self.ckXAuto)
        self.ckYAuto.Bind(wx.EVT_CHECKBOX, self.OnAutoY, self.ckYAuto)
        self.ckOver.Bind(wx.EVT_CHECKBOX, self.OnOverlay, self.ckOver)
        self.ckLog.Bind(wx.EVT_CHECKBOX, self.OnLog, self.ckLog)
        self.ckLogX.Bind(wx.EVT_CHECKBOX, self.OnLogX, self.ckLogX) ##[inamura 140307]
        
        # 各部品に値を設定
        self._SetValues()
        # パラメータ設定ダイアログオープンイベントを発行
        self.ifi.NotifyEvent(self, "paradg", False)  
        # ダイアログ表示
        self.dg.Show()
        
    ##########################################################
    def _SetValues(self):
        """
        現在のパラメータを取得して画面に設定
        @param  無し
        @retval 無し
        """ 
       
        # 現在のスケールX範囲をテキストボックスにセット
        self.ckXAuto.SetValue(self.ifi.GetProperty('autox'))
        self._SetEnableXRange()

        # 現在のスケールY範囲をテキストボックスにセット
        self.ckYAuto.SetValue(self.ifi.GetProperty('autoy'))
        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'))
        # オーバレイモードを設定
        self.ckOver.SetValue(self.ifi.GetProperty('overlay'))
        
        # オーバレイモードにより、スピンボタンの最大値を設定
        if self.ifi.GetProperty('overlay'):
            self.spinN.SetRange(1, 50) 
        else:
            #self.spinN.SetRange(1, 4)
            self.spinN.SetRange(1, 10) ##[inamura 100715]
              
        # ログモードを設定
        self.ckLog.SetValue(self.ifi.GetProperty('log'))
        #   オーバレイモードであれば
        if self.ckOver.GetValue():
            # オフセットを選択可
            self.spinX.Enable(True)    
            self.spinY.Enable(True)
        else:
            # オフセットを選択不可
            self.spinX.Enable(False)    
            self.spinY.Enable(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.Append(it_fnl)
        self.chFontName.SetStringSelection( self.initFI[3][1] )
        ##<--[inamura 120513]
    ##########################################################
    def OnSpinXY(self, evt):
        """
        オフセットスピンボックスイベント処理
        @param  evt イベント情報
        @retval 無し
        """ 
        x = self.spinX.GetValue()
        y = self.spinY.GetValue()
        # オフセット変更通知発行
        self.ifi.NotifyEvent(self, "offset", (x, y))

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

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

    ##########################################################        
    def _SetEnableXRange(self):
        """
        X Range の選択可/不可を設定
        @param  evt イベント情報
        @retval 無し
        """ 
  
        # 自動モードであれば
        if self.ckXAuto.GetValue():
            # テキストボックスを選択不可とする
            self.tx0.Enable(False)    
            self.tx1.Enable(False)
            self.applyX.Enable(False)
            
        # マニュアルモードなら
        else:
            # 範囲プロパティを取得し文字列に変換
            strx0 = "%g" % self.ifi.GetProperty('x0') ##[inamura 160322]
            strx1 = "%g" % self.ifi.GetProperty('x1') ##[inamura 160322]
            # テキストボックスに値を設定    
            self.tx0.SetValue(strx0)
            self.tx1.SetValue(strx1)
            # スケール入力テキストボックスを選択可とする
            self.tx0.Enable(True)
            self.tx1.Enable(True)
            # Apply ボタンを選択可とする
            self.applyX.Enable(True)

            
    ##########################################################        
    def OnAutoY(self, evt=None):
        """
        AutoYチェックボックスイベント処理
        @param  evt イベント情報
        @retval 無し
        """ 
        self._SetEnableYRange()
        # スケール変更通知をリスナーへ送信
        # do auto scale when OFF -> ON
        if self.ckYAuto.GetValue():
            self.ifi.NotifyEvent(self, "yscale", (True, None, None))
        
    ##########################################################        
    def _SetEnableYRange(self):
        """
        X Range の選択可/不可を設定
        @param  evt イベント情報
        @retval 無し
        """     
        # 自動モードであれば
        if self.ckYAuto.GetValue():
            # テキストボックスを選択不可とする
            self.ty0.Enable(False)    
            self.ty1.Enable(False)
            self.applyY.Enable(False)
        # マニュアルモードなら
        else:
            # 範囲プロパティを取得し文字列に変換
            stry0 = "%g" % self.ifi.GetProperty('y0') ##[inamura 160322]
            stry1 = "%g" % self.ifi.GetProperty('y1') ##[inamura 160322]
            # テキストボックスに値を設定    
            self.ty0.SetValue(stry0)
            self.ty1.SetValue(stry1) 
            # スケール入力テキストボックスを選択可とする
            self.ty0.Enable(True)    
            self.ty1.Enable(True)
            # Apply ボタンを選択可とする
            self.applyY.Enable(True)
               
    ##########################################################    
    def OnOverlay(self, evt):
        """
        Overlayチェックボックスイベント処理
        @param  evt イベント情報
        @retval 無し
        """ 
        # オーバレイモードであれば
        if self.ckOver.GetValue():
            # オフセット選択可
            self.spinX.Enable(True)    
            self.spinY.Enable(True)
            # グラフ数最大値は50
            self.spinN.SetRange(1, 50)
            # グラフ数を設定
            self.spinN.SetValue(20)
            tnum = 20
        else:
            # オフセット選択不可
            self.spinX.Enable(False)    
            self.spinY.Enable(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)

        # オーバレイモード変更通知
        self.ifi.NotifyEvent(self, "overlay", self.ckOver.GetValue())

    ##########################################################    
    def OnLog(self, evt):
        """
        Log チェックボックスイベント処理
        @param  evt イベント情報
        @retval 無し
        """ 
        self.ifi.NotifyEvent(self, "log", self.ckLog.GetValue()) 

    ##[inamura 140307]-->
    ##########################################################    
    def OnLogX(self, evt):
        """
        LogX チェックボックスイベント処理
        @param  evt イベント情報
        @retval 無し
        """ 
        self.ifi.NotifyEvent(self, "logx", self.ckLogX.GetValue()) 
    ##<--[inamura 140307]
    
    ##########################################################
    def OnClose(self, evt):
        """
        ダイアログクローズイベント処理
        @param  evt イベント情報
        @retval 無し
        """ 
        # パラメータ設定ダイアログクローズイベントを発行
        self.ifi.NotifyEvent(self, "paradg", True) 
        self.dg.Destroy() 

    ##########################################################    
    def OnApplyX(self, evt):
        """
        Applyボタンイベント処理
        @param  evt イベント情報
        @retval 無し
        """ 
        # テキストボックスより値を取得
        # 数値か
        try:
            x0 = float(self.tx0.GetValue())
        except:
            x0 = 0.0 
        try:
            x1 = float(self.tx1.GetValue())
        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.SetValue(strX0)
        self.tx1.SetValue(strX1)
         
        # スケール変更通知をリスナーへ送信
        self.ifi.NotifyEvent(self, "xscale", (False, x0, x1))
        
    ##########################################################    
    def OnApplyY(self, evt):
        """
        Applyボタンイベント処理
        @param  evt イベント情報
        @retval 無し
        """ 
        # テキストボックスより値を取得
        # 数値か
        try:
            y0 = float(self.ty0.GetValue())
        except:
            y0 = 0.0 
        try:
            y1 = float(self.ty1.GetValue())
        except:
            y1 = 1.0
        # 同値か
        if y0 == y1:
            y1 = y0+1.0
        # 逆転していたら
        if y0 > y1 :
            # 入れ替える
            tmp = y0
            y0 = y1
            y1 = tmp
        
        # 数値を再表示  
        strY0 = "%g" % y0   ##[inamura 160322]
        strY1 = "%g" % y1   ##[inamura 160322]
        self.ty0.SetValue(strY0)
        self.ty1.SetValue(strY1)
        # スケール変更通知をリスナーへ送信
        self.ifi.NotifyEvent(self, "yscale", (False, y0, y1))    



#########################################
#       PlotDialog
#########################################        
class PlotDialog(wx.Dialog):
    """
    プロット条件設定ダイアログクラス
    """
    
    ##########################################################
    def __init__(self, parent, order, select, postfix):
        """
        コンストラクタ
        @param  parent   親ウィンドウのID
        @param  order    プロッタの起動順序
        @param  selects  選択中データのインデックスリスト 
        @param  postfix 画面タイトルに付ける親の識別子   
        @retval 無し
        """ 
        # インターフェイスクラスのインスタンスを取得
        self.ifi = IFEvtProp(order)
        self.select = select
        # リソースよりダイアログボックスを取得して作成
        self.res = ResourceFile()
        self.dg = self.res.GetDialog(parent, 'DgPlot')
        # アイコンを設定
        self.dg.SetIcon(Images().GetMainIcon())

        self.flagAutoApply = True ##[inamura 101007]
        # タイトル文字列を取得
        strT = self.dg.GetTitle()
        # 順番を付してタイトル文字列を作成
        self.dg.SetTitle(strT + postfix)
        
        # ボタンのイベントハンドラを登録
        self.dg.Bind(wx.EVT_BUTTON, self.OnClose, id=self.res.GetId('btClose'))
        self.dg.Bind(wx.EVT_BUTTON, self.OnApplyAll, id=self.res.GetId('btApply'))
        ## [inamura 101007]-->
        self.btApplyThis = self.res.GetCtrl(self.dg, 'btApplyThis' )
        self.dg.Bind(wx.EVT_BUTTON, self.OnApplyThis, self.btApplyThis)
        ##<--[inamura 101007]
        ## [inamura 110223]-->
        self.btSaveDefAtt = self.res.GetCtrl(self.dg, 'btSaveDefAtt' )
        self.dg.Bind(wx.EVT_BUTTON, self.OnSaveDefAtt, self.btSaveDefAtt)
        ##<--[inamura 110223]
        
        # リソースよりコントロールを取得
        # コンボボックス
        self.cbLS = self.res.GetCtrl(self.dg, 'line')
        self.cbLC = self.res.GetCtrl(self.dg, 'lcolor')
        self.cbMK = self.res.GetCtrl(self.dg, 'mark')
        self.cbMC = self.res.GetCtrl(self.dg, 'mcolor')
        self.cbEC = self.res.GetCtrl(self.dg, 'ecolor')
        
        # コンボボックスのイベントハンドラ登録
        self.cbLS.Bind(wx.EVT_COMBOBOX, self.OnComboLS, self.cbLS)
        self.cbLC.Bind(wx.EVT_COMBOBOX, self.OnComboLC, self.cbLC)
        self.cbMK.Bind(wx.EVT_COMBOBOX, self.OnComboMK, self.cbMK)
        self.cbMC.Bind(wx.EVT_COMBOBOX, self.OnComboMC, self.cbMC)
        self.cbEC.Bind(wx.EVT_COMBOBOX, self.OnComboEC, self.cbEC)
        
        # スピンボタン
        self.spinLW = self.res.GetCtrl(self.dg, 'width')
        self.spinMS = self.res.GetCtrl(self.dg, 'msize')
        self.spinCS = self.res.GetCtrl(self.dg, 'csize')
        
        # スピンボタンのイベントハンドラ登録
        self.spinLW.Bind(wx.EVT_SPINCTRL, self.OnSpinLW, self.spinLW)
        self.spinMS.Bind(wx.EVT_SPINCTRL, self.OnSpinMS, self.spinMS)
        self.spinCS.Bind(wx.EVT_SPINCTRL, self.OnSpinCS, self.spinCS)
        
        # チェックボックス
        self.ckAutoApply = self.res.GetCtrl(self.dg,'ckAutoApply') ##[inamura 101007]
        self.ckEB = self.res.GetCtrl(self.dg, 'erbar')
        self.ckHist = self.res.GetCtrl(self.dg, 'ckHist')
        self.ckFilledFace = self.res.GetCtrl(self.dg, 'ckFilledFace') ##[inamura 120512]
        
        # チェックボックスのイベントハンドラ登録
        self.ckAutoApply.Bind(wx.EVT_CHECKBOX, self.OnAutoApply, self.ckAutoApply) ##[inamura 101007]
        self.ckEB.Bind(wx.EVT_CHECKBOX, self.OnErrBar, self.ckEB)
        self.ckHist.Bind(wx.EVT_CHECKBOX, self.OnHist, self.ckHist)
        self.ckFilledFace.Bind(wx.EVT_CHECKBOX, self.OnFilledFase, self.ckFilledFace) ##[inamura 120512]
        
        #クローズイベント登録
        self.dg.Bind(wx.EVT_CLOSE, self.OnClose)
        
        # ダイアログに、選択データの表示属性現在値を設定
        self._SetValues()
        
        # ダイアログを表示
        self.dg.Show()
         
      
    ##########################################################
    def _SetValues(self):
        """
        現在のパラメータを取得して画面に設定
        @param  無し
        @retval 無し
        """ 
        # トレース属性リストを取得
        attList = self.ifi.GetProperty('traceattrs')
        # 選択されているトレースの属性を取得
        attr = attList[self.select]
        
        # ラインスタイルの設定
        self.cbLS.SetSelection(self._GetAttrNum(attr["ls"], TraceAtt.linestyle))
        # ヒストグラムスタイルを指定
        if attr["hs"] == 0:
            self.ckHist.SetValue(False)
        else:
            self.ckHist.SetValue(True)
            
        # ライン幅の設定
        self.spinLW.SetValue(attr["lw"])
        # ラインカラーの設定
        self.cbLC.SetSelection(self._GetAttrNum(attr["lc"], TraceAtt.color))

        # マークの設定
        self.cbMK.SetSelection(self._GetAttrNum(attr["mk"], TraceAtt.marker))
        # マークサイズの設定
        self.spinMS.SetValue(attr["ms"])
        # マークカラーの設定
        self.cbMC.SetSelection(self._GetAttrNum(attr["mc"], TraceAtt.color))
        
        ##[inamura 120512]-->
        if self._GetAttrNum(attr["mf"],TraceAtt.mface)==0:
            self.ckFilledFace.SetValue(True)
        else:
            self.ckFilledFace.SetValue(False)
        ##<--[inamura 120512]
        
        # エラーバー付きを指定
        if attr["eb"] == 0:
            self.ckEB.SetValue(False)
        else:
            self.ckEB.SetValue(True)
            
        # キャップサイズの設定
        self.spinCS.SetValue(attr["es"])
        # エラーバーカラーの設定
        self.cbEC.SetSelection(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):
        """
        ラインスタイル変更イベント処理
        [inamura 101007: use self.flagAutoApply]
        @param  evt イベント情報
        @retval 無し
        """
        if self.flagAutoApply:
            # 線種を取得
            ls=TraceAtt.linestyle[self.cbLS.GetSelection()]
            # トレース属性変更要求をだす
            self.ifi.NotifyEvent(self, "plotparam", (self.select+1, {"ls":ls}))  
        
    ##########################################################    
    def OnHist(self, evt):
        """
        ヒストグラムモスタイル変更イベント処理
        [inamura 101007: use self.flagAutoApply]
        @param  evt イベント情報
        @retval 無し
        """
        if self.flagAutoApply:
            # ヒストグラムモスタイル取得
            if self.ckHist.GetValue() == False:
                # ヒストグラムモスタイル変更要求をだす
                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):
        """
        ラインカラー変更イベント処理
        [inamura 101007: use self.flagAutoApply]
        @param  evt イベント情報
        @retval 無し
        """
        if self.flagAutoApply:
            # 色を取得
            color=TraceAtt.color[self.cbLC.GetSelection()]
            # トレース属性変更要求をだす
            self.ifi.NotifyEvent(self, "plotparam", (self.select+1, {"lc":color}))     

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

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

    ##########################################################    
    def OnSpinLW(self, evt):
        """
        ライン幅スピンボタンイベント処理
        [inamura 101007: use self.flagAutoApply]
        @param  evt イベント情報
        @retval 無し
        """
        if self.flagAutoApply:
            # 線幅を取得
            lw=self.spinLW.GetValue()
            # トレース属性変更要求をだす
            self.ifi.NotifyEvent(self, "plotparam", (self.select+1, {"lw":lw}))     
        
    ##########################################################    
    def OnSpinMS(self, evt):
        """
        マーカーサイズスピンボタンイベント処理
        [inamura 101007: use self.flagAutoApply]
        @param  evt イベント情報
        @retval 無し
        """
        if self.flagAutoApply:
            # マーカーサイズを取得
            ms=self.spinMS.GetValue()
            # トレース属性変更要求をだす
            self.ifi.NotifyEvent(self, "plotparam", (self.select+1, {"ms":ms}))     
        
    ##########################################################    
    def OnSpinCS(self, evt):
        """
        キャップサイズスピンボタンイベント処理
        [inamura 101007: use self.flagAutoApply]
        @param  evt イベント情報
        @retval 無し
        """
        if self.flagAutoApply:
            # キャップーサイズを取得
            es=self.spinCS.GetValue()
            # トレース属性変更要求をだす
            self.ifi.NotifyEvent(self, "plotparam", (self.select+1, {"es":es})) 
        
    ##########################################################    
    def OnErrBar(self, evt):
        """
        エラーバーチェックボックスイベント処理
        [inamura 101007: use self.flagAutoApply]
        @param  evt イベント情報
        @retval 無し
        """
        if self.flagAutoApply:
            # エラーバー付きを取得
            if self.ckEB.GetValue() == False:
                # トレース属性変更要求をだす
                self.ifi.NotifyEvent(self, "plotparam", (self.select+1, {"eb":0})) 
            else:
                # トレース属性変更要求をだす
                self.ifi.NotifyEvent(self, "plotparam", (self.select+1, {"eb":1})) 
    
    ##########################################################
    def OnFilledFase(self, evt):
        """
        [inamura 120512]
        @param  evt イベント情報
        @retval 無し
        """
        if self.flagAutoApply:
            if self.ckFilledFace.GetValue() == True:
                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.dg.Show() 
        
    ##########################################################
    def OnClose(self, evt):
        """
        ダイアログクローズイベント処理
        @param  evt イベント情報
        @retval 無し
        """ 
        # プロット条件設定ダイアログクローズイベント発行
        self.ifi.NotifyEvent(self, "plotdg") 
        self.dg.Destroy() 

    ##########################################################    
    def OnApplyAll(self, evt):
        """
        Applyボタンイベント処理
        [inamura 110223]
        @param  evt イベント情報
        @retval 無し
        """ 
        
        self.ifi.NotifyEvent(self, "plotparam", (0, self._GetAllAttr() ))
                             
    ##########################################################    
    def OnAutoApply(self, evt):
        """
        AutoApplyチェックボックスイベント処理
        [inamura 101007]
        @param  evt イベント情報
        @retval 無し
        """ 
        # Get status of check box
        if self.ckAutoApply.GetValue() == True:
            # change flag and enable button
            self.flagAutoApply = True
            self.btApplyThis.Enable(False)
        else:
            # change flag and button disable
            self.flagAutoApply = False
            self.btApplyThis.Enable(True)
        
    ##########################################################    
    def OnApplyThis(self, evt):
        """
        ApplyThisボタンイベント処理
        [inamura 110223]
        @param  evt イベント情報
        @retval 無し
        """ 
        self.ifi.NotifyEvent(self, "plotparam", (self.select+1, self._GetAllAttr() ))
        
    ##########################################################
    def OnSaveDefAtt(self, evt):
        """
        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.GetSelection()]
        # get HistogramStyle
        if self.ckHist.GetValue() == False:
            hs = 0
        else:
            hs = 1
        # get LineWidth
        lw =self.spinLW.GetValue()
        # get LineColor
        lc = TraceAtt.color[self.cbLC.GetSelection()]

        # get MarkerType
        mk = TraceAtt.marker[self.cbMK.GetSelection()]
        # get MarkerSize
        ms = self.spinMS.GetValue()
        # get MarkerColor
        mc = TraceAtt.color[self.cbMC.GetSelection()]
        
        # get flag for marker face status [inamura 120512]
        if self.ckFilledFace.GetValue() == True:
            mf = "fill"
        else:
            mf = "none"
        
        # get flag to error bar
        if self.ckEB.GetValue() == False:
            eb = 0
        else:
            eb = 1
        # get size of cap of error bar
        es = self.spinCS.GetValue()
        # get color of error bar
        ec = TraceAtt.color[self.cbEC.GetSelection()]
        
        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(wx.Dialog):
    """
    タイトル設定ダイアログクラス
    """
    ##########################################################
    def __init__(self, parent, order, postfix):
        """
        コンストラクタ
        @param  parent   親ウィンドウのID
        @param  order  プロッタの起動順序
        @param  postfix 画面タイトルに付ける親の識別子    
        @retval 無し
        """ 

        self.ifi = IFEvtProp(order)
        
        # リソース取得      
        res = ResourceFile()
        self.dialog = res.GetDialog(parent, 'DgTitle')
        
        if order > 0:
            # タイトル文字列を取得
            strT = self.dialog.GetTitle()
            # 順番を付してタイトル文字列を作成
            self.dialog.SetTitle(strT + postfix)
        
        # テキストボックスのコントローラ取得        
        self.text1 = res.GetCtrl(self.dialog, 'tx1')
        self.text2 = res.GetCtrl(self.dialog, 'tx2')
        
        self.text1.SetValue(self.ifi.GetProperty("title1"))
        self.text2.SetValue(self.ifi.GetProperty("title2"))
        # ボタンのイベントハンドラ登録
        self.dialog.Bind(wx.EVT_BUTTON, self.OnOk, id=res.GetId('btOk'))
        self.dialog.Bind(wx.EVT_BUTTON, self.OnCancel, id=res.GetId('btCancel'))

        ##[inamura 120513]-->
        iff = self.ifi.GetProperty('fontinfo')
        ift = self.ifi.GetProperty('textinfo')
        self.initFI = iff[:]
        self.initTI = ift[:]

        self.spinFS= res.GetCtrl(self.dialog, 'spFS') 
        self.spinFS.Bind(wx.EVT_SPINCTRL, self.OnSetFont, self.spinFS)
        self.spinFS.SetValue( self.initFI[0][0] )
        
        self.chFontName = res.GetCtrl(self.dialog, 'chFontName')
        self.chFontName.Bind(wx.EVT_CHOICE, self.OnSetFont, self.chFontName)
        fnl = self.ifi.GetProperty('fontnamelist')
        for it_fnl in fnl:
            self.chFontName.Append(it_fnl)
        self.chFontName.SetStringSelection( self.initFI[0][1] )
        ##<--[inamura 120513]

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

    ##########################################################
    def OnSetFont(self, evt):
        """
        [inamura 120513]
        @param  evt
        @retval None
        """
        self.ifi.NotifyEvent(self, "setfontinfo", (0,[self.spinFS.GetValue(),self.chFontName.GetStringSelection()]))

    ##########################################################
    def OnOk(self, evt):
        """
        OK ボタンイベント処理
        @param  evt イベント情報
        @retval 無し
        """ 
        # テキストボックスから値を取得
        main = self.text1.GetValue()
        sub = self.text2.GetValue()
        try:
            # 日本語文字列が含まれているかどうかをチェック
            try:
                str(main)
            except:
                raise PlotException('Common', 'C025', ("Main Title",))
            try:
                str(sub)
            except:
                raise PlotException('Common', 'C025', ("Sub Title",))
        except PlotException, ex:
            PlotMessage(self.dialog, ex)
        
        else:    
            # 前と変わらなかったら
            if self.ifi.GetProperty("title1") == main:
                # 変更無記号を送信(自動更新を解除しないため)
                # 注: 一度メインタイトル変更すると、自動更新モードを解除する
                # サブタイトルは、自動更新モードに影響しない
                main = '*'
            # タイトル変更要求送信    
            self.ifi.NotifyEvent(self, "title", (main, sub))
            self.ifi.NotifyEvent(self, "titledg", True)
            self.dialog.Destroy()
          
    ##########################################################
    def OnCancel(self, evt):
        """
        Cancel ボタンイベント処理
        @param  evt イベント情報
        @retval 無し
        """ 
        self.ifi.NotifyEvent(self, "titledg", True)
        self.ifi.NotifyEvent(self, "setfontinfo", (0,[self.initFI[0][0],self.initFI[0][1]]))##[inamura 120513]
        self.dialog.Destroy()        

#########################################
#       LabelDialog
#########################################
class LabelDialog(wx.Dialog):
    """
    スケールラベル設定ダイアログクラス
    """
    ##########################################################
    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 無し
        """ 

        self.ifi = IFEvtProp(order)
        
        # リソース取得      
        res = ResourceFile()
        self.dialog = res.GetDialog(parent, 'DgScaleLabel')
        # タイトル文字列を取得
        strT = self.dialog.GetTitle()
        # 順番を付してタイトル文字列を作成
        self.dialog.SetTitle(strT + postfix)
        # テキストボックスのコントローラ取得        
        self.xlabel = res.GetCtrl(self.dialog, 'xlabel')
        self.ylabel = res.GetCtrl(self.dialog, 'ylabel')
        ##[inamura 110620]--> (add text box for xunit and yunit)
        self.xunit = res.GetCtrl(self.dialog, 'xunit')
        #self.xunit.SetValue( dataobj.GetXUnit(0) )
        self.xunit.SetValue( self.ifi.GetProperty("xunit") )##[inamura 110704]
        self.yunit = res.GetCtrl(self.dialog, 'yunit')
        #self.yunit.SetValue( dataobj.GetYUnit(0) )
        self.yunit.SetValue( self.ifi.GetProperty("yunit") )##[inamura 110704]
        ##<--[inamrua 110620]
        ##[inamura 120513]-->
        iff = self.ifi.GetProperty('fontinfo')
        ift = self.ifi.GetProperty('textinfo')
        self.initFI = iff[:]
        self.initTI = ift[:]

        self.spinFS= res.GetCtrl(self.dialog, 'spFS') 
        self.spinFS.Bind(wx.EVT_SPINCTRL, self.OnSetFont, self.spinFS)
        self.spinFS.SetValue( self.initFI[1][0] )
        
        self.chFontName = res.GetCtrl(self.dialog, 'chFontName')
        self.chFontName.Bind(wx.EVT_CHOICE, self.OnSetFont, self.chFontName)
        fnl = self.ifi.GetProperty('fontnamelist')
        for it_fnl in fnl:
            self.chFontName.Append(it_fnl)
        self.chFontName.SetStringSelection( self.initFI[1][1] )
        ##<--[inamura 120513]
        
        xl= self.ifi.GetProperty("xlabel")
        yl= self.ifi.GetProperty("ylabel")
        
        # プロパティが取得できたら、テキストボックスに設定
        self.xlabel.SetValue(xl)
        self.ylabel.SetValue(yl)
            
        # ボタンのイベントハンドラ登録
        self.dialog.Bind(wx.EVT_BUTTON, self.OnOk, id=res.GetId('btOk'))
        self.dialog.Bind(wx.EVT_BUTTON, self.OnCancel, id=res.GetId('btCancel'))
        #[X]ボタン押下時のイベントハンドラ登録
        self.dialog.Bind(wx.EVT_CLOSE, self.OnCancel)
        # ダイアログオープンイベント発行
        self.ifi.NotifyEvent(self, "labeldg", False)
        # ダイアログ表示
        self.dialog.Show()

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


#######################################
#  DataList
####################################### 
class DataList(wx.Frame):
    """
    データ一覧表示ボックスクラス
    """
    ##########################################################
    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')
        # リソース取得      
        res = ResourceFile()
        # フローティングボックスフレーム作成
        self.fbFrame = res.GetFrame(plot.frame, 'floatbox')
        # アイコンを設定
        self.fbFrame.SetIcon(Images().GetMainIcon())
        # タイトル文字列を取得
        strT = self.fbFrame.GetTitle()
        # 順番を付してタイトル文字列を作成
        self.fbFrame.SetTitle(strT + postfix)
        
        # リソースからコントロールを取得     
        self.list = res.GetCtrl(self.fbFrame, 'spectList')
        self.text = res.GetCtrl(self.fbFrame, 'txEdit')
        self.spin = res.GetCtrl(self.fbFrame, 'spin')
        self.btPlot = res.GetCtrl(self.fbFrame, 'btPlot')
        self.btUp = res.GetCtrl(self.fbFrame, 'btUp')
        self.btDown = res.GetCtrl(self.fbFrame, 'btDown')
        self.btDelete = res.GetCtrl(self.fbFrame, 'btDelete')
        self.btChange = res.GetCtrl(self.fbFrame, 'btChange')
        self.btDuplicate = res.GetCtrl(self.fbFrame, 'btDuplicate') #[inamura 160714]
        self.txDupFactor = res.GetCtrl(self.fbFrame, 'txDupFactor') #[inamura 160714]

        # データがあれば
        if len(self.ldata) > 0:
            # データ一覧リストを表示
            self.DispList()
            # データ数最大値をスピンに設定
            self.spin.SetRange(1, len(self.ldata))
            # 最初のトレースラベルをテキストボックスに設定
            self.text.SetValue(self.ldata[0])
            # 最初のリストアイテムを選択状態とする
            self.list.SetSelection(0)
        else:
            # 各種ボタンを選択不可とする
            self.SetEnable(False) 
              
        # ボタンのイベントハンドラ登録
        self.fbFrame.Bind(wx.EVT_BUTTON, self.OnPlotParam, id=res.GetId('btPlot'))
        self.fbFrame.Bind(wx.EVT_BUTTON, self.OnUp, id=res.GetId('btUp'))
        self.fbFrame.Bind(wx.EVT_BUTTON, self.OnDown, id=res.GetId('btDown'))
        self.fbFrame.Bind(wx.EVT_BUTTON, self.OnDelete, id=res.GetId('btDelete'))
        self.fbFrame.Bind(wx.EVT_BUTTON, self.OnChange, id=res.GetId('btChange'))
        self.fbFrame.Bind(wx.EVT_BUTTON, self.OnClose, id=res.GetId('btClose'))
        self.fbFrame.Bind(wx.EVT_BUTTON, self.OnDuplicate, id=res.GetId('btDuplicate')) #[inamura 160714]
        # リスト選択時のイベントハンドラ登録
        self.fbFrame.Bind(wx.EVT_LISTBOX, self.OnSelect, id=res.GetId('spectList'))

        # スピンボタンのイベントハンドラ登録
        self.spin.Bind(wx.EVT_SPINCTRL, self.OnSpin, self.spin)

        #[X]ボタン押下時のイベントハンドラ登録
        self.fbFrame.Bind(wx.EVT_CLOSE, self.OnClose)
        
        # データ追加のリスナー登録
        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.Append(strNum + item)
            num += 1
        # 現在のデータ数を更新 
        self.num = num - 1
        
    ##########################################################        
    def SetEnable(self, flag):
        """
        データ数各種コントロール選択可・不可を設定
        (データ数0時に選択不可)
        @param  flag   True  or False
        @retval 無し
        """ 
        self.btPlot.Enable(flag)
        self.text.Enable(flag)
        self.spin.Enable(flag)
        self.btUp.Enable(flag)
        self.btDown.Enable(flag)
        self.btDelete.Enable(flag)
        self.btChange.Enable(flag)
        self.btDuplicate.Enable(flag) #[inamura 160714]
        # 選択不可とするの場合
        if not flag:
            # ラベル変更テキストボックスをクリア
            self.text.SetValue("")

    ##########################################################        
    def DeselectAll(self):
        """
        全トレースを非選択状態にする
        @param  無し
        @retval 無し
        """ 
        for i in range(len(self.ldata)):
            self.list.Deselect(i)
         
    ##########################################################   
    def OnUp(self, evt):
        """
        選択されているトレースの表示順番を上げる
        @param  evt イベント情報
        @retval 無し
        """ 
        # 選択中データのインデックスを取得
        select = self.list.GetSelection()
        # 選択中のトレースが最初のトレースでないならば
        if select > 0:
            # データ順番変更要求イベント発行
            self.ifi.NotifyEvent(self, "shuffle", (select+1, select))
    
    ##########################################################
    def OnDown(self, evt):
        """
        選択されているトレースの表示順番を下げる
        (選択されているトレースの一番上のみ)
        @param  evt イベント情報
        @retval 無し
        """ 
        # 選択中データのインデックスを取得
        select = self.list.GetSelection()
        # 選択中のトレースが最後のトレースでないならば 
        if select  < self.num-1:
            # データ順番変更要求イベント発行
            self.ifi.NotifyEvent(self, "shuffle", (select+1, select+2))
    
    ##########################################################
    def OnDelete(self, evt):
        """
        選択されているトレースを、データオブジェクトから削除
        @param  evt イベント情報
        @retval 無し
        """ 
        # 選択されているトレースを取得
        select = self.list.GetSelection()
        # データ削除要求イベント発行
        self.ifi.NotifyEvent(self, "remove", select+1)
        
    #[inamura 160714]-->
    ##########################################################
    def OnDuplicate(self, evt):
        """
        Copy selected trace with factor
        @param  evt イベント情報
        @retval 無し
        """ 
        # 選択されているトレースを取得
        select = self.list.GetSelection()
        #
        (xx_o,yy_o,ee_o,head_o,xunit_o,yunit_o,histx_o) = self.plot.dataobj.lstData[select]
        fact=float(self.txDupFactor.GetValue())
        if fact<=0.0:
            return
        """
        if isinstance(xx_o,list):
            xx = xx_o[:]
            yy = yy_o[:]
            ee = ee_o[:]
        else:
            xx=xx_o.copy()
            yy=yy_o.copy()
            ee=ee_o.copy()
        """
            
        size_of_data = len(xx_o)
        xx=numpy.zeros( size_of_data )
        yy=numpy.zeros( size_of_data )
        ee=numpy.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!=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 160714]

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

    ##########################################################   
    def OnSpin(self, evt):
        """
        トレース変更(ラベル表示ボックス)
        @param  evt イベント情報
        @retval 無し
        """ 
        # データがあるなら
        if len(self.ldata)> 0:
            # スピンの値を取得
            selNo =  self.spin.GetValue()
            # 指定されたトレースを選択する
            try:
                self.list.SetSelection(selNo-1)
            except:
                return
            # テキストボックスにトレースラベルを設定
            self.text.SetValue(self.ldata[selNo-1])
    
    ##########################################################    
    def OnChange(self, evt):
        """
        トレースラベル変更
        @param  evt イベント情報
        @retval 無し
        """ 
        # データがあるなら
        if len(self.ldata)> 0:
            # スピンボタンの値を取得
            selNo =  self.spin.GetValue()
            # テキストボックスの値を取得し
            tlabel = self.text.GetValue()
            try:
                # 日本語文字列が含まれているかどうかをチェック
                try:
                    str(tlabel)
                except:
                    raise PlotException('Common', 'C025', ("Trace Label",))
            except PlotException, ex:
                PlotMessage(self.fbFrame, ex)
            
            else:
                # トレースラベルに設定
                self.ldata[selNo-1] = tlabel
                self.ifi.NotifyEvent(self, "setlabeltodata", [selNo,tlabel]) ##[inamura 120128]
                # リストの再表示
                self.DispList()
                # 変更したトレースを選択
                self.list.SetSelection(selNo-1)
                # 当該データが表示されているページを計算
                tnum = self.ifi.GetProperty('tracenum')
                pnum = selNo/ tnum
                if selNo % tnum > 0:
                    pnum +=1
                    
                # 現在のページと同じなら
                if self.ifi.GetProperty('page') == pnum-1:   
                    # 表示範囲を変更せずにデータをプロット
                    self.ifi.NotifyEvent(self, "replot") 
     
    ##########################################################
    def OnPlotParam(self, evt):
        """
        Plot Pattern ボタンイベント処理
        @param  evt イベント情報
        @retval 無し
        """ 
        try:
            # 選択されているデータのインデックスを取得
            select = self.list.GetSelection()
        except:
            # 選択されているトレースがなかったら何もしない
            return
        
        # ボタンを選択不可とする
        self.btPlot.Enable(False)
        # ダイアログを表示
        # プロット条件設定ダイアログ表示     
        self.pdg = PlotDialog(self.fbFrame, self.order, select, self.post)

    
    ##########################################################    
    def HideFB(self):
        """
        フローティングボックス画面を非表示
        @param  無し
        @retval 無し
        """ 
        # プロットダイアログが表示されていたら
        if not self.pdg == None:
            # 消す
            self.pdg.dg.Destroy()  
        # フローティングボックスを非表示
        self.fbFrame.Hide()  
    
    ##########################################################    
    def ShowFB(self):
        """
        フローティングボックス画面を表示
        @param  無し
        @retval 無し
        """ 
        self.fbFrame.Show() 
    
    ##########################################################
    def OnNotifyChangeData(self, wid, evt, value):
        """
        データ追加またはデータ削除のイベント処理
        @param  wid イベント発生元のインスタンス
        @param  evt イベントタイプ
        @param  value イベントの値
        @retval 無し
        """ 
        # データ取得
        self.ldata = self.ifi.GetProperty('tracelabels')
        # データ数最大値をスピンに設定
        self.spin.SetRange(1, len(self.ldata))
        # リストの再表示
        self.DispList()

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

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



#######################################
#  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]
        
        
    ######################################################
    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)    
        # データ追加イベント発行
        self.ifi.NotifyEvent(self, "add", [data])
        
    ######################################################
    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]
        
        # データの終了まで
        while 1:
            # 読み込み終了
            if stat == 5:
                #return (x, y, er, header, xunit, yunit)
                return (x, y, er, header, (xlabel,xunit), (ylabel,yunit))
            
            line = fp.readline().strip()
            if "--------" in line:
                stat += 1
            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 = 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): #[inamura 160714]
        """
        テキストファイルにデータを出力(トレースの数だけ)
        @param  path ファイルパス
        @param  dataobj データクラスのインスタンス
        @retval 無し
        """ 

        # 拡張子を分離
        fbody, ext = os.path.splitext(path)
        
        num = 1
        for data in dataobj.lstData:
#            label = data[3]["Label"]
#            fname = "%s-%d %s.txt" % (fbody, num, label)
            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)#[inamura 160714]

    ######################################################
    def _WriteTextFile(self, fp, data, maskInfo=None): #[inamura 160714]
        """
        テキストファイルにデータを出力(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] == None:
        #    xx = data[0]
        #else:
        #    # ヒストグラムデータのx値
        #    xx = data[6]
        ##  if existing histogram data AND Histogram output mode?
        #if (data[6] != None) and self.histFlag:
        if type(data[6])!=type(None) and self.histFlag: #[inamura 171107]
            xx = data[6]
        else:
            xx = data[0]
        ##<--[inamura 100819]
            
        # データ書き込み    
        #[inamura 160714]-->
        #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==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)
        #<--[inamura 160714]
                    
        # ヒストグラムデータなら
        if len(xx) > len(data[1]):
            # 最後のX値を書き込む
            dline = "%15e \n" % xx[i+1]
            fp.write(dline)
            
        # データ終了
        fp.write("-----------------------------------------------\n")
        # ファイルをクローズ
        fp.close           
                
##[inamura 160722]-->
#########################################
#       SetAxisGridStyleDialog
#########################################
class SetAxisGridStyleDialog(wx.Dialog):
    """
    AxisGridStyle 設定ダイアログクラス
    """
    ##########################################################
    def __init__(self, parent, order, postfix):
        """
        コンストラクタ
        @param  parent   親ウィンドウのID
        @param  order  プロッタの起動順序
        @param  postfix 画面タイトルに付ける親の識別子    
        @retval 無し
        """ 
        
        self.ifi = IFEvtProp(order)
        self.parent = parent
        
        # リソース取得      
        self.res = ResourceFile()
        self.dialog = self.res.GetDialog(parent, 'Dg2DGridSetting')
        # アイコンを設定
        self.dialog.SetIcon(Images().GetMainIcon())
        
        # ボタンのイベントハンドラを登録
        self.dialog.Bind(wx.EVT_BUTTON, self.OnClose, id=self.res.GetId('btClose'))
        
        # リソースよりコントロールを取得
        # コンボボックス
        self.cbXLC = self.res.GetCtrl(self.dialog, 'XlineColor')
        self.cbXLS = self.res.GetCtrl(self.dialog, 'XlineStyle')
        self.cbYLC = self.res.GetCtrl(self.dialog, 'YlineColor')
        self.cbYLS = self.res.GetCtrl(self.dialog, 'YlineStyle')
        
        # コンボボックスのイベントハンドラ登録
        self.cbXLC.Bind(wx.EVT_COMBOBOX, self.OnComboXLC, self.cbXLC)
        self.cbXLS.Bind(wx.EVT_COMBOBOX, self.OnComboXLS, self.cbXLS)
        self.cbYLC.Bind(wx.EVT_COMBOBOX, self.OnComboYLC, self.cbYLC)
        self.cbYLS.Bind(wx.EVT_COMBOBOX, self.OnComboYLS, self.cbYLS)

        # スピンボタン
        self.spinXLW = self.res.GetCtrl(self.dialog, 'XlineWidth')
        self.spinYLW = self.res.GetCtrl(self.dialog, 'YlineWidth')
        
        # スピンボタンのイベントハンドラ登録
        self.spinXLW.Bind(wx.EVT_SPINCTRL, self.OnSpinXLW, self.spinXLW)
        self.spinYLW.Bind(wx.EVT_SPINCTRL, self.OnSpinYLW, self.spinYLW)
        
        #[X]ボタン押下時のイベントハンドラ登録
        self.dialog.Bind(wx.EVT_CLOSE, self.OnClose)
        
        # ダイアログオープンイベント発行
        self.ifi.NotifyEvent(self, "setaxisgridstyledg", False)
        
        # Set Values
        self.initialize()
        
        # ダイアログ表示
        self.dialog.Show()
        
    ##########################################################
    def initialize(self):
        """
        """
        ddic = self.ifi.GetProperty('gridstyledic')
        self.cbXLC.SetSelection( self._GetAttrNum( ddic["XlineColor"], TraceAtt.color )-1 )
        self.cbYLC.SetSelection( self._GetAttrNum( ddic["YlineColor"], TraceAtt.color )-1 )
        self.cbXLS.SetSelection( self._GetAttrNum( ddic["XlineStyle"], TraceAtt.linestyle ) )
        self.cbYLS.SetSelection( 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):
        """
        ラインColor変更イベント処理
        @param  evt イベント情報
        @retval 無し
        """
        lc = TraceAtt.color[self.cbXLC.GetSelection()+1]
        ddic = self.ifi.GetProperty('gridstyledic')
        ddic['XlineColor'] = lc
        self.ifi.NotifyEvent(self,'replot', None)
    ##########################################################    
    def OnComboXLS(self, evt):
        """
        ラインスタイル変更イベント処理
        @param  evt イベント情報
        @retval 無し
        """
        ls = TraceAtt.linestyle[self.cbXLS.GetSelection()]
        ddic = self.ifi.GetProperty('gridstyledic')
        ddic['XlineStyle'] = ls
        self.ifi.NotifyEvent(self,'replot', None)
    ##########################################################
    def OnSpinXLW(self, evt):
        """
        """
        lw = TraceAtt.linewidth[int(self.spinXLW.GetValue())]
        if lw==0:
            lw = 0.5
        ddic = self.ifi.GetProperty('gridstyledic')
        ddic['XlineWidth'] = lw
        self.ifi.NotifyEvent(self,'replot', None)
        
    ##########################################################    
    def OnComboYLC(self, evt):
        """
        ラインスタイル変更イベント処理
        @param  evt イベント情報
        @retval 無し
        """
        lc = TraceAtt.color[self.cbYLC.GetSelection()+1]
        ddic = self.ifi.GetProperty('gridstyledic')
        ddic['YlineColor'] = lc
        self.ifi.NotifyEvent(self,'replot', None)
        
    ##########################################################    
    def OnComboYLS(self, evt):
        """
        ラインスタイル変更イベント処理
        @param  evt イベント情報
        @retval 無し
        """
        ls = TraceAtt.linestyle[self.cbYLS.GetSelection()]
        ddic = self.ifi.GetProperty('gridstyledic')
        ddic['YlineStyle'] = ls
        self.ifi.NotifyEvent(self,'replot', None)
        
    ##########################################################
    def OnSpinYLW(self, evt):
        """
        """
        lw = TraceAtt.linewidth[int(self.spinYLW.GetValue())]
        if lw==0:
            lw = 0.5
        ddic = self.ifi.GetProperty('gridstyledic')
        ddic['YlineWidth'] = lw
        self.ifi.NotifyEvent(self,'replot', None)
        
    ##########################################################
    def OnClose(self, evt):
        """
        Closeボタンイベント処理
        @param  evt イベント情報
        @retval 無し
        """ 
        self.ifi.NotifyEvent(self, "setaxisgridstyle2ddg", True) 
        self.dialog.Destroy()

        
##<--[inamura 160722]

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

        self.order = order
        self.res = ResourceFile()
        self.frame = self.res.GetFrame(parent, 'plotframe')
        # リソースからフレームが取得できなかった
        if self.frame == None:
            return
        
        self.menuBar= self.res.GetMenuBar('PlotMenuBar')
        self.frame.SetMenuBar(self.menuBar)
        # アイコンの設定
        self.frame.SetIcon(Images().GetMainIcon())
        # フレームのタイトルに番号を付ける
        strT = self.frame.GetTitle()
        # フレームのタイトルが指定されているか
        if fTitle:
            self.post = " - %s" % fTitle
        else:
            # フレームのタイトルに番号を付ける    
            self.post = " (%d)" % order
            
        self.frame.SetTitle(strT + self.post)
        
        # データオブジェクトを設定
        self.dataobj = PlotData(self, data, order)
        
        panel = self.res.GetCtrl(self.frame, 'panel')

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

        self.canvas= FigCanvas(self.frame, -1, self.fig)
        # 垂直サイザーを作成
        sizer = wx.BoxSizer(wx.VERTICAL)
        # プロッタフレーム用ツールバー作成
        self.toolbar = ChartToolBar2(self, order)
        sizer.Add(self.toolbar, 0, wx.LEFT|wx.TOP|wx.GROW)
        self.toolbar.Show()

        # サイザーにキャンバスを追加
        sizer.Add(self.canvas, 1, wx.LEFT | wx.EXPAND)

        # サイザーにパネルを追加
        sizer.Add(panel, 0, wx.LEFT | wx.EXPAND)
        self.frame.SetSizer(sizer)
        self.frame.Fit()
        
        # マウス移動イベント登録(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')

        # 表示テキストのコントロール取得
        self.numtxt = self.res.GetCtrl(panel, 'strNum')
        self.xytxt = self.res.GetCtrl(panel, '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.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('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)
        
        # データ数を表示
        self.OnNotifyDisplayPage(None, "page", 1)
        # プロッタフレームを表示
        self.frame.Show(True)
        # データ一覧表示ボックスを作成(非表示のまま)
        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'))
        # 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'))
        self.frame.Bind(wx.EVT_MENU, self.OnGrid, id=self.res.GetId('menu_grid')) ##[inamura 160722]
        self.frame.Bind(wx.EVT_MENU, self.OnTicks, id=self.res.GetId('menu_ticks')) ##[inamura 160726-2]
        # Process メニューのイベントハンドラー登録
#        self.frame.Bind(wx.EVT_MENU, self.OnProcess,  id=xrc.XRCID('menu_process'))
        self.frame.Bind(wx.EVT_MENU, self.OnFitting,  id=xrc.XRCID('menu_fitting')) #[inamura 160714]

        # アクセラレータキーの、メニュー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]
        # ファイルを開くダイアログを表示
        dlg =wx.FileDialog(self.frame, "Open text file", tdir, style=wx.OPEN, wildcard='Text(*.txt)|*.txt')
                         
        # OK であればファイルを開く
        if dlg.ShowModal() == wx.ID_OK:
            try:
                dat = TextFile(self.order).ReadFrom(dlg.GetPath())
                ##[inamura 120128]-->
                flp = dlg.GetPath()
                self.DefaultDialogPath["OPEN"]=flp[:flp.rfind("/")]
                ##<--[inamura 120128]
            except PlotException, ex:
                PlotMessage(self.frame, ex)


    ######################################################
    def OnSaveas(self, *args):
        """
        Save as メニューイベント処理
        テキストファイルに出力(トレースの数だけ)
        印刷ダイアログを表示
        @param  *args イベント情報
        @retval 無し
        """
        # Txtファイルのパスを取得
        ##[inamura 120128]-->
        #path = AcqPath().GetHome()
        #tdir = os.path.join(path, "ana")
        tdir = self.DefaultDialogPath["SAVE"]
        
        #[inamura 160714]-->
        dlg = SetSaveAsTextDialog( self, isHist=False )
        """
        ##<--[inamura 120128]
        # ファイル保存ダイアログを表示
        dlg =wx.FileDialog(self.frame, "Save to text files",tdir, style=wx.SAVE, wildcard='Text(*.*)|*.*')
        # OK であればファイルを保存

        if dlg.ShowModal() == wx.ID_OK:
            try:
                #TextFile(self.order).WriteTo(dlg.GetPath(), self.dataobj)
                TextFile(self.order, False).WriteTo(dlg.GetPath(), self.dataobj)   ##[inamura 100819]
                ##[inamura 120128]-->
                flp = dlg.GetPath()
                self.DefaultDialogPath["SAVE"]=flp[:flp.rfind("/")]
                ##<--[inamura 120128]
            except PlotException, ex:
                PlotMessage(self.frame, ex)
        """
        #<--[inamura160714]

    ##[inamura 100819]-->
    ######################################################
    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]!=None:
                num_of_not_hist += 1
        if num_of_not_hist != 0:
            if num_of_not_hist==1:
                msg = "One trace does not include histogram data. This trace are saved as same format as Save As... menu."
            else:
                msg = "%d traces do not include histogram data. These traces are saved as same format as Save As... menu."%(num_of_not_hist)
            dial = wx.MessageDialog(None, msg, "Warning", wx.OK | wx.ICON_EXCLAMATION )
            dial.ShowModal()
        ##<--[inamura 160205]
        # Txtファイルのパスを取得
        ##[inamura 120128]-->
        #path = AcqPath().GetHome()
        #tdir = os.path.join(path, "ana")
        tdir = self.DefaultDialogPath["SAVE"]

        #[inamura 160714]-->
        dlg = SetSaveAsTextDialog( self, isHist=False )
        """
        ##<--[inamura 120128]
        # ファイル保存ダイアログを表示
        dlg =wx.FileDialog(self.frame, "Save to text files",tdir, style=wx.SAVE, wildcard='Text(*.*)|*.*')
        # OK であればファイルを保存

        if dlg.ShowModal() == wx.ID_OK:
            try:
                TextFile(self.order).WriteTo(dlg.GetPath(), self.dataobj)
                ##[inamura 120128]-->
                flp = dlg.GetPath()
                self.DefaultDialogPath["SAVE"]=flp[:flp.rfind("/")]
                ##<--[inamura 120128]
            except PlotException, ex:
                PlotMessage(self.frame, ex)
        """
        #<--[inamura 160714]
    ##<--[inamura 100819]
    ######################################################
    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, ex:
                PlotMessage(self.frame, ex)
            time.sleep(2.0)
        # Linux または Mac OS 以外(Windowsを想定)
        else:
            # 現在の解像度を取得
            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, ex:
                PlotMessage(self.frame, ex)
        # トレース選択マークを再表示するためにprintfigイベントを発行
        self.ifi.NotifyEvent(self, "printfig", True)
        # 再描画
        self.canvas.draw() 
        
    ######################################################    
    def OnShow(self, event):
        """
        Show Plotting data window メニューイベント処理
        データ一覧ボックスを表示
        @param  event イベント情報
        @retval 無し
        """      
        # メニューを選択可とする
        self.menuBar.Enable(self.res.GetId('menu_show'), False)
        # フローティングボックスを表示
        self.fb.ShowFB()
    
    ######################################################        
    def OnParam(self, event=None):
        """
        Set Potting Parameter メニューイベント処理
        パラメータ設定ダイアログを表示
        @param  event イベント情報
        @retval 無し
        """      
        dg = ParamDialog(self.frame, self.order, self.post)
        
    ######################################################
    def OnTitle(self, event):
        """
        Set Graph Title メニューイベント処理
        スケール設定ダイアログを表示
        @param  event イベント情報
        @retval 無し
        """ 
        dlg = TitleDialog(self.frame, self.order, self.post)
 

    ######################################################
    def OnLabel(self, event):
        """
        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]

    #[inamura 160722]-->
    ######################################################
    def OnGrid(self, event):
        """
        Set Grid Style メニューイベント処理
        スケール設定ダイアログを表示
        @param  event イベント情報
        @retval 無し
        """ 
        dlg = SetAxisGridStyleDialog(self.frame, self.order, self.post)
        
    #<--[inamura 160722]
    #[inamura 160726-2]-->
    ######################################################
    def OnTicks(self, event):
        """
        Set Ticks Style メニューイベント処理
        スケール設定ダイアログを表示
        @param  event イベント情報
        @retval 無し
        """ 
        dlg = SetAxisTickStyleDialog(self.frame, self.order, self.post)
        
    #<--[inamura 160726-2]
    #[inamura 160714]-->
    ######################################################
    def OnFitting(self, event):
        """
        """
        frame = FittingFrame( self, self.post, 0 )
    #<--[inamura 160714]
    ######################################################
    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)
        
        
    ######################################################
    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)
        elif evt == "titledg":
            self.menuBar.Enable(self.res.GetId('menu_title'), flag)
        elif evt == "labeldg":
            self.menuBar.Enable(self.res.GetId('menu_label'), 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.SetLabel(strTxt)
            
    ###################################################
    def OnNotifyDoIconize(self, wid, evtType, flag):
        """
        ウィンドウアイコン化または復元要求受信処理
        @param  wid ウィンドウID
        @param  evtType　イベントタイプ
        @param  flg    True: アイコン化　False: 元に戻す
        @retval 無し
        """ 
        # アイコン化する、または元に戻す
        self.frame.Iconize(flag)
        
    ###################################################            
    def OnPrevious(self, evt):
        """
        Previousボタンクリックイベント処理関数
        (前のページを表示)
        @param  evt  イベント
        @retval 無し
        """        
        # 現在のページを取得
        page = self.ifi.GetProperty('page')+1
        # ページ変更要求イベント発行
        self.ifi.NotifyEvent(self, "page", page-1)

    ###################################################        
    def OnNext(self, evt):
        """
        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 = dno / gno
        if dno % gno > 0:
            maxp += 1
            
        if dno==0:
            maxp = 0    
        # 次ページがあれば
        if maxp > pno:
            # Next ボタンを選択可
            self.btNxt.Enable(True)
        else:
            # Next ボタンを選択不可 
            self.btNxt.Enable(False)
            
        # 前のページがあれば
        if pno > 1 :
            # Previus ボタンを選択可
            self.btPrv.Enable(True) 
        else:
            # Previus ボタンを選択不可
            self.btPrv.Enable(False) 
        # 現在ページの最後のデータ番号を計算       
        dxno = (pno)*gno
        if dxno > dno:
            dxno = dno
            
        # ページと表示グラフ数を更新
        strNum = "Page: %d / %d    (%d / %d)" % (pno, maxp, dxno, dno)
        self.numtxt.SetLabel(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()
        # I/F をクリア
        self.ifi.InitIF()
        # 画面を閉じる
        self.frame.Destroy()

    
    ###################################################    
    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":"off",
                              "RightSide":"off"}
        ##<--[inamura 160726-2]
        self.isAutoScaleY = False ##[inamura 171220]
        
        # トレースのラベルリストと属性リストを準備
        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==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)
        self.ifi.AddListner('replace', self.OnNotifyReplaceData) ##[inamura 100715]
        self.ifi.AddListner('setunits', self.OnNotifySetUnits )##[inamura 110620]
        self.ifi.AddListner('setfontinfo', self.OnNotifySetFontInfo )##[inamura 120513]
        self.ifi.AddListner('settextinfo', self.OnNotifySetTextInfo )##[inamura 120513]
        self.ifi.AddListner('setautoscaley', self.OnNotifySetAutoScaleY )##[inamura 171220]
        
        # 公開プロパティを登録
        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]
        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 120513]
        ##[inamura 100716]-->
        self.ifi.AddListner('moncursoron', self.OnNotifyMoniCursorOn )
        self.ifi.AddListner('moncursorpos', self.OnNotifyMoniCursorSet )
        ##<--[inamura 100716]
        self.ifi.AddProperty('gridstyledic', lambda : self.GridStyleDic) ##[ianmrua 160722]
        self.ifi.AddProperty('tickstyledic', lambda : self.TickStyleDic) ##[ianmrua 160726-2]
        
    ###################################################    
    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 == True:
             # オーバレイグラフを表示
            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 (type(xunit_in)==type( () )) 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 (type(yunit_in)==type( () )) 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 not self.xunit == "":
            xlabel = "%s [%s]" % (self.xlabel,self.xunit)
        else:
            xlabel = self.xlabel
        if not self.yunit == "":
            ylabel = "%s [%s]" % (self.ylabel,self.yunit)
        else:
            ylabel = self.ylabel

        # スケールのラベルを表示
        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]
        ##[inamura 170615]-->
        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]-->
        self.ax.xaxis.set_tick_params( which='major', length=self.TickStyleDic["MajorLength"], width=self.TickStyleDic["MajorWidth"], top=self.TickStyleDic["TopSide"] )
        self.ax.yaxis.set_tick_params( which='major', length=self.TickStyleDic["MajorLength"], width=self.TickStyleDic["MajorWidth"], right=self.TickStyleDic["RightSide"] )
        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"] )
            self.ax.yaxis.set_tick_params( which='minor', length=self.TickStyleDic["MinorLength"], width=self.TickStyleDic["MinorWidth"], right=self.TickStyleDic["RightSide"] )
        ##<--[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"] )
            ax.yaxis.set_tick_params( which='major', length=self.TickStyleDic["MajorLength"], width=self.TickStyleDic["MajorWidth"], right=self.TickStyleDic["RightSide"] )
            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"] )
                ax.yaxis.set_tick_params( which='minor', length=self.TickStyleDic["MinorLength"], width=self.TickStyleDic["MinorWidth"], right=self.TickStyleDic["RightSide"] )
            ##<--[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"]
        # キャップサイズを取得
        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 == True:
            # ヒストグラムモードか 
            if hflag == 1:
                if self.logFlagX == True:
                    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)
                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)
            else:    
                if self.logFlagX == True:
                    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)
                
        # エラーバー付き指定時
        elif eb == 1:
            if not MATPLOTLIB98:  ##[inamura 110626]
                 yye = self.do.GetNonMaskY(i)
            else:
                 yye = yy
            # ヒストグラムモードか 
            if hflag == 1:
                 if self.logFlagX == True:
                     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 == True:
                    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 == True:
                    # ヒストグラムの線をマーカ無しで描画
                    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 == True:
                    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))
        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 not self.hb == None:
            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 = x0 + evt.x
        # フレームのサイズを取得
        xx, yy =  self.plot.frame.GetSize()
        # マウスクリック点の y 位置を求める 
        y0 = y0 + yy - y0dpi- evt.y
        # ヘッダー表示ボックスを表示
        self.hb = HeaderBox(self.plot.frame, (x0+5, y0+20), header)

    ###################################################        
    def OnMouseUp(self, evt):
        """
        マウス左ボタンアップイベント処理関数
        @param  evt  イベント
        @retval 無し
        """ 
        # ヘッダー表示関数がでているか           
        if not self.hb == 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(None)
            if self.doubleClick_state1[0]==1:
                self.plot.OnParam(None)
            if self.doubleClick_state1[0]==2:
                self.plot.OnLabel(None)
            if self.doubleClick_state1[0]==3:
                self.plot.OnTitle(None)
            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==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 = 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 171220]-->
            if self.isAutoScaleY:
                self.PlotOrgChart(True)
            else:
                self.RePlotChart()
             #<--[inamura 171220]
            
        # ページ数・データ数表示更新要求
        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 = (dnum-1) / self.traceNum +1
            
            # データ数を取得
            dno = self.ifi.GetProperty('datanum')
            # ページ数を計算
            maxp = 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
        # メインタイトルが変更されたか
        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 171220]-->
    ###################################################
    def OnNotifySetAutoScaleY(self, wid, evtType, flag):
        """
        
        """
        if isinstance( flag, bool ):
            self.isAutoScaleY = flag
    ##<--[inamura 171220]
    ###################################################    
    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, 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.keys():
        
            # 属性があれば
            if tattr.has_key(key):
                # 属性を変更
                tattr[key] = attrs[key]
            else:
                # 内部処理エラー
                try:
                    strEr = "Set Param key %s" % key
                    raise PlotException('Common', 'C001', (strEr, "Chart:_ChangeTraceAttr"))
                except PlotException, ex:
                    PlotMessage(self.plot.frame, ex)
     
    
    ###################################################
    def SetScales(self, ax):
        """
        スケール範囲プロパティセット
        @param  ax : サブプロットの軸 
        @retval 無し
        """
        if self.logFlag == False and self.logFlagX == False: #[inamura 160408]
            if MATPLOTLIB110:
                ax.ticklabel_format(style="sci",scilimits=(-5,5)) #[inamura 160328]
        # X自動スケールが指定されていたら
        if self.autoXFlag:
            # 現在の範囲を取得してプロパティにセット
            self.xx0, self.xx1 = ax.get_xlim()
            #[inamura 160717]-->
            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:
                ax.set_xlim( (self.xx0,self.xx1) )
            #<--[inamura 160717]
        # マニュアル指定なら
        else:
            # プロパティをスケールにセット
            ax.set_xlim((self.xx0, self.xx1))
            
        # Y自動スケールが指定されていたら 
        if self.autoYFlag:
            self.yy0, self.yy1 = ax.get_ylim()
            #[inamura 160717]-->
            isChangedScaleY = False
            for atrace in self.do.lstData:
                if isinstance(atrace[1],list):
                    ymin = min(atrace[1])
                    ymax = max(atrace[1])
                else:
                    ymin = atrace[1].min()
                    ymax = atrace[1].max()
                if self.yy0>ymin:
                    self.yy0=ymin
                    isChangedScaleY = True
                if ymax<MASKVALUE and self.yy1<ymax:
                    self.yy1=ymax
                    isChangedScaleY = True
            if isChangedScaleY:
                ax.set_ylim( (self.yy0,self.yy1) )
            #<--[inamura 160717]
        # マニュアル指定なら
        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 not data == None:
            # リストか
            try:
                data[0][0][0]
            except:
                # 単独データであれば
                datTpl = self._ConvertData(data)
                if not datTpl == None:
                    # 1個のデータを変換して格納する
                    self.lstData.append(datTpl)
            # リストであれば    
            else:
                # リスト中の各データに対し
                for datum in data:
                    # 変換して格納する
                    datTpl = self._ConvertData(datum)
                    if not datTpl == 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]
        self.ifi.AddListner('setlabeltodata', self.OnNotifySetLabel) ##[inamura 120128]
        
    ###################################################        
    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 = numpy.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 = numpy.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, ex:
            PlotMessage(self.parent.frame, ex)
            return None
    

        # エラーリストがあるか
        if lenTpl > 2: 
            if datum[2] is not None:
                er = numpy.array(datum[2])
            else:
                # エラー値がなければ、0値のアレイを作る
                er = numpy.zeros(len(yy))        
        else:
            # エラー値がなければ、0値のアレイを作る
            er = numpy.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 type(data)!=type([]):
            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, 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, 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, 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 type(data[1])==type(u""):
                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 == 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 = 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, 
                      "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()
        # 通信クラスの終了処理コールバック関数を実行
        apply(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 == 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 = 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 flag == False:    
            # 個別モードの場合、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 arg
        @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 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== True:
                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 len(sys.argv) > 2:
        # CUI-GUI コミュニケータのサーバアプリ(wxPython) 起動
        app = WxCom.WxApp() 
        # 汎用プロッタ(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)
        
    # wxPython のメインループ開始
    app.MainLoop()
