#!/usr/bin/python
# -*- coding: utf-8 -*-
"""
u2dplot.py
uGao 汎用2次元プロッタ処理
"""
from __future__ import print_function
import scipy
import six
import logging
import numpy as np
import sys
import codecs
import os
from os.path import expanduser
import Manyo
import Manyo.MLF as mm
import uGao.MPlot as mp
import uGao.FastPlotQt as fastplot

from uGao.uGaoUtil import IFEvtProp, Validator, PlotException, PlotMessage, MASKVALUE, NAVIGATIONTOOLBAR_CHANGED_VER, MATPLOTLIB_VER
from uGao.u2dplotBase import D2Chart, U2Params, ScaleParams

import math
import time
# from matplotlib.backends.backend_qt4agg import (FigureCanvasQTAgg as FigCanvas,
#                                                NavigationToolbar2QT, )
import matplotlib
from matplotlib.figure import Figure
from matplotlib import (image)

PYSIDEVER = 1
try:
    from PySide6 import QtCore, QtGui, QtWidgets
    from PySide6.QtGui import QAction
    PYSIDEVER = 6
except ModuleNotFoundError:
    try:
        from PySide2 import QtCore, QtGui, QtWidgets
        from PySide2.QtWidgets import QAction
        PYSIDEVER = 2
    except ModuleNotFoundError:
        from PySide import QtCore, QtGui
        import PySide.QtGui as QtWidgets
        from PySide.QtGui import QAction

if QtCore.__version__ < '5.0.0':
    from matplotlib.backends.backend_qt4agg import (FigureCanvasQTAgg as FigCanvas,
                                                    NavigationToolbar2QT, )

    from uGao.ui_u2dplot import Ui_MainWindow, Ui_DlgViewPrms, Ui_DlgRegion, Ui_DlgSlice, Ui_DgOverPlot
else:
    from matplotlib.backends.backend_qt5agg import (FigureCanvasQTAgg as FigCanvas,
                                                    NavigationToolbar2QT, )
    if PYSIDEVER == 2:
        from uGao.ui2_u2dplot import Ui_MainWindow, Ui_DlgViewPrms, Ui_DlgRegion, Ui_DlgSlice, Ui_DgOverPlot
    elif PYSIDEVER == 6:
        from uGao.ui6_u2dplot import Ui_MainWindow, Ui_DlgViewPrms, Ui_DlgRegion, Ui_DlgSlice, Ui_DgOverPlot

if six.PY2:
    import cPickle as pickle
else:
    import pickle

__author__ = "ITO, Takayoshi (CROSS)"
__version__ = "19.03.10b"
__date__ = "7th Aug. 2019"

# DPI setting
try:
    matplotlib.rcParams["figure.dpi"] = 100
    matplotlib.rcParams["savefig.dpi"] = 100
except:
    pass


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

    ##########################################################
    def __init__(self, parent):
        """
        コンストラクタ
        @param  parent   親ウィンドウのクラスのインスタンス
        @retval 無し
        """
        logging.debug("SliceDialog::__init__")
        super(SliceDialog, self).__init__(parent)
        self.ui = Ui_DlgSlice()
        if self.ui is None:
            return
        self.ui.setupUi(self)
        # インターフェイスクラスのインスタンスを取得
        self.ifi = IFEvtProp(parent.order)
        # 最後に適用されたdataを保持
        # [[xc, xw],[xstart, xend],[yc, yw],[ystart, yend]]
        self.last_data = [[0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [0.0, 0.0]]

        q_validator = QtGui.QDoubleValidator()
        children = self.findChildren(QtWidgets.QLineEdit)
        for child in children:
            child.setValidator(q_validator)

        self.buttonBox = self.findChild(
            QtWidgets.QDialogButtonBox, 'buttonBox')
        self.buttonBox.clicked.connect(self.OnClick)

        # スライスの横軸Rebin用のパーツ
        self.ckb_sliceX = self.findChild(QtWidgets.QCheckBox, 'cb_sliceXbin')
        self.ckb_sliceY = self.findChild(QtWidgets.QCheckBox, 'cb_sliceYbin')
        self.ckb_sliceX.stateChanged.connect(self.OnStateChangeCB)
        self.ckb_sliceY.stateChanged.connect(self.OnStateChangeCB)
        self.ckb_sliceX.setCheckState(QtCore.Qt.Unchecked)
        self.ckb_sliceY.setCheckState(QtCore.Qt.Unchecked)
        self.txt_xbin = self.findChild(QtWidgets.QLineEdit, 'txt_xbin')
        self.txt_ybin = self.findChild(QtWidgets.QLineEdit, 'txt_ybin')
        self.txt_xbin.setEnabled(False)
        self.txt_ybin.setEnabled(False)
        self.txt_xbin.setText("0.0")
        self.txt_ybin.setText("0.0")

        # Parts for Along-X Slice
        self.txt_y_center = self.findChild(QtWidgets.QLineEdit, 'txt_y_center')
        self.txt_y_start = self.findChild(QtWidgets.QLineEdit, 'txt_y_start')
        self.txt_y_end = self.findChild(QtWidgets.QLineEdit, 'txt_y_end')
        self.txt_y_width = self.findChild(QtWidgets.QLineEdit, 'txt_y_width')
        self.radio_yvalue = self.findChild(QtWidgets.QRadioButton, 'radio_yvalue')
        self.radio_yrange = self.findChild(QtWidgets.QRadioButton, 'radio_yrange')

        # Parts for Along-Y Slice
        self.txt_x_center = self.findChild(QtWidgets.QLineEdit, 'txt_x_center')
        self.txt_x_start = self.findChild(QtWidgets.QLineEdit, 'txt_x_start')
        self.txt_x_end = self.findChild(QtWidgets.QLineEdit, 'txt_x_end')
        self.txt_x_width = self.findChild(QtWidgets.QLineEdit, 'txt_x_width')
        self.radio_xvalue = self.findChild(QtWidgets.QRadioButton, 'radio_xvalue')
        self.radio_xrange = self.findChild(QtWidgets.QRadioButton, 'radio_xrange')

    ##########################################################
    def OnClick(self, button):
        """
        ButtonBoxクリック時の挙動の振り分け

        Parameters:
            button (QAbstractButton) クリックされたボタン
        """

        buttonRole = self.buttonBox.buttonRole(button)
        if buttonRole == QtWidgets.QDialogButtonBox.ApplyRole:
            self.OnApply()
        elif buttonRole == QtWidgets.QDialogButtonBox.ResetRole:
            self.OnReset()
        elif buttonRole == QtWidgets.QDialogButtonBox.RejectRole:
            self.reject()

    ##########################################################
    def OnStateChangeCB(self):
        """
        Sliceのrebinのチェックボックスの状態変化への対応
        """
        sender_name = self.sender().objectName()
        if sender_name == "cb_sliceXbin":
            if self.ckb_sliceX.checkState() == QtCore.Qt.Checked:
                self.txt_xbin.setEnabled(True)
            else:
                self.txt_xbin.setEnabled(False)
        elif sender_name == "cb_sliceYbin":
            if self.ckb_sliceY.checkState() == QtCore.Qt.Checked:
                self.txt_ybin.setEnabled(True)
            else:
                self.txt_ybin.setEnabled(False)

    ##########################################################
    def PutBins(self):
        """
        Sliceのrebinの値をタプルで取り出す
        """
        xbin = 0.0
        ybin = 0.0
        if self.ckb_sliceX.checkState() == QtCore.Qt.Checked:
            try:
                xbin = float(self.txt_xbin.text())
            except:
                xbin = 0.0
        if self.ckb_sliceY.checkState() == QtCore.Qt.Checked:
            try:
                ybin = float(self.txt_ybin.text())
            except:
                ybin = 0.0
        return (xbin, ybin)

    ##########################################################
    def PutRange(self):
        """
        テキストボックスから値を取得しスライス範囲として返す

        Returns:
            Tuple[float, float] or Tuple[float, float, float, float]:
            座標(x, y) or (x0, y0, x1, y1)
        """
        if self.findChild(QtWidgets.QRadioButton, 'radio_yvalue').isChecked():
            center = float(self.findChild(
                QtWidgets.QLineEdit, "txt_y_center").text())
            width = float(self.findChild(
                QtWidgets.QLineEdit, "txt_y_width").text())
            if width == 0.0:
                y0 = center
                y1 = center
            else:
                if width > 0.0:
                    y0 = center - width
                    y1 = center + width
                else:
                    y0 = center + width
                    y1 = center - width
        else:
            y0 = float(self.findChild(
                QtWidgets.QLineEdit, "txt_y_start").text())
            y1 = float(self.findChild(QtWidgets.QLineEdit, "txt_y_end").text())
            # if y0 > y1:
            #    y0, y1 = y1, y0
        if self.findChild(QtWidgets.QRadioButton, 'radio_xvalue').isChecked():
            center = float(self.findChild(
                QtWidgets.QLineEdit, "txt_x_center").text())
            width = float(self.findChild(
                QtWidgets.QLineEdit, "txt_x_width").text())
            if width == 0.0:
                x0 = center
                x1 = center
            else:
                if width > 0.0:
                    x0 = center - width
                    x1 = center + width
                else:
                    x0 = center + width
                    x1 = center - width
        else:
            x0 = float(self.findChild(
                QtWidgets.QLineEdit, "txt_x_start").text())
            x1 = float(self.findChild(QtWidgets.QLineEdit, "txt_x_end").text())
            # if x0 > x1:
            #    x0, x1 = x1, x0
        if x0 == x1 and y0 == y1:
            # return (x0, y0)
            return [x0, y0]
        else:
            # return (x0, y0, x1, y1)
            return [x0, y0, x1, y1]

    ##########################################################
    def OnReset(self):
        """
        スライス範囲変更を戻す
        """
        self.findChild(QtWidgets.QLineEdit, "txt_y_center").setText(
            "{0:.3f}".format(self.last_data[2][0]))
        self.findChild(QtWidgets.QLineEdit, "txt_y_width").setText(
            "{0:.3f}".format(self.last_data[2][1]))
        self.findChild(QtWidgets.QLineEdit, "txt_y_start").setText(
            "{0:.3f}".format(self.last_data[3][0]))
        self.findChild(QtWidgets.QLineEdit, "txt_y_end").setText(
            "{0:.3f}".format(self.last_data[3][1]))
        self.findChild(QtWidgets.QLineEdit, "txt_x_center").setText(
            "{0:.3f}".format(self.last_data[0][0]))
        self.findChild(QtWidgets.QLineEdit, "txt_x_width").setText(
            "{0:.3f}".format(self.last_data[0][1]))
        self.findChild(QtWidgets.QLineEdit, "txt_x_start").setText(
            "{0:.3f}".format(self.last_data[1][0]))
        self.findChild(QtWidgets.QLineEdit, "txt_x_end").setText(
            "{0:.3f}".format(self.last_data[1][1]))

    ##########################################################
    def OnApply(self):
        """
        スライス範囲適用を実行
        """
        self.ifi.NotifyEvent(self, 'slice', self.PutRange())




#######################################
#  ChartToolBar
#######################################
class ChartToolBar(NavigationToolbar2QT):
    """
    matplotlib 画像操作用のツールバーの拡張クラス
    印刷処理追加と、画面設定処理のオーバーライド
    """

    #######################################
    def __init__(self, parent, order):
        """
        コンストラクタ
        @param parent  親クラスのインスタンス
        @param order  イベントディスパッチャのID
        @retval 無
        """
        try:
            if matplotlib.rcParams['savefig.directory'] == "~":
                matplotlib.rcParams['savefig.directory'] = os.getcwd()
        except:
            pass
        self.parentObj = parent
        # イベント管理クラスのインスタンスを取得
        self.ifi = IFEvtProp(order)
        # 先にスーパークラスのコンストラクタを実行させる
        super(ChartToolBar, self).__init__(
            parent.canvas, parent, coordinates=False)
        self.init_toolbar()
        # フラグ類の初期化
        self._idle = True
        self.statbar = None
        self.downEvt = None
        self.printingFlag = False
        # イベント格納用リストを準備
        self.evtlst = [None]
        # self._init_toolbar2()

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

        # Remove "Customize" item from ToolBar #[inamura 210312]
        for an_item in self.actions():
            # print(an_item.text())
            if an_item.text() == 'Customize':
                self.removeAction(an_item)

        # パラメータ設定アイコンをツールバーに追加
        self.addSeparator()
        self.btn_params = self.addAction(QtGui.QIcon(
            ":border_color.svg"), 'Set View Parameters', self.OnParams)
        self.btn_show = self.addAction(QtGui.QIcon(
            ":visibility.svg"), 'Show/Hide', self.OnTurnVisible)
        self.btn_show.setObjectName("showButton")
        self.btn_show.setCheckable(True)
        self.btn_show.setChecked(False)
        self.btn_slice = self.addAction(QtGui.QIcon(
            ":1d-graph.png"), 'Slice', self.parentObj.OnViewSlice)
        self.btn_slice.setObjectName("sliceButton")
        self.btn_slice.setCheckable(True)
        self.btn_slice.setChecked(True)
        self.btn_turn_cursor = self.addAction(QtGui.QIcon(
            ":border_inner.svg"), 'Hide the Cursor', self.OnShowCursor)
        self.btn_turn_cursor.setCheckable(True)
        self.btn_turn_cursor.setChecked(True)
        xpm_icon_data = [
            "24 24 4 1",
            " 	c None",
            ".	c #BACDF3",
            "+	c #000000",
            "@	c #8896B2",
            "                        ",
            " ...................... ",
            " ....+.....+.....+..... ",
            " ....+@....+@....+@.... ",
            " ....+@....+@....+@.... ",
            " ....+@....+@....+@.... ",
            " +++++++++++++++++++++. ",
            " .@@@+@@@@@+@@@@@+@@@@@ ",
            " ....+@....+@....+@.... ",
            " ....+@....+@....+@.... ",
            " ....+@....+@....+@.... ",
            " ....+@....+@....+@.... ",
            " .++++++++++++++++++++. ",
            " ..@@+@@@@@+@@@@+@@@@@@ ",
            " ....+@....+@....+@.... ",
            " ....+@....+@....+@.... ",
            " ....+@....+@....+@.... ",
            " ....+@....+@....+@.... ",
            " +++++++++++++++++++++. ",
            " .@@@+@@@@@+@@@@@+@@@@@ ",
            " ....+@....+@....+@.... ",
            " ....+@....+@....+@.... ",
            " .....@.....@.....@.... ",
            "                        "]
        self.btn_turn_grid = self.addAction(QtGui.QIcon(
            QtGui.QPixmap(xpm_icon_data)), 'Hide the Cursor', self.OnShowGrid)
        self.btn_turn_grid.setCheckable(True)
        self.btn_turn_grid.setChecked(False)
        self.addSeparator()
        # pixIcon = QtWidgets.QApplication.style().standardIcon(QtWidgets.QStyle.SP_ArrowBack)
        pixIcon = QtGui.QIcon()
        pixIcon.addPixmap(QtGui.QPixmap(":flip_to_front.svg"),
                          QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.btn_params = self.addAction(
            pixIcon, 'Find Parent Window', self.OnFindParent)

    ##################################
    def OnShowCursor(self):
        """
        カーソル表示／非表示ボタン処理
        """
        if self.btn_turn_cursor.isChecked():
            self.btn_turn_cursor.setToolTip("Hide the Cursor")
        else:
            self.btn_turn_cursor.setToolTip("Show the Cursor")
        self.ifi.NotifyEvent(self, "show_cursor",
                             self.btn_turn_cursor.isChecked())
        return

    ##################################
    def OnShowGrid(self):
        """
        Grid表示／非表示ボタン処理
        """
        if self.btn_turn_grid.isChecked():
            self.btn_turn_grid.setToolTip("Hide the grid")
        else:
            self.btn_turn_grid.setToolTip("Show the grid")
        self.ifi.NotifyEvent(self, "show_grid", self.btn_turn_grid.isChecked())
        return

    ##################################
    def OnTurnVisible(self):
        """
        領域表示／非表示ボタン処理
        """
        self.SetShowBtn(self.btn_show.isChecked())
        self.parentObj.regShowMode = self.btn_show.isChecked()

    ##################################
    def OnAutoSlice(self):
        """
        自動スライス機能切り替え
        obsolete
        """
        # self.parent.sliceMode = self.btn_slice.isChecked()
        pass

    ##################################
    def OnParams(self):
        """
        パラメータ設定ダイアログ表示要求
        @retval 無し
        """
        # パラメータダイアログイベント通知
        self.ifi.NotifyEvent(self, "dg_params")

    ##################################
    def OnFindParent(self):
        """
        u2dplotを起動している親ウィンドウを最前面に持ってくる
        """
        # もし、親ウィンドウがあるのなら
        if (self.parentObj.parent is not None):
            # 一旦隠して再表示する
            # self.parentObj.parent.hide()
            # self.parentObj.parent.show()

            # Try and Error history
            # not meanings
            # self.parentObj.parent.activateWindow()

            # This way kill Origin
            # self.parentObj.parent.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint)
            # self.parentObj.parent.show()

            """ not work
            p=self.parentObj.geometry()
            q=self.parentObj.parent.geometry()
            s=QtCore.QRect(p.top(),p.left(),q.width(),q.height())
            print( "s.top={}, s.left={}".format(s.top(),s.left()))
            print( "s.width={}, s.heigt={}".format(s.width(),s.height()))
            self.parentObj.parent.setGeometry(s)
            getattr( self.parentObj.parent, "raise")()
            """

            # self.parentObj.parent.raise() # error

            # simple is best.
            getattr(self.parentObj.parent, "raise")()

    ##################################
    def BtParamsEnable(self, flag):
        """
        パラメータ設定ボタンの選択可/不可設定
        @param  flag (bool)
        @retval 無し
        """
        self.EnableTool(self._NTB3_PARAMS, flag)

    ##################################
    def SetShowBtn(self, flag):
        """
        領域表示・非表示処理
        @param  flag  True: On  False: Off
        @retval 無し
        """
        # 領域表示/非表示ボタンの On/Off 変更
        self.btn_show.setChecked(flag)
        #  領域表示/非表示変更イベント通知
        self.ifi.NotifyEvent(self, "show_all", flag)

    ##################################
    def save(self, evt):
        """
        キャンバスに描画されている画像を保存(オーバライド関数)

        不要？未使用。
        @param evt イベント
        @retval 無
        """
        # 画像保存用ファイルの絶対パスを取得
        # 保存ファイルタイプの拡張子を取得
        wildcard = "PNG (*.png);;PS (*.ps);;EPS (*.eps)"
        # ファイル保存ダイアログを表示
        dlg = QtWidgets.QFileDialog(
            self, "Save the image", expanduser("."), wildcard)
        dlg.setAcceptMode(QtWidgets.QFileDialog.AcceptSave)
        # パスを取得。
        if dlg.exec_():
            fileNames = dlg.selectedFiles()
            try:
                # 指定された形式で保存
                self.parent.canvas.print_figure(fpath, dpi=300)
            except PlotException as ex:
                PlotMessage(self, ex)


#########################################
#       ScaleTab
#########################################
class ScaleTab(object):
    """
    スケールパラメータ設定パネルクラス
    """

    ##########################################################
    def __init__(self, dialog, widget_dict, scale):
        """コンストラクタ

        Parameters:
            widget_dict (dict) : WidgetのobjectName
            scale (string): 軸名

        widget_dict.keys = ["label", "auto_range", "min", "max", "auto_tick", "format", "prec", "log", "inversion"]

        """
        logging.debug("ScaleTab::__init__@{0}".format(scale))
        self.dialog = dialog
        self.onchange = dialog.OnChange  # 変更時の処理関数
        self.vld = dialog.vld  # バリデータ
        self.scale = scale
        self.widget_dict = widget_dict

        # チックラベル表示形式ComboBoxへの追加
        cb_format = dialog.findChild(
            QtWidgets.QComboBox, widget_dict["format"])
        for f in ScaleParams.tick_formats:
            cb_format.addItem(f)
        cb_format.setCurrentIndex(0)
        cb_format.setDisabled(True)

    ##########################################################
    def ConnectSignals(self):
        """
        ウィジェットをメソッドに接続

        """
        self.dialog.findChild(
            QtWidgets.QCheckBox, self.widget_dict["auto_range"]).stateChanged.connect(self.onchange)
        # [TI, task]この後の二行を入れるべきか？起動時の呼び出しは避けつつ、その後は呼び出されるようにするには？
        self.dialog.findChild(
            QtWidgets.QLineEdit, self.widget_dict["min"]).editingFinished.connect(self.onchange)
        self.dialog.findChild(
            QtWidgets.QLineEdit, self.widget_dict["max"]).editingFinished.connect(self.onchange)
        self.dialog.findChild(
            QtWidgets.QCheckBox, self.widget_dict["auto_tick"]).stateChanged.connect(self.onchange)
        self.dialog.findChild(
            QtWidgets.QSpinBox, self.widget_dict["prec"]).valueChanged.connect(self.onchange)
        self.dialog.findChild(QtWidgets.QComboBox, self.widget_dict["format"]).currentIndexChanged.connect(
            self.onchange)
        self.dialog.findChild(
            QtWidgets.QCheckBox, self.widget_dict["log"]).stateChanged.connect(self.onchange)
        self.dialog.findChild(
            QtWidgets.QCheckBox, self.widget_dict["inversion"]).stateChanged.connect(self.onchange)

    ##########################################################
    def SetParams(self, scalePrms):
        """
        スケールパラメータをパネルにセット
        @param  scalePrms スケールパラメータクラスのインスタンス
        @retval 無し
        """
        logging.debug("ScaleTab::SetParams")
        # 画面に設定
        self.dialog.findChild(
            QtWidgets.QCheckBox, self.widget_dict["auto_range"]).setChecked(scalePrms.autoRange)
        self.dialog.findChild(
            QtWidgets.QCheckBox, self.widget_dict["auto_tick"]).setChecked(scalePrms.autoTick)
        # レンジが指定されているか
        if scalePrms.range is not None:
            stR0 = "%g" % scalePrms.range[0]
            stR1 = "%g" % scalePrms.range[1]
            self.dialog.findChild(QtWidgets.QLineEdit,
                                  self.widget_dict["min"]).setText(stR0)
            self.dialog.findChild(QtWidgets.QLineEdit,
                                  self.widget_dict["max"]).setText(stR1)

        self.dialog.findChild(
            QtWidgets.QLineEdit, self.widget_dict["label"]).setText(scalePrms.label)
        self.dialog.findChild(QtWidgets.QLineEdit,
                              self.widget_dict["unit"]).setText(scalePrms.unit)
        self.dialog.findChild(
            QtWidgets.QCheckBox, self.widget_dict["auto_tick"]).setChecked(scalePrms.autoTick)
        self.dialog.findChild(
            QtWidgets.QComboBox, self.widget_dict["format"]).setCurrentIndex(scalePrms.format)
        self.dialog.findChild(QtWidgets.QSpinBox, self.widget_dict["prec"]).setValue(
            scalePrms.precision)
        self.dialog.findChild(QtWidgets.QCheckBox, self.widget_dict["log"]).setChecked(
            scalePrms.logScale)
        self.dialog.findChild(
            QtWidgets.QCheckBox, self.widget_dict["inversion"]).setChecked(scalePrms.inversion)

    ##########################################################
    def GetParams(self, scalePrms):
        """
        スケールパラメータ取得
        @param  scalePrms スケールパラメータクラスのインスタンス
        @retval True: OK   False: NG
        """
        logging.debug("ScaleTab::GetParams")
        # 画面からパラメータを取得
        auto = self.dialog.findChild(
            QtWidgets.QCheckBox, self.widget_dict["auto_range"]).isChecked()
        # 自動でなければ
        if not auto:
            r0 = self.dialog.findChild(
                QtWidgets.QLineEdit, self.widget_dict['min']).text()
            r1 = self.dialog.findChild(
                QtWidgets.QLineEdit, self.widget_dict['max']).text()
            # 数値変換並びに範囲チェック
            # if not self.vld.ValidateRange(r0, r1, self.scale + " Range", " Start value", "End value"):
            #    return False
        # データを格納
        scalePrms.autoRange = auto
        if not auto:
            scalePrms.range = (float(r0), float(r1))
        scalePrms.label = self.dialog.findChild(
            QtWidgets.QLineEdit, self.widget_dict['label']).text()
        scalePrms.unit = self.dialog.findChild(
            QtWidgets.QLineEdit, self.widget_dict['unit']).text()
        # scalePrms.grid = grid # [TI, 20160329] 不要では？
        scalePrms.autoTick = self.dialog.findChild(
            QtWidgets.QCheckBox, self.widget_dict['auto_tick']).isChecked()
        scalePrms.format = self.dialog.findChild(
            QtWidgets.QComboBox, self.widget_dict['format']).currentIndex()
        scalePrms.precision = self.dialog.findChild(
            QtWidgets.QSpinBox, self.widget_dict['prec']).value()
        scalePrms.logScale = self.dialog.findChild(
            QtWidgets.QCheckBox, self.widget_dict['log']).isChecked()
        scalePrms.inversion = self.dialog.findChild(
            QtWidgets.QCheckBox, self.widget_dict['inversion']).isChecked()
        return True


#########################################
#       RegionTable
#########################################
class RegionTable(QtWidgets.QTableWidget):
    """
    領域テーブルクラス
    """

    ##########################################################
    def __init__(self, parent, groups, ifi):
        """
        コンストラクタ
        @param  parent  (QObject)
        @param  groups  (string list) グループのリスト
        @param  ifi  (インスタンス) IFクラスのインスタンス
        @retval なし
        """
        super(RegionTable, self).__init__(parent)
        self.setObjectName("tableRegion")
        self.setGeometry(11, 221, 261, 339)
        self.setRowCount(0)
        self.setColumnCount(9)
        self.setColumnWidth(0, 20)
        self.setColumnWidth(1, 140)
        self.setColumnWidth(2, 80)

        self.groups = groups
        self.ifi = ifi
        self.regionData = []

        # ヘッダ設定。
        self.setHorizontalHeaderLabels(["", "Group", "Regions"])
        vh = self.verticalHeader()
        vh.sectionClicked.connect(self.OnLabelClick)
        # 領域データの公開プロパティを登録
        self.ifi.AddProperty('region_data', lambda: self.regionData)
        # セルクリックイベント登録
        self.cellClicked.connect(self.OnCellClick)

    ##########################################################
    def OnComboBox(self, index):
        """
        コンボボックス選択イベントハンドラ
        @param  index (int) Comboboxのindex
        @retval なし
        """
        # 領域再描画要求送信
        self.ifi.NotifyEvent(self, 'change_regions')

    ####################################################
    def OnLabelClick(self, index):
        """
        ラベルクリックイベントハンドラ。
        @param  index (int) 行index
        @retval なし
        """
        # 選択行変更メッセージ送信
        self.ifi.NotifyEvent(self, 'change_selected_row', index)

    ####################################################
    def OnCellClick(self, row, column):
        """
        セルクリックイベントハンドラ
        @param  evt (event) イベント
        @retval なし
        """
        num_rows = self.rowCount()
        # 最初の列がクリックされたか
        if column == 0:
            isChecked_table = self.cellWidget(row, 0).checkState()
            if isChecked_table == QtCore.Qt.Checked:
                isChecked_menu = True
            else:
                isChecked_menu = False
            # メニューのチェック状態変更要求
            self.ifi.NotifyEvent(self, 'change_state', (row, isChecked_menu))
            # 領域再描画要求送信
            self.ifi.NotifyEvent(self, 'change_regions')
        else:
            # 選択行変更メッセージ送信
            self.ifi.NotifyEvent(self, 'change_selected_row', row)
        self.setRangeSelected(QtWidgets.QTableWidgetSelectionRange(
            0, 0, num_rows - 1, 8), False)  # 全ての選択を外す
        self.setRangeSelected(QtWidgets.QTableWidgetSelectionRange(
            row, 0, row, 8), True)  # クリックした行を選択

    ####################################################
    def SetSelect(self, index, isShown):
        """
        チェックボックスのOn/Off
        @param  index インデックス -1の場合は全行
        @param  isShown (bool)
        @retval なし
        """
        if isShown:
            setV = QtCore.Qt.Checked
        else:
            setV = QtCore.Qt.Unchecked

        # 全行か
        if index < 0:
            num_rows = self.rowCount()
            for i in range(num_rows - 1):
                self.cellWidget(i, 0).setCheckState(setV)
        else:
            self.cellWidget(index, 0).setCheckState(setV)
        # 領域再描画要求送信
        self.ifi.NotifyEvent(self, 'change_regions')

    ####################################################
    def SetGroups(self, groups):
        """
        グリッドのプルダウンメニューに、グローブ名をセット
        @param  groups (list) グループ名とカラーのリスト
        @retval なし
        """
        attrChoice = gridlib.GridCellAttr()
        attrChoice.SetEditor(gridlib.GridCellChoiceEditor(choices=groups))
        attrChoice.SetRenderer(gridlib.GridCellEnumRenderer())
        self.SetColAttr(1, attrChoice)
        self.groups = groups

    ####################################################
    def AppendRegion(self, region, values, groupIndex):
        """
        指定行にデータをセットし、一行（空行）を追加
        @param  region (string) 領域名
        @param  values (string list) 領域の値
        @param  groupIndex (int) グループ指定
        @retval なし
        """
        num_rows = self.rowCount()  # RegionTableの行数
        row = num_rows  # 編集する行番号は行数と同じ
        self.insertRow(row)  # RegionTableの最後に一行追加
        # 追加行を選択状態とする
        self.selectRow(row)

        # 領域表示フラグを取得
        showFlag = self.ifi.GetProperty('show_all_flag')
        # 領域表示チェックボックスを1列目に設定
        flag_widget = QtWidgets.QCheckBox()
        if showFlag:
            flag_widget.setCheckState(QtCore.Qt.Checked)
        else:
            flag_widget.setCheckState(QtCore.Qt.Unchecked)
        flag_widget.stateChanged[int].connect(self.OnCheckbox)
        self.setCellWidget(row, 0, flag_widget)
        self.regionData.append(())
        # データを設定
        self.SetRegionPrms(row, region, values, groupIndex)

    ####################################################
    def SetRegionPrms(self, index, region, values, groupIndex):
        """
        指定行にデータをセット
        @param  index (int)   行インデックス
        @param  region (string) 領域名
        @param  values (string list) 領域の値
        @param  groupIndex (int) グループ指定
        @retval なし
        """
        self.regionData[index] = (region, values, groupIndex)
        # グループを設定
        grp_widget = QtWidgets.QComboBox()
        for g in self.groups:
            grp_widget.addItem(g)
        if len(self.groups) > groupIndex:
            grp_widget.setCurrentIndex(groupIndex)
        else:
            # 不正なgroupIndexの場合はgroupIndex = 0としておく。
            grp_widget.setCurrentIndex(0)
        grp_widget.currentIndexChanged.connect(self.OnComboBox)
        self.setCellWidget(index, 1, grp_widget)
        #
        reg_item = QtWidgets.QTableWidgetItem(region)
        reg_item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
        self.setItem(index, 2, reg_item)

        for i, value in enumerate(values):
            item_tx = QtWidgets.QTableWidgetItem(value)
            item_tx.setFlags(QtCore.Qt.ItemIsEnabled)
            self.setItem(index, i + 3, item_tx)

    ####################################################
    def RemoveRegion(self, index):
        """
        選択行の削除
        @param  index (int)
        @retval 無し
        """
        del self.regionData[index]
        # 選択行を削除
        self.removeRow(index)
        #
        num_rows = self.rowCount()
        if num_rows == 0:
            return
        if (num_rows - 1) >= index:
            row = index
        else:
            row = num_rows - 1
        self.setRangeSelected(
            QtWidgets.QTableWidgetSelectionRange(row, 0, row, 8), True)

    ####################################################
    def GetRowData(self, row):
        """
        指定された行のデータを取得
        @param  row  行インデックス
        @retval [チェックフラグ, 領域名、数値データのリスト]
        """
        print("{0}::{1}".format(self.__class__.__name__,
                                sys._getframe().f_code.co_name))
        # 領域名を取得
        rname = self.item(row, 2).text()
        # 数値データを取得
        values = [None for j in range(6)]
        for col in range(3, 9):
            txt = self.item(row, col).text()
            if txt != "":
                # values[col-3] = float(txt) # [TI, task] floatにcastする必要がないのでは？
                values[col - 3] = txt
        return (rname, values)

    ####################################################
    def GetValidRows(self):
        """
        有効な(表示がOn)のデータを取得
        @param  無し
        @retval 領域情報のリスト　[領域名、カラー、数値データのリスト, 選択フラグ]
        """
        # 現在選択されている行を取得　（必要？）
        current = self.currentRow()
        regions = []
        num_rows = self.rowCount()
        for i in range(num_rows):
            # 非表示指定行は無視
            if self.cellWidget(i, 0).checkState() == QtCore.Qt.Unchecked:
                continue
            # 領域名を取得
            name = self.item(i, 2).text()
            # 色コードを取得
            group = self.cellWidget(i, 1).currentText()
            color = group.split(':')[1]
            ccode = color[:1].lower()
            if color == "Black":
                ccode = 'k'
            elif color == "Purple":
                ccode = 'm'
            # 数値データを取得
            values = [None for j in range(6)]
            for col in range(3, 9):
                txt = self.item(i, col).text()
                if txt != "":
                    values[col - 3] = float(txt)
            if i == current:
                isSelected = True
            else:
                isSelected = False
            regions.append([name, ccode, values, isSelected])
        return regions

    #########################################
    def ToggleAllCheckBox(self, flag):
        """
        全ての表示／非表示チェックボックスをflagに変更する。
        """
        num_rows = self.rowCount()
        for i in range(num_rows):
            if flag:
                self.cellWidget(i, 0).setCheckState(QtCore.Qt.Checked)
            else:
                self.cellWidget(i, 0).setCheckState(QtCore.Qt.Unchecked)

    #########################################
    def OnCheckbox(self, isChecked):
        """
        Checkbox状態変更イベントハンドラー
        @param  isChecked (QCheckState) イベント
        @retval なし
        """
        if isChecked == QtCore.Qt.Checked:
            isChecked_menu = True
        else:
            isChecked_menu = False
        checkbox = self.sender()
        num_rows = self.rowCount()
        for i in range(num_rows):
            if self.cellWidget(i, 0) == checkbox:
                # メニューのチェック状態変更要求
                self.ifi.NotifyEvent(self, 'change_state', (i, isChecked_menu))
                # 領域再描画要求送信
                self.ifi.NotifyEvent(self, 'change_regions')
                return


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

    ##########################################################
    def __init__(self, parent, isY, cbFunc):
        """
        コンストラクタ
        @param  parent   親ウィンドウのクラスのインスタンス
        @param  isY (bool) 表示軸がXであるか
        @param  cbFunc コールバック関数
        @retval 無し
        """
        logging.debug("ParamDialog::__init__")
        super(ParamDialog, self).__init__(parent)
        self.ui = Ui_DlgViewPrms()
        if self.ui is None:
            return
        self.ui.setupUi(self)
        self.cb_grid_style_h = self.findChild(QtWidgets.QComboBox, 'cb_grid_style_h')
        self.cb_grid_style_v = self.findChild(QtWidgets.QComboBox, 'cb_grid_style_v')
        self.cb_grid_color_h = self.findChild(QtWidgets.QComboBox, 'cb_grid_color_h')
        self.cb_grid_color_v = self.findChild(QtWidgets.QComboBox, 'cb_grid_color_v')
        self.txt_grid_width_h = self.findChild(QtWidgets.QLineEdit, 'txt_grid_width_h')
        self.txt_grid_width_v = self.findChild(QtWidgets.QLineEdit, 'txt_grid_width_v')
        self.txt_h_interval = self.findChild(QtWidgets.QLineEdit, 'txt_h_interval')
        self.txt_v_interval = self.findChild(QtWidgets.QLineEdit, 'txt_v_interval')
        self.grp_grid_h = self.findChild(QtWidgets.QGroupBox, 'grp_grid_h')
        self.grp_grid_v = self.findChild(QtWidgets.QGroupBox, 'grp_grid_v')

        self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
        self.parent = parent  # [inamura 181112]
        # インターフェイスクラスのインスタンスを取得
        self.ifi = IFEvtProp(parent.order)

        self.cbFunc = cbFunc
        # バリデータ登録
        self.vld = Validator(self)
        self.org = False
        # スケールパネルを準備
        self.xscale = ScaleTab(self, {"label": "txt_x_label",
                                      "unit": "txt_x_unit",
                                      "auto_range": "check_x_auto_range",
                                      "log": "check_x_log",
                                      "inversion": "check_x_inv",
                                      "min": "txt_x_min",
                                      "max": "txt_x_max",
                                      "auto_tick": "check_x_auto_tick",
                                      "format": "combo_x_format",
                                      "prec": "spin_x_prec"},
                               "X scale")
        self.yscale = ScaleTab(self, {"label": "txt_y_label",
                                      "unit": "txt_y_unit",
                                      "auto_range": "check_y_auto_range",
                                      "log": "check_y_log",
                                      "inversion": "check_y_inv",
                                      "min": "txt_y_min",
                                      "max": "txt_y_max",
                                      "auto_tick": "check_y_auto_tick",
                                      "format": "combo_y_format",
                                      "prec": "spin_y_prec"},
                               "Y scale")
        # Grid線種ComboBoxへの追加
        _linestyles = ["Solid", "Dotted", "Dashed", "Dashdot"]
        for _ls in _linestyles:
            self.cb_grid_style_h.addItem(_ls)
            self.cb_grid_style_v.addItem(_ls)
        self.cb_grid_color_h.setCurrentIndex(1)
        self.cb_grid_color_v.setCurrentIndex(1)
        # Grid色ComboBoxへの追加
        for c in U2Params.grid_colors:
            self.cb_grid_color_h.addItem(c)
            self.cb_grid_color_v.addItem(c)
        self.cb_grid_color_h.setCurrentIndex(0)
        self.cb_grid_color_v.setCurrentIndex(0)

        # Grid width validator設定
        _width_validator = QtGui.QDoubleValidator()
        _width_validator.setBottom(0.0)
        self.txt_grid_width_h.setValidator(_width_validator)
        self.txt_grid_width_v.setValidator(_width_validator)

        # Grid interval validator設定
        _interval_validator = QtGui.QDoubleValidator()
        _interval_validator.setBottom(0.0)
        self.txt_h_interval.setValidator(_interval_validator)
        self.txt_h_interval.setValidator(_interval_validator)
        # Color Map形式ComboBoxへの追加
        cb_cmap = self.findChild(QtWidgets.QComboBox, "cb_cmap")
        for t in U2Params.cmap_types:
            cb_cmap.addItem(t)
        cb_cmap.setCurrentIndex(0)

        # Fontタブ設定
        _fs_validator = QtGui.QIntValidator()
        _fs_validator.setBottom(1)
        for _target in ['title', 'comment', 'x', 'y', 'xticks', 'yticks', 'cbticks']:
            self.findChild(QtWidgets.QLineEdit, 'txt_fs_{0}'.format(
                _target)).setValidator(_fs_validator)
            _cb = self.findChild(QtWidgets.QComboBox,
                                 'cb_ft_{0}'.format(_target))
            for _ft in U2Params.font_types:
                _cb.addItem(_ft)
            _cb.setCurrentIndex(0)

        # Detector Map Mode判定
        #if self.ifi.GetProperty("is_det_map_mode"):
        if parent.params.detectmapmode:
            self.findChild(QtWidgets.QCheckBox,
                           'check_bank_separator').setEnabled(True)
        else:
            parent.params.bankseparator = False

        # パラメータを取得し画面に設定
        self.SetParams()

        # ボタンのイベントハンドラ登録
        self.findChild(QtWidgets.QPushButton, 'btn_backToInitial').pressed.connect(
            self.OnBackToInitial)
        self.findChild(QtWidgets.QPushButton, 'btn_backToDefault').pressed.connect(
            self.OnBackToDefault)
        self.findChild(QtWidgets.QPushButton, 'btn_saveAsDefault').pressed.connect(
            self.OnSaveAsDefault)
        self.findChild(QtWidgets.QPushButton, 'btn_saveAsDefault_local').pressed.connect(
            self.OnSaveAsDefaultLocal)
        self.findChild(QtWidgets.QPushButton,
                       'btn_apply').pressed.connect(self.OnApply)
        self.findChild(QtWidgets.QPushButton,
                       "btn_close").pressed.connect(self.close)
        self.findChild(QtWidgets.QPushButton, "btn_winsize").pressed.connect(
            self.OnGetCurrentWinSize)  # [inamura 181112]

        # その他のイベントハンドラ登録
        self.findChild(QtWidgets.QCheckBox, 'check_trans').stateChanged.connect(
            self.OnChange)  # X軸Y軸転置
        self.txt_grid_width_h.editingFinished.connect(
            self.OnGridAttr)  # グリッド線幅変更
        self.txt_grid_width_v.editingFinished.connect(
            self.OnGridAttr)  # グリッド線幅変更
        self.cb_grid_color_h.currentIndexChanged.connect(
            self.OnGridAttr)  # グリッド線のカラー変更
        self.cb_grid_color_v.currentIndexChanged.connect(
            self.OnGridAttr)  # グリッド線のカラー変更
        self.cb_grid_style_h.currentIndexChanged.connect(
            self.OnGridAttr)  # グリッド線種変更
        self.cb_grid_style_v.currentIndexChanged.connect(
            self.OnGridAttr)  # グリッド線種変更
        self.txt_h_interval.editingFinished.connect(
            self.OnGridAttr)  # グリッド間隔変更
        self.txt_v_interval.editingFinished.connect(
            self.OnGridAttr)  # グリッド間隔変更
        self.grp_grid_h.toggled.connect(self.OnChange)  # 水平グリッド
        self.grp_grid_v.toggled.connect(self.OnChange)  # 垂直グリッド
        cb_cmap.currentIndexChanged.connect(self.OnChange)  # カラーマップ変更
        self.findChild(QtWidgets.QCheckBox, 'check_cmap_auto_range').stateChanged.connect(
            self.OnChange)  # 強度範囲自動
        self.findChild(QtWidgets.QCheckBox, 'check_cmap_log').stateChanged.connect(
            self.OnChange)  # ログスケール
        self.findChild(QtWidgets.QSlider, 'slider_cmap').valueChanged.connect(
            self.OnChange)  # スライダー
        self.findChild(QtWidgets.QCheckBox, 'check_bank_separator').stateChanged.connect(
            self.OnChange)  # バンクセパレータ
        self.findChild(QtWidgets.QCheckBox, 'check_smooth').stateChanged.connect(
            self.OnChange)  # スムージングチェック
        self.findChild(QtWidgets.QLineEdit, 'txt_smooth_window').textChanged.connect(
            self.OnChange)  # スムージングウィンドウ
        self.findChild(QtWidgets.QLineEdit, 'txt_smooth_times').textChanged.connect(
            self.OnChange)  # スムージングTimes
        self.findChild(QtWidgets.QCheckBox,
                       'ch_TF_MinorTicks').stateChanged.connect(self.OnChange)
        self.findChild(QtWidgets.QCheckBox,
                       'ch_TF_BottomSideTicks').stateChanged.connect(self.OnChange)
        self.findChild(QtWidgets.QCheckBox,
                       'ch_TF_LeftSideTicks').stateChanged.connect(self.OnChange)
        self.findChild(QtWidgets.QCheckBox,
                       'ch_TF_TopSideTicks').stateChanged.connect(self.OnChange)
        self.findChild(QtWidgets.QCheckBox,
                       'ch_TF_RightSideTicks').stateChanged.connect(self.OnChange)
        self.findChild(QtWidgets.QComboBox,
                       'cb_TF_MaskColor').currentIndexChanged.connect(self.OnChange)
        self.findChild(QtWidgets.QComboBox,
                       'cb_TF_BGColor').currentIndexChanged.connect(self.OnChange)
        self.findChild(QtWidgets.QComboBox,
                       'cb_TF_TicksColor').currentIndexChanged.connect(self.OnChange)

        self.rb_isAve = self.findChild(QtWidgets.QRadioButton, 'rb_isAveSlice')
        self.rb_isAve.toggled.connect(self.OnRadioButtonAS)
        self.rb_isSum = self.findChild(QtWidgets.QRadioButton, 'rb_isSumSlice')
        self.rb_isSum.toggled.connect(self.OnRadioButtonSS)
        #self.rb_isAve.setChecked(True)
        #self.rb_isSum.setChecked(False)
        # メッセージのリスナー登録
        self.id_change_params = self.ifi.AddListner(
            'change_params', self.SetParams)
        self.id_change_displayed_params = self.ifi.AddListner(
            'change_displayed_params', self.SetParams)
        for _target in ['title', 'comment', 'x', 'y', 'xticks', 'yticks', 'cbticks']:
            self.findChild(QtWidgets.QLineEdit, 'txt_fs_{0}'.format(
                _target)).editingFinished.connect(self.OnChange)
            self.findChild(QtWidgets.QComboBox, 'cb_ft_{0}'.format(
                _target)).currentIndexChanged.connect(self.OnChange)

        if isY:
            self.findChild(QtWidgets.QTabWidget,
                           "tabWidget").setCurrentIndex(1)

        self.xscale.ConnectSignals()
        self.yscale.ConnectSignals()

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

    ##########################################################
    def SetParams(self, *args):
        """
        パラメータを取得し画面に設定
        @param  無し
        @retval 無し
        """
        logging.debug("ParamDialog::SetParams")
        # 自分がだしたイベントか
        if self.org:
            self.org = False
            return
        # パラメータをメイン画面より取得
        # いくつかのGUIパーツの状態を変更すると、それに合わせてself.paramsも自動的に変更されるので
        # 一旦パラメータをコピーしてそれを使ってGUIに代入する
        self.params = self.ifi.GetProperty('params')
        params = U2Params()
        params.__dict__.update(self.params.__dict__)
        params.TickStyleDic = self.params.TickStyleDic.copy()

        # Window size and font setting must be placed at the begging of whole settings Y.I. 210312
        # Window Size Settings
        if params.window_size[0] is not None:
            self.findChild(QtWidgets.QLineEdit, 'txt_width').setText(
                "{:g}".format(params.window_size[0]))
        if params.window_size[1] is not None:
            self.findChild(QtWidgets.QLineEdit, 'txt_height').setText(
                "{:g}".format(params.window_size[1]))

        # Font settings
        for _target in ['title', 'comment', 'x', 'y', 'xticks', 'yticks', 'cbticks']:
            self.findChild(QtWidgets.QLineEdit, 'txt_fs_{0}'.format(_target)).setText(
                '{0:d}'.format(params.fontDict[_target][0]))
            self.findChild(QtWidgets.QComboBox, 'cb_ft_{0}'.format(_target)).setCurrentIndex(
                U2Params.font_types.index(self.params.fontDict[_target][1]))

        # General セクションを設定
        self.findChild(QtWidgets.QLineEdit, 'txt_title').setText(params.title)
        self.findChild(QtWidgets.QPlainTextEdit,
                       'txt_comment').setPlainText(params.comment)
        self.findChild(QtWidgets.QCheckBox, 'check_auto_update').setChecked(
            params.autoUpdate)
        self.findChild(QtWidgets.QCheckBox, 'check_trans').setChecked(
            params.transPosition)

        if params.slice_ave_mode:
            self.findChild(QtWidgets.QRadioButton, 'rb_isAveSlice').setChecked(True)
            self.findChild(QtWidgets.QRadioButton, 'rb_isSumSlice').setChecked(False)
        else:
            self.findChild(QtWidgets.QRadioButton, 'rb_isAveSlice').setChecked(False)
            self.findChild(QtWidgets.QRadioButton, 'rb_isSumSlice').setChecked(True)


        # Xスケールパネルに設定
        self.xscale.SetParams(params.xscale)
        # Yスケールパネルに設定
        self.yscale.SetParams(params.yscale)
        # グリッドセクションに設定
        self.cb_grid_color_h.setCurrentIndex(params.gridColorH)
        self.cb_grid_color_v.setCurrentIndex(params.gridColorV)
        self.txt_grid_width_h.setText(params.gridWidthH)
        self.txt_grid_width_v.setText(params.gridWidthV)
        self.cb_grid_style_h.setCurrentIndex(
            self.cb_grid_style_h.findText(params.gridStyleH))
        self.cb_grid_style_v.setCurrentIndex(
            self.cb_grid_style_v.findText(params.gridStyleV))
        self.grp_grid_h.setChecked(params.hgrid)
        self.grp_grid_v.setChecked(params.vgrid)
        stHI = ""
        if params.hgridInterval is not None:
            stHI = "%.3f" % params.hgridInterval
        self.txt_h_interval.setText(stHI)

        stVI = ""
        if params.vgridInterval is not None:
            stVI = "%.3f" % params.vgridInterval
        self.txt_v_interval.setText(stVI)
        # カラーマップセクションを設定
        self.findChild(QtWidgets.QComboBox,
                       'cb_cmap').setCurrentIndex(params.colorMap)
        self.findChild(QtWidgets.QCheckBox, 'check_cmap_auto_range').setChecked(
            params.autoRange)
        self.findChild(QtWidgets.QCheckBox,
                       'check_cmap_log').setChecked(params.logScale)
        self.findChild(QtWidgets.QSlider, 'slider_cmap').setValue(
            params.relRange)

        # Smoothing
        if params.smoothing[0]:
            self.findChild(QtWidgets.QCheckBox, 'check_smooth').setCheckState(
                QtCore.Qt.Checked)
        else:
            self.findChild(QtWidgets.QCheckBox, 'check_smooth').setCheckState(
                QtCore.Qt.Unchecked)
        self.findChild(QtWidgets.QLineEdit, 'txt_smooth_window').setText(
            "{0:3.1f}".format(params.smoothing[1]))
        self.findChild(QtWidgets.QLineEdit, 'txt_smooth_times').setText(
            "{0:d}".format(int(params.smoothing[2])))

        # self.params.bankseparator = False # [20180116, TI] TODO:ひとまずファイル記録なしで
        self.findChild(QtWidgets.QCheckBox, 'check_bank_separator').setChecked(
            params.bankseparator)
        if params.range is not None:
            stR0 = "%g" % params.range[0]
            stR1 = "%g" % params.range[1]
            self.findChild(QtWidgets.QLineEdit, 'txt_cmap_min').setText(stR0)
            self.findChild(QtWidgets.QLineEdit, 'txt_cmap_max').setText(stR1)
        self.OnGetCurrentWinSize()  # [inamura 181112]

        # Ticks and Frame settings
        _ColorDic = {"black": 0, "white": 1}
        self.findChild(QtWidgets.QComboBox, 'cb_TF_MaskColor').setCurrentIndex(
            _ColorDic[params.TickStyleDic["BadColor"]])
        self.findChild(QtWidgets.QComboBox, 'cb_TF_BGColor').setCurrentIndex(
            _ColorDic[params.TickStyleDic["BGColor"]])
        self.findChild(QtWidgets.QComboBox, 'cb_TF_TicksColor').setCurrentIndex(
            _ColorDic[params.TickStyleDic["TickColor"]])
        if params.TickStyleDic["Minor"]:
            flag = QtCore.Qt.Checked
        else:
            flag = QtCore.Qt.Unchecked
        self.findChild(QtWidgets.QCheckBox,
                       'ch_TF_MinorTicks').setCheckState(flag)

        if params.TickStyleDic["BottomSide"]:
            flag = QtCore.Qt.Checked
        else:
            flag = QtCore.Qt.Unchecked
        self.findChild(QtWidgets.QCheckBox,
                       'ch_TF_BottomSideTicks').setCheckState(flag)

        if params.TickStyleDic["LeftSide"]:
            flag = QtCore.Qt.Checked
        else:
            flag = QtCore.Qt.Unchecked
        self.findChild(QtWidgets.QCheckBox,
                       'ch_TF_LeftSideTicks').setCheckState(flag)
        if params.TickStyleDic["TopSide"]:
            flag = QtCore.Qt.Checked
        else:
            flag = QtCore.Qt.Unchecked
        self.findChild(QtWidgets.QCheckBox,
                       'ch_TF_TopSideTicks').setCheckState(flag)

        if params.TickStyleDic["RightSide"]:
            flag = QtCore.Qt.Checked
        else:
            flag = QtCore.Qt.Unchecked
        self.findChild(QtWidgets.QCheckBox,
                       'ch_TF_RightSideTicks').setCheckState(flag)

        self.findChild(QtWidgets.QLineEdit, 'txt_TF_MajorTicks_L').setText(
            "{0}".format(params.TickStyleDic["MajorLength"]))
        self.findChild(QtWidgets.QLineEdit, 'txt_TF_MinorTicks_L').setText(
            "{0}".format(params.TickStyleDic["MinorLength"]))
        self.findChild(QtWidgets.QLineEdit, 'txt_TF_MajorTicks_W').setText(
            "{0}".format(params.TickStyleDic["MajorWidth"]))
        self.findChild(QtWidgets.QLineEdit, 'txt_TF_MinorTicks_W').setText(
            "{0}".format(params.TickStyleDic["MinorWidth"]))
        self.findChild(QtWidgets.QLineEdit, 'txt_TF_FrameLine_W').setText(
            "{0}".format(params.TickStyleDic["FrameLineWidth"]))

        # 最後にGUIへ代入したパラメータを本物へコピーしておく
        self.params.__dict__.update(params.__dict__)
        self.params.TickStyleDic = params.TickStyleDic.copy()

    ##########################################################
    def GetParams(self):
        """
        画面よりパラメータを取得
        @param  無し
        @retval True: OK   False: NG
        """
        logging.debug("ParamDialog::GetParams")
        # 画面よりパラメータを取得
        self.params.title = self.findChild(
            QtWidgets.QLineEdit, 'txt_title').text()
        self.params.comment = self.findChild(
            QtWidgets.QPlainTextEdit, 'txt_comment').toPlainText()
        self.params.autoUpdate = self.findChild(
            QtWidgets.QCheckBox, 'check_auto_update').isChecked()
        self.params.transPosition = self.findChild(
            QtWidgets.QCheckBox, 'check_trans').isChecked()
        # Xスケールパラメータを取得
        if not self.xscale.GetParams(self.params.xscale):
            return False
        # Yスケールパラメータを取得
        if not self.yscale.GetParams(self.params.yscale):
            return False
        # グリッドパラメータを取得
        self.params.gridColorH = self.cb_grid_color_h.currentIndex()
        self.params.gridColorV = self.cb_grid_color_v.currentIndex()
        self.params.gridWidthH = self.txt_grid_width_h.text()
        self.params.gridWidthV = self.txt_grid_width_v.text()
        self.params.gridStyleH = self.cb_grid_style_h.currentText()
        self.params.gridStyleV = self.cb_grid_style_v.currentText()
        self.params.hgrid = self.grp_grid_h.isChecked()
        if self.params.hgrid:
            hi = self.txt_h_interval.text()
            if hi == "":
                self.params.hgridInterval = None
            else:
                # 数値変換ならびに範囲チェック
                if not self.vld.ValidatePlus(hi, "Interval"):
                    return False
                self.params.hgridInterval = float(hi)
        self.params.vgrid = self.grp_grid_v.isChecked()
        if self.params.vgrid:
            vi = self.txt_v_interval.text()
            if vi == "":
                self.params.vgridInterval = None
            else:
                # 数値変換並びに範囲チェック
                if not self.vld.ValidatePlus(vi, "Interval"):
                    return False
                self.params.vgridInterval = float(vi)
        # マップパラメータを取得
        self.params.colorMap = self.findChild(
            QtWidgets.QComboBox, 'cb_cmap').currentIndex()
        autoRange = self.findChild(
            QtWidgets.QCheckBox, 'check_cmap_auto_range').isChecked()
        self.params.logScale = self.findChild(
            QtWidgets.QCheckBox, 'check_cmap_log').isChecked()
        self.params.relRange = self.findChild(
            QtWidgets.QSlider, 'slider_cmap').value()
        # 自動レンジでなければ
        if not autoRange:
            r0 = self.findChild(QtWidgets.QLineEdit, 'txt_cmap_min').text()
            r1 = self.findChild(QtWidgets.QLineEdit, 'txt_cmap_max').text()
            # 数値変換並びに範囲チェック
            if not self.vld.ValidateRange(r0, r1, "Int. Range", "Start value", "End value"):
                return False
            self.params.range = (float(r0), float(r1))
        self.params.autoRange = autoRange
        self.params.bankseparator = self.findChild(
            QtWidgets.QCheckBox, 'check_bank_separator').isChecked()

        # Smoothing
        self.params.smoothing[0] = self.findChild(
            QtWidgets.QCheckBox, 'check_smooth').isChecked()
        _smooth_window = self.findChild(
            QtWidgets.QLineEdit, 'txt_smooth_window').text()
        if self.vld.ValidateRange("1.0", _smooth_window, "Smoothing window", "1.0", "The Smoothing window"):
            self.params.smoothing[1] = float(_smooth_window)
        else:
            return False
        _smooth_times = self.findChild(
            QtWidgets.QLineEdit, 'txt_smooth_times').text()
        if self.vld.ValidateRange("1.0", _smooth_times, "the number of times", "1.0", "The number of times "):
            self.params.smoothing[2] = float(_smooth_times)
        else:
            return False

        # Ticks and Frame settings
        if self.findChild(QtWidgets.QComboBox, 'cb_TF_MaskColor').currentIndex() == 0:
            self.params.TickStyleDic["BadColor"] = "black"
        else:
            self.params.TickStyleDic["BadColor"] = "white"
        if self.findChild(QtWidgets.QComboBox, 'cb_TF_BGColor').currentIndex() == 0:
            self.params.TickStyleDic["BGColor"] = "black"
        else:
            self.params.TickStyleDic["BGColor"] = "white"

        if self.findChild(QtWidgets.QComboBox, 'cb_TF_TicksColor').currentIndex() == 0:
            self.params.TickStyleDic["TickColor"] = "black"
        else:
            self.params.TickStyleDic["TickColor"] = "white"

        self.params.TickStyleDic["Minor"] = self.findChild(
            QtWidgets.QCheckBox, 'ch_TF_MinorTicks').isChecked()
        if self.findChild(QtWidgets.QCheckBox, 'ch_TF_BottomSideTicks').isChecked():
            self.params.TickStyleDic["BottomSide"] = True
        else:
            self.params.TickStyleDic["BottomSide"] = False
        if self.findChild(QtWidgets.QCheckBox, 'ch_TF_LeftSideTicks').isChecked():
            self.params.TickStyleDic["LeftSide"] = True
        else:
            self.params.TickStyleDic["LeftSide"] = False
        if self.findChild(QtWidgets.QCheckBox, 'ch_TF_TopSideTicks').isChecked():
            self.params.TickStyleDic["TopSide"] = True
        else:
            self.params.TickStyleDic["TopSide"] = False
        if self.findChild(QtWidgets.QCheckBox, 'ch_TF_RightSideTicks').isChecked():
            self.params.TickStyleDic["RightSide"] = True
        else:
            self.params.TickStyleDic["RightSide"] = False

        self.params.TickStyleDic["MajorLength"] = float(
            self.findChild(QtWidgets.QLineEdit, 'txt_TF_MajorTicks_L').text())
        self.params.TickStyleDic["MinorLength"] = float(
            self.findChild(QtWidgets.QLineEdit, 'txt_TF_MinorTicks_L').text())
        self.params.TickStyleDic["MajorWidth"] = float(
            self.findChild(QtWidgets.QLineEdit, 'txt_TF_MajorTicks_W').text())
        self.params.TickStyleDic["MinorWidth"] = float(
            self.findChild(QtWidgets.QLineEdit, 'txt_TF_MinorTicks_W').text())
        self.params.TickStyleDic["FrameLineWidth"] = float(
            self.findChild(QtWidgets.QLineEdit, 'txt_TF_FrameLine_W').text())

        # Font settings
        for _target in ['title', 'comment', 'x', 'y', 'xticks', 'yticks', 'cbticks']:
            self.params.fontDict[_target][0] = int(
                self.findChild(QtWidgets.QLineEdit, 'txt_fs_{0}'.format(_target)).text())
            self.params.fontDict[_target][1] = self.findChild(QtWidgets.QComboBox,
                                                              'cb_ft_{0}'.format(_target)).currentText()

        # ウィンドウサイズ指定
        w = self.findChild(QtWidgets.QLineEdit, 'txt_width').text()
        if w == "":
            self.params.window_size[0] = None
        elif self.vld.ValidateInteger(w, "Window width", minV=0, maxV=None):
            self.params.window_size[0] = int(w)
        else:
            self.params.window_size[0] = None
            self.findChild(QtWidgets.QLineEdit, 'txt_width').setText("")
        h = self.findChild(QtWidgets.QLineEdit, 'txt_height').text()
        if h == "":
            self.params.window_size[1] = None
        elif self.vld.ValidateInteger(h, "Window height", minV=0, maxV=None):
            self.params.window_size[1] = int(h)
        else:
            self.params.window_size[1] = None
            self.findChild(QtWidgets.QLineEdit, 'txt_height').setText("")
        # パラメータOK
        return True

    #########################################
    def OnGridAttr(self):
        """
        グリッド線属性指定ボックスイベントハンドラ
        @retval 無し
        """
        logging.debug("ParamDialog::OnGridAttr")
        # どちらかのグリッドが指定されているか
        if self.grp_grid_v.isChecked() or self.grp_grid_h.isChecked():
            self.OnChange()

    ##########################################################
    def OnBackToInitial(self):
        """
        起動時のパラメータに戻す
        """
        logging.debug("ParamDialog::OnBackToInitial")
        # 起動時のパラメータ読み込み要求
        params = self.ifi.GetProperty('params')
        xlabel = params.xscale.label
        xunit = params.xscale.unit
        ylabel = params.yscale.label
        yunit = params.yscale.unit
        if self.parent.initial_viewParams_xLabel != "":
            xlabel = self.parent.initial_viewParams_xLabel
        if self.parent.initial_viewParams_yLabel != "":
            ylabel = self.parent.initial_viewParams_yLabel
        init_params = U2Params()
        params.__dict__.update(init_params.__dict__)
        params.TickStyleDic = init_params.TickStyleDic.copy()
        params.xscale.label = xlabel
        params.xscale.unit = xunit
        params.yscale.label = ylabel
        params.yscale.unit = yunit
        params.title = self.parent.initial_viewParams_Title
        params.comment = self.parent.initial_viewParams_Comment
        # print(repr(params))

        # パラメータ再表示
        self.SetParams()
        self.ifi.NotifyEvent(self, 'change_params')

    ##########################################################
    def OnBackToDefault(self):
        """
        起動時のパラメータに戻す
        """
        logging.debug("ParamDialog::OnBackToDefault")
        # 起動時のパラメータ読み込み要求
        self.ifi.NotifyEvent(self, 'init_params')
        # パラメータ再表示
        self.SetParams()
        self.ifi.NotifyEvent(self, 'change_params')

    ##########################################################
    def OnSaveAsDefault(self):
        """
        パラメータを初期値として保存する
        """
        logging.debug("ParamDialog::OnSaveAsDefault")
        # パラメータ保存要求
        self.ifi.NotifyEvent(self, 'save_as_init_params')

    ##########################################################
    def OnSaveAsDefaultLocal(self):
        """
        パラメータを初期値として保存する（カレントフォルダに）
        """
        logging.debug("ParamDialog::OnSaveAsDefaultLocal")
        # パラメータ保存要求
        self.ifi.NotifyEvent(self, 'save_as_local_init_params')

    ##########################################################
    def OnApply(self, *args):
        """
        パラメータ適用処理
        @param  evt イベント情報
        @retval 無し
        """
        logging.debug("ParamDialog::OnApply")
        # 画面よりパラメータを取得
        if self.GetParams():
            self.org = True
            # パラメータ変更通知
            self.ifi.NotifyEvent(self, 'change_params')

    ##########################################################
    def OnChange(self, *args):
        """
        パラメータ変更イベント処理
        @param  evt イベント情報
        @retval 無し
        """
        logging.debug("ParamDialog::OnChange")
        # Auto Update が指定されているか
        if self.findChild(QtWidgets.QCheckBox, "check_auto_update").isChecked():
            # 変更を有効にする
            self.OnApply()

    ##########################################################
    def OnGetCurrentWinSize(self, *args):
        """
        [inamura 181112]
        """
        self.parent.GetWindowSizeParams()
        if self.params.window_size[0] is not None and self.params.window_size[1] is not None:
            self.findChild(QtWidgets.QLineEdit, 'txt_width').setText(
                "%d" % (self.params.window_size[0]))
            self.findChild(QtWidgets.QLineEdit, 'txt_height').setText(
                "%d" % (self.params.window_size[1]))

    ##########################################################
    def OnRadioButtonAS(self, *args):
        """
        [inamura 190226]
        """
        self.rb_isSum.setChecked(not self.rb_isAve.isChecked())
        self.params.slice_ave_mode = bool(self.rb_isAve.isChecked())
        self.OnApply()

    ##########################################################
    def OnRadioButtonSS(self, *args):
        """
        [inamura 190226]
        """
        self.rb_isAve.setChecked(not self.rb_isSum.isChecked())
        self.params.slice_ave_mode = bool(self.rb_isAve.isChecked())
        self.OnApply()

    ##########################################################
    def closeEvent(self, event):
        """
        ダイアログクローズイベント処理
        closeEventのOverride
        @retval 無し
        """
        logging.debug("ParamDialog::closeEvent")
        # 画面よりパラメータを取得
        if self.GetParams():
            # リスナー登録を削除
            for _idx, l in enumerate(self.ifi.listner):
                if l[0] == 'change_params' and 'ParamDialog.SetParams' in l[1].__repr__():
                    self.ifi.DelListner(_idx)
            for _idx, l in enumerate(self.ifi.listner):
                if l[0] == 'change_displayed_params':
                    self.ifi.DelListner(_idx)
            # コールバック関数を実行
            self.cbFunc(*(True,))
        event.accept()

    ##########################################################
    def keyPressEvent(self, event):
        """
        ダイアログクローズイベント処理
        keyPressEventのOverride
        Parameters:
            event (QtWidgets.QKeyEvent)
        """
        if event.key() == QtCore.Qt.Key_Escape:
            self.close()


REG_TABS = ['tabRectangle', 'tabLine', 'tabPoint',
            'tabCircle', 'tabRing', 'tabSector', 'tabRingSector']


#########################################
#       RegionTab
#########################################
class RegionTab(object):
    """
    領域パラメータ設定タブ操作クラス
    """

    ##########################################################
    def __init__(self, parent, tab):
        """
        コンストラクタ
        @param  parent     親クラスのインスタンス
        @param  tab        一枚のタブ
        @retval 無し
        """
        self.vld = parent.vld  # バリデータ
        self.tab = tab

    #########################################
    def GetRegionName(self):
        """
        領域名(ラジオボタンのラベル)取得
        @param  無し
        @retval 領域名
        """
        return self.tab.property("tabName")

    #########################################
    def ClearTxBoxes(self):
        """
        テキストボックスをクリアする
        @param  無し
        @retval 無し
        """
        # パネル上のテキストボックスを全クリア
        if PYSIDEVER != 6:
            reg = QtCore.QRegExp("*tx?", syntax=QtCore.QRegExp.Wildcard)
        else:
            # reg = QtCore.QRegularExpression.wildcardToRegularExpression("*tx?")
            reg = QtCore.QRegularExpression.fromWildcard("*tx?")
        for tx in self.tab.findChildren(QtWidgets.QLineEdit, reg):
            tx.setText("")

    #########################################
    def SetValues(self, values):
        """
        テキストボックスに値を設定する
        @param  values  領域TableViewから得られた値のリスト
        @retval 無し
        """
        for i, v in enumerate(values):
            if PYSIDEVER != 6:
                reg = QtCore.QRegExp(
                    "*tx{0:d}".format(i), syntax=QtCore.QRegExp.Wildcard)
            else:
                # reg = QtCore.QRegularExpression.wildcardToRegularExpression("*tx{0:d}".format(i))
                reg = QtCore.QRegularExpression.fromWildcard(
                    "*tx{0:d}".format(i))
            children = self.tab.findChildren(QtWidgets.QLineEdit, reg)
            if len(children) != 0:
                try:
                    children[0].setText(v)
                except TypeError:
                    children[0].setText("{0:.5g}".format(v))


#########################################
#       RegionDialog
#########################################
class RegionDialog(QtWidgets.QDialog):
    """
    領域ダイアログクラス
    """

    ##########################################################
    def __init__(self, parent, cbFunc):
        """
        コンストラクタ
        @param  parent   親ウィンドウのクラスのインスタンス
        @param  cbFunc コールバック関数
        @retval 無し
        """
        super(RegionDialog, self).__init__(parent)
        self.ui = Ui_DlgRegion()
        if self.ui is None:
            return
        self.ui.setupUi(self)
        # self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
        # インターフェイスクラスのインスタンスを取得
        self.ifi = IFEvtProp(parent.order)
        self.cbFunc = cbFunc

        # ボタンのイベントハンドラ登録
        self.findChild(QtWidgets.QPushButton,
                       'btnAdd').pressed.connect(self.OnAdd)
        self.findChild(QtWidgets.QPushButton,
                       'btnDelete').pressed.connect(self.OnDelete)
        self.findChild(QtWidgets.QPushButton,
                       'btnClose').pressed.connect(self.close)
        # バリデータ登録
        self.vld = Validator(self)

        # 領域タブクラス作成
        self.regTabs = []  # タブクラスリスト
        self.tabs = self.findChild(QtWidgets.QTabWidget)
        for tabName in REG_TABS:
            tab = self.findChild(QtWidgets.QWidget, tabName)
            regTab = RegionTab(self, tab)
            self.regTabs.append(regTab)
        # 矩形のタブにフォーカスにする
        self.findChild(QtWidgets.QTabWidget).setCurrentIndex(2)

        # パラメータをメイン画面より取得
        self.params = self.ifi.GetProperty('params')
        # 領域テーブルを作成
        groups = self._GetGroups()
        self.regTable = RegionTable(self, groups, self.ifi)
        # 領域変更メッセージのリスナー登録
        self.ifi.AddListner('change_regions', self.OnNotifyChangeRegions)
        # 領域選択メッセージのリスナー登録
        self.ifi.AddListner('change_selected_row', self.OnNotifyChangeSelected)
        # 領域変更メッセージのリスナー登録
        self.ifi.AddListner('select_region', self.OnNotifySelectRegion)
        # 他アプリからの領域変更メッセージのリスナー登録
        self.ifi.AddListner('add_region_from_other',
                            self.OnNotifyAddRegionFromOther)
        # 領域パラメータ変更メッセージのリスナー登録
        self.ifi.AddListner('change_region_prms',
                            self.OnNotifyChangeRegionPrms)
        # 領域ダイアログからの領域追加メッセージのリスナー登録
        self.ifi.AddListner('add_region_from_dlg',
                            self.OnNotifyAddRegionFromDlg)

        self.tableGroup = GroupTable(
            self, self.params.groups, self.params.colors, self.ifi)
        vl = self.findChild(QtWidgets.QVBoxLayout, "vLayout_group")
        vl.insertWidget(0, self.tableGroup)
        # Debug時はHiddenしない。
        hidden = True
        for i in range(3, 9):
            self.regTable.setColumnHidden(i, hidden)

    ##########################################################
    def GetSelectedRegion(self):
        """
        選択されている領域名を返す
        @param  無し
        @retval
        """
        return self.GetCurrentTabName()

    #########################################
    def ShowRegion(self, index, isShown):
        """
        TableWidgetチェック変更
        @param  index (int) 行のindex
        @param  isShown (bool)
        @retval 無し
        """
        self.regTable.SetSelect(index, isShown)

    ##########################################################
    def _GetGroups(self):
        """
        グループ名とカラーのリストを作る
        @param  無し
        @retval グループ名とカラーのリスト
        """
        gcolors = []
        for i, group in enumerate(self.params.groups):
            color = U2Params.REG_COLORS[i]
            gcolor = group + ":" + color
            gcolors.append(gcolor)

        return gcolors

    ##########################################################
    def OnAdd(self):
        """
        領域追加処理
        @param  無し
        @retval 無し
        """
        # self.show()
        regName = self.GetCurrentTabName()
        widget = self.tabs.currentWidget()
        values = ["" for i in range(6)]
        for i in range(6):
            if PYSIDEVER != 6:
                reg = QtCore.QRegExp("*tx%d" %
                                     i, syntax=QtCore.QRegExp.Wildcard)
            else:
                # reg = QtCore.QRegularExpression.wildcardToRegularExpression("*tx{0:d}".format(i))
                reg = QtCore.QRegularExpression.fromWildcard(
                    "*tx{0:d}".format(i))
            children = widget.findChildren(QtWidgets.QLineEdit, reg)
            if len(children) != 0:
                values[i] = children[0].text()
        self._AddRegion(regName, values, 0)

    ##########################################################
    def _AddRegion(self, regName, values, groupIndex):
        """
        領域追加処理
        @param  regName (string) 領域名称
        @param  values (tpl) パラメータ
        @retval 無し
        """
        # グリッドに追加
        self.regTable.AppendRegion(regName, values, groupIndex)
        item_label = "{0:d}:{1:s}".format(self.regTable.rowCount(), regName)
        # 領域追加メッセージ送信
        self.ifi.NotifyEvent(self, 'add_region', item_label)
        # 領域変更処理
        self.OnNotifyChangeRegions()

    ##########################################################
    def OnNotifyChangeRegions(self, *args):
        """
        領域変更処理
        @param  無し
        @retval 無し
        """
        # グリッドより、表示が指定されている行のデータを取得
        regions = self.regTable.GetValidRows()
        # 領域再描画要求送信
        self.ifi.NotifyEvent(self, 'redraw_regions', regions)

    ##########################################################
    def OnNotifySelectRegion(self, eventSrc, evtType, regName):
        """
        領域タブを領域タイプに変更
        @param eventSrc   イベント発生元インスタンス
        @param  evtType (str) 発生したイベントのタイプ
        @param  regName (string) 領域名（元はintだったのをstrに変更）
        @retval 無し
        """
        # 領域パネルを探索
        for regTab in self.regTabs:
            # 先の値をクリア
            if regTab.GetRegionName() == regName:
                # 当該パネルを選択状態とする
                self.tabs.setCurrentWidget(regTab.tab)
                break

    ##########################################################
    def OnNotifyChangeSelected(self, eventSrc, evtType, row):
        """
        選択領域変更処理
        @param eventSrc   イベント発生元インスタンス
        @param  evtType (str) 発生したイベントのタイプ
        @param  row (int)  変更のあった行
        @retval 無し
        """
        self.findChild(QtWidgets.QTableWidget,
                       "tableRegion").selectRow(row)  # 必要？
        # グリッドより、選択行のデータを取得
        rname, values = self.regTable.GetRowData(row)
        # 領域パネルを探索
        for regTab in self.regTabs:
            # 先の値をクリア
            regTab.ClearTxBoxes()
            if regTab.GetRegionName() == rname:
                # 選択されたパネルに値を設定
                regTab.SetValues(values)
                # 当該パネルを選択状態とする
                self.tabs.setCurrentWidget(regTab.tab)
                break

        # 領域変更処理
        self.OnNotifyChangeRegions()

    ##########################################################
    def OnNotifyAddRegionFromDlg(self, eventSrc, evtType, data=None):
        """
        領域追加処理
        @param eventSrc   イベント発生元インスタンス
        @param  evtType (str) 発生したイベントのタイプ
        @param  data (None)
        @retval 無し
        """
        self.OnAdd()

    ##########################################################
    def OnNotifyAddRegionFromOther(self, eventSrc, evtType, data):
        """
        他アプリからの領域追加処理
        @param eventSrc   イベント発生元インスタンス
        @param  evtType (str) 発生したイベントのタイプ
        @param  data (regName, (values), groupIndex)  変更のあった行
        @retval 無し
        """
        regName, values, groupIndex = data
        self._AddRegion(regName, values, groupIndex)

    ##########################################################
    def OnNotifyDelRegionFromOther(self, wid, evtype, index):
        """
        他アプリからの領域削除処理
        @param wid   ウィンドウID
        @param  evt  イベント
        @param  index (int)  行インデックス
        @retval 無し
        """
        # 指定行を削除
        self._DeleteRegion(index)

    ##########################################################
    def OnNotifyChangeRegionPrms(self, wid, evtype, data):
        """
        他アプリからの領域変更処理
        @param wid   ウィンドウID
        @param  evt  イベント
        @param  data (regName, (values), groupIndex)  変更のあった行
        @retval 無し
        """
        index, regName, values, groupIndex = data
        # データを設定
        self.regTable.SetRegionPrms(index, regName, values, groupIndex)
        # 再描画
        self.OnNotifyChangeRegions()

    ##########################################################
    def OnDelete(self):
        """
        領域削除ボタンイベントハンドラ
        @param 無し
        @retval 無し
        """
        # 選択行を取得
        selectedRanges = self.regTable.selectedRanges()
        try:
            if len(selectedRanges) != 0:
                # 1行しか選択されていないはずだが、念のため最上段をとる処理　
                for i, r in enumerate(selectedRanges):
                    if i == 0:
                        index = r.topRow()
                    else:
                        if r.topRow() < index:
                            index = r.topRow()
                # 選択行を削除
                self._DeleteRegion(index)
            else:
                raise PlotException('UGAO', 'U000', ())
        except PlotException as ex:
            PlotMessage(self.dg, ex)

    ##########################################################
    def _DeleteRegion(self, index):
        """
        領域削除処理
        @param  index (int) 行インデックス
        @retval 無し
        """
        # 選択行を削除
        self.regTable.RemoveRegion(index)
        # 領域削除メッセージ送信
        self.ifi.NotifyEvent(self, 'del_region', index)
        # 領域変更処理
        self.OnNotifyChangeRegions()

    ##########################################################
    def SetValues(self, values):
        """
        領域データを、選択されているパネルに設定
        @param  values 領域データ
        @retval 無し
        """
        # 選択されている領域に値を設定
        widget = self.tabs.currentWidget()
        for tab in self.regTabs:
            if tab.tab == widget:
                tab.SetValues(values)
                return

    ##########################################################
    def GetCurrentTabName(self):
        """
        現在選択されているタブの名前を返す。
        @param 無し
        @retval 無し
        """
        tab_index = self.tabs.currentIndex()  # 選択タブのindexを得て、
        return self.tabs.tabText(tab_index)  # そのindexのタブの名前を得る。

    ##########################################################
    def closeEvent(self, *args):
        """
        ダイアログクローズイベント処理
        closeEventのOverride
        @retval 無し
        """
        # コールバック関数を実行
        self.cbFunc()

    ##########################################################
    def keyPressEvent(self, event):
        """
        ダイアログクローズイベント処理
        keyPressEventのOverride
        Parameters:
            event (QtWidgets.QKeyEvent)
        """
        if event.key() == QtCore.Qt.Key_Escape:
            self.close()


#########################################
#       GroupTable
#########################################
class GroupTable(QtWidgets.QTableWidget):
    """
    グループテーブルクラス
    """

    ##########################################################
    def __init__(self, dlg, groups, colors, ifi):
        """
        コンストラクタ
        @param  dlg   親ウィンドウdialog
        @param  groups (string list) グループ名
        @param  colors (string list) グループカラー
        @param  ifi  (インスタンス) IFクラスのインスタンス
        @retval 無し
        """
        super(GroupTable, self).__init__()
        self.setObjectName("tableGroup")
        self.setRowCount(0)
        self.setColumnCount(2)
        self.dlg = dlg
        self.ifi = ifi
        self.groups = groups
        self.colors = colors

        # ヘッダ設定。
        self.setHorizontalHeaderLabels(["Group", "Color"])
        # グループがあれば
        if len(groups) > 0:
            for i in range(len(groups)):
                num_rows = self.rowCount()
                self.insertRow(num_rows)
                item_grp = QtWidgets.QTableWidgetItem(groups[i])
                self.setItem(i, 0, item_grp)
                grp_widget = QtWidgets.QComboBox()
                for g in U2Params.REG_COLORS:
                    grp_widget.addItem(g)
                grp_widget.setCurrentIndex(colors[i])
                grp_widget.currentIndexChanged.connect(self.OnColorChanged)
                self.setCellWidget(i, 1, grp_widget)
        # ボタンのイベントハンドラ登録
        self.dlg.findChild(QtWidgets.QPushButton,
                           'btnAddGrp').pressed.connect(self.OnAdd)
        self.dlg.findChild(QtWidgets.QPushButton,
                           'btnDeleteGrp').pressed.connect(self.OnDelete)

        # バリデータ登録
        self.vld = Validator(self.parent())

        self.cellChanged.connect(self.OnGroupChanged)

    ##########################################################
    def OnAdd(self):
        """
        グループ追加処理
        @param  無し
        @retval 無し
        """
        num_rows = self.rowCount()  # 既存のグループ数
        gname = "group{0:d}".format(num_rows + 1)  # グループ名を行番号から作成
        # 未使用のcolor_indexのうち最小を採用。全て使用されているなら0
        for color_index in range(len(U2Params.REG_COLORS)):
            if color_index not in self.colors:
                break
        else:
            color_index = 0
        # 整合性チェック
        if not self.vld.ValidateString(gname, "Group Name", 1, 10):
            return

        # グループ名重複チェック
        if self.CheckDuplicate(gname):
            # リストに1行追加
            self.insertRow(num_rows)
            grp_widget = QtWidgets.QComboBox()
            for g in U2Params.REG_COLORS:
                grp_widget.addItem(g)
            grp_widget.setCurrentIndex(color_index)
            grp_widget.currentIndexChanged.connect(self.OnColorChanged)
            self.setCellWidget(num_rows, 1, grp_widget)
            item_grp = QtWidgets.QTableWidgetItem(gname)
            self.setItem(num_rows, 0, item_grp)

            self.groups.append(gname)
            self.colors.append(color_index)

    ##########################################################
    def CheckDuplicate(self, gname, index=-1):
        """
        グループ名重複チェック
        @param  gname グループ名
        @param  index チェックを除外するグループのインデックス
        @retval True: OK, False: NG
        """
        # リストの行数を取得
        num_rows = self.rowCount()
        try:
            for i in range(num_rows):
                if i == index:
                    continue
                if gname == self.item(i, 0).text():
                    raise PlotException('Common', 'C042', (gname,))
        except PlotException as ex:
            PlotMessage(self.parent(), ex)
            return False
        return True

    ##########################################################
    def OnDelete(self):
        """
        グループ削除処理
        @param  無し
        @retval 無し
        """
        # 選択されている行を取得
        row = self.currentRow()
        # 選択されていなければ
        if row < 0:
            return

        # 選択行を削除
        self.removeRow(row)
        self.groups.pop(row)
        self.colors.pop(row)

    ##########################################################
    def OnGroupChanged(self, row, column):
        """
        グループ編集イベントハンドラ
        @param  無し
        @retval 無し
        """
        if len(self.dlg.regTable.groups) <= row:
            color_new = self.cellWidget(row, 1).currentText()
            grp_new = "{0}:{1}".format(
                self.item(row, column).text(), color_new)
            self.dlg.regTable.groups.append(grp_new)
            for i in range(self.dlg.regTable.rowCount()):
                w = self.dlg.regTable.cellWidget(i, 1)
                w.addItem(grp_new)
        else:
            grp_old = self.dlg.regTable.groups[row]
            name_old, color_old = grp_old.split(":")
            grp_new = "{0}:{1}".format(
                self.item(row, column).text(), color_old)
            self.dlg.regTable.groups[row] = grp_new
            for i in range(self.dlg.regTable.rowCount()):
                w = self.dlg.regTable.cellWidget(i, 1)
                w.setItemText(row, grp_new)
            self.groups[row] = self.item(row, column).text()

    ##########################################################
    def OnColorChanged(self, index):
        """
        色変更イベントハンドラ
        @param  index (int) ComboBoxのindex
        @retval 無し
        """
        cb = self.sender()
        row = -1
        for i in range(self.rowCount()):
            if self.cellWidget(i, 1) == cb:
                row = i
                break
        grp_old = self.dlg.regTable.groups[row]
        name_old, color_old = grp_old.split(":")
        grp_new = "{0}:{1}".format(name_old, cb.currentText())
        self.dlg.regTable.groups[row] = grp_new
        for i in range(self.dlg.regTable.rowCount()):
            w = self.dlg.regTable.cellWidget(i, 1)
            w.setItemText(row, grp_new)
        self.colors[row] = cb.currentIndex()
        self.ifi.NotifyEvent(self, 'change_regions')


#############################################
# PlotTrace:
#############################################
class PlotTrace(object):
    """
    オーバープロットデータ
    """

    ####################################################
    def __init__(self, xdata, ydata, xlabel="", ylabel="", color="#ffffff", draw=True, linewidth=1.0, edata=None):
        """
        コンストラクタ
        @param  (array) xdata
        @param  (array) ydata
        @param  (string) xlabel xデータのラベル
        @param  (string) ylabel yデータのラベル
        @param  (string) color カラーコード
        @param  (bool) draw 描画フラグ
        @retval 無し
        """
        self.xdata = xdata
        self.ydata = ydata
        self.edata = edata
        self.xlabel = xlabel
        self.ylabel = ylabel
        self.color = color
        self.draw = draw
        self.linewidth = linewidth
        self.linestyle = "solid"
        self.marker = ""
        self.markerface = "none"
        self.markersize = 5.0
        self.errorbar = False
        if edata is not None:
            self.errorbar = True

    ####################################################
    def SetColorCode(self, color):
        """
        カラーコード設定
        @param  (string) color カラーコード
        @retval 無し
        """
        self.color = color

    ####################################################
    def SetDrawFlag(self, draw):
        """
        描画フラグ設定
        @param  (bool) draw 描画フラグ
        @retval 無し
        """
        self.draw = draw

    ####################################################
    def SetLineWidth(self, lw=1.0):
        """
        Line Width setting
        @param  (float) lw Line Width
        @retval 無し
        """
        self.linewidth = lw

    ####################################################
    def SetLineStyle(self, ls="solid"):
        """
        Line Style setting
        @param  (str) ls Line Style
        @retval 無し
        """
        self.linestyle = ls

    ####################################################
    def SetMarkerParam(self, marker="o", markerface="none", markersize=5.0):
        """
        Maker settings
        @param  (str) marker : 'none', '.','o','s','v','d','+','x'
        @param  (str) markerface : 'none', 'fill'
        @param  (float) markersize
        @retval 無し
        """
        if marker in ['none', '.', 'o', 's', 'v', 'd', '+', 'x']:
            if marker == 'none':
                marker = ''
            self.marker = marker
        if markerface in ['fill', 'none']:
            if markerface == 'fill':
                self.markerface = self.color
            else:
                self.markerface = 'none'
        if markersize > 0.0:
            self.markersize = markersize
        else:
            self.marker = ''

    ####################################################
    def SetErrorBarOn(self, flag):
        """
        Error Bar setting
        @param  (bool) flag : show error bars or not.
        @retval 無し
        """
        if flag in [True, False]:
            self.errorbar = flag


#############################################
# GridOverPlot:
#############################################
class GridOverPlot(QtWidgets.QTableWidget):
    """
    オーバープロットのグリッド
    """

    ####################################################
    def __init__(self, parent, func):
        """
        コンストラクタ
        @param  (cont) panel グリッドを作るパネル
        @param  (func) func 再描画関数
        @retval 無し
        """
        self.parent = parent
        self.func = func

        # 空のグリッド作成
        super(GridOverPlot, self).__init__(parent)
        self.setRowCount(0)
        self.setColumnCount(11)

        hheader = QtWidgets.QHeaderView(QtCore.Qt.Orientation.Horizontal)
        self.setHorizontalHeader(hheader)
        self.setHorizontalHeaderLabels(
            ['Disp', 'File Name', 'Color', 'Style', 'LW', 'Marker', 'Size', 'Err', 'R', 'B', 'G'])
        self.resize(470, 300)
        self.move(10, 10)
        self.setColumnWidth(0, 35)  # Disp checkbox
        self.setColumnWidth(1, 200)  # File name
        self.setColumnWidth(2, 75)  # Line Color Combo box
        self.setColumnWidth(3, 75)  # Line Style Combo box
        self.setColumnWidth(4, 30)  # Line Width
        self.setColumnWidth(5, 75)  # Marker Combo box
        self.setColumnWidth(6, 40)  # Marker Size
        self.setColumnWidth(7, 35)  # Error bar checkbox
        self.setColumnWidth(8, 30)  # R code
        self.setColumnWidth(9, 30)  # B code
        self.setColumnWidth(10, 30)  # G code
        for i in range(8):
            if QtCore.__version__ < '5.0.0':
                self.horizontalHeader().setResizeMode(i, QtWidgets.QHeaderView.Fixed)
            else:
                self.horizontalHeader().setSectionResizeMode(i, QtWidgets.QHeaderView.Fixed)

        self.colors = ['white', 'black', 'blue',
                       'yellow', 'red', 'green', 'magenta', 'cyan']
        self.colorCodes = ['ffffff', '000000', '0000ff', 'ffff00', 'ff0000',
                           '008000', 'ff00ff', '00ffff']
        self.linestyles = ["Line", "Dotted", "Dashed", "Dot-dashed", "None"]
        self.linestylesdict = {"Line": "solid", "Dotted": "dotted",
                               "Dashed": "dashed", "Dot-dashed": "dashdot", "None": ''}

        self.markers = ['None', 'circle', 'point', 'square', 'triangle',
                        'diamond', 'plus', 'x', 'cir-fil', 'sq-fil', 'tri-fil', 'dia-fil']
        self.markersdict = {'None': ('none', 'none'), 'circle': ('o', 'none'), 'point': ('.', 'none'), 'square': ('s', 'none'), 'triangle': ('^', 'none'), 'diamond': (
            'D', 'none'), 'plus': ('+', 'none'), 'x': ('x', 'none'), 'cir-fil': ('o', 'fill'), 'sq-fil': ('s', 'fill'), 'tri-fil': ('^', 'fill'), 'dia-fil': ('D', 'fill')}

        self.isItemChangedPending = True
        self.itemChanged.connect(self.OnItemChanged)

    ####################################################
    def OnChange(self, row):
        """
        プロット変更
        @param  row 選択された行
        @retval 無し
        """
        # 選択行が範囲内か
        if row < 0 or row >= self.rowCount():
            return

        # ラインの属性を用意する
        attrs = []
        # チェックボックス情報
        flag = False
        if self.cellWidget(row, 0).checkState() == QtCore.Qt.Checked:
            flag = True
        attrs.append(flag)
        # カラーコード情報
        code = "#"
        code += self.item(row, 8).text()
        code += self.item(row, 9).text()
        code += self.item(row, 10).text()
        attrs.append(code)
        # 線幅の情報
        lw = float(self.item(row, 4).text())
        attrs.append(lw)
        # Line Style
        attrs.append(
            self.linestylesdict[self.cellWidget(row, 3).currentText()])

        # Marker Params
        mk, fil = self.markersdict[self.cellWidget(row, 5).currentText()]
        attrs.append(mk)
        attrs.append(fil)

        # Marker Size
        attrs.append(float(self.item(row, 6).text()))

        # ErrorBar checkbox
        flag = False
        if self.cellWidget(row, 7).checkState() == QtCore.Qt.Checked:
            flag = True
        attrs.append(flag)

        # プロット変更の実行
        self.func(*(row, attrs))

    ##########################################################
    def OnComboBox(self):
        """
        コンボボックスの変更イベントハンドラ
        @param None
        @retval None
        """
        # 呼び出し側のオブジェクトを取り出す
        sender = self.sender()
        # 行数取り出し
        num = self.rowCount()
        # 呼び出し側のコンボボックスがどの行なのかを探す
        currentRow = -1
        for i in range(num):
            # 一致するコンボボックスがあれば
            if sender == self.cellWidget(i, 2):
                currentRow = i
                break
        # 選択中の行が正しく取り出せれば
        if currentRow != -1:
            # コンボボックスから選択中の文字取り出し
            color = self.cellWidget(currentRow, 2).currentText()
            for i in range(len(self.colors)):
                # 一致するカラーコードがあれば
                if color == self.colors[i]:
                    code = self.colorCodes[i]
                    # itemChanged イベントに反応しないようにしてから
                    self.isItemChangedPending = True
                    # テーブルにコードを入れる
                    self.item(currentRow, 8).setText(code[:2])
                    self.item(currentRow, 9).setText(code[2:4])
                    self.item(currentRow, 10).setText(code[4:])
            self.isItemChangedPending = False
            # プロットの変更を行う
            self.OnChange(currentRow)

    ##########################################################
    def OnComboBoxStyle(self):
        """
        コンボボックス(Line Style)の変更イベントハンドラ
        @param None
        @retval None
        """
        # 呼び出し側のオブジェクトを取り出す
        sender = self.sender()
        # 行数取り出し
        num = self.rowCount()
        # 呼び出し側のコンボボックスがどの行なのかを探す
        currentRow = -1
        for i in range(num):
            # 一致するコンボボックスがあれば
            if sender == self.cellWidget(i, 3):
                currentRow = i
                break
        # 選択中の行が正しく取り出せれば
        if currentRow != -1:
            self.isItemChangedPending = False
            # プロットの変更を行う
            self.OnChange(currentRow)

    ##########################################################
    def OnComboBoxMarker(self):
        """
        コンボボックス(Marker)の変更イベントハンドラ
        @param None
        @retval None
        """
        # 呼び出し側のオブジェクトを取り出す
        sender = self.sender()
        # 行数取り出し
        num = self.rowCount()
        # 呼び出し側のコンボボックスがどの行なのかを探す
        currentRow = -1
        for i in range(num):
            # 一致するコンボボックスがあれば
            if sender == self.cellWidget(i, 5):
                currentRow = i
                break
        # 選択中の行が正しく取り出せれば
        if currentRow != -1:
            self.isItemChangedPending = False
            # プロットの変更を行う
            self.OnChange(currentRow)

    ##########################################################
    def OnCheckBox(self):
        """
        チェックボックスの変更イベントハンドラ
        @param None
        @retval None
        """
        # 呼び出し側のオブジェクトを取り出す
        sender = self.sender()
        # 行数取り出し
        num = self.rowCount()
        # 呼び出し側のチェックボックスがどの行なのかを探す
        currentRow = -1
        flag = False
        for i in range(num):
            # 一致するチェックボックスがあれば
            if sender == self.cellWidget(i, 0):
                # 選択中の行を保管し
                currentRow = i
                # チェックボックスの状態を取り出す
                if self.cellWidget(i, 0).checkState() == QtCore.Qt.Checked:
                    flag = True
                break
        # 選択中の行が正しく取り出せれば
        if currentRow != -1:
            # プロットの変更を行う
            self.OnChange(currentRow)

    ##########################################################
    def OnCheckBoxErrorBar(self):
        """
        ErrorBarチェックボックスの変更イベントハンドラ
        @param None
        @retval None
        """
        # 呼び出し側のオブジェクトを取り出す
        sender = self.sender()
        # 行数取り出し
        num = self.rowCount()
        # 呼び出し側のチェックボックスがどの行なのかを探す
        currentRow = -1
        flag = False
        for i in range(num):
            # 一致するチェックボックスがあれば
            if sender == self.cellWidget(i, 7):
                # 選択中の行を保管し
                currentRow = i
                # チェックボックスの状態を取り出す
                if self.cellWidget(i, 7).checkState() == QtCore.Qt.Checked:
                    flag = True
                break
        # 選択中の行が正しく取り出せれば
        if currentRow != -1:
            # プロットの変更を行う
            self.OnChange(currentRow)

    ##########################################################
    def OnItemChanged(self, item):
        """
        QTableWidgetItem変更イベントハンドラ
        @param item 変更を受けたitem
        @retval None
        """
        # もしこのイベントハンドラを無視するなら
        if self.isItemChangedPending:
            return

        currentRow = -1
        # 変更されたitemから行を取り出す
        currentRow = self.row(item)
        # 正しく取得できれば
        if currentRow != -1:
            # プロットの変更を行う
            self.OnChange(currentRow)

    ####################################################
    def AppendFile(self, fname, errbar=False):
        """
        グリッドの最後に行を追加し、データを表示
        @param  (string) fname テキストファイル名
        @param  (bool) errbar
        @retval 無し
        """
        # Item変更イベントを無視する
        self.isItemChangedPending = True
        # 行数取得
        num = self.rowCount()
        # 1行追加
        self.setRowCount(num + 1)

        # １行分のデータを追加
        checkbox = QtWidgets.QCheckBox()
        checkbox.resize(20, 20)
        checkbox.setCheckState(QtCore.Qt.Checked)
        checkbox.stateChanged.connect(self.OnCheckBox)
        self.setCellWidget(num, 0, checkbox)
        fnamelabel = QtWidgets.QLabel()
        fnamelabel.setText(fname)
        self.setCellWidget(num, 1, fnamelabel)
        cbox = QtWidgets.QComboBox()
        for a_color in self.colors:
            cbox.addItem(a_color)
        cbox.activated.connect(self.OnComboBox)
        self.setCellWidget(num, 2, cbox)

        cbox_style = QtWidgets.QComboBox()
        for a_style in self.linestyles:
            cbox_style.addItem(a_style)
        cbox_style.activated.connect(self.OnComboBoxStyle)
        self.setCellWidget(num, 3, cbox_style)

        self.setItem(num, 4, QtWidgets.QTableWidgetItem('1.0'))

        cbox_marker = QtWidgets.QComboBox()
        for a_marker in self.markers:
            cbox_marker.addItem(a_marker)
        cbox_marker.activated.connect(self.OnComboBoxMarker)
        self.setCellWidget(num, 5, cbox_marker)

        self.setItem(num, 6, QtWidgets.QTableWidgetItem('5.0'))

        checkbox_eb = QtWidgets.QCheckBox()
        checkbox_eb.resize(20, 20)
        if errbar:
            checkbox_eb.setCheckState(QtCore.Qt.Checked)
        else:
            checkbox_eb.setCheckState(QtCore.Qt.Unchecked)
        checkbox_eb.stateChanged.connect(self.OnCheckBoxErrorBar)
        self.setCellWidget(num, 7, checkbox_eb)

        self.setItem(num, 8, QtWidgets.QTableWidgetItem('ff'))
        self.setItem(num, 9, QtWidgets.QTableWidgetItem('ff'))
        self.setItem(num, 10, QtWidgets.QTableWidgetItem('ff'))

        # item変更イベントを復活
        self.isItemChangedPending = False

    ####################################################
    def Remove(self):
        """
        選択行の削除
        @param  無し
        @retval [int] 削除した行のインデックス
        """
        row = self.currentRow()
        if row < 0:
            return -1
        self.removeRow(row)
        return row


#########################################
#       OverPlotDialog Deffinition
#########################################
FILE_HEADER = "**  MPLOT FILE **"
XLABEL = "X label"
YLABEL = "Y label"


#########################################
#       OverPlotDialog
#########################################
class OverPlotDialog(QtWidgets.QDialog):
    """
    オーバープロットダイアログクラス
    """

    ##########################################################
    def __init__(self, parent):
        """
        コンストラクタ
        @param  parent   親ウィンドウのObject
        @retval 無し
        """
        self.openFlag = True
        self.traces = []  # 描画データ
        self.path = os.getenv("UTSUSEMI_USR_PRIV_HOME")
        # インターフェイスクラスのインスタンスを取得
        self.ifi = IFEvtProp(parent.order)
        # リソースよりダイアログボックスを取得して作成
        super(OverPlotDialog, self).__init__(parent)
        self.dg = Ui_DgOverPlot()
        if self.dg is None:
            return
        self.dg.setupUi(self)

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

        # ボタンイベント登録
        self.btAdd = self.findChild(QtWidgets.QPushButton, u'btAdd')
        self.btRemove = self.findChild(QtWidgets.QPushButton, u'btRemove')
        self.btClose = self.findChild(QtWidgets.QPushButton, u'btClose')
        self.btAdd.clicked.connect(self.OnAddFiles)
        self.btRemove.clicked.connect(self.OnRemove)
        self.btClose.clicked.connect(self.OnClose)

        # 空のグリッド作成
        self.grd = GridOverPlot(self, self.ChangeLineAttr)

        self.show()

    ##########################################################
    def ChangeLineAttr(self, row, attrs):
        """
        プロットの属性の変更
        @param  row  行のインデックス
        @retval 無し
        """
        self.traces[row].SetDrawFlag(attrs[0])
        self.traces[row].SetColorCode(attrs[1])
        self.traces[row].SetLineWidth(attrs[2])
        self.traces[row].SetLineStyle(attrs[3])
        self.traces[row].SetMarkerParam(attrs[4], attrs[5], attrs[6])
        self.traces[row].SetErrorBarOn(attrs[7])
        self.ifi.NotifyEvent(self.dg, 'overplot', self.traces)

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

    ##########################################################
    def OnAddFiles(self, evt=None):
        """
        Add ボタンイベント処理
        ファイルを読み込み、グリッドに追加
        @param  evt イベント情報
        @retval 無し
        """

        # ファイルオープンダイアログ(複数ファイル選択可)
        paths, filt = QtWidgets.QFileDialog().getOpenFileNames(self, u"Open Text File ...", self.path,
                                                               filter="Text File (*.txt)")

        # キャンセルか
        if len(paths) == 0:
            return
        # 次回のためにディレクトリを保存
        self.path = os.path.dirname(paths[0])

        # 選択されたファイルについて
        for path in paths:
            # トレースデータの読み込み
            trace = self._ReadTxtFile(path)
            # よみこめたなら
            if trace is not None:
                self.traces.append(trace)
                # グリッドにファイル名を表示
                fname = os.path.basename(path)
                self.grd.AppendFile(fname, trace.errorbar)
        # データがあれば
        if len(self.traces) > 0:
            # トレース再描画
            self.ifi.NotifyEvent(self.dg, 'overplot', self.traces)

    ##########################################################
    def _ReadTxtFile(self, path):
        """
        テキストファイル読み込み
        @param  paths (string) フルパス
        @retval ([xVzlues],[yValues])
        """
        try:
            # 指定されたファイルを開く
            try:
                fp = codecs.open(path, 'r', "utf-8")
            except:
                raise PlotException('Common', 'C006', (path,))
            # タイトル行を読み込む
            line = fp.readline().strip()
            xlabel = ""
            ylabel = ""
            # 正しいタイトル行か
            if line != FILE_HEADER:
                try:
                    x, y, e = self._ReadOtherFile(fp, line)
                    if len(e) == 0:
                        plotDat = PlotTrace(x, y)
                    else:
                        plotDat = PlotTrace(x, y, edata=e)
                except:
                    raise PlotException('Common', 'C015', (path,))
            else:
                # データ読み込み
                x, y, xlabel, ylabel, e = self._ReadMPlotFile(fp)
                plotDat = PlotTrace(x, y, xlabel, ylabel, edata=e)
                if len(x) < 2:
                    raise PlotException('Common', 'C040', ())
        except PlotException as ex:
            PlotMessage(self.dg, ex)
            return None

        xvalues = np.array(x, dtype=float)
        yvalues = np.array(y, dtype=float)
        numDat = len(yvalues)
        # X点とY点の数が等しいか
        if len(xvalues) == numDat:
            return plotDat
        # ヒストグラムであれば、X点の中心値を求める
        xnew = np.zeros(numDat, float64)
        for i in range(len(yvalues)):
            xnew[i] = xvalues[i] + (xvalues[i + 1] - xvalues[i]) / 2.0
        plotDat.xdata = xnew
        return plotDat

    ######################################################
    def _ReadMPlotFile(self, fp):
        """
        MPlot 形式のテキストファイルにデータを出力(1トレース)
        @param  fp ファイルポインタ
        @retval data (x, y, er, header, xunit, yunit)
        """
        x = []
        y = []
        e = []
        xlabel = ""
        ylabel = ""
        stat = 0
        comment = False  # コメント読み飛ばし

        # データの終了まで
        while 1:
            # 読み込み終了
            if stat == 5:
                break
            line = fp.readline()
            if line == "":
                break
            line = line.strip()
            if '"""' in line:
                if comment:
                    comment = False
                else:
                    comment = True
                continue
            elif comment:
                continue

            if "--------" in line:
                stat += 1
            elif stat == 3:
                # 単位読み込み
                words = line.split(':')
                if len(words) == 2 and XLABEL in line:
                    xlabel = words[1]
                if len(words) == 2 and YLABEL in line:
                    ylabel = words[1]
            elif stat == 4:
                # データ読み込み
                nums = line.split()
                if len(nums) == 3:
                    try:
                        xx = (float(nums[0]))
                        yy = (float(nums[1]))
                        ee = (float(nums[2]))
                    except:
                        pass
                    else:
                        x.append(xx)
                        y.append(yy)
                        e.append(ee)
                # 最後のXデータか
                # ヒストグラムデータの場合、Xデータの個数が1個多い
                elif len(nums) == 1:
                    try:
                        xx = (float(nums[0]))
                    except:
                        pass
                    else:
                        x.append(xx)
        fp.close

        return (x, y, xlabel, ylabel, e)

    ######################################################
    def _ReadOtherFile(self, fp, line):
        """
        テキストファイルにデータを出力(1トレース)
        FastPlot で出力したデータではないファイルの読み込み
        @param  fp ファイルポインタ
        @param  line 最初に読み込んだ行
        @retval data (x, y, er)
        """
        x = []
        y = []
        e = []

        comment = False

        # データの終了まで
        while True:
            if '"""' in line:
                if comment:
                    comment = False
                else:
                    comment = True
                line = fp.readline().strip()
                continue
            elif comment:
                line = fp.readline().strip()
                continue

            if line.find(",") > 0:
                nums = line.split(",")
            else:
                nums = line.split()
            if len(nums) >= 2:
                try:
                    xx = (float(nums[0]))
                    yy = (float(nums[1]))
                except:
                    fp.close()
                    raise
                x.append(xx)
                y.append(yy)

            if len(nums) >= 3:
                try:
                    ee = (float(nums[2]))
                except:
                    fp.close()
                    raise
                e.append(ee)

            # データ読み込み
            line = fp.readline().strip()
            if line == "":
                break
        fp.close
        return (x, y, e)

    ##########################################################
    def OnRemove(self, evt=None):
        """
        Remove ボタンイベント処理
        ファイルをグリッドから削除
        @param  evt イベント情報
        @retval 無し
        """
        row = self.grd.Remove()
        if row < 0:
            return
        # トレースリストを削除
        self.traces.pop(row)
        # トレース再描画
        self.ifi.NotifyEvent(self.dg, 'overplot', self.traces)

    ##########################################################
    def ShowDg(self):
        """
        Cancel ボタンイベント処理
        @param  evt=None イベント情報
        @retval 無し
        """
        if not self.openFlag:
            self.show()
            self.openFlag = True


#######################################
#  D2Frame
#######################################
class D2Frame(QtWidgets.QMainWindow):
    """2次元プロッタフレーム画面クラス

    2次元プロッタの最上位クラス
    """

    #########################################################
    def __init__(self, parent, data=None, order=1, fTitle=None):
        """コンストラクタ

        Parameters:
            parent (QWidget): 親ウィンドウのID, None の場合はトップレベルウィンドウ
            data (tpl(array, array,array) ): 表示データ
            order (int): プロッタ番号(タイトルバーに順番を表示)
            fTitle (strlフレームタイトル
        """
        logging.debug("D2Frame::__init__")
        super(D2Frame, self).__init__(parent)
        self.ui = Ui_MainWindow()
        if self.ui is None:
            return
        self.ui.setupUi(self)
        self.verticalLayout = self.findChild(QtWidgets.QVBoxLayout, 'verticalLayout')
        self.menubar = self.findChild(QtWidgets.QMenuBar, 'menubar')
        self.statusbar = self.findChild(QtWidgets.QStatusBar, 'statusbar')
        self.parent = parent
        self.data = data
        self.mdownTime = None  # マウスダウン時間
        self.beforeTime = None  # マウスアップ時間
        self.ShowFlag = True  # 領域全表示フラグ
        self.order = order
        self.inhibitClose = False  # クローズ禁止
        self.autoAddRegion = False  # 領域指定マウスアップ時に自動追加
        self.sliceMode = True  # スライス指定モード
        self.regShowMode = True  # 領域表示モード
        self._r_click_event = None
        self._last_slice_drag_values = [None, None, None, None]
        self.mp_top = None  # スライスプロット上で呼び出すMPlotインスタンス．初期はNone．
        self.mp_right = None  # スライスプロット右で呼び出すMPlotインスタンス．初期はNone．
        self.mp_main = None  # メイン2Dプロットで呼び出すMPlotインスタンス．初期はNone．
        self.mp_diagonal = None  # Diagonalカットした結果をプロットするインスタンス

        self.viewMenu = self.findChild(QtWidgets.QMenu, 'menuView')
        self.anaMenu = self.findChild(QtWidgets.QMenu, 'menuAnalyze')
        self.paramsMenu = self.findChild(QAction, 'actionSet_View_Parameters')
        self.paramsMenu.triggered.connect(self.OnParams)
        self.regionMenu = self.findChild(QAction, 'actionSet_Regions')
        self.regionMenu.triggered.connect(self.OnRegion)

        self.sliceMenu = self.findChild(QAction, 'actionSlice_setting')
        self.sliceMenu.triggered.connect(self.OnSliceParams)

        showAll = self.findChild(QAction, "actionShow_All_Regions")
        showAll.triggered.connect(self.OnShowAll)
        hideAll = self.findChild(QAction, "actionHide_All_Regions")
        hideAll.triggered.connect(self.OnHideAll)

        _view_slice = self.anaMenu.addAction("Slice")
        _view_slice.setObjectName("menuSlice")
        _view_slice.setCheckable(True)
        _view_slice.setChecked(True)
        _view_slice.triggered.connect(self.OnViewSlice)

        _mplot_top = self.anaMenu.addAction("MPlot (X-Intensity)")
        _mplot_right = self.anaMenu.addAction("MPlot (Y-Intensity)")
        _mplot_top.setObjectName("menuMPlotTop")
        _mplot_right.setObjectName("menuMPlotRight")
        _mplot_top.triggered.connect(self.OnMPlotFromMenu)
        _mplot_right.triggered.connect(self.OnMPlotFromMenu)

        _oplot = self.anaMenu.addAction("Over Plot")
        _oplot.setObjectName("menuOverPlot")
        _oplot.triggered.connect(self.OnOverPlotFromMenu)
        self.overplotdg = None

        # フレームのタイトルに番号を付ける
        strT = self.windowTitle()
        if fTitle:
            self.post = " - %s" % fTitle
            self.setWindowTitle(strT + self.post)

        # キャンバスを作成
        # self.fig   = Figure((7.82, 7.06), 100)
        # Inital figure shape should be regular square ( See D2Chart::__init__ )
        self.fig = Figure((7.00, 7.00), 100)
        self.canvas = FigCanvas(self.fig)
        self.verticalLayout.addWidget(self.canvas)
        # self.setCentralWidget(self.canvas)

        # contexet menuを作成
        self.canvasMenu = QtWidgets.QMenu(self)
        self.canvasMenu.addAction("MPlot", self.OnMPlotFromContextMenu)

        self.canvasMenuSide = QtWidgets.QMenu(self)
        self.canvasMenuSide.addAction(
            "Add To MPlot", self.OnMPlotFromContextMenu)
        self.canvasMenuSide.addAction(
            "Plot Clear", self.OnClearMPlotFromContextMenu)

        # プロッタフレーム用ツールバー作成
        self.toolbar = ChartToolBar(self, order)
        self.toolbar.setMovable(False)
        self.addToolBar(self.toolbar)

        self.infotxt = self.findChild(QtWidgets.QStatusBar, "statusbar")

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

        # ホームディレクトリを取得(Windows の場合は、Users の下のユーザ名)
        home = expanduser("~")
        path = os.path.join(home, 'ana')
        path = os.path.join(path, 'xml')
        # デフォルトファイル名称
        #self.default_prms = os.path.join(path, 'initial.upr')
        self.default_prms = os.path.join(path, 'm2plotp_initial.prm')
        default_prms_local = os.path.join(os.getcwd(), 'm2plotp_initial.prm')
        # ディレクトリが無ければ再帰的に作成
        if not os.path.exists(path):
            os.makedirs(path)
        # デフォルトパラメータファイルがあれば読み込み
        default_prms_path = self.default_prms
        if os.path.exists(default_prms_local):
            default_prms_path = default_prms_local
        #if os.path.exists(self.default_prms):
        if os.path.exists(default_prms_path):
            try:
                self.params = U2Params()
                #_params = pickle.load(open(self.default_prms, "rb"))
                _params = pickle.load(open(default_prms_path, "rb"))
                # 必ずデフォルト値で始めるパラメータを読み込みから削除
                del _params.__dict__["title"]
                del _params.__dict__["comment"]
                del _params.__dict__["smoothing"]
                # del _params.__dict__["window_size"]
                del _params.__dict__["bankseparator"]
                for a_key in ["BottomSide", "TopSide", "LeftSide", "RightSide"]:
                    if type(_params.TickStyleDic[a_key]) == str:
                        if _params.TickStyleDic[a_key] == "on":
                            _params.TickStyleDic[a_key] = True
                        else:
                            _params.TickStyleDic[a_key] = False
                # 読み込みでupdate
                self.params.__dict__.update(_params.__dict__)
                self.params.TickStyleDic.update(_params.TickStyleDic)
                self.params.fontDict.update(_params.fontDict)
                # Saved parameter file format is old ? (210317)
                if not hasattr(self.params.xscale, "unit"):
                    # print("#[inamura 210317] Saved file is old format")
                    self.params.xscale = ScaleParams("X")
                    self.params.xscale.__dict__.update(_params.xscale.__dict__)
                    self.params.yscale = ScaleParams("Y")
                    self.params.yscale.__dict__.update(_params.yscale.__dict__)
                logging.debug("D2Frame::__init__ [o] load param")
            except:
                # 無い場合はデフォルトのパラメータを作成
                self.params = U2Params()
                logging.debug("D2Frame::__init__ [x] load param")
        # 無い場合は
        else:
            # デフォルパラメータを作成
            self.params = U2Params()
            logging.debug("D2Frame::__init__ Param file dose not exist")

        # イベントハンドラ登録
        self.SetEventHandler()

        # パラメータの公開プロパティを登録
        self.ifi.AddProperty('params', lambda: self.params)
        self.ifi.AddProperty('show_all_flag', lambda: self.ShowFlag)
        self.ifi.AddProperty('slice_mode', lambda: self.sliceMode)
        self.ifi.AddProperty('reg_show_mode', lambda: self.regShowMode)

        self.dragFlag = False
        self.d2 = None
        if data is not None:
            # マップの描画
            self.d2 = D2Chart(self, self.canvas, data)
        else:
            # 画像があれば表示
            pngfile = SearchPath('uGao.png')
            if pngfile != "":
                img = image.imread(pngfile)
                ax = self.fig.add_subplot(111)
                ax.imshow(img)
                # スケールのラベルを消す
                ax.set_xticks([])
                ax.set_yticks([])

        # メッセージのリスナー登録
        self.ifi.AddListner('dg_params', self.OnParams)  # パラメータダイアログ起動
        self.ifi.AddListner(
            'init_params', self.OnNotifyInitPrms)  # パラメータを起動時に戻す
        self.ifi.AddListner('save_as_init_params',
                            self.OnNotifySavePrmsAsInit)  # パラメータを初期値として保存
        self.ifi.AddListner('save_as_local_init_params',
                            self.OnNotifySavePrmsAsLocalInit)
        self.ifi.AddListner('add_region', self.OnNotifyAddRegion)  # 領域追加
        self.ifi.AddListner('del_region', self.OnNotifyDelRegion)  # 領域削除
        self.ifi.AddListner(
            'change_state', self.OnNotifyChangeState)  # 領域表示状態変更
        self.ifi.AddListner('show_all', self.OnNotifyShowAll)  # 領域表示状態変更
        self.ifi.AddListner('change_data', self.OnNotifyChangeData)  # データ変更
        self.ifi.AddListner('slice', self.OnNotifyAutoSlice)  # 自動スライス
        self.ifi.AddListner(
            'show_cursor', self.OnNotifyShowCursor)  # カーソル表示／非表示
        self.ifi.AddListner('show_grid', self.OnNotifyShowGrid)  # grid表示／非表示
        self.listner_index_slice = self.ifi.AddListner(
            'left_mouse_click_cb', call_ndarray_slice)  # スライスコールバック

        # ラムダ式にてコールバック関数を定義(メニューを選択可に戻す)
        def cbFunc():
            return self.regionMenu.setEnabled(True)
        # 領域ダイアログを作成(表示はしない)
        self.rgDg = RegionDialog(self, cbFunc)
        # スライスダイアログを作成(表示はしない)
        self.sliceDg = SliceDialog(self)
        # Mouse Position
        self.downP = None
        self.last_clicked_point = None

        # Update ShowGrid button
        if self.params.hgrid or self.params.vgrid:
            self.toolbar.btn_turn_grid.setChecked(True)

        # Initial View Params
        self.initial_viewParams_Title = ""
        self.initial_viewParams_Comment = ""
        self.initial_viewParams_xLabel = ""
        self.initial_viewParams_yLabel = ""

        # Catch WindowActivate event
        self.installEventFilter(self)

    #########################################
    def eventFilter(self, widget, event):
        # if WindowActivate event, raise parent panel window
        if event.type() == QtCore.QEvent.WindowActivate:
            getattr(self.parent, "raise")()
            getattr(self, "raise")()
            return False
        return False

    #########################################
    def OnSliceMPlot(self, gid):
        """スライスのMPlot呼び出し

        Parameters:
            gid (str) D2Chartのスライスaxesに設定したgroup id
        """
        if gid == "ax_top":
            ax = self.d2.ax_top
        else:
            ax = self.d2.ax_right
        lines = ax.get_lines()
        if len(lines) == 1:
            # selfはu2dplot。parentはM2PlotPlus。parentがNoneならu2dplot直接呼び出し。
            parent = self.parentWidget()
            if parent is None:
                if gid == "ax_top":
                    p = fastplot.PlotFrame(
                        self, (lines[0].get_xdata(), lines[0].get_ydata()))
                else:
                    p = fastplot.PlotFrame(
                        self, (lines[0].get_ydata(), lines[0].get_xdata()))
            else:
                if gid == "ax_top":
                    if parent._sliced_ec_top is not None:
                        # スライスプロット上が作られたことがない、もしくは死んでいる場合
                        if self.mp_top is None or (not self.mp_top.plot.IsAliveComm()):
                            self.mp_top = mp.MPlot(parent._sliced_ec_top)
                            self.mp_top.SetMainTitle(self.params.title)
                            # self.mp_top.SetSubTitle(self.params.comment)
                            sub_title = self.params.comment.replace("\n", " ")
                            self.mp_top.SetSubTitle(sub_title)
                            self.mp_top.SetXLabel(self.params.xscale.label)
                            self.mp_top.SetYLabel("Intensity")
                        else:
                            self.mp_top.AddData(parent._sliced_ec_top)
                        """
                        if self.mp_top is None: # スライスプロット上が作られたことがあるか
                            self.mp_top = mp.MPlot(parent._sliced_ec_top)
                        else:
                            if self.mp_top.plot.IsAliveComm(): # 死活判定
                                self.mp_top.AddData(parent._sliced_ec_top)
                            else:
                                self.mp_top = mp.MPlot(parent._sliced_ec_top)
                        """
                else:
                    if parent._sliced_ec_right is not None:
                        # スライスプロット右が作られたことがない、もしくは死んでいる場合
                        if self.mp_right is None or (not self.mp_right.plot.IsAliveComm()):
                            self.mp_right = mp.MPlot(parent._sliced_ec_right)
                            self.mp_right.SetMainTitle(self.params.title)
                            # self.mp_right.SetSubTitle(self.params.comment)
                            sub_title = self.params.comment.replace("\n", " ")
                            self.mp_right.SetSubTitle(sub_title)
                            self.mp_right.SetXLabel(self.params.yscale.label)
                            self.mp_right.SetYLabel("Intensity")
                        else:
                            self.mp_right.AddData(parent._sliced_ec_right)
                        """
                        if self.mp_right is None: # スライスプロット右が作られたことがあるか
                            self.mp_right = mp.MPlot(parent._sliced_ec_right)
                        else:
                            if self.mp_right.plot.IsAliveComm(): # 死活判定
                                self.mp_right.AddData(parent._sliced_ec_right)
                            else:
                                self.mp_right = mp.MPlot(parent._sliced_ec_right)
                        """
        return
    #########################################

    def OnClearMPlotFromContextMenu(self):
        """スライスのMPlot Clear
        """
        parent = self.parentWidget()  # selfはu2dplot。parentはM2PlotPlus。parentがNoneならu2dplot直接呼び出し。
        ax = self._r_click_event.inaxes  # 呼び出しAxes
        gid = ax.get_gid()  # 呼び出しAxesのGroup ID。ax_top or ax_right

        if gid is None:
            return

        if gid == "ax_top":
            ax = self.d2.ax_top
        else:
            ax = self.d2.ax_right
        lines = ax.get_lines()
        if len(lines) == 1:
            # selfはu2dplot。parentはM2PlotPlus。parentがNoneならu2dplot直接呼び出し。
            parent = self.parentWidget()
            if parent is not None:
                if gid == "ax_top":
                    # スライスプロット上が作られたことがない、もしくは死んでいる場合
                    if self.mp_top is None or (not self.mp_top.plot.IsAliveComm()):
                        return
                    else:
                        self.mp_top.Remove(0)  # Clear All plot data
                else:
                    # スライスプロット右が作られたことがない、もしくは死んでいる場合
                    if self.mp_right is None or (not self.mp_right.plot.IsAliveComm()):
                        return
                    else:
                        self.mp_right.Remove(0)  # Clear All plot data
        return

    #########################################
    def OnMPlotFromMenu(self):
        """メニューからのMPlot呼び出し

        """
        if self.sender().objectName() == "menuMPlotTop":
            gid = "ax_top"
        else:
            gid = "ax_right"
        self.OnSliceMPlot(gid)

    #########################################
    def OnMPlotFromContextMenu(self):
        """コンテキストメニューからのMPlot呼び出し

        """
        parent = self.parentWidget()  # selfはu2dplot。parentはM2PlotPlus。parentがNoneならu2dplot直接呼び出し。
        ax = self._r_click_event.inaxes  # 呼び出しAxes
        gid = ax.get_gid()  # 呼び出しAxesのGroup ID。ax_top or ax_right

        if gid is not None:
            self.OnSliceMPlot(gid)
            return

        # xdata = self._r_click_event.xdata
        # ydata = self._r_click_event.ydata
        if self.last_clicked_point is None:
            xdata = self._r_click_event.xdata
            ydata = self._r_click_event.ydata
        else:
            xdata = self.last_clicked_point[0]
            ydata = self.last_clicked_point[1]

        # 表示軸ndarray取り出し
        xbin = self.data[1][0]
        ybin = self.data[2].T[0]

        n_x_plot = len(xbin)  # プロットX軸区切り数
        if not self.params.transPosition:
            plot_index_x = int(np.searchsorted(xbin, xdata)) - 1  # xbinでのindex
        else:
            plot_index_x = int(np.searchsorted(xbin, ydata)
                               ) - 1  # 転置前のxbinでのindex
        if parent is not None:
            n_x_data = parent.data.PutSize()  # データECM中のECA数 or ECA中のEC数
            if parent.converter.isInelasticPowder:  # データがInelastic Powderの場合何もしない
                return
            # ECM/ECAでのindex
            data_index_x = parent.converter.indices_sort[plot_index_x]
            if isinstance(parent.data, Manyo.ElementContainerArray):
                # p = mp.MPlot(parent.data(data_index_x))
                # スライスプロットメインが作られたことがない、もしくは死んでいる場合
                if self.mp_main is None or (not self.mp_main.plot.IsAliveComm()):
                    self.mp_main = mp.MPlot(parent.data(data_index_x))
                    self.mp_main.SetMainTitle(self.params.title)
                    self.mp_main.SetSubTitle(self.params.comment)
                else:
                    self.mp_main.AddData(parent.data(data_index_x))
                """
                if self.mp_main is None: # スライスプロット上が作られたことがあるか
                    self.mp_main = mp.MPlot(parent.data(data_index_x))
                else:
                    if self.mp_main.plot.IsAliveComm(): # 死活判定
                        self.mp_main.AddData(parent.data(data_index_x))
                    else:
                        self.mp_main = mp.MPlot(parent.data(data_index_x))
                """
                return
            else:  # ECMの場合のMPlot呼び出しで何を表示するか要検討
                # y_plot = self.data[2].transpose()[0].tolist()
                n_y_plot = len(ybin)  # プロットy軸区切り数
                n_y_data = parent.data(0).PutSize()  # データECM中のECA中のEC数
                if (n_y_plot - 1) == n_y_data:
                    if not self.params.transPosition:
                        plot_index_y = int(np.searchsorted(ybin, ydata)) - 1
                    else:
                        plot_index_y = int(np.searchsorted(ybin, xdata)) - 1
                pv = parent.converter.slicer.PutDetectMapIndex(
                    plot_index_x, plot_index_y)
                if len(pv) == 0:
                    raise PlotException(
                        'Common', 'C001', ("Range over", "D2Frame:OnMonuseUp"))
                else:
                    # p = mp.MPlot(parent.data(pv[0], pv[1]))
                    # スライスプロットメインが作られたことがない、もしくは死んでいる場合
                    if self.mp_main is None or (not self.mp_main.plot.IsAliveComm()):
                        self.mp_main = mp.MPlot(parent.data(pv[0], pv[1]))
                        self.mp_main.SetMainTitle(self.params.title)
                        self.mp_main.SetSubTitle(self.params.comment)

                    else:
                        self.mp_main.AddData(parent.data(pv[0], pv[1]))
                    """
                    if self.mp_main is None: # スライスプロット上が作られたことがあるか
                        self.mp_main = mp.MPlot(parent.data(pv[0], pv[1]))
                    else:
                        if self.mp_main.plot.IsAliveComm(): # 死活判定
                            self.mp_main.AddData(parent.data(pv[0], pv[1]))
                        else:
                            self.mp_main = mp.MPlot(parent.data(pv[0], pv[1]))
                    """

                    self.mp_main.SetXLabel("{}".format(
                        parent.data(pv[0], pv[1]).PutXKey()))
                    self.mp_main.SetYLabel("{}".format(
                        parent.data(pv[0], pv[1]).PutYKey()))
        else:
            return

    #########################################
    def OnDiagonalSlice(self):
        """対角線にスライスする
        """
        parent = self.parentWidget()
        if parent is not None:
            if parent.converter.isInelasticPowder:
                return
            x0 = self.params.mouseDragPath[0][0]
            y0 = self.params.mouseDragPath[0][1]
            x1 = self.params.mouseDragPath[1][0]
            y1 = self.params.mouseDragPath[1][1]
            if x1 < x0:
                tmp_x = x0
                x1 = x0
                x0 = tmp_x
            width = self.params.diagonalSliceInfo[0]
            binning = self.params.diagonalSliceInfo[1]
            if isinstance(parent.data, Manyo.ElementContainerArray):
                ec = parent.converter.arraySlicer.CutDiagonal(
                    x0, y0, x1, y1, width, binning, True)
            elif isinstance(parent.data, Manyo.ElementContainerMatrix):
                xkey = parent.converter.xkey
                ykey = parent.converter.ykey
                if xkey is None:
                    xkey = ""
                if ykey is None:
                    ykey = ""
                slicer = mm.MlfArraySlicer(parent.converter._eca, xkey, ykey)
                ec = slicer.CutDiagonal(x0, y0, x1, y1, width, binning, True)
                del slicer
            else:
                return
            if self.mp_diagonal is None:  # スライスプロット上が作られたことがあるか
                self.mp_diagonal = mp.MPlot(ec)
            else:
                if self.mp_diagonal.plot.IsAliveComm():  # 死活判定
                    self.mp_diagonal.AddData(ec)
                else:
                    del self.mp_diagonal
                    self.mp_diagonal = mp.MPlot(ec)
        return

    #########################################
    def OnContextMenu(self, event):
        """コンテキストメニュー呼び出し

        Parameters:
            event (matplotlib.backend_bases.MouseEvent)
        """
        self._r_click_event = event
        # self.canvasMenu.exec_(self.canvas.mapToGlobal(point))
        self.canvasMenu.exec_(QtGui.QCursor.pos())

    #########################################
    def OnContextMenuSide(self, event):
        """コンテキストメニュー呼び出し

        Parameters:
            event (matplotlib.backend_bases.MouseEvent)
        """
        self._r_click_event = event
        self.canvasMenuSide.exec_(QtGui.QCursor.pos())

    #########################################
    def OnOverPlotFromMenu(self, event=None):
        """
        """
        if self.overplotdg is None:
            self.overplotdg = OverPlotDialog(self)
        else:
            try:
                self.overplotdg.show()
            except:
                self.overplotdg = OverPlotDialog(self)

    #########################################
    def SetEventHandler(self):
        """
        イベントハンドラ登録
        @param  無し
        @retval 無し
        """
        # Fileメニューのイベントハンドラ登録
        self.findChild(QAction, "actionOpen").triggered.connect(self.OnOpen)
        self.findChild(QAction, "actionSave_as_Binary").triggered.connect(
            self.OnSaveBin)
        self.findChild(QAction, "actionSave_as_Text").triggered.connect(
            self.OnSaveTxt)
        self.findChild(QAction, "actionExit").triggered.connect(self.close)

        # Editメニューのイベントハンドラ登録
        self.findChild(QAction, "actionOpen_View_Parameters").triggered.connect(
            self.OnOpenParams)
        self.findChild(QAction, "actionSave_View_Parameters").triggered.connect(
            self.OnSaveParams)

        # マウスイベントのリスナ登録
        self.cid_mouse_move = self.canvas.mpl_connect(
            'motion_notify_event', self.OnMouseMove)
        self.canvas.mpl_connect('button_press_event', self.OnMouseDown)
        self.canvas.mpl_connect('button_release_event', self.OnMouseUp)

    ###################################################
    def OnNotifyInitPrms(self, wid, evt, value=None):
        """
        パラメータを起動時に戻すメッセージ処理
        @param wid   ウィンドウID
        @param  evt  イベント
        @retval 無し
        """
        # デフォルトパラメータファイルがあれば読み込み
        if os.path.exists(self.default_prms):
            pre_title = self.params.__dict__["title"]
            pre_comment = self.params.__dict__["comment"]
            del self.params
            # 起動時のパラメータファイルを再度読み込む
            self.params = U2Params()
            _params = pickle.load(open(self.default_prms, "rb"))
            # 必ずデフォルト値で始めるパラメータを読み込みから削除
            _params.__dict__["title"] = pre_title
            _params.__dict__["comment"] = pre_comment
            for a_key in ["BottomSide", "TopSide", "LeftSide", "RightSide"]:
                if type(_params.TickStyleDic[a_key]) == str:
                    if _params.TickStyleDic[a_key] == "on":
                        _params.TickStyleDic[a_key] = True
                    else:
                        _params.TickStyleDic[a_key] = False
            self.params.__dict__.update(_params.__dict__)
            self.params.TickStyleDic.update(_params.TickStyleDic)
            self.params.fontDict.update(_params.fontDict)
            # print(repr(self.params))
        else:
            # デフォルト条件
            self.params = U2Params()
        # パラメータ変更通知
        self.ifi.NotifyEvent(self, 'change_params')

    ###################################################
    def OnNotifySavePrmsAsInit(self, wid, evt, value=None):
        """
        パラメータを初期設定として保存するメッセージ処理
        @param wid   ウィンドウID
        @param  evt  イベント
        @retval 無し
        """
        # 自動指定のパラメータ群をデフォルトに戻す
        if self.params.autoRange:
            self.range = None
        self.params.relRange = 100
        if not self.params.hgrid:
            self.params.hgridInterval = None

        if not self.params.vgrid:
            self.params.vgridInterval = None

        self._BackDefault(self.params.xscale)
        self._BackDefault(self.params.yscale)
        try:
            for a_key in ["BottomSide", "TopSide", "LeftSide", "RightSide"]:
                if type(self.params.TickStyleDic[a_key]) == str:
                    if self.params.TickStyleDic[a_key] == "on":
                        self.params.TickStyleDic[a_key] = True
                    else:
                        self.params.TickStyleDic[a_key] = False
            pickle.dump(self.params, open(self.default_prms, 'wb'))
        except:
            pass

    ###################################################
    def OnNotifySavePrmsAsLocalInit(self, wid, evt, value=None):
        """
        パラメータを初期設定としてカレントフォルダに保存するメッセージ処理
        @param wid   ウィンドウID
        @param  evt  イベント
        @retval 無し
        """
        # 自動指定のパラメータ群をデフォルトに戻す
        if self.params.autoRange:
            self.range = None
        self.params.relRange = 100
        if not self.params.hgrid:
            self.params.hgridInterval = None

        if not self.params.vgrid:
            self.params.vgridInterval = None

        self._BackDefault(self.params.xscale)
        self._BackDefault(self.params.yscale)
        try:
            for a_key in ["BottomSide", "TopSide", "LeftSide", "RightSide"]:
                if type(self.params.TickStyleDic[a_key]) == str:
                    if self.params.TickStyleDic[a_key] == "on":
                        self.params.TickStyleDic[a_key] = True
                    else:
                        self.params.TickStyleDic[a_key] = False
            param_path = os.path.join(os.getcwd(), os.path.basename(self.default_prms))
            pickle.dump(self.params, open(param_path, 'wb'))
        except:
            pass

    #########################################
    def OnNotifyAddRegion(self, wid, evt, label):
        """
        領域追加メッセージ処理
        @param  wid イベント発生元
        @param  evt イベントデータ
        @param  label メニューアイテムのラベル
        @retval 無し
        """
        check_item = self.viewMenu.addAction(label)
        check_item.setCheckable(True)
        check_item.setChecked(True)
        check_item.setObjectName(label)
        check_item.toggled[bool].connect(self.OnCheckMenu)

    #########################################
    def OnViewSlice(self):
        """スライス表示／非表示切替
        """
        self.sliceMode = self.sender().isChecked()
        if self.sender().objectName() == "sliceButton":
            self.findChild(QAction, "menuSlice").setChecked(self.sliceMode)
        else:
            self.findChild(QAction, "sliceButton").setChecked(self.sliceMode)
        if not self.sliceMode:
            self._last_slice_drag_values = [
                None, None, None, None]  # スライス位置情報を初期化
        self.GetWindowSizeParams()  # Get Window Size
        self.ifi.NotifyEvent(self, 'slice_mode', self.sliceMode)
        self.ifi.NotifyEvent(self, 'change_data', self.data)

    #########################################
    def OnCheckMenu(self, isShown):
        """
        個別の領域名メニューイベントハンドラー
        @param isShown (bool)
        @retval 無し
        """
        menu_name = self.sender().objectName()  # 領域indexを得るためにまず、メニューのObject Nameを得る。
        index = int(menu_name.split(":")[0]) - 1  # その":"の前が領域index
        self.rgDg.ShowRegion(index, isShown)  # 領域Tableのチェック変更

    #########################################
    def OnNotifyDelRegion(self, wid, evt, index):
        """
        領域削除メッセージ受信
        @param  event イベントデータ
        @retval 無し
        """
        # 当該メニューを削除
        for a in self.viewMenu.actions():
            if a.objectName().startswith("{0:d}:".format(index + 1)):
                self.viewMenu.removeAction(a)
                break
        # 以後の番号を付け直す
        index += 1
        for a in self.viewMenu.actions():
            if a.objectName().startswith("{0:d}:".format(index + 1)):
                new_label = "{0:d}:{1:s}".format(
                    index, a.objectName().split(":")[1])
                a.setObjectName(new_label)
                a.setText(new_label)
                index += 1

    #########################################
    def OnNotifyAutoSlice(self, eventSrc, evt, data):
        """
        自動スライスメッセージ処理
        Parameters:
            eventSrc イベント発生元
            evt イベントデータ
            data (x, y) or (x0, y0, x1, y1)
        """
        logging.debug("D2Frame::OnNotifyAutoSlice {0}".format(eventSrc))
        self.SetSliceRegionToDialog(data)
        self.ifi.NotifyEvent(self, 'draw_slice_region', data)
        # self.ifi.NotifyEvent(self, 'left_mouse_click_cb', data)
        if type(data) == list:
            data2 = data[:]
            data2.append(self.params.slice_ave_mode)
        elif type(data) == tuple:
            data2 = data + (self.params.slice_ave_mode,)
        self.ifi.NotifyEvent(self, 'left_mouse_click_cb', data2)

    #########################################
    def OnNotifyChangeState(self, eventSrc, evt, data):
        """
        領域表示状態変更メッセージ処理
        @param  eventSrc イベント発生元
        @param  evt イベントデータ
        @param  data (index, isShown)
        @retval 無し
        """
        index, isShown = data
        for a in self.viewMenu.actions():
            if a.objectName().startswith("{0:d}:".format(index + 1)):
                a.setChecked(isShown)
                break

    #########################################
    def OnNotifyShowCursor(self, eventSrc, evt, checked):
        """
        カーソル表示／非表示変更メッセージ処理
        @param  eventSrc イベント発生元
        @param  evt イベントデータ
        @param  checked (bool)
        @retval 無し
        """
        self.d2.sliceAxes.set_visible(checked)
        self.canvas.draw()

    #########################################
    def OnNotifyShowGrid(self, eventSrc, evt, checked):
        """
        grid表示／非表示変更メッセージ処理
        @param  eventSrc イベント発生元
        @param  evt イベントデータ
        @param  checked (bool)
        @retval 無し
        """
        self.params.hgrid = checked
        self.params.vgrid = checked
        self.GetWindowSizeParams()
        self.ifi.NotifyEvent(self, 'change_params')

    #########################################
    def Close(self):
        """
        Close u2dplot::D2Frame #[inamura 181001]
        @param  None
        @retval 無し
        """
        # 2次元プロッタフレームクローズイベント発行
        self.ifi.NotifyEvent(self, "u2dclosed")
        """
        # 自動指定のパラメータ群をデフォルトに戻す
        if self.params.autoRange:
            self.range = None
        self.params.relRange = 100
        if not self.params.hgrid:
            self.params.hgridInterval = None

        if not self.params.vgrid:
            self.params.vgridInterval = None

        self._BackDefault(self.params.xscale)
        self._BackDefault(self.params.yscale)
        # パラメータをファイルに保存
        try:
            pickle.dump(self.params, open(self.default_prms, 'wb'))
        except:
            pass
        """
        # プロッタクローズイベントを送信
        self.ifi.NotifyEvent(self, 'close_plot')
        # インターフェイスのクリア
        IFEvtProp(self.order).InitIF()

        # ダイアログクローズ
        self.sliceDg.close()
        self.rgDg.close()

        self.close()

    #########################################
    def OnOpen(self):
        """
        データファイルオープン処理
        @param  無し
        @retval 無し
        """
        wildcard = "Map (*.map);;Text (*.txt)"
        # ファイル保存ダイアログを表示
        dlg = QtWidgets.QFileDialog(
            self, "Select a file", expanduser("."), wildcard)
        dlg.setFileMode(QtWidgets.QFileDialog.ExistingFile)
        # パスを取得。
        if dlg.exec_():
            fileNames = dlg.selectedFiles()
            try:
                dat = self.ReadDataFile(fileNames[0])
            except PlotException as ex:
                PlotMessage(self, ex)
                return
            # データ変更メッセージ送信
            self.ifi.NotifyEvent(self, 'change_data', dat)

    #########################################
    def ReadDataFile(self, filename):
        """
        データファイルを読み込み、マップデータに変換
        @param  filename (string) ファイルのパス
        @retval マップデータ(Int, X, Y)
        """
        if not os.path.exists(filename):
            raise PlotException('Common', 'C006', (filename,))
        root, ext = os.path.splitext(filename)
        try:
            if ext == ".map":
                # デシリアライズして
                dat = pickle.load(open(filename, "rb"))
            else:
                fp = codecs.open(filename, 'r', 'utf-8')
                dat = self._ReadTxtFile(fp)
        except:
            raise PlotException('Common', 'C040', ())
        return dat

    #########################################
    def _ReadTxtFile(self, fp):
        """
        テキスト形式のデータファイルを読み込み、マップデータに変換
        @param  fp ファイルポインタ
        @retval マップデータ(Int, X, Y)
        """
        zList = []
        xList = []
        yList = []
        z = []
        x = []
        y = []

        # 1行づつ読み込む
        while True:
            line = fp.readline()
            # ファイルの終わりか
            if not line:
                break

            # コメント行か
            if line[0] == '#':
                continue
            # 空白行か
            if line == os.linesep:
                zList.append(z)
                xList.append(x)
                yList.append(y)
                z = []
                x = []
                y = []
                continue
            # 3個の数値があるか(空白区切り)
            data = line.split()
            if len(data) != 3:
                # タブ区切りで試してみる
                data = line.split('\t')
                if len(data) != 3:
                    raise
            x.append(float(data[0]))
            y.append(float(data[1]))
            z.append(float(data[2]))

        fp.close()

        # マップデータを復元する
        numh = len(zList)
        numv = len(zList[0])
        Zint = np.zeros((numv, numh), float64)
        X = np.zeros((numv + 1, numh + 1), float64)
        Y = np.zeros((numv + 1, numh + 1), float64)

        for i in range(numv):
            for j in range(numh):
                Zint[i, j] = zList[j][i]
        for i in range(numv - 1):
            for j in range(numh - 1):
                X[i + 1, j + 1] = (xList[j][i] + xList[j + 1][i]) / 2.0
                Y[i + 1, j + 1] = (yList[j][i] + yList[j][i + 1]) / 2.0
            X[i + 1, 0] = xList[0][i] - (xList[1][i] - xList[0][i]) / 2.0
            X[i + 1, numh] = xList[numh - 1][i] + \
                (xList[numh - 1][i] - xList[numh - 2][i]) / 2.0
            Y[i + 1, 0] = Y[i + 1, 1]
            Y[i + 1, numh] = Y[i + 1, numh - 1]
        for j in range(numh + 1):
            X[0, j] = X[1, j]
            X[numv, j] = X[numv - 1, j]
            Y[0, j] = Y[1, j] - Y[2, j] + Y[1, j]
            Y[numv, j] = Y[numv - 1, j] + Y[numv - 1, j] - Y[numv - 2, j]

        return (Zint, X, Y)

    #########################################
    def OnSaveBin(self):
        """
        データファイルをバイナリ形式で保存処理
        @param  無し
        @retval 無し
        """
        if self.data is None:
            return
        wildcard = "Map (*.map)"
        # ファイル保存ダイアログを表示
        dlg = QtWidgets.QFileDialog(
            self, "Save a map file", expanduser("."), wildcard)
        dlg.setAcceptMode(QtWidgets.QFileDialog.AcceptSave)
        # パスを取得。
        if dlg.exec_():
            fileNames = dlg.selectedFiles()
            try:
                # シリアライズして書き込み
                self.SaveAsBin(fileNames[0])
            except PlotException as ex:
                PlotMessage(self, ex)

    #########################################
    def SaveAsBin(self, filename):
        """
        データファイルをバイナリ形式で保存処理
        @param  filename (string) ファイルのパス
        @retval 無し
        """
        root, ext = os.path.splitext(filename)
        if ext == "":
            filename = root + ".map"
        elif ext != ".map":
            raise PlotException('Common', 'C043', ("map",))
        try:
            # シリアライズして書き込み
            pickle.dump(self.data, open(filename, 'wb'))
        except:
            raise PlotException('Common', 'C018', (filename,))

    #########################################
    def OnSaveTxt(self):
        """
        データファイルをテキスト形式で保存処理
        @param  無し
        @retval 無し
        """
        if self.data is None:
            return
        wildcard = "Text (*.txt)"
        # ファイル保存ダイアログを表示
        dlg = QtWidgets.QFileDialog(
            self, "Save a text file", expanduser("."), wildcard)
        dlg.setAcceptMode(QtWidgets.QFileDialog.AcceptSave)
        # パスを取得。
        if dlg.exec_():
            fileNames = dlg.selectedFiles()
            try:
                # シリアライズして書き込み
                self.SaveAsTxt(fileNames[0])
            except PlotException as ex:
                PlotMessage(self, ex)

    #########################################
    def SaveAsTxt(self, filename):
        """
        データファイルをテキスト形式で保存処理
        @param  filename (string) ファイルのパス
        @retval 無し
        """
        root, ext = os.path.splitext(filename)
        if ext == "":
            filename = root + ".txt"
        elif ext != ".txt":
            raise PlotException('Common', 'C043', ("txt",))
        try:
            # テキストファイルを開く
            fw = codecs.open(filename, 'w', 'utf-8')
        except:
            raise PlotException('Common', 'C018', (filename,))
        # グラフのタイトルをコメントとして書き込む
        fw.write("# Title: " + self.params.title + os.linesep)
        # グラフのコメントを書き込む
        lines = self.params.comment.split('\n')
        if len(lines) > 0:
            fw.write("# Comment: " + lines[0] + os.linesep)
        if len(lines) > 1:
            fw.write("#          " + lines[1] + os.linesep)
        if len(lines) > 2:
            fw.write("#          " + lines[2] + os.linesep)

        # 行タイトル
        fw.write("#       X           Y         Int" + os.linesep)
        # データを展開
        Z, X, Y = self.data
        # テキストファイルに書き込み
        for i in range(len(Z[0])):
            for j in range(len(Z)):
                xx = (X[j][i] + X[j][i + 1]) / 2.0
                yy = (Y[j][i] + Y[j + 1][i]) / 2.0
                value = Z[j][i]
                if value >= MASKVALUE:
                    value *= 1.1
                line = "%.5e %.5e %.5e" % (xx, yy, value)
                fw.write(line + os.linesep)
            fw.write(os.linesep)
        fw.close()

    #########################################
    def closeEvent(self, event):
        """
        主ウィンドウクローズイベントハンドラ
        @param  event or 無し
        @retval 無し
        """
        logging.debug("D2Frame::closeEvent")
        try:
            # クローズ禁止が指定されていたなら
            if self.inhibitClose:
                raise PlotException('UGAO', 'U007', ())
        except PlotException as ex:
            PlotMessage(self, ex)
            return

        # MPlotクローズ
        for p in [self.mp_main, self.mp_top, self.mp_right]:
            if p is not None:
                p.Close()

        # 2次元プロッタフレームクローズイベント発行
        self.ifi.NotifyEvent(self, "u2dclosed")
        """
        # 自動指定のパラメータ群をデフォルトに戻す
        if self.params.autoRange:
            self.range = None
        self.params.relRange = 100
        if not self.params.hgrid:
            self.params.hgridInterval = None

        if not self.params.vgrid:
            self.params.vgridInterval = None

        self._BackDefault(self.params.xscale)
        self._BackDefault(self.params.yscale)
        # パラメータをファイルに保存
        try:
            pickle.dump(self.params, open(self.default_prms, 'wb'))
        except:
            pass
        """
        # プロッタクローズイベントを送信
        self.ifi.NotifyEvent(self, 'close_plot')
        # インターフェイスのクリア
        IFEvtProp(self.order).InitIF()

        # ダイアログクローズ
        self.sliceDg.close()
        self.rgDg.close()
        for _child in self.children():
            if isinstance(_child, ParamDialog):
                _child.close()

        # 画面のクローズ
        event.accept()
        logging.info("D2Frame closing")

    ###################################################
    def _BackDefault(self, scalePrm):
        """
        スケールパラメータの自動設定値をデフォルトに戻す
        @param scalePrm   スケールパラメータ
        @retval 無し
        """
        if scalePrm.autoRange:
            scalePrm.range = None
        if scalePrm.autoTick:
            scalePrm.format = 0
            scalePrm.precision = 3
            scalePrm.fontSize = 8

    #########################################
    def OnSliceParams(self, *args):
        """
        スライスパラメータダイアログを開く処理
        @param args
            メニュー選択時: eventSrc   イベント発生元インスタンス
                            evtType (str) 発生したイベントのタイプ
        @retval 無し
        """
        # スライスダイアログを開く
        self.sliceDg.show()

    #########################################
    def OnParams(self, *args):
        """
        パラメータダイアログを開く処理
        @param args
            メニュー選択時: eventSrc   イベント発生元インスタンス
                            evtType (str) 発生したイベントのタイプ
                            isY (bool) 表示軸がYであるか
            その他の場合: isY (bool) 表示軸がYであるか （任意）
        @retval 無し
        """
        if len(args) == 0:
            isY = False
        elif len(args) == 1:
            isY = args[0]
        else:
            if args[2]:
                isY = True
            else:
                isY = False
        # メニューが選択可であれば(パラメータダイアログが表示されていなければ)
        menu_params = self.findChild(QAction, "actionSet_View_Parameters")
        if menu_params.isEnabled():
            # メニューとボタンを選択不可とする
            self.ParamsEnable(False)
            # Get Window Size #[inamura 181112]
            self.GetWindowSizeParams()
            # パラメータダイアログを開く
            ParamDialog(self, isY, self.ParamsEnable)

    #########################################
    def GetWindowSizeParams(self):
        """
        [inamura 181112]
        [inamura 190724 updated]
        """
        if self.sliceMode:
            target = self.d2.DrawDic["MultiMode"]
            right_width, top_height = target["SubSize"]
            main_width, main_height = target["MainSize"]
            x_gap, y_gap = target["Gap"]
            left_pad, bottom_pad, right_pad, top_pad = target["Padding"]
            dpi = matplotlib.rcParams["figure.dpi"]
            self.params.window_size[0] = int(
                (self.fig.get_figwidth() * (1.0 - 0.1) - float(x_gap + right_width + right_pad)) * float(
                    dpi)) + 3  # 3 is magic number
            self.params.window_size[1] = int(
                (self.fig.get_figheight() * (1.0 - 0.1) - float(top_height + top_pad + y_gap)) * float(
                    dpi)) + 3  # 3 is magic number
        else:
            _canvas_size = self.canvas.size()
            target = self.d2.DrawDic["SingleMode"]
            self.params.window_size[0] = _canvas_size.width(
            ) * target["MainPosi"][2]
            self.params.window_size[1] = _canvas_size.height(
            ) * target["MainPosi"][3]

    #########################################
    def ParamsEnable(self, flag):
        """
        パラメータダイアログ起動可/不可設定処理
        @param  flag (bool)
        @retval 無し
        """
        # ニューを選択可/不可とする
        menu_params = self.findChild(QAction, "actionSet_View_Parameters")
        menu_params.setEnabled(flag)
        # ツールバーボタンを選択可/不可とする
        self.toolbar.btn_params.setEnabled(flag)

    #########################################
    def OnRegion(self, *args):
        """
        領域ダイアログを開く処理
        @param  イベントデータ(メニュー選択時) or 無し(その他の場合)
        @retval 無し
        """
        # メニューが選択可であれば(パラメータダイアログが表示されていなければ)
        if self.regionMenu.isEnabled():
            # メニューを選択不可とする
            self.regionMenu.setEnabled(False)
            self.rgDg.show()

    #########################################
    def RegionEnable(self, flag):
        """
        領域ダイアログ起動可/不可設定処理
        @param  flag (bool)
        @retval 無し
        """
        # メニューを選択 可/不可とする
        self.regionMenu.setEnabled(flag)

    #########################################
    def SetAutoAddRegion(self, flag):
        """
        領域指定マウスアップ時自動追加モード設定処理
        @param  flag (bool)
        @retval 無し
        """
        self.autoAddRegion = flag

    #########################################
    def SetInhibitClose(self, flag):
        """
        プロッタクローズの禁止モード設定処理
        @param  flag (bool)
        @retval 無し
        """
        self.inhibitClose = flag

    #########################################
    def OnOpenParams(self):
        """
        パラメータファイルを開く処理
        @param  無し
        @retval 無し
        """
        # ファイルを開くダイアログを表示
        dlg = QtWidgets.QFileDialog(
            self, "Open a parameter file", expanduser("."), "Parameter (*.upr)")
        dlg.setFileMode(QtWidgets.QFileDialog.ExistingFile)
        # パスを取得。
        if dlg.exec_():
            fileNames = dlg.selectedFiles()
            try:
                try:
                    self.params = U2Params()
                    _params = pickle.load(open(fileNames[0], "rb"))
                    for a_key in ["BottomSide", "TopSide", "LeftSide", "RightSide"]:
                        if type(_params.TickStyleDic[a_key]) == str:
                            if _params.TickStyleDic[a_key] == "on":
                                _params.TickStyleDic[a_key] = True
                            else:
                                _params.TickStyleDic[a_key] = False
                    self.params.__dict__.update(_params.__dict__)
                    self.params.TickStyleDic = _params.TickStyleDic.copy()
                except:
                    raise PlotException('Common', 'C006', (fileNames[0],))
                else:
                    # パラメータ変更通知
                    self.ifi.NotifyEvent(self, 'change_params')
            except PlotException as ex:
                PlotMessage(self, ex)

    #########################################
    def OnSaveParams(self):
        """
        パラメータファイル保存処理
        @param  無し
        @retval 無し
        """
        dlg = QtWidgets.QFileDialog(
            self, "Save a parameter file", expanduser("."), "Parameter (*.upr)")
        dlg.setAcceptMode(QtWidgets.QFileDialog.AcceptSave)
        # パスを取得。
        if dlg.exec_():
            fileNames = dlg.selectedFiles()
            path = fileNames[0]
            root, ext = os.path.splitext(path)
            if ext != ".upr":
                path = root + ".upr"
            try:
                try:
                    # シリアライズして書き込み
                    for a_key in ["BottomSide", "TopSide", "LeftSide", "RightSide"]:
                        if type(self.params.TickStyleDic[a_key]) == str:
                            if self.params.TickStyleDic[a_key] == "on":
                                self.params.TickStyleDic[a_key] = True
                            else:
                                self.params.TickStyleDic[a_key] = False
                    pickle.dump(self.params, open(path, 'wb'))
                except:
                    raise PlotException('Common', 'C018', (path,))
            except PlotException as ex:
                PlotMessage(self, ex)

    #########################################
    def OnShowAll(self):
        """
        領域全表示処理
        @param  event イベントデータ
        @retval 無し
        """
        # ツールバーのボタンを変更
        self.toolbar.SetShowBtn(True)

    #########################################
    def OnNotifyShowAll(self, wid, evt, flag):
        """
        ツールバーからの領域表示/非表示切替メッセージ
        @param  wid イベント発生元
        @param  evt イベントデータ
        @param  flag True or False
        @retval 無し
        """
        self.ShowFlag = flag
        # 領域ダイアログのチェックを全て変更
        self.rgDg.regTable.ToggleAllCheckBox(flag)
        # メニューのチェックを全て変更
        actions = self.viewMenu.actions()
        for a in actions[2:]:  # ３番目以降が各領域のAction
            a.setChecked(flag)

    ###################################################
    def OnNotifyChangeData(self, eventSrc, evtType, data):
        """
        データ変更メッセージ処理
        @param eventSrc   イベント発生元インスタンス
        @param  evtType (str) 発生したイベントのタイプ
        @param  data (tpl(array, array,array) ) 表示データ
        @retval 無し
        """
        self.data = data
        if self.d2 is None:
            # マップの描画
            self.d2 = D2Chart(self, self.canvas, data)
            self.d2.DrawRegions()
            self.canvas.draw()
        else:
            self.d2.ChangeData(data)

    #########################################
    def CalcLogScaleValueFromEvent(self, scaleParam, val):
        """
        与えた軸のマウス位置情報からデータ座標を返す
        リニアスケールならeventの値をそのまま利用できるが、ログスケールでもリニアの値が戻ってくるため変換する必要がある
        @param scalParam ScaleParamsインスタンス
        @param val マウス位置座標 (event.xdata or event.ydata)
        @retval (float) マウスのデータ座標
        """
        # 軸はログスケールなら、マウス位置からログスケールでのデータ値に変換
        if scaleParam.logScale:
            # 軸の範囲を取得し
            vmin, vmax = scaleParam.range
            # 与えられた値の場所の比率を計算し
            alpha = (val - vmin)/(vmax - vmin)
            # ログスケールでの値へ換算を比率を用いて求める
            vmin2 = math.log10(vmin)
            vmax2 = math.log10(vmax)
            val2 = vmin2 + alpha * (vmax2 - vmin2)
            return 10**(val2)
        # ログスケールでなければそのまま返す
        else:
            return val

    #########################################
    def PutMousePointInfo(self, event):
        """
        マウス位置情報作成
        @param   event イベント情報
        @retval (str) マウス位置情報
        """
        strTx = ""
        # データ無しなら
        if self.d2 is None:
            return strTx

        # マウス位置がグラフ内かどうかをチェック
        if event.inaxes:
            # グラフ内であっても、None が来ることがあるのでプロテクト
            if (event.ydata is not None) and (event.xdata is not None):
                # マウス位置における強度データを取得
                gid = event.inaxes.get_gid()
                if gid is None:
                    # それぞれの軸のマウス位置情報をデータ座標に変換
                    xval = self.CalcLogScaleValueFromEvent(self.params.xscale, event.xdata)
                    yval = self.CalcLogScaleValueFromEvent(self.params.yscale, event.ydata)
                    # intValue = self.d2.GetIntValue(event.xdata, event.ydata)
                    intValue = self.d2.GetIntValue(xval, yval)
                    strInt = "---"
                    if intValue is not None:
                        strInt = "%.3f" % intValue
                    if self.params.transPosition:
                        strTx = "X1={0:.4f}    Y1={1:.4f}    Int= {2}".format(
                            yval, xval, strInt)
#                            event.ydata, event.xdata, strInt)
                    else:
                        strTx = "X2={0:.4f}    Y2={1:.4f}    Int= {2}".format(
                            xval, yval, strInt)
#                            event.xdata, event.ydata, strInt)
                else:
                    strTx = "X={0:.4f}    Y={1:.4f}".format(
                        event.xdata, event.ydata)

                # ドラッグ中か
                if self.dragFlag:
                    # 領域名を取得
                    if self.sliceMode:
                        rname = "Rectangle"
                    else:
                        rname = self.rgDg.GetSelectedRegion()
                    # 指定領域がポイント以外なら
                    if rname != 'Point' and self.d2 is not None:
                        # 領域情報を計算
                        values = self._MakeValues(
                            rname, event.xdata, event.ydata)
                        if values is not None:
                            # 領域カーソルを表示
                            self.d2.ShowDragCursol(rname, values)
        return strTx

    #########################################
    def OnMouseMove(self, event):
        """
        マウス-ポインタ移動イベント処理
        @param   event イベント情報
        @retval 無し
        """
        strTx = self.PutMousePointInfo(event)
        # マウス位置情報表示
        self.infotxt.showMessage(strTx)

    #########################################
    def _MakeValues(self, rname, xx, yy):
        """
        領域データ作成
        Parameters:
            rname  領域名
            xx  x値
            yy  y値
        Returns:
            領域データ
        """
        # プロッタ範囲外でmouse-downされていた時は戻る
        if self.downP is None:
            return
        values = [self.downP[0], self.downP[1]]
        if rname == "Line" or rname == "Rectangle":
            values.append(xx)
            values.append(yy)
            # if rname == "Line":
            #    width = self.d2.GetDefaultWidth()
            #    values.append(width)
        else:
            x2 = (xx - self.downP[0]) * (xx - self.downP[0])
            y2 = (yy - self.downP[1]) * (yy - self.downP[1])
            # 半径を計算
            r = math.sqrt(x2 + y2)
            if r == 0.0:
                return None
            values.append(r)
            if rname == "Ring" or rname == "Ring Sector":
                # 内径を設定
                values.append(r / 4.0)
            if rname == "Sector" or rname == "Ring Sector":
                if rname == "Sector":
                    values.append(None)
                ydif = yy - self.downP[1]
                xdif = xx - self.downP[0]
                # マウス位置を中心に±45度を計算
                if xdif == 0.0:
                    return None
                if abs(ydif) > 0.0:

                    rtheta = math.atan(ydif / xdif)
                    theta = rtheta * 180.0 / math.pi
                    if xdif < 0.0:
                        theta += 180
                else:
                    if xdif > 0:
                        theta = 0.0
                    else:
                        theta = 180.0
                if theta < 0.0:
                    theta += 360.0
                values.append(theta)
                values.append(45.0)

        return values

    #########################################
    def OnMouseDown(self, event):
        """マウス-ボタンクリックイベント処理

        Parameters:
            event (MouseEvent): イベント情報
        """
        # パン処理中またはズーム処理中であれば、以下の処理を実行しない
        if MATPLOTLIB_VER < NAVIGATIONTOOLBAR_CHANGED_VER:
            if self.toolbar._active == 'PAN' or self.toolbar._active == 'ZOOM':
                return
        else:
            if self.toolbar._actions['pan'].isChecked() or self.toolbar._actions['zoom'].isChecked():
                return

        self.mdownTime = time.time()

        # グラフ範囲内か
        if event.inaxes:
            ax = event.inaxes  # 呼び出しAxes
            gid = ax.get_gid()  # 呼び出しAxesのGroup ID。ax_top or ax_right
            self.downP_gid = gid  # どのグラフなのかを記憶しておく
            if gid is not None:
                return
            if event.dblclick and (not self.sliceMode):
                # 領域ダイアログを表示
                self.OnRegion()
                return
            # 左クリック
            if event.button == 1:
                # マウスクリック点のデータを保存
                self.downP = (event.xdata, event.ydata)
                # ドラッグ開始
                self.dragFlag = True
                return
            elif event.button == 3:
                # マウスクリック点のデータを保存
                self.downP = (event.xdata, event.ydata)
                # 右クリックはドラッグにしない
                self.dragFlag = False
                return
        else:
            # ダブルクリックか
            if event.dblclick:
                # スケールラベル付近のダブルクリックであれば
                canvas_size = self.canvas.size()
                xx = event.x * 1.0 / canvas_size.width()
                yy = event.y * 1.0 / canvas_size.height()
                # 縦軸ラベルのダブルクリックであれば
                if self.sliceMode:
                    main_posi = self.d2.DrawDic["MultiMode"]["MainPosi"]
                else:
                    main_posi = self.d2.DrawDic["SingleMode"]["MainPosi"]
                if xx < main_posi[0] and yy > main_posi[1] and yy < main_posi[3]:
                    # パラメータダイアログを開く
                    self.OnParams(True)
                # 横軸ラベルのダブルクリックであれば
                elif yy < main_posi[1] and xx > main_posi[0] and xx < main_posi[2]:
                    # パラメータダイアログを開く
                    self.OnParams()
            # グラフ枠外なので、downPは指定なし（消去）
            self.downP = None

    #########################################
    def OnMouseUp(self, event):
        """
        マウス-ボタンアップイベント処理
        @param   event イベント情報
        @retval 無し
        """
        # ドラッグ中(マップ内でボタン押下された)か
        if self.dragFlag:
            # ドラッグ終了
            self.dragFlag = False

        # データ無しなら
        if self.d2 is None:
            return

        # パン処理中またはズーム処理中であれば、以下の処理を実行しない
        if MATPLOTLIB_VER < NAVIGATIONTOOLBAR_CHANGED_VER:
            if self.toolbar._active == 'PAN' or self.toolbar._active == 'ZOOM':
                return
        else:
            if self.toolbar._actions['pan'].isChecked() or self.toolbar._actions['zoom'].isChecked():
                # matplotlib 3.9以上では,パン・ズーム処理中であればプロッタの範囲を追随させる必要があるため
                if MATPLOTLIB_VER >= "030900":
                    self.d2.ax.set_xlim(self.d2.regAxes.get_xlim())
                    self.d2.ax.set_ylim(self.d2.regAxes.get_ylim())
                return

        if self.mdownTime is None:
            return

        # ボタンを押してから、放すまでの時間を取得
        mtime = time.time() - self.mdownTime

        # グラフ範囲内か
        if event.inaxes:
            ax = event.inaxes  # 呼び出しAxes
            gid = ax.get_gid()  # 呼び出しAxesのGroup ID。ax_top or ax_right

            # if gid is not None:
            #    return

            # クリックか
            if mtime < 0.2:
                # 右クリックでMPlot呼び出し
                if event.button == 3:
                    if gid is None:  # メインプロッタ内なら
                        self.OnContextMenu(event)
                        return
                    else:  # サブプロッタ内なら
                        self.OnContextMenuSide(event)
                        return

                # マウスアップメッセージ送信
                msg = (self.params.transPosition,
                       event.xdata, event.ydata, None, None)
                self.ifi.NotifyEvent(self, 'mouse_up', msg)
                # 選択中の領域に、x0,y0設定
                self.SetPointValues(event)

                # Clear last clicked point
                self.last_clicked_point = None
                # print("#[inamura 190222] set self.last_clicked_point to None")

                if self.sliceMode:
                    # メインプロッタでなければ何もせずに戻る
                    if gid is not None:
                        self.d2.canvas.draw()
                        return
                    self.ifi.NotifyEvent(
                        self, 'slice', [event.xdata, event.ydata])
                    self.last_clicked_point = [
                        event.xdata, event.ydata]  # Set Only click
                    # print("#[inamura 190222] set clicked point ")
                else:
                    rname = self.rgDg.GetSelectedRegion()
                    # 指定領域がポイントであれば
                    if rname == 'Point' and self.autoAddRegion:
                        # [inamura 220719]
                        self.ifi.NotifyEvent(self, 'add_region_from_dlg')
                        pass
            else:
                # ドラッグであれば
                # Clear last clicked point
                self.last_clicked_point = None
                # print("#[inamura 190222] set self.last_clicked_point to None")
                # グラフ外から始まるドラッグの場合は何もせず戻る
                # どのグラフからでもない:self.downP=None, 別のグラフから:self.downP_gid is not None
                if self.downP is None or self.downP_gid is not None:
                    if self.sliceMode:
                        self.d2.canvas.draw()
                    return
                # マウスアップメッセージ送信
                msg = (self.params.transPosition,
                       self.downP[0], self.downP[1], event.xdata, event.ydata)
                self.ifi.NotifyEvent(self, 'mouse_up', msg)

                if self.sliceMode:
                    # メインプロッタでなければ無効なのでスライスせずに戻る
                    if gid is not None:
                        # 選択領域再表示（元の選択領域へ戻す）
                        # self.d2.DrawRegions()
                        self.sliceDg.OnApply()
                        self.d2.canvas.draw()
                        return
                    if event.button == 3:
                        pass
                    else:
                        # 領域の数値情報作成
                        values = self._MakeValues(
                            "Rectangle", event.xdata, event.ydata)
                        self.ifi.NotifyEvent(self, 'slice', values)
                        self._last_slice_drag_values = values[:]
                else:
                    rname = self.rgDg.GetSelectedRegion()
                    # 指定領域がポイントであれば
                    if rname == 'Point':
                        # 選択中の領域に、x0,y0設定
                        self.SetPointValues(event)
                    else:
                        # 領域の数値情報作成
                        values = self._MakeValues(
                            rname, event.xdata, event.ydata)
                        self.d2.ShowDragCursol(rname, values)
                        # 軸の転置が指定されていれば
                        if self.params.transPosition:
                            # X値とY値の入れ替え
                            self.d2.TransPosition(rname, values)
                        self.rgDg.SetValues(values)
                    if self.autoAddRegion:
                        # [inamura 220719]
                        self.ifi.NotifyEvent(self, 'add_region_from_dlg')
                        # 選択領域再表示（カーソル消去）
                        self.d2.DrawRegions()
                        self.d2.canvas.draw()
        # グラフ範囲外でマウスアップした場合
        else:
            """ カーソル消去ボタンを付け不要になった
            # かつスライスモードなら
            if self.sliceMode:
                # 選択領域再表示（カーソル消去）
                self.d2.DrawRegions()
                self.d2.canvas.draw()
            """
            # マウスダウンがメイングラフ内の場合（ドラッグ）、無効とする（スライスモード なら元の選択領域へ戻す）
            if self.downP is not None and self.downP_gid is None:
                if self.sliceMode:
                    self.sliceDg.OnApply()
                else:
                    self.d2.DrawRegions()
                self.d2.canvas.draw()

        self.beforeTime = self.mdownTime

    #########################################
    def SetPointValues(self, event):
        """
        指定点のデータを領域ダイアログに設定
        @param  event  マウスイベント
        @retval 無し
        """
        # 軸の転置が指定されているか
        if self.params.transPosition:
            self.rgDg.SetValues((event.ydata, event.xdata))
        else:
            self.rgDg.SetValues((event.xdata, event.ydata))

    ###################################################
    def SetSliceRegionToDialog(self, data):
        """
        マウス操作指定のスライス領域をスライス設定ダイアログに反映
        """
        if len(data) == 2:
            self.sliceDg.findChild(QtWidgets.QLineEdit, "txt_y_center").setText(
                "{0:.3f}".format(data[1]))
            self.sliceDg.findChild(QtWidgets.QLineEdit,
                                   "txt_y_width").setText("0.0")
            self.sliceDg.findChild(QtWidgets.QLineEdit, "txt_y_start").setText(
                "{0:.3f}".format(data[1]))
            self.sliceDg.findChild(QtWidgets.QLineEdit, "txt_y_end").setText(
                "{0:.3f}".format(data[1]))
            self.sliceDg.findChild(QtWidgets.QLineEdit, "txt_x_center").setText(
                "{0:.3f}".format(data[0]))
            self.sliceDg.findChild(QtWidgets.QLineEdit,
                                   "txt_x_width").setText("0.0")
            self.sliceDg.findChild(QtWidgets.QLineEdit, "txt_x_start").setText(
                "{0:.3f}".format(data[0]))
            self.sliceDg.findChild(QtWidgets.QLineEdit, "txt_x_end").setText(
                "{0:.3f}".format(data[0]))
            self.sliceDg.last_data[0] = [data[0], 0.0]
            self.sliceDg.last_data[1] = [data[0], data[0]]
            self.sliceDg.last_data[2] = [data[1], 0.0]
            self.sliceDg.last_data[3] = [data[1], data[1]]
            self.params.mouseDragPath = [
                [data[0], data[1]], [data[0], data[1]]]
        else:
            x0, y0, x1, y1 = data
            self.params.mouseDragPath = [[x0, y0], [x1, y1]]
            if x0 > x1:
                x0, x1 = x1, x0
            if y0 > y1:
                y0, y1 = y1, y0
            center = (y0 + y1) * 0.5
            self.sliceDg.findChild(QtWidgets.QLineEdit, "txt_y_center").setText(
                "{0:.3f}".format(center))
            width = (y1 - y0) * 0.5
            self.sliceDg.findChild(QtWidgets.QLineEdit, "txt_y_width").setText(
                "{0:.3f}".format(width))
            self.sliceDg.findChild(QtWidgets.QLineEdit, "txt_y_start").setText(
                "{0:.3f}".format(y0))
            self.sliceDg.findChild(QtWidgets.QLineEdit, "txt_y_end").setText(
                "{0:.3f}".format(y1))
            self.sliceDg.last_data[2] = [center, width]
            self.sliceDg.last_data[3] = [y0, y1]
            center = (x0 + x1) * 0.5
            self.sliceDg.findChild(QtWidgets.QLineEdit, "txt_x_center").setText(
                "{0:.3f}".format(center))
            width = (x1 - x0) * 0.5
            self.sliceDg.findChild(QtWidgets.QLineEdit, "txt_x_width").setText(
                "{0:.3f}".format(width))
            self.sliceDg.findChild(QtWidgets.QLineEdit, "txt_x_start").setText(
                "{0:.3f}".format(x0))
            self.sliceDg.findChild(QtWidgets.QLineEdit, "txt_x_end").setText(
                "{0:.3f}".format(x1))
            self.sliceDg.last_data[0] = [center, width]
            self.sliceDg.last_data[1] = [x0, x1]

    #########################################
    def OnXYlimChanged(self, axes):
        """XY軸変更コールバック関数

        Parameters:
            axes (matplotlib.axes.Axes)
        """
        params = self.ifi.GetProperty('params')
        if params.transPosition:
            params.xscale.range = list(axes.get_ylim())
            params.yscale.range = list(axes.get_xlim())
        else:
            params.xscale.range = list(axes.get_xlim())
            params.yscale.range = list(axes.get_ylim())
        self.ifi.NotifyEvent(self, 'change_displayed_params')

    #########################################
    def OnHideAll(self):
        """
        領域全表示処理
        @param  event イベントデータ
        @retval 無し
        """
        # ツールバーのボタンを変更
        self.toolbar.SetShowBtn(False)



def call_ndarray_slice(eventSrc, eventType, values):
    """
    マウスイベントからのndarrayスライスコールバック関数
    Parameters:
        eventSrc (Object): イベント発生元インスタンス
        eventType (str): 発生したイベントのタイプ
        values list[float, float] or list[float, float, float, float]:
            座標(x, y) or (x0, y0, x1, y1)
        values list[float, float, bool] or list[float, float, float, float, bool]
            座標(x, y, ave_mode) or (x0, y0, x1, y1, ave_mode)
    """
    logging.info('numpy slice')

    slice_ave_mode = True
    if len(values) == 3:
        if type(values[2]) == bool:
            slice_ave_mode = values[2]
        values = values[:-1]
    if len(values) == 5:
        if type(values[4]) == bool:
            slice_ave_mode = values[4]
        values = values[:-1]

    if len(values) == 4:
        if values[0] > values[2]:
            values[0], values[2] = values[2], values[0]
        if values[1] > values[3]:
            values[1], values[3] = values[3], values[1]

    # 表示軸ndarray取り出し
    xbin = eventSrc.data[1][0]
    ybin = eventSrc.data[2].T[0]
    plot_index_x0 = np.searchsorted(xbin, values[0]) - 1  # xbinでのindex
    plot_index_y0 = np.searchsorted(ybin, values[1]) - 1  # ybinでのindex
    if len(values) == 4:
        plot_index_x1 = np.searchsorted(xbin, values[2]) - 1  # xbinでのindex
        plot_index_y1 = np.searchsorted(ybin, values[3]) - 1  # ybinでのindex
    else:
        plot_index_x1 = plot_index_x0  # xbinでのindex
        plot_index_y1 = plot_index_y0  # ybinでのindex

    # Y - Intensity
    sliced = np.zeros(len(ybin) - 1)
    cnt = 0
    for i, l in enumerate(eventSrc.data[0]):
        if len(values) == 2 or (plot_index_x1 - plot_index_x0) == 0:
            sliced[i] = l[plot_index_x0]
        else:
            for j in range(plot_index_x0, plot_index_x1 + 1):
                sliced[i] += l[j]
                cnt += 1
    sliced = np.ma.masked_where(sliced >= MASKVALUE, sliced)
    if slice_ave_mode and (cnt != 0):
        sliced = sliced / float(cnt)
    if len(eventSrc.d2.ax_right.lines) == 0:
        eventSrc.d2.ax_right.plot(sliced, reduce_bin(ybin))
    else:
        eventSrc.d2.ax_right.lines[0].set_ydata(reduce_bin(ybin))
        eventSrc.d2.ax_right.lines[0].set_xdata(sliced)
        eventSrc.d2.ax_right.set_xlim(min(sliced), max(sliced))
    eventSrc.d2.ax_right.set_ylim(eventSrc.d2.ax.get_ylim())
    # X - Intensity
    cnt = 0
    if len(values) == 2 or (plot_index_y1 - plot_index_y0 == 0):
        sliced = eventSrc.data[0][plot_index_y0]
    else:
        sliced = np.zeros(len(xbin) - 1)
        for i, l in enumerate(eventSrc.data[0].T):
            for j in range(plot_index_y0, plot_index_y1 + 1):
                sliced[i] += l[j]
                cnt += 1
    sliced = np.ma.masked_where(sliced >= MASKVALUE, sliced)
    if slice_ave_mode and (cnt != 0):
        sliced = sliced / float(cnt)
    if len(eventSrc.d2.ax_top.lines) == 0:
        eventSrc.d2.ax_top.plot(reduce_bin(xbin), sliced)
    else:
        eventSrc.d2.ax_top.lines[0].set_xdata(reduce_bin(xbin))
        eventSrc.d2.ax_top.lines[0].set_ydata(sliced)
        eventSrc.d2.ax_top.set_ylim(min(sliced), max(sliced))
    eventSrc.d2.ax_top.set_xlim(eventSrc.d2.ax.get_xlim())
    eventSrc.canvas.draw()


def reduce_bin(b):
    """ビンの中央値リストを返す

    Parameters:
        b (list)

    Returns:
        (list)
    """
    lft = b[:-1]
    rgt = b[1:]
    return [(i + j) / 2.0 for i, j in zip(lft, rgt)]


def _main(args):
    import numpy as np
    FORMAT = "%(asctime)s: %(message)s"
    DATE_FORMAT = "%Y-%m-%d %H:%M:%S"
    logging.basicConfig(format=FORMAT, datefmt=DATE_FORMAT,
                        level=logging.DEBUG)
    # テストパターン作成
    h = np.arange(1.0, 10.0, 1.0)
    v = np.arange(21.0, 30.0, 1.0)

    numh = len(h) - 1
    numv = len(v) - 1
    # グリッド作成
    H, V = np.meshgrid(h, v)

    data = np.zeros((numv, numh), float64)

    data[0, 3] = 200.4
    data[0, 4] = 500.8
    data[0, 5] = 300.0
    data[1, 1] = 800.1
    data[1, 3] = 400.5
    data[1, 4] = 1000.0
    data[1, 5] = 600.0
    data[1, 7] = 700.0
    data[2, 4] = 100.5
    data[3, 0] = 520.8
    data[3, 3] = 400.0
    data[3, 4] = 200.5
    data[3, 5] = 300.5
    data[4, 1] = 237.5
    data[4, 6] = 45.3
    data[5, 2] = 600.3
    data[6, 0] = 200.5
    data[6, 4] = 100.8
    data[7, 6] = 900.0
    data[3, 2] = MASKVALUE
    data[7, 2] = MASKVALUE
    # Hi-resolution Display for windows
    if hasattr(QtCore.Qt, 'AA_EnableHighDpiScaling'):
        QtWidgets.QApplication.setAttribute(
            QtCore.Qt.AA_EnableHighDpiScaling, True)
    app = QtWidgets.QApplication(args[:])
    # Set Default Font Size to (default 14)
    deffont = app.font()
    if "UTSUSEMI_DEFAULT_FONTSIZE" in os.environ:
        deffontsize = int(os.environ["UTSUSEMI_DEFAULT_FONTSIZE"])
        deffont.setPointSize(deffontsize)
    else:
        deffont.setPointSize(10)
    app.setFont(deffont)
    main_window = D2Frame(None, (data, H, V))
    # main_window = D2Frame(None)
    main_window.show()
    if PYSIDEVER == 6:
        sys.exit(app.exec())
    else:
        sys.exit(app.exec_())


if __name__ == '__main__':
    _main(sys.argv[1:])
