#!/usr/bin/python
# -*- coding: utf-8 -*-
"""
M2PlotPlus
"""
from __future__ import print_function
from uGao.uGaoUtil import STRING_TO_REPLACE_SPACE, STRING_TO_REPLACE_LF, MASKVALUE
import uGao.M2PlotPlus_rc
import uGao.M2PlotPlusCui as m2cui
from uGao.QtCom import QtApp
import uGao.MPlot as mp
import numpy as np
from os.path import expanduser
from uGao.u2dplot import call_ndarray_slice
from uGao import U2IF
from uGao.uGaoUtil import IFEvtProp, Validator, PlotException, MessageFile, PlotMessage, TempFile, MATPLOTLIB_VER
import sys
import os
import platform
import logging
import logging.handlers
import datetime
import Manyo
import Manyo.MLF as mm
from matplotlib.patches import (Rectangle,)
# from uGao.ui_M2PlotPlus import Ui_MainWindow, Ui_DlgSaveAsText
PYSIDEVER = 1
try:
    from PySide6 import QtCore, QtGui, QtWidgets
    from PySide6.QtGui import QAction
    PYSIDEVER = 6
except:
    try:
        from PySide2 import QtCore, QtGui, QtWidgets
        from PySide2.QtWidgets import QAction
        PYSIDEVER = 2
    except:
        from PySide import QtCore, QtGui
        import PySide.QtGui as QtWidgets
        from PySide.QtGui import QAction

if QtCore.__version__ < '5.0.0':
    from uGao.ui_M2PlotPlus import Ui_MainWindow, Ui_DlgSaveAsText
else:
    if PYSIDEVER == 2:
        from uGao.ui2_M2PlotPlus import Ui_MainWindow, Ui_DlgSaveAsText
    elif PYSIDEVER == 6:
        from uGao.ui6_M2PlotPlus import Ui_MainWindow, Ui_DlgSaveAsText


__author__ = "ITO, Takayoshi (CROSS)"
__version__ = "19.03.10b"
__date__ = "7th Aug. 2019"
EPCILON = 1.0e-15
#########################################
#       SetSaveAsTextDialog
#########################################


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

    def __init__(self, parent):
        """
        コンストラクタ
        @param  parent   親ウィンドウのID
        @retval 無し
        """
        self.ifi = IFEvtProp(parent.order_plotter)
        self.parent = parent

        # リソース取得
        super(SetSaveAsTextDialog, self).__init__(parent)
        self.ui = Ui_DlgSaveAsText()
        if self.ui is None:
            return
        self.ui.setupUi(self)
        # アイコンを設定
        # self.dialog.SetIcon(Images().GetMainIcon())

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

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

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

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

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

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

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

        # Get GUI control
        self.ckIgnoreMask = self.findChild(QtWidgets.QCheckBox, 'ckIgnoreMask')
        self.txQbin = self.findChild(QtWidgets.QLineEdit, 'txQbin')
        self.stQbin = self.findChild(QtWidgets.QLabel, 'stQbin')

        # Set Values
        self.initialize()

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

    ##########################################################
    def initialize(self):
        """
        初期化
        @param None
        @retval None
        """
        self.isIgnoreMask = False
        self.useGivenMaskVal = False
        self.ckIgnoreMask.setChecked(False)
        self.chMaskVal.setEnabled(True)
        self.chMaskVal.setCurrentIndex(3)
        self.txMaskVal.setEnabled(False)
        if self.parent.converter.isInelasticPowder:
            self.txQbin.setEnabled(True)
            self.stQbin.setEnabled(True)
        else:
            self.txQbin.setEnabled(False)
            self.stQbin.setEnabled(False)
        return

    ##########################################################
    def OnIgnoreMask(self):
        """
        IgnoreMask チェックボックスイベント処理
        @param  None
        @retval None
        """
        # チェックされたのか
        self.isIgnoreMask = self.ckIgnoreMask.isChecked()
        if self.isIgnoreMask:
            # MaskValue テキストボックスを選択不可
            self.chMaskVal.setEnabled(False)
            self.txMaskVal.setEnabled(False)
        else:
            self.chMaskVal.setEnabled(True)
            self.txMaskVal.setEnabled(False)
            index = self.chMaskVal.currentIndex()
            if index == 0:
                self.txMaskVal.setEnabled(True)

    ##########################################################
    def OnMaskVal(self):
        """
        MaskValコンボボックスイベント処理
        @param None
        @retval None
        """
        self._CtrlParts(True)

    ##########################################################
    def OnSave(self):
        """
        テキスト保存ボタンが押された場合の処理
        @param None
        @retval None
        """
        self._CtrlParts(False)
        maskval = 0.0
        if (not self.isIgnoreMask) and self.useGivenMaskVal:
            try:
                maskval = float(self.txMaskVal.text())
            except:
                msg = "Given Mask Value is invalid (%s)" % (
                    self.txMaskVal.text())
                dial = QtWidgets.QMessageBox().warning(
                    self, u"Warning", msg, QtWidgets.QMessageBox.Ok)
                self._CtrlParts(True)
                return
        dQ = 0.0
        if self.parent.converter.isInelasticPowder:
            try:
                dQ = float(self.txQbin.text())
            except:
                msg = "Given Q-bin Value is invalid (%s)" % (
                    self.txQbin.text())
                dial = QtWidgets.QMessageBox().warning(
                    self, u"Warning", msg, QtWidgets.QMessageBox.Ok)
                self._CtrlParts(True)
                return

        maskinfo = [self.useGivenMaskVal, maskval]
        wildcard = "Text (*.txt)"
        # ファイル保存ダイアログを表示
        dlg = QtWidgets.QFileDialog(
            self, "Save data as text file", expanduser("."), wildcard)
        dlg.setAcceptMode(QtWidgets.QFileDialog.AcceptSave)
        # パスを取得。
        if dlg.exec_():
            fileName = dlg.selectedFiles()
            if fileName[0] != "":
                fileNamePath = fileName[0]
                if fileNamePath[-4:] != ".txt":
                    fileNamePath += ".txt"
                FIO = M2PlotPlusTextFileIO(self.parent)
                FIO.Save(fileNamePath, dQ, self.isIgnoreMask, maskinfo)
                self.OnCancel()

        self._CtrlParts(True)

    ##########################################################
    def _CtrlParts(self, isEnable=True):
        """
        ダイアログ内のパーツのオンオフ
        @param isEnable (bool) True なら設定に合わせてオン、Falseなら全てオフ
        @retval None
        """
        if not (isEnable in [True, False]):
            return

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

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

    def OnCancel(self):
        """
        Cancel ボタンイベント処理
        @param  None
        @retval None
        """
        self.close()

#########################################
#       M2PlotPlusTextFileIO
#########################################


class M2PlotPlusTextFileIO(object):
    """
    M2PlotやM2PlotPlus用のデータ保存用テキストファイルのIOクラス
    """
    ##########################################################

    def __init__(self, parent):
        # 各種初期化
        self.parent = parent
        self.XRANGE = "XRANGE"
        self.YRANGE = "YRANGE"
        self.XKEY = "XKEY"
        self.YKEY = "YKEY"
        self.XUNIT = "XUNIT"
        self.YUNIT = "YUNIT"
        self.MASKVALUE = "MASKVALUE"
        self.XLABEL = "XLABEL"
        self.YLABEL = "YLABEL"
        self.TITLE = "Title"
        self.COMMENT = "Comment"
        from datetime import datetime as dt
        self.HEADER = "## M2Plot+ Output (%s)\n"
        self.DATATITLE = "## X,Y,Intensity,Error"

    ##########################################################
    def Save(self, filename, dQ=0.0, isIgnoreMask=False, maskinfo=[False, 0.0]):
        """
        テキスト保存用メソッド
        @param filename (str) 保存先のフルパス
        @param dQ (float) 非弾性散乱粉末データ用の運動量軸のbin幅
        @param isIgnoreMask (bool) 強度がMASKVALUEだった時に、その点を書き出すかどうか
        @param maskinfo (list) MASKVALUEの値をどうするかを決める [<bool>,<float>] bool : Trueのとき float の値を使用、bool : Falseのとき本来のMASKVALUEを使用
        @retval None
        """
        self.params = self.parent.ifi.GetProperty('params')
        # fd = open( filename,'w' )
        try:
            fd = open(filename, 'w')
        except:
            msg = "SaveAsText : failed to open file = %s" % (filename)
            raise UserWarning(msg)

        # プロットされたbinデータを取り出し
        xbin = self.parent.u2.plot.data[1][0]
        ybin = self.parent.u2.plot.data[2].T[0]

        # キーの取り出し
        _ykey = self.parent.converter.ykey
        _xkey = self.parent.converter.xkey

        # クリップ範囲の初期化
        clip_region = [0.0, 0.0, 0.0, 0.0]

        # データは非弾性散乱粉末データか？
        if self.parent.converter.isInelasticPowder:
            # キーはデフォルト
            _xkey = "Q"
            _ykey = "hw"
            # スライス関数の取り出しとスライス領域のクリア
            clip = self.parent.converter.arraySlicer
            clip.ClearClipRegion()

            # dQの設定（Q範囲はデータ内最大範囲）
            clip.SetQbin(dQ, -1.0, -1.0)

            # ybin （Energy軸）で区切ってスライス設定
            for i in range(len(ybin) - 1):
                clip_region[0] = -1.0
                clip_region[1] = ybin[i]
                clip_region[2] = -1.0
                clip_region[3] = ybin[i + 1]
                clip.SetClipRegion(*clip_region)

            # スライスの実行＆結果を取り出す
            ret_eca = clip.CutAlongX(True)

        else:
            # DetectMapモードなら
            # if self.parent.isDetMapMode:
            # データがElementContainerMatrixなら
            if isinstance(self.parent.data, Manyo.ElementContainerMatrix):
                data = self.parent.converter._eca
            else:
                data = self.parent.data

            # 非弾性散乱粉末データのスライスデータの構造に合わせてArrayの構造を変換する
            ret_eca = Manyo.ElementContainerArray()
            num_of_y = len(data(0).PutXList()) - 1

            II = []
            EE = []
            for i in range(data.PutSize()):
                II.append(data(i).PutYList())
                EE.append(data(i).PutEList())

            for i in range(num_of_y):
                ii = []
                ee = []
                for j in range(len(II)):
                    ii.append(II[j][i])
                    ee.append(EE[j][i])
                ec = Manyo.ElementContainer()
                ec.Add("X", xbin.tolist())
                ec.Add("I", ii)
                ec.Add("E", ee)
                ec.SetKeys("X", "I", "E")
                ret_eca.Add(ec)

        XX = ret_eca(0).PutXList()
        YY = np.array(ybin)

        # テキストファイル書き出し開始
        t_now = datetime.datetime.now()
        fd.write(self.HEADER % (t_now.strftime('%Y-%m-%d %H:%M:%S')))
        # 領域情報
        # 非弾性粉末か？
        if self.parent.converter.isInelasticPowder:
            xrange_text = "## %s=%g,%g,%g \n" % (self.XRANGE, (XX[0] + XX[1]) / 2.0, (XX[-1] + XX[-2]) / 2.0, dQ)
        else:
            xrange_text = "## %s=%g,%g,%g \n" % (self.XRANGE, (XX[0] + XX[1]) / 2.0, (XX[-1] + XX[-2]) / 2.0, XX[1] - XX[0])

        yrange_text = "## %s=%g,%g,%g \n" % (self.YRANGE, (YY[0] + YY[1]) / 2.0, (YY[-1] + YY[-2]) / 2.0, (ybin[1] - ybin[0]))
        fd.write(xrange_text)
        fd.write(yrange_text)

        # ラベル情報
        fd.write("## %s=%s\n" % (self.XLABEL, self.params.xscale.label))
        fd.write("## %s=%s\n" % (self.YLABEL, self.params.yscale.label))

        # UNIT情報
        fd.write("## %s=%s\n" % (self.XUNIT, self.parent.txt_unit_x.text()))
        fd.write("## %s=%s\n" % (self.YUNIT, self.parent.txt_unit_y.text()))

        # マスク情報
        if not isIgnoreMask:
            if maskinfo[0]:
                fd.write("## %s=%g\n" % (self.MASKVALUE, maskinfo[1]))

        # 軸のキー名
        fd.write("## %s=%s\n" % (self.XKEY, _xkey))
        fd.write("## %s=%s\n" % (self.YKEY, _ykey))

        # タイトル・コメント
        p_title = self.params.title.replace("\n", STRING_TO_REPLACE_LF)
        p_comm = self.params.comment.replace("\n", STRING_TO_REPLACE_LF)
        fd.write("# %s=%s\n" % (self.TITLE, p_title))
        fd.write("# %s=%s\n" % (self.COMMENT, p_comm))

        # データ
        fd.write(self.DATATITLE + " \n")
        for i in range(ret_eca.PutSize()):
            yy = (ybin[i] + ybin[i + 1]) / 2.0
            if yy < 1e-13 and yy > -1e-13:
                yy = 0.0
            ec = ret_eca(i)
            XX = ec.PutXList()
            YY = ec.PutYList()
            EE = ec.PutEList()
            for j in range(len(YY)):
                xx = (XX[j] + XX[j + 1]) / 2.0
                ii = YY[j]
                ee = EE[j]
                if ii < mm.MLF_MASKVALUE:
                    fd.write("%g, %g, %g, %g\n" % (xx, yy, ii, ee))
                else:
                    if isIgnoreMask:
                        continue
                    if maskinfo[0]:
                        fd.write("%g, %g, %g, %g\n" %
                                 (xx, yy, maskinfo[1], 0.0))
                    else:
                        fd.write("%g, %g, %g, %g\n" % (xx, yy, ii, ee))
        # ファイル閉
        fd.close()

    ##########################################################
    def Read(self, filepath):
        """
        テキストファイルからの読み込み
        @param filepath (str) ファイルのフルパス
        @retval tuple of information from text data (<ECA>,[<XKEY>,<YKEY>],<XLABEL>,<YLABEL>,<TITLE>,<COMMENT>)
        """
        # ファイル開
        try:
            fo = open(filepath, "r")
        except:
            return (None, None, None, None, None)

        # 初期値
        x_range_list = []
        y_range_list = []
        p_keys = []
        xlabel = None
        ylabel = None
        xunit = ""
        yunit = ""
        p_title = ""
        p_comment = ""

        # 格納用
        xkey = "X"
        ykey = "Y"
        ikey = "Intensity"
        ekey = "Error"
        MaskValue = mm.MLF_MASKVALUE
        XX = []
        YY = []
        II = []
        EE = []

        # ファイル読み込み
        while(True):
            a_line = fo.readline()
            if a_line == "":
                break
            if a_line == "\n":
                continue
            # コメント行(M2Plot方式）なら各種情報読み込み
            if a_line.find("##") == 0:
                if a_line.find(self.XRANGE) != -1:
                    xr_line_sp = a_line.split("=")
                    if len(xr_line_sp) >= 2:
                        xrange_list_s = xr_line_sp[1].split(",")
                        if len(xrange_list_s) == 3:
                            x_range_list = []
                            for a_val in xrange_list_s:
                                x_range_list.append(float(a_val))

                if a_line.find(self.YRANGE) != -1:
                    yr_line_sp = a_line.split("=")
                    if len(yr_line_sp) >= 2:
                        yrange_list_s = yr_line_sp[1].split(",")
                        if len(yrange_list_s) == 3:
                            y_range_list = []
                            for a_val in yrange_list_s:
                                y_range_list.append(float(a_val))
                if a_line.find(self.MASKVALUE) != -1:
                    a_line_sp = a_line.split("=")
                    if len(a_line_sp) >= 2:
                        MaskValue = float(a_line_sp[1].strip())
                if a_line.find(self.XLABEL) != -1:
                    a_line_sp = a_line.split("=")
                    if len(a_line_sp) >= 2:
                        xlabel = a_line_sp[1].strip()
                if a_line.find(self.YLABEL) != -1:
                    a_line_sp = a_line.split("=")
                    if len(a_line_sp) >= 2:
                        ylabel = a_line_sp[1].strip()
                if a_line.find(self.XUNIT) != -1:
                    a_line_sp = a_line.split("=")
                    if len(a_line_sp) >= 2:
                        xunit = a_line_sp[1].strip()
                if a_line.find(self.YUNIT) != -1:
                    a_line_sp = a_line.split("=")
                    if len(a_line_sp) >= 2:
                        yunit = a_line_sp[1].strip()
                if a_line.find(self.XKEY) != -1:
                    f_id = a_line.find("=")
                    if f_id >= 1:
                        xkey = a_line[(f_id + 1):].strip()
                if a_line.find(self.YKEY) != -1:
                    f_id = a_line.find("=")
                    if f_id >= 1:
                        ykey = a_line[(f_id + 1):].strip()

            # コメント行(u2dplot方式）ならタイトルとコメント読み込み
            elif a_line.find("# ") == 0:
                if a_line.find(self.TITLE) != -1:
                    f_id = a_line.find("=")
                    if f_id >= 1:
                        p_title = a_line[(f_id + 1):].replace(STRING_TO_REPLACE_LF, "\n")
                if a_line.find(self.COMMENT) != -1:
                    f_id = a_line.find("=")
                    if f_id >= 1:
                        p_comment = a_line[(f_id + 1):].replace(STRING_TO_REPLACE_LF, "\n")

            # コメントでなければ、データとして読み込み
            else:
                a_line = a_line.strip()
                if a_line != "":
                    val_list_s = a_line.split(",")
                    if len(val_list_s) == 4:
                        XX.append(float(val_list_s[0]))
                        YY.append(float(val_list_s[1]))
                        II.append(float(val_list_s[2]))
                        EE.append(float(val_list_s[3]))
        # ファイル閉
        fo.close()

        # Grid軸の作成
        isGrid = True
        if len(x_range_list) == 3 or len(y_range_list) == 3:
            XX_list = np.arange(x_range_list[0] - (x_range_list[2] / 2.0), x_range_list[1] + x_range_list[2], x_range_list[2])
            YY_list = np.arange(y_range_list[0] - (y_range_list[2] / 2.0), y_range_list[1] + y_range_list[2], y_range_list[2])
        else:
            isGrid = False
            XX_list_t = []
            YY_list_t = []
            for xx in XX:
                if xx not in XX_list_t:
                    XX_list_t.append(xx)
            XX_list_t.sort()
            XX_list_p = [XX_list_t[0] - (XX_list_t[1] - XX_list_t[0]) / 2.0]
            for i in range(len(XX_list_t) - 1):
                XX_list_p.append((XX_list_t[i] + XX_list_t[i + 1]) / 2.0)
            XX_list_p.append(XX_list_t[-1] + (XX_list_t[-1] - XX_list_t[-2]) / 2.0)

            for yy in YY:
                if yy not in YY_list_t:
                    YY_list_t.append(yy)
            YY_list_t.sort()
            YY_list_p = [YY_list_t[0] - (YY_list_t[1] - YY_list_t[0]) / 2.0]
            for i in range(len(YY_list_t) - 1):
                YY_list_p.append((YY_list_t[i] + YY_list_t[i + 1]) / 2.0)
            YY_list_p.append(YY_list_t[-1] + (YY_list_t[-1] - YY_list_t[-2]) / 2.0)

            XX_list = np.array(XX_list_p)
            YY_list = np.array(YY_list_p)

        # データ構築
        ECA = Manyo.ElementContainerArray()
        num_of_EC = len(XX_list) - 1
        num_of_EC_i = len(YY_list) - 1
        init_vals = [mm.MLF_MASKVALUE for i in range(num_of_EC_i)]
        init_vals_e = [-1.0 for i in range(num_of_EC_i)]
        for i in range(num_of_EC):
            hh = Manyo.HeaderBase()
            xrv = Manyo.MakeDoubleVector()
            xrv.append(XX_list[i])
            xrv.append(XX_list[i + 1])
            hh.Add(xkey, ((xrv[0] + xrv[1]) / 2.0))
            hh.Add("_UNIT_{}".format(xkey), xunit)
            EC = Manyo.ElementContainer(hh)
            EC.Add(ykey, YY_list.tolist(), yunit)
            EC.Add(ikey, init_vals, "Counts")
            EC.Add(ekey, init_vals_e, "Counts")
            EC.SetKeys(ykey, ikey, ekey)
            ECA.Add(EC)

        for xx, yy, ii, ee in zip(XX, YY, II, EE):
            if isGrid:
                x_i = int(
                    (xx - x_range_list[0] + (x_range_list[2] / 2.0)) / x_range_list[2])
                y_i = int(
                    (yy - y_range_list[0] + (y_range_list[2] / 2.0)) / y_range_list[2])
            else:
                x_i = -1
                y_i = -1
                for i in range(len(XX_list) - 1):
                    if xx >= XX_list[i] and xx < XX_list[i + 1]:
                        x_i = i
                    elif xx == XX_list[i + 1]:
                        x_i = i + 1
                    else:
                        pass
                for i in range(len(YY_list) - 1):
                    if yy >= YY_list[i] and yy < YY_list[i + 1]:
                        y_i = i
                    elif yy == YY_list[i + 1]:
                        y_i = i + 1
                    else:
                        pass

            if x_i >= 0 and y_i >= 0:
                int_v = ECA(x_i).PutP(ikey)
                err_v = ECA(x_i).PutP(ekey)
                if ii < MaskValue:
                    int_v[y_i] = ii
                    err_v[y_i] = ee
                else:
                    int_v[y_i] = mm.MLF_MASKVALUE
                    err_v[y_i] = -1.0 * abs(ee)

        p_keys = [xkey, ykey]
        return (ECA, p_keys, xlabel, ylabel, xunit, yunit, p_title, p_comment)

#######################################
#  M2PlotPlus
#######################################


class M2PlotPlus(QtWidgets.QMainWindow):
    """
    ECM, ECA表示
    Attributes:
        statusbar (QStatusBar): ステータスバー
        data (ECM or ECA): データ
        u2 (U2IF): プロッタI/F
        ifi (IFEvtProp): イベント＆プロパティ授受I/F
        valid (Validator): バリデータ
        converter (DataConverter): データコンバータ
    """

    #########################################################
    def __init__(self, parent, data=None, order=1):
        logging.debug("M2PlotPlus::__init__")
        super(M2PlotPlus, self).__init__(parent)
        self.ui = Ui_MainWindow()
        if self.ui is None:
            return
        self.ui.setupUi(self)
        self.statusbar = self.findChild(
            QtWidgets.QStatusBar, "statusbar")  # ステータスバー
        self.data = data  # データ
        self.valid = Validator(self)  # バリデータ
        self.u2 = None  # U2IF:プロッタI/F
        self._sliced_ec_right = None  # スライスデータ保持
        self._sliced_ec_top = None  # スライスデータ保持
        self.order_plotter = order + 1
        self.ifi = IFEvtProp(self.order_plotter)  # イベント＆プロパティ授受I/F
        self.ifi_mine = IFEvtProp(order)
        self.converter = U2IF.DataConverter()
        self.isReady = True  # to be used to know when a command finishes
        self.bank_separators = []
        self._currentXKey = None
        self._currentYKey = None
        # イベントのリスナー登録
        self.ifi_mine.AddListner('changedata', self.OnNotifyChangeData)
        self.ifi_mine.AddListner('detectmapmode', self.OnNotifyDetectMapMode)
        self.ifi_mine.AddListner('showdata', self.OnNotifyShowData)
        self.ifi_mine.AddListner('setlabels', self.OnNotifySetLabels)
        self.ifi_mine.AddListner('setunits', self.OnNotifySetUnits)
        self.ifi_mine.AddListner('settitles', self.OnNotifySetTitles)
        self.ifi_mine.AddProperty('isready', lambda: self.isReady)
        self.ifi_mine.AddListner('setsmooth', self.OnNotifySmoothing)
        self.ifi_mine.AddListner('setlogscale', self.OnNotifyLogScale)
        self.ifi_mine.AddListner('setautoscale', self.OnNotifyAutoScale)
        self.ifi_mine.AddListner('setaxisinversion', self.OnNotifyAxisInversion)
        self.ifi_mine.AddListner('setaxisscale', self.OnNotifyAxisScale)
        self.ifi_mine.AddListner(
            'setwindowsize', self.OnNotifySetWindowSize)  # [inamura 181113]
        self.ifi_mine.AddListner(
            'setwindowtitle', self.OnNotifySetWindowTitle)  # [inamura 190125]
        self.ifi_mine.AddListner(
            'setslicemethod', self.OnNotifySetSliceMethod)  # [inamura 190226]
        self.ifi_mine.AddListner(
            'setcurrentkey', self.OnNotifySetCurrentKey)  # [tito 190313]
        self.ifi_mine.AddListner(
            'turnmodeplotonly', self.OnNotifyTurnModePlotOnly)
        self.ifi_mine.AddListner(
            'close', self.OnNotifyClose)  # [inamura 200120]
        self.ifi_mine.AddListner(
            'saveastext', self.OnNotifySaveAsText)  # [inamura 210416]
        # Get GUI control
        self.getGui()
        # イベントハンドラ登録
        self.SetEventHandler()

        self.show()
        logging.info("M2PlotPlus starting")
        logging.info("Python: {0}, Qt: {1}, uGao.M2PlotPlus: {2}({3})".format(platform.python_version(),
                                                                              QtCore.__version__,
                                                                              __version__,
                                                                              __date__))
    #########################################
    def getGui(self):
        self.cb_DetMapMode = self.findChild(QtWidgets.QCheckBox, 'cb_DetMapMode')
        self.txt_label_x = self.findChild(QtWidgets.QLineEdit, 'txt_label_x')
        self.txt_label_y = self.findChild(QtWidgets.QLineEdit, 'txt_label_y')
        self.txt_unit_x = self.findChild(QtWidgets.QLineEdit, 'txt_unit_x')
        self.txt_unit_y = self.findChild(QtWidgets.QLineEdit, 'txt_unit_y')
        self.btIntApply = self.findChild(QtWidgets.QPushButton, 'btIntApply')
        self.chk_int_auto_range = self.findChild(QtWidgets.QCheckBox, 'chk_int_auto_range')
        self.chk_int_log = self.findChild(QtWidgets.QCheckBox, 'chk_int_log')
        self.chk_smooth = self.findChild(QtWidgets.QCheckBox, 'chk_smooth')
        self.chk_xscale_auto_range = self.findChild(QtWidgets.QCheckBox, 'chk_xscale_auto_range')
        self.chk_xscale_log = self.findChild(QtWidgets.QCheckBox, 'chk_xscale_log')
        self.chk_xscale_inv = self.findChild(QtWidgets.QCheckBox, 'chk_xscale_inv')
        self.chk_yscale_auto_range = self.findChild(QtWidgets.QCheckBox, 'chk_yscale_auto_range')
        self.chk_yscale_log = self.findChild(QtWidgets.QCheckBox, 'chk_yscale_log')
        self.chk_yscale_inv = self.findChild(QtWidgets.QCheckBox, 'chk_yscale_inv')
        self.btXZSlice1d = self.findChild(QtWidgets.QPushButton, 'btXZSlice1d')
        self.btXZSlice1dclear = self.findChild(QtWidgets.QPushButton, 'btXZSlice1dclear')
        self.btYZSlice1d = self.findChild(QtWidgets.QPushButton, 'btYZSlice1d')
        self.btYZSlice1dclear = self.findChild(QtWidgets.QPushButton, 'btYZSlice1dclear')
        self.btDiagonal1d = self.findChild(QtWidgets.QPushButton, 'btDiagonal1d')
        self.btXZSlice2d = self.findChild(QtWidgets.QPushButton, 'btXZSlice2d')
        self.btYZSlice2d = self.findChild(QtWidgets.QPushButton, 'btYZSlice2d')
        self.txt_xzslice_center = self.findChild(QtWidgets.QLineEdit, 'txt_xzslice_center')
        self.txt_xzslice_width = self.findChild(QtWidgets.QLineEdit, 'txt_xzslice_width')
        self.txt_xzslice_start = self.findChild(QtWidgets.QLineEdit, 'txt_xzslice_start')
        self.txt_xzslice_end = self.findChild(QtWidgets.QLineEdit, 'txt_xzslice_end')
        self.txt_xzslice_delta = self.findChild(QtWidgets.QLineEdit, 'txt_xzslice_delta')
        self.txt_yzslice_center = self.findChild(QtWidgets.QLineEdit, 'txt_yzslice_center')
        self.txt_yzslice_width = self.findChild(QtWidgets.QLineEdit, 'txt_yzslice_width')
        self.txt_yzslice_start = self.findChild(QtWidgets.QLineEdit, 'txt_yzslice_start')
        self.txt_yzslice_end = self.findChild(QtWidgets.QLineEdit, 'txt_yzslice_end')
        self.txt_yzslice_delta = self.findChild(QtWidgets.QLineEdit, 'txt_yzslice_delta')
        self.cb_xzslice_bin = self.findChild(QtWidgets.QCheckBox, 'cb_xzslice_bin')
        self.cb_yzslice_bin = self.findChild(QtWidgets.QCheckBox, 'cb_yzslice_bin')
        self.txt_xzslice_bin = self.findChild(QtWidgets.QLineEdit, 'txt_xzslice_bin')
        self.txt_yzslice_bin = self.findChild(QtWidgets.QLineEdit, 'txt_yzslice_bin')
        self.rb_isAveSlice = self.findChild(QtWidgets.QRadioButton, 'rb_isAveSlice')
        self.rb_isSumSlice = self.findChild(QtWidgets.QRadioButton, 'rb_isSumSlice')
        self.statusbar = self.findChild(QtWidgets.QStatusBar, 'statusbar')
        self.cbX = self.findChild(QtWidgets.QComboBox, 'cbX')
        self.cbY = self.findChild(QtWidgets.QComboBox, 'cbY')
        self.cbR = self.findChild(QtWidgets.QComboBox, 'cbR')
        self.showButton = self.findChild(QtWidgets.QPushButton, 'showButton')
        self.cbZ = self.findChild(QtWidgets.QComboBox, 'cbZ')
        self.rd_xzslice_range = self.findChild(QtWidgets.QRadioButton, 'rd_xzslice_range')
        self.txt_xzslice_center_to = self.findChild(QtWidgets.QLineEdit, 'txt_xzslice_center_to')
        self.txt_xzslice_center_step = self.findChild(QtWidgets.QLineEdit, 'txt_xzslice_center_step')
        self.rd_xzslice_value = self.findChild(QtWidgets.QRadioButton, 'rd_xzslice_value')
        self.rd_yzslice_range = self.findChild(QtWidgets.QRadioButton, 'rd_yzslice_range')
        self.txt_yzslice_center_to = self.findChild(QtWidgets.QLineEdit, 'txt_yzslice_center_to')
        self.txt_yzslice_center_step = self.findChild(QtWidgets.QLineEdit, 'txt_yzslice_center_step')
        self.rd_yzslice_value = self.findChild(QtWidgets.QRadioButton, 'rd_yzslice_value')
        self.txt_diagonal_sp_x = self.findChild(QtWidgets.QLineEdit, 'txt_diagonal_sp_x')
        self.txt_diagonal_sp_y = self.findChild(QtWidgets.QLineEdit, 'txt_diagonal_sp_y')
        self.txt_diagonal_ep_x = self.findChild(QtWidgets.QLineEdit, 'txt_diagonal_ep_x')
        self.txt_diagonal_ep_y = self.findChild(QtWidgets.QLineEdit, 'txt_diagonal_ep_y')
        self.txt_diagonal_width = self.findChild(QtWidgets.QLineEdit, 'txt_diagonal_width')
        self.txt_diagonal_binning = self.findChild(QtWidgets.QLineEdit, 'txt_diagonal_binning')
        self.groupBox_int = self.findChild(QtWidgets.QGroupBox, 'groupBox_int')
        self.groupBox_xscale = self.findChild(QtWidgets.QGroupBox, 'groupBox_xscale')
        self.groupBox_yscale = self.findChild(QtWidgets.QGroupBox, 'groupBox_yscale')
        self.groupBox_slice = self.findChild(QtWidgets.QGroupBox, 'groupBox_slice')
        self.txt_int_min = self.findChild(QtWidgets.QLineEdit, 'txt_int_min')
        self.txt_int_max = self.findChild(QtWidgets.QLineEdit, 'txt_int_max')
        self.label_int_range = self.findChild(QtWidgets.QLabel, 'label_int_range')
        self.label_int_range_h = self.findChild(QtWidgets.QLabel, 'label_int_range_h')
        self.txt_smooth_win = self.findChild(QtWidgets.QLineEdit, 'txt_smooth_win')
        self.txt_smooth_tim = self.findChild(QtWidgets.QLineEdit, 'txt_smooth_tim')
        self.txt_xscale_min = self.findChild(QtWidgets.QLineEdit, 'txt_xscale_min')
        self.txt_xscale_max = self.findChild(QtWidgets.QLineEdit, 'txt_xscale_max')
        self.label_xscale_range = self.findChild(QtWidgets.QLabel, 'label_xscale_range')
        self.label_xscale_h = self.findChild(QtWidgets.QLabel, 'label_xscale_h')
        self.txt_yscale_min = self.findChild(QtWidgets.QLineEdit, 'txt_yscale_min')
        self.txt_yscale_max = self.findChild(QtWidgets.QLineEdit, 'txt_yscale_max')
        self.label_yscale_range = self.findChild(QtWidgets.QLabel, 'label_yscale_range')
        self.label_yscale_h = self.findChild(QtWidgets.QLabel, 'label_yscale_h')

        self.cb_currentIndexChanged_connected = False #[inamura 240822] whether 'self.cbX.currentIndexChanged.connect' is done or not

    #########################################
    def SetEventHandler(self):
        """イベントハンドラ登録
        """
        # メニューのイベントハンドラ登録
        self.findChild(QAction, "actionAbout").triggered.connect(self.OnAbout)
        self.findChild(QAction, "actionOpen_data").triggered.connect(
            self.OnOpen)
        self.findChild(QAction, "actionExit").triggered.connect(
            self.closeEvent)
        self.findChild(QAction, "actionX_axis_2D").triggered.connect(
            self.OnM2PlotPlus)
        self.findChild(QAction, "actionY_axis_2D").triggered.connect(
            self.OnM2PlotPlus)
        self.findChild(QAction, "actionTest").triggered.connect(self.OnTest)
        self.findChild(QAction, "actionChangeLogLevel").triggered.connect(
            self.OnChangeLogLevel)
        self.findChild(QAction, "actionShow").triggered.connect(self.OnShow)
        # self.findChild(QAction, "actionSlice").triggered.connect(self.OnSlice)
        self.findChild(QAction, "actionConfirm_region").triggered.connect(
            self.OnConfirmReg)
        self.findChild(QAction, "actionPoint").triggered.connect(
            self.OnChangeRegionType)
        self.findChild(QAction, "actionCircle").triggered.connect(
            self.OnChangeRegionType)
        self.findChild(QAction, "actionRectangle").triggered.connect(
            self.OnChangeRegionType)
        self.findChild(QAction, "actionAuto_confirm").triggered.connect(
            self.OnAutoConfirm)
        self.findChild(QAction, "actionSave_as_Text").triggered.connect(
            self.OnSaveAsText)
        self.findChild(QtWidgets.QPushButton,
                       "showButton").pressed.connect(self.OnShow)
        self.findChild(QtWidgets.QPushButton,
                       "openButton").pressed.connect(self.OnOpen)
        self.cb_DetMapMode.stateChanged.connect(self.OnCheckDetMapMode)
        self.cb_DetMapMode.setEnabled(False)
        # self.findChild(QtWidgets.QPushButton, "exitButton").pressed.connect(self.close)
        self.btFindPlt = self.findChild(QtWidgets.QPushButton, "btFindPlotter")
        # btFindPlt_icon = self.btFindPlt.style().standardIcon(QtWidgets.QStyle.SP_ArrowForward)
        btFindPlt_icon = QtGui.QIcon()
        btFindPlt_icon.addPixmap(QtGui.QPixmap(
            ":flip_to_front.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.btFindPlt.setIcon(btFindPlt_icon)
        self.btFindPlt.pressed.connect(self.OnFindPlotter)

        self.txt_label_x.editingFinished.connect(self.UpdateLabels)
        self.txt_label_y.editingFinished.connect(self.UpdateLabels)
        self.txt_unit_x.editingFinished.connect(self.UpdateLabels)
        self.txt_unit_y.editingFinished.connect(self.UpdateLabels)

        # プロット情報のイベントハンドラ登録
        # Apply Button
        self.btIntApply.clicked.connect(self.OnPlotParamsApply)

        # Intensity
        self.chk_int_auto_range.stateChanged.connect(self.OnCheckAutoInt)
        self.chk_int_log.stateChanged.connect(self.OnCheckIntLog)
        self.chk_smooth.stateChanged.connect(self.OnCheckSmooth)

        # X Scale
        self.chk_xscale_auto_range.stateChanged.connect(self.OnCheckXAutoRange)
        self.chk_xscale_log.stateChanged.connect(self.OnCheckXLog)
        self.chk_xscale_inv.stateChanged.connect(self.OnCheckXInv)

        # Y Scale
        self.chk_yscale_auto_range.stateChanged.connect(self.OnCheckYAutoRange)
        self.chk_yscale_log.stateChanged.connect(self.OnCheckYLog)
        self.chk_yscale_inv.stateChanged.connect(self.OnCheckYInv)

        # Slice and clear Button
        self.btXZSlice1d.clicked.connect(self.OnXZSlice1d)
        self.btXZSlice1dclear.clicked.connect(self.OnSlice1dClear)
        self.btYZSlice1d.clicked.connect(self.OnYZSlice1d)
        self.btYZSlice1dclear.clicked.connect(self.OnSlice1dClear)
        self.btDiagonal1d.clicked.connect(self.OnDiagonal1d)
        self.btXZSlice2d.clicked.connect(self.OnXZSlice2d)
        self.btYZSlice2d.clicked.connect(self.OnYZSlice2d)

        # Slice info
        self.txt_xzslice_center.editingFinished.connect(self.UpdateSliceInfo)
        self.txt_xzslice_width.editingFinished.connect(self.UpdateSliceInfo)
        self.txt_xzslice_start.editingFinished.connect(self.UpdateSliceInfo)
        self.txt_xzslice_end.editingFinished.connect(self.UpdateSliceInfo)
        self.txt_xzslice_delta.editingFinished.connect(self.UpdateSliceInfo)
        self.txt_yzslice_center.editingFinished.connect(self.UpdateSliceInfo)
        self.txt_yzslice_width.editingFinished.connect(self.UpdateSliceInfo)
        self.txt_yzslice_start.editingFinished.connect(self.UpdateSliceInfo)
        self.txt_yzslice_end.editingFinished.connect(self.UpdateSliceInfo)
        self.txt_yzslice_delta.editingFinished.connect(self.UpdateSliceInfo)

        self.cb_xzslice_bin.stateChanged.connect(self.OnCheckSliceBin)
        self.cb_yzslice_bin.stateChanged.connect(self.OnCheckSliceBin)
        self.txt_xzslice_bin.editingFinished.connect(self.UpdateSliceBin)
        self.txt_yzslice_bin.editingFinished.connect(self.UpdateSliceBin)

        # Slice mode (Average/Summation)
        self.rb_isAveSlice.toggled.connect(self.OnRadioButtonAS)
        self.rb_isSumSlice.toggled.connect(self.OnRadioButtonSS)
        self.rb_isAveSlice.setChecked(True)
        self.rb_isSumSlice.setChecked(False)

        # プロット情報パネルをオフ
        self.PlotParamsPanelTurnOn(False)

        # Initial Title and Comment
        self.initial_viewParams_Title = ""
        self.initial_viewParams_Comment = ""

        # Catch WindowActivate event
        self.installEventFilter(self)

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

    #########################################
    def OnOpen(self):
        """ファイル読み込み処理
        """
        xlabel = None
        ylabel = None
        xunit = ""
        yunit = ""
        p_title = ""
        p_comment = ""
        wildcard = "ECA/ECM mdb (*.mdb);;ECA srlz (*.srlz);;ECM srlz (*.srlz);;M2Plot text (*.txt)"
        # ファイル保存ダイアログを表示
        dlg = QtWidgets.QFileDialog(
            self, "Select a file", expanduser("."), wildcard)
        dlg.setFileMode(QtWidgets.QFileDialog.ExistingFile)
        # パスを取得。
        if dlg.exec_():
            filenames = dlg.selectedFiles()
            filename = str(filenames[-1])
            data_type, data_format, wildcard = dlg.selectedNameFilter().split()
            msg = "Data loading : {}".format(os.path.basename(filename))
            self.statusbar.showMessage(msg)
            try:
                if data_format == "srlz":
                    if data_type == "ECM":
                        self.data = Manyo.ElementContainerMatrix()
                    else:
                        self.data = Manyo.ElementContainerArray()
                    r = Manyo.ReadSerializationFileBinary(filename)
                    r.Load(self.data)
                    del r
                elif data_format == "mdb":
                    mdb = Manyo.ManyoDataIO()
                    data_type = mdb.PutDataType(filename)
                    if data_type == "ElementContainerMatrix":
                        self.data = mdb.ReadElementContainerMatrix(filename)
                    elif data_type == "ElementContainerArray":
                        self.data = mdb.ReadElementContainerArray(filename)
                    else:
                        raise PlotException('Common', 'C015', (filename,))
                    del mdb
                # テキストファイル読み込みか
                elif data_format == "text":
                    FIO = M2PlotPlusTextFileIO(self)
                    (ret_data, p_keys, xlabel, ylabel, xunit,
                     yunit, p_title, p_comment) = FIO.Read(filename)
                    if ret_data is None:
                        print("Failed to read text file ({})".format(filename))
                        return
                    self.data = ret_data
                else:
                    raise UserWarning("Open Failed.")
            except PlotException as ex:
                PlotMessage(self, ex)
                return
            self.findChild(QAction, "actionShow").setEnabled(True)
        else:
            return
        try:
            if self.cb_currentIndexChanged_connected:
                self.cbX.currentIndexChanged.disconnect(self.CopyKeyToLabel)
                self.cbY.currentIndexChanged.disconnect(self.CopyKeyToLabel)
        except RuntimeError:
            pass
        self._currentXKey = None
        self._currentYKey = None
        _m2pp_x_key = None
        _m2pp_y_key = None
        _m2pp_rng_key = None
        self.RefreshAxisCombobox()
        if self.converter.CheckInelasticPowderData(self.data):
            self.TurnEnabledCombobox(False)
            data_type = "Powder Data"
            self.txt_label_x.setEnabled(False)
            self.txt_label_y.setEnabled(False)
            self.txt_unit_x.setEnabled(False)
            self.txt_unit_y.setEnabled(False)
            xlabel = "|Q|"
            ylabel = "Energy Transfer"
            xunit = "1/A"
            yunit = "meV"
        else:
            self.TurnEnabledCombobox(True)
            self.txt_label_x.setEnabled(True)
            self.txt_label_y.setEnabled(True)
            self.txt_unit_x.setEnabled(True)
            self.txt_unit_y.setEnabled(True)
            if xlabel is None:
                xlabel = str(self.cbX.currentText())
                xunit = self.cbX_units[int(self.cbX.currentIndex())]
            if ylabel is None:
                ylabel = str(self.cbY.currentText())
                yunit = self.cbY_units[int(self.cbY.currentIndex())]
            # dataのHeaderにM2PP_*_KEYでStringがあれば、*Keyにそれらを設定
            if self.data.PutHeaderPointer().PutKeyLocation("M2PP_X_KEY") == 3:
                _m2pp_x_key = self.data.PutHeaderPointer().PutString("M2PP_X_KEY")
            if self.data.PutHeaderPointer().PutKeyLocation("M2PP_Y_KEY") == 3:
                _m2pp_y_key = self.data.PutHeaderPointer().PutString("M2PP_Y_KEY")
            if self.data.PutHeaderPointer().PutKeyLocation("M2PP_RNG_KEY") == 3:
                _m2pp_rng_key = self.data.PutHeaderPointer().PutString("M2PP_RNG_KEY")
        # データ読込時Labelを更新
        self.txt_label_x.setText(xlabel)
        self.txt_label_y.setText(ylabel)
        self.txt_unit_x.setText(xunit)
        self.txt_unit_y.setText(yunit)

        # Combobox更新があるためこのタイミングでconnectする
        self.cbX.currentIndexChanged.connect(self.CopyKeyToLabel)
        self.cbY.currentIndexChanged.connect(self.CopyKeyToLabel)
        self.cb_currentIndexChanged_connected = True

        # data.HeaderのM2PP_*_KEYを反映
        if _m2pp_x_key is not None:
            _idx_x_key = self.cbX.findText(_m2pp_x_key)
            if _idx_x_key != -1:
                self.cbX.setCurrentIndex(_idx_x_key)
                logging.info("M2PP_X_KEY {0} was set.".format(_m2pp_x_key))
            else:
                logging.info(
                    "M2PP_X_KEY {0} was not found in the combobox.".format(_m2pp_x_key))
        if _m2pp_y_key is not None:
            _idx_y_key = self.cbY.findText(_m2pp_y_key)
            if _idx_y_key != -1:
                self.cbY.setCurrentIndex(_idx_y_key)
                logging.info("M2PP_Y_KEY {0} was set.".format(_m2pp_y_key))
            else:
                logging.info(
                    "M2PP_Y_KEY {0} was not found in the combobox.".format(_m2pp_y_key))
        if _m2pp_rng_key is not None:
            _idx_rng_key = self.cbR.findText(_m2pp_rng_key)
            if _idx_rng_key != -1:
                self.cbR.setCurrentIndex(_idx_rng_key)
                logging.info("M2PP_RNG_KEY {0} was set.".format(_m2pp_rng_key))
            else:
                logging.info(
                    "M2PP_RNG_KEY {0} was not found in the combobox.".format(_m2pp_rng_key))

        msg = "Data load complete: type {0}".format(data_type)
        self.statusbar.showMessage(msg)
        # タイトルにファイル名を付与
        title = "M2Plot+ [{}]".format(str(os.path.basename(filename)))
        if QtCore.__version__ < '5.0.0':
            self.setWindowTitle(QtWidgets.QApplication.translate(
                "MainWindow", title, None, QtGui.QApplication.UnicodeUTF8))
        else:
            self.setWindowTitle(QtWidgets.QApplication.translate(
                "MainWindow", title, None, -1))
        self.showButton.setEnabled(True)
        self.showButton.setFocus(QtCore.Qt.OtherFocusReason)
        self.btFindPlt.setEnabled(False)

        # もしテキスト読み込みならそのままプロット（タイトルとコメントを表示するため）
        if data_format == "text":
            # Xキーとラベルの再設定
            idx = self.cbX.findText(p_keys[0])
            self.cbX.setCurrentIndex(idx)
            self.txt_label_x.setText(xlabel)
            # Yキーとラベルの再設定
            idy = self.cbY.findText(p_keys[1])
            self.cbY.setCurrentIndex(idy)
            self.txt_label_y.setText(ylabel)
            # プロット表示とタイトルコメント表示
            self.OnShow()
            params = self.ifi.GetProperty('params')
            params.title = p_title
            params.comment = p_comment
            self.initial_viewParams_Title = p_title
            self.initial_viewParams_Comment = p_comment
            self.ifi.NotifyEvent(self, 'change_params')

    #########################################
    def RefreshAxisCombobox(self):
        """コンボボックスの項目を作り直す
        """
        isEcm = isinstance(
            self.data, Manyo.ElementContainerMatrix)  # ECM/ECAフラグ
        # 各コンボボックスを取得
        cbX = self.findChild(QtWidgets.QComboBox, "cbX")
        cbY = self.findChild(QtWidgets.QComboBox, "cbY")
        cbZ = self.findChild(QtWidgets.QComboBox, "cbZ")
        cbR = self.findChild(QtWidgets.QComboBox, "cbR")
        r0 = self.findChild(QtWidgets.QLineEdit, "txtR0")
        r1 = self.findChild(QtWidgets.QLineEdit, "txtR1")

        # 各コンボボックスの項目を消去
        for cb in [cbX, cbY, cbZ, cbR]:
            cb_count = cb.count()
            for i in range(cb_count):
                cb.removeItem(cb_count - 1 - i)

        for txt in [r0, r1]:
            txt.setText("")

        for w in [cbR, r0, r1]:
            w.setDisabled(True)

        # X軸コンボボックス項目追加
        cbX.addItem("Index")
        self.cbX_units = [""]
        xKeys, xUnits = self._GetIntKeys(self.data(0))
        self.converter._ConvOldM2PlotKeys(self.data, isEcm)
        xkeys2, xunits2 = self._GetDoubleKeys(self.data(0))
        xKeys.extend(xkeys2)
        xUnits.extend(xunits2)
        for key in xKeys:
            self.cbX.addItem(key)
        self.cbX_units.extend(xUnits[:])

        # Y軸コンボボックス項目追加
        if isEcm:
            cbY.addItem("Index")
            yKeys, yUnits = self._GetIntKeys(self.data(0, 0))
            # yKeys.extend(self._GetDoubleKeys(self.data(0, 0)))
            ykeys2, yunits2 = self._GetDoubleKeys(self.data(0, 0))
            yKeys.extend(ykeys2)
            yUnits.extend(yunits2)
        else:
            yKeys, yUnits = self._GetVecKeys(self.data(0))
        for key in yKeys:
            self.cbY.addItem(key)
        self.cbY_units = yUnits[:]

        # Z軸コンボボックス項目追加
        if isEcm:
            zKeys, zUnits = self._GetVecKeys(self.data(0, 0), getAllKeys=True)
        else:
            zKeys, zUnits = self._GetVecKeys(self.data(0), getAllKeys=True)
        for key in zKeys:
            self.cbZ.addItem(key)
        self.cbZ_units = zUnits[:]

        # 範囲指定参照軸コンボボックス項目追加
        if isEcm:
            for w in [cbR, r0, r1]:
                w.setEnabled(True)
            rKeys, rUnits = self._GetVecKeys(self.data(0, 0))
            for key in rKeys:
                self.cbR.addItem(key)

    #########################################
    def TurnEnabledCombobox(self, flag):
        """
        """
        # 各コンボボックスを取得
        self.findChild(QtWidgets.QComboBox, "cbX").setEnabled(flag)
        self.findChild(QtWidgets.QComboBox, "cbY").setEnabled(flag)
        self.findChild(QtWidgets.QComboBox, "cbZ").setEnabled(flag)
        self.findChild(QtWidgets.QComboBox, "cbR").setEnabled(flag)
        self.findChild(QtWidgets.QLineEdit, "txtR0").setEnabled(flag)
        self.findChild(QtWidgets.QLineEdit, "txtR1").setEnabled(flag)
        self.findChild(QtWidgets.QGroupBox, "SumRangePanel").setEnabled(
            flag)  # [inamura 181106]

    #########################################
    def OnSaveAsText(self):
        """Save as Text... メニューが選択された時実行
        """
        # もしプロッタがまだ開かれていない場合は戻る
        if self.u2 is None:
            return
        if self.u2.plot is None:
            return
        dlg = SetSaveAsTextDialog(self)

    #########################################
    def OnAbout(self):
        """Aboutダイアログの表示
        """
        msgBox = QtWidgets.QMessageBox()
        url = "https://knowledge.mlf.plus/open.knowledge/view/71"
        message = "{0}\nVersion: {1}\nAuthor: {2}\nDate: {3}\nManual: {4}".format(
            __doc__, __version__, __author__, __date__, url)
        msgBox.about(self, "About M2PlotPlus", message)
        # msgBox.exec_()

    #########################################
    def OnChangeLogLevel(self):
        """ログレベル変更
        """
        # self.u2.plot.close()
        logger = logging.getLogger()
        if logger.level == logging.DEBUG:
            logger.setLevel(logging.INFO)
        else:
            logger.setLevel(logging.DEBUG)
        self.statusbar.showMessage("New log level: {}".format(
            logging.getLevelName(logger.level)))
        return

    #########################################
    def OnTest(self):
        """機能テスト用関数
        """
        print(__author__)
        return

    #########################################
    def OnAverage(self, isAve=True):
        """
        選択領域にかかっているピクセルのAverageをMPlotで表示
        """
        xbin, ybin = self.u2.GetBins()  # これらは転置で変化しない
        n_x_data = len(xbin) - 1
        n_y_data = len(ybin) - 1

        psd_v = Manyo.MakeUInt4Vector()  # AverageEC用
        pix_v = Manyo.MakeUInt4Vector()  # AverageEC用

        sender_name = self.sender().objectName()
        # if sender_name in ["actionAverage_context"]:
        if sender_name in ["actionMPlot_context"]:
            rname = "Rectangle"
            values = self.u2.plot._last_slice_drag_values[:]  # これらは転置に対応して変化する
            if values[0] is None:
                logging.info(
                    "Averaging from the context menu can be used after the rectangular slicing.")
                ex = PlotException('Common', 'C035', ("Averaging region", ))
                PlotMessage(self, ex)
                return
            xdef = values[2] - values[0]
            ydef = values[3] - values[1]
            diagram = Rectangle((values[0], values[1]), xdef, ydef)
            selected_path = diagram.get_patch_transform().transform_path(diagram.get_path())
        else:
            rname, color, values, isSelected = self.u2.GetSelectedRegInfo()  # 選択領域情報
            if rname in ["Point", "Line"]:
                return
            selected_path = self.u2.GetSelectedRegPath()  # 選択領域のmatplotlib.path.Path 転置で変化
        mesh = self.u2.GetQuadMesh()  # 順序は転置で変化する。
        for idx, p in enumerate(mesh.get_paths()):
            if selected_path.intersects_path(p):
                i = idx % n_x_data
                j = idx // n_x_data
                pv = self.converter.slicer.PutDetectMapIndex(i, j)
                if len(pv) == 0:
                    raise PlotException(
                        'Common', 'C001', ("Range over", "M2PlotPlus:OnAverage"))
                else:
                    if (pv[0] != -1) and (pv[1] != -1):  # If given detector is not masked
                        psd_v.append(pv[0])
                        pix_v.append(pv[1])
                    # print("#[inamura 190222] pv  = %3d, %3d, i,j= %3d,%3d"%(pv[0],pv[1],i,j))
        average = mm.AverageElementContainerMatrix(self.data, psd_v, pix_v)
        rtn = None
        if isAve:
            rtn = average.GetAverage()
        else:
            rtn = average.GetSum()
        # p = mp.MPlot(rtn)
        if self.u2.plot.mp_main is None:  # スライスプロット上が作られたことがあるか
            self.u2.plot.mp_main = mp.MPlot(rtn)
        else:
            if self.u2.plot.mp_main.plot.IsAliveComm():  # 死活判定
                self.u2.plot.mp_main.AddData(rtn)
            else:
                self.u2.plot.mp_main = mp.MPlot(rtn)

        self.u2.plot.mp_main.SetXLabel("{}".format(rtn.PutXKey()))
        self.u2.plot.mp_main.SetYLabel("{}".format(rtn.PutYKey()))

    #########################################
    def OnMPlotFromContext(self):
        """
        """
        params = self.ifi.GetProperty('params')
        if self.u2.plot.last_clicked_point is None:
            self.OnAverage(params.slice_ave_mode)
        else:
            self.u2.plot.OnMPlotFromContextMenu()

    #########################################
    def OnAutoConfirm(self):
        """領域指定マウスアップ時自動追加の切り替え
        """
        self.u2.plot.SetAutoAddRegion(self.sender().isChecked())

    #########################################
    def OnChangeRegionType(self):
        """領域タイプを変更
        """
        regName = self.sender().property("regName")  # メニューのDynamicPropertyから領域名を得る
        self.ifi.NotifyEvent(self, 'select_region', regName)

    #########################################
    def OnConfirmReg(self):
        """描画領域の追加確定
        """
        self.ifi.NotifyEvent(self, 'add_region_from_dlg')

    #########################################
    def OnSlice(self):
        """スライス
        """
        regInfos = self.ifi.GetProperty('region_info')
        for region in regInfos:
            rname, color, values, isSelected = region
            if isSelected:
                logging.debug(rname, values)
                xdata = float(values[0])
                ydata = float(values[1])
                logging.debug(xdata, ydata)
                n_x_plot = len(self.u2.plot.data[1][0])  # プロットX軸区切り数
                n_x_data = self.data.PutSize()  # データECM中のECA数 or ECA中のEC数
                if (n_x_plot - 1) == n_x_data:
                    i = np.searchsorted(
                        self.u2.plot.data[1][0], xdata)  # xbinでのindex
                    x_index = self.u2.indices_sort[i - 1]  # ECM/ECAでのindex
                    logging.info("X index at ECM/ECA: {0}".format(x_index))
                if isinstance(self.data, Manyo.ElementContainerArray):
                    return
                else:
                    y_plot = self.u2.plot.data[2].transpose()[0].tolist()
                    n_y_plot = len(y_plot)  # プロットy軸区切り数
                    n_y_data = self.data(0).PutSize()  # データECM中のECA中のEC数
                    if (n_y_plot - 1) == n_y_data:
                        i = np.searchsorted(y_plot, ydata)  # ybinでのindex
                        y_index_at_eca = i - 1  # ECM中のECAでのindex
                    logging.info("Y index at ECA: {0}".format(y_index_at_eca))
                    return

    #########################################
    def OnCheckDetMapMode(self):
        """
        """
        if (self.data is None) and (not isinstance(self.data, Manyo.ElementContainerMatrix)) and (self.converter.isInelasticPowder):
            self.cb_DetMapMode.setEnabled(False)
            return

        if self.cb_DetMapMode.checkState() == QtCore.Qt.Checked:
            cbX = self.findChild(QtWidgets.QComboBox, "cbX")
            xkey = str(cbX.currentText())
            self._currentXKey = xkey
            if xkey == "Index":
                xkey = None
            if self.data(0, 0).PutHeaderPointer().CheckKey("PixelPolarAngle") == 1 and (xkey in [None, "DETID", "PSDID"]):
                pass
            else:
                self.cb_DetMapMode.setCheckState(False)

    #########################################
    def OnShow(self):
        """プロット表示
        """
        isEcm = isinstance(
            self.data, Manyo.ElementContainerMatrix)  # ECM/ECAフラグ
        if self.u2 is None:
            self.u2 = U2IF.U2IF(self, order=self.order_plotter)  # U2IFインスタンス作成

        isNewU2 = False
        if self.u2.plot is None:
            isNewU2 = True

        # 各軸のキーを取得
        cbX = self.findChild(QtWidgets.QComboBox, "cbX")
        xkey = str(cbX.currentText())
        self._currentXKey = xkey
        if xkey == "Index":
            xkey = None

        cbY = self.findChild(QtWidgets.QComboBox, "cbY")
        ykey = str(cbY.currentText())
        self._currentYKey = ykey
        if ykey == "Index":
            ykey = None

        cbZ = self.findChild(QtWidgets.QComboBox, "cbZ")
        zkey = str(cbZ.currentText())

        # DetectMapモードの設定はGUIから取得：自動的に判別ではなくユーザーの意思による（CUIからはGUIのみを変更）
        is_DetMapMode = False
        if isEcm:
            if self.cb_DetMapMode.checkState() == QtCore.Qt.Checked:
                is_DetMapMode = True

            cbR = self.findChild(QtWidgets.QComboBox, "cbR")
            rkey = str(cbR.currentText())
            self.u2.SetKeys(xkey, ykey, zkey, rkey)
            r0 = self.findChild(QtWidgets.QLineEdit, "txtR0")
            r1 = self.findChild(QtWidgets.QLineEdit, "txtR1")
            r0_str = r0.text()
            r1_str = r1.text()
            if r0_str != "" and r1_str != "":
                if self.valid.ValidateRange(r0_str, r1_str, "Range reference", 0, 0):
                    # self.u2.SetIntRange(r0_str, r1_str)  # [20170425, TI] Obsolete. ConvertDataを直接やるので
                    ndata = self.converter.ConvertData(
                        self.data, (xkey, ykey, zkey, rkey), U2IF.format_int_range(r0_str, r1_str), is_DetMapMode)
            else:
                # [20170425, TI] Obsolete. ConvertDataを直接やるので
                self.u2.SetIntRange(None, None)
                ndata = self.converter.ConvertData(self.data, (xkey, ykey, zkey, rkey), None, is_DetMapMode)
            if "bank_separators" in self.converter.params:
                self.bank_separators = self.converter.params["bank_separators"]

        else:
            # [20170425, TI] Obsolete. ConvertDataを直接やるので
            self.u2.SetKeys(xkey, ykey, zkey)
            try:
                ndata = self.converter.ConvertData(
                    self.data, (xkey, ykey, zkey), None)
            except PlotException as ex:
                msg = ex.GetMessage()
                self.statusbar.showMessage("Failed to data: {0}".format(msg))
                PlotMessage(self, ex)
                return
        self.u2.left_mouse_click_cb = call_slice
        self.u2.SetData(ndata)
        xlabel = self.txt_label_x.text()
        ylabel = self.txt_label_y.text()
        xunit = self.txt_unit_x.text()
        yunit = self.txt_unit_y.text()
        # For M2Plot data with XLABEL and YLABEL
        if self.data.PutHeaderPointer().CheckKey("XLABEL") == 1:
            xlabel = self.data.PutHeaderPointer().PutString("XLABEL")
        if self.data.PutHeaderPointer().CheckKey("Xunit") == 1:
            xunit = self.data.PutHeaderPointer().PutString("Xunit")
        if self.data.PutHeaderPointer().CheckKey("YLABEL") == 1:
            ylabel = self.data.PutHeaderPointer().PutString("YLABEL")
        if self.data.PutHeaderPointer().CheckKey("Yunit") == 1:
            yunit = self.data.PutHeaderPointer().PutString("Yunit")

        # 領域自動追加を設
        self.u2.plot.SetAutoAddRegion(self.findChild(
            QAction, "actionAuto_confirm").isChecked())

        # 領域表示のメニュー、ボタンを非表示
        self.u2.plot.viewMenu.menuAction().setVisible(False)
        self.u2.plot.regionMenu.setVisible(False)
        self.u2.plot.toolbar.btn_show.setVisible(False)

        if isNewU2:
            # _action_av = self.u2.plot.canvasMenu.addAction("Average", self.OnAverage)
            # _action_av.setObjectName("actionAverage_context")
            self.u2.plot.canvasMenu.clear()
            _action_mplot = self.u2.plot.canvasMenu.addAction(
                "MPlot", self.OnMPlotFromContext)
            _action_mplot.setObjectName("actionMPlot_context")
            _action_x = self.u2.plot.canvasMenu.addAction(
                "X axis 2D", self.OnM2PlotPlus)
            _action_x.setObjectName("actionX_axis_2D_context")
            _action_y = self.u2.plot.canvasMenu.addAction(
                "Y axis 2D", self.OnM2PlotPlus)
            _action_y.setObjectName("actionY_axis_2D_context")
            """ #[inamura 190301] removed from menu bar
            _action_av_d2 = self.u2.plot.anaMenu.addAction("Average", self.OnAverage)
            _action_av_d2.setObjectName("actionAverage")
            _action_x_d2 = self.u2.plot.anaMenu.addAction("X axis 2D", self.OnM2PlotPlus)
            _action_x_d2.setObjectName("actionX_axis_2D")
            _action_y_d2 = self.u2.plot.anaMenu.addAction("Y axis 2D", self.OnM2PlotPlus)
            _action_y_d2.setObjectName("actionY_axis_2D")
            """
            # バンクセパレータ公開プロパティを登録
            self.ifi.AddProperty(
                'bank_separators', lambda: self.bank_separators)  # [20180116, TI]

        for a in self.u2.plot.canvasMenu.actions():
            if a.objectName() in ["actionMPlot_context", "actionX_axis_2D_context", "actionY_axis_2D_context"]:
                if self.converter.isInelasticPowder:  # データがInelastic Powderの場合 "average"以下は使用不能
                    a.setEnabled(False)
                elif isEcm:
                    a.setEnabled(True)
                else:
                    a.setEnabled(False)
        for a in self.u2.plot.anaMenu.actions():
            if a.objectName() in ["actionAverage", "actionX_axis_2D", "actionY_axis_2D"]:
                if self.converter.isInelasticPowder:  # データがInelastic Powderの場合 "average"以下は使用不能
                    a.setEnabled(False)
                elif isEcm:
                    a.setEnabled(True)
                else:
                    a.setEnabled(False)
        if self.converter.isInelasticPowder:
            msg = "Show data: Inelastic Powder Data"
        elif isEcm:
            msg = "Show data: type ElementContainerMatrix"
        else:
            msg = "Show data: type ElementContainerArray"

        self.u2.SetLabels(xlabel, ylabel)
        self.u2.SetUnits(xunit, yunit)
        self.statusbar.showMessage(msg)

        # If DetectMap mode, show bank separators
        #if len(self.bank_separators) != 0:
        #    self.u2.SetBankSeparator(True)

        # データがDetectMapモードで表示できるかを判定、設定する
        """
        self.isDetMapMode = False
        if isEcm:
            # xkeyがNoneか、DETID, PSDIDならDetectMapモードへ別のものが与えられていたらDetectMapでなくて良い
            if self.data(0, 0).PutHeaderPointer().CheckKey("PixelPolarAngle") == 1 and (xkey in [None, "DETID", "PSDID"]):
                self.isDetMapMode = True
                if self.converter.isInelasticPowder:
                    self.isDetMapMode = False
            self.EraseDummyContainerArray(self.data)
        self.u2.SetDetectMapMode(self.isDetMapMode)
        """
        params = self.ifi.GetProperty('params')
        params.detectmapmode = is_DetMapMode
        # もしDetectMapモードならラベルのデフォルトを変更
        if is_DetMapMode:
            if len(self.bank_separators) != 0:
                self.u2.SetBankSeparator(True)
            self.txt_label_x.setText("Bank")
            self.txt_label_y.setText("Pixel")
            self.UpdateLabels()
        else:
            self.u2.SetBankSeparator(False)

        # D2Frame statusbar表示関数の変更
        if is_DetMapMode:
            if xkey is None and ykey is None:
                self.MakePixelInfosWithBankGap()
            else:
                self.MakePixelInfos(xkey)
            self.u2.plot.canvas.mpl_disconnect(self.u2.plot.cid_mouse_move)
            self.u2.plot.cid_mouse_move = self.u2.plot.canvas.mpl_connect(
                'motion_notify_event', self.OnMouseMove)
        elif self.converter.isInelasticPowder:
            # self.u2.SetLabels("|Q| (1/A)","EnergyTransfer (meV)")
            self.MakePixelInfosForInelaPowder()
            self.u2.plot.canvas.mpl_disconnect(self.u2.plot.cid_mouse_move)
            self.u2.plot.cid_mouse_move = self.u2.plot.canvas.mpl_connect(
                'motion_notify_event', self.OnMouseMove)
        else:
            self.u2.plot.canvas.mpl_disconnect(self.u2.plot.cid_mouse_move)
            self.u2.plot.cid_mouse_move = self.u2.plot.canvas.mpl_connect(
                'motion_notify_event', self.u2.plot.OnMouseMove)

        # プロット情報パネル関連のD2Frameへのイベントリスナー設定
        self.ifi.AddListner('slice', self.OnNotifyAutoSlice)
        self.ifi.AddListner('u2dclosed', self.OnNotifyU2DClose)
        # update view parameters on M2Plot
        self.ifi.AddListner('change_params', self.OnNotifyChangePrms)

        # プロット情報パネルの初期化
        self.InitPlotParamsPanel()

        # プロッタのFileメニューの無効化
        self.u2.plot.findChild(QAction, "actionOpen").setEnabled(False)
        self.u2.plot.findChild(
            QAction, "actionSave_as_Binary").setEnabled(False)
        self.u2.plot.findChild(QAction, "actionSave_as_Text").setEnabled(False)

        # Initial Title and Comment
        if self.initial_viewParams_Title == "":
            title = ""
            comment = self.initial_viewParams_Comment
            runno = self.GetRunNo()
            if runno != "":
                title = "Run No.: {0}".format(runno)
            ei_val = self.GetIncidentEnergy()
            if ei_val > 0.0:
                if comment == "":
                    comment = "Ei = {} meV".format(ei_val)
                else:
                    comment += "\nEi = {} meV".format(ei_val)
            if title != "" or comment != "":
                self.u2.SetTitles(title, comment)
        if self.initial_viewParams_Title != "" or self.initial_viewParams_Comment != "":
            self.u2.SetTitles(self.initial_viewParams_Title,
                              self.initial_viewParams_Comment)
            self.u2.plot.initial_viewParams_Title = self.initial_viewParams_Title
            self.u2.plot.initial_viewParams_Comment = self.initial_viewParams_Comment

    #########################################
    def OnFindPlotter(self):
        """u2dplotウィンドウを浮上させる
        """
        # If u2dplot is alive, turn it hide and show to bring u2dplot front
        if self.u2.plot is not None:
            # self.u2.plot.hide()
            # time.sleep(0.1)
            # self.u2.plot.show()
            getattr(self.u2.plot, "raise")()
            # self.u2.plot.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint) # panel disappeared
            # self.u2.plot.show()

    #########################################
    def OnCheckSliceBin(self):
        """X-およびY-Intensityスライスの横軸のrebinを有効か無効か
           現時点(2019.04.05)は非弾性Powderデータの時のみ機能する
           rebinのチェックボックス状態をu2dplotに送ってApply（再描画）する
        """
        if self.sender() == self.cb_xzslice_bin:
            self.u2.plot.sliceDg.ckb_sliceX.setCheckState(
                self.cb_xzslice_bin.checkState())
            if self.cb_xzslice_bin.checkState() == QtCore.Qt.Checked:
                self.txt_xzslice_bin.setEnabled(True)
            else:
                self.txt_xzslice_bin.setEnabled(False)
        elif self.sender() == self.cb_yzslice_bin:
            self.u2.plot.sliceDg.ckb_sliceY.setCheckState(
                self.cb_yzslice_bin.checkState())
            if self.cb_yzslice_bin.checkState() == QtCore.Qt.Checked:
                self.txt_yzslice_bin.setEnabled(True)
            else:
                self.txt_yzslice_bin.setEnabled(False)
        self.u2.plot.sliceDg.OnApply()

    #########################################
    def UpdateSliceBin(self):
        """X-およびY-Intensityスライスの横軸のrebinの欄を書き換えたら実行
           現時点(2019.04.05)は非弾性Powderデータの時のみ機能する
           rebin入力値をu2dplotに送ってApply（再描画）する
        """
        sender_obj = self.sender()
        if sender_obj == self.txt_xzslice_bin:
            self.u2.plot.sliceDg.txt_xbin.setText(self.txt_xzslice_bin.text())
        elif sender_obj == self.txt_yzslice_bin:
            self.u2.plot.sliceDg.txt_ybin.setText(self.txt_yzslice_bin.text())
        else:
            return
        self.u2.plot.sliceDg.OnApply()

    ########################################
    def UpdateSliceInfo(self):
        """X-およびY-Intensityスライスの情報を書き換えたら実行
           現時点(2019.04.05)は非弾性Powderデータの時のみ機能する
           入力値をu2dplotに送ってApply（再描画）する
        """
        sender_obj = self.sender()
        if sender_obj in [self.txt_xzslice_center, self.txt_xzslice_width, self.txt_xzslice_start, self.txt_xzslice_end]:
            self._ApplySliceParamsToSliceDlg("X")
        elif sender_obj in [self.txt_yzslice_center, self.txt_yzslice_width, self.txt_yzslice_start, self.txt_yzslice_end]:
            self._ApplySliceParamsToSliceDlg("Y")
        else:
            return

    #########################################
    def OnXZSlice1d(self):
        """
        指定値によるX-Z 1Dスライスボタン
        """
        logging.debug("M2PP::OnXZSlice1d")
        if self.rd_xzslice_range.isChecked():  # 範囲を指定した場合
            self.u2.plot.sliceDg.txt_y_start.setText(
                self.txt_xzslice_start.text())
            self.u2.plot.sliceDg.txt_y_end.setText(self.txt_xzslice_end.text())
            self.u2.plot.sliceDg.radio_yrange.setChecked(True)
            xz_delta = 0
            try:
                xz_delta = float(self.txt_xzslice_delta.text())
            except:
                xz_delta = 0.0
            if xz_delta <= 0.0:
                xz_delta = 0.0
                self.txt_xzslice_delta.setText("{}".format(0.0))
            if xz_delta == 0.0:  # スライス幅が0のとき
                # 単独スライスを行う
                self.u2.plot.sliceDg.txt_y_start.setText(
                    self.txt_xzslice_start.text())
                self.u2.plot.sliceDg.txt_y_end.setText(
                    self.txt_xzslice_end.text())
                self.u2.plot.sliceDg.ckb_sliceX.setCheckState(
                    self.cb_xzslice_bin.checkState())
                self.u2.plot.sliceDg.txt_xbin.setText(
                    self.txt_xzslice_bin.text())
                self.u2.plot.sliceDg.OnApply()
                self.u2.plot.OnSliceMPlot("ax_top")
            else:  # スライス幅が指定されていた場合
                # 連続してスライス
                xz_start = float(self.txt_xzslice_start.text())
                xz_end = float(self.txt_xzslice_end.text())
                if (xz_end - xz_start) < xz_delta:
                    xz_delta = xz_end - xz_start
                yval = xz_start
                while(yval <= xz_end):
                    # それぞれの範囲でスライス
                    self.u2.plot.sliceDg.txt_y_start.setText("{}".format(yval))
                    self.u2.plot.sliceDg.txt_y_end.setText("{}".format(yval + xz_delta))
                    self.u2.plot.sliceDg.ckb_sliceX.setCheckState(
                        self.cb_xzslice_bin.checkState())
                    self.u2.plot.sliceDg.txt_xbin.setText(
                        self.txt_xzslice_bin.text())
                    self.u2.plot.sliceDg.OnApply()
                    self.u2.plot.OnSliceMPlot("ax_top")
                    yval += xz_delta
                # 最初の設定値に戻す
                self.txt_xzslice_start.setText("{}".format(xz_start))
                self.txt_xzslice_end.setText("{}".format(xz_end))
        else:  # 中心と幅で指定した場合
            isSingleSlice = False
            # 連続スライス用のパラメータが設定されているか
            try:
                center_to = float(self.txt_xzslice_center_to.text())
                center_step = float(self.txt_xzslice_center_step.text())
            except:
                isSingleSlice = True
            if isSingleSlice:
                # 単独スライスを行う
                self.u2.plot.sliceDg.txt_y_center.setText(
                    self.txt_xzslice_center.text())
                self.u2.plot.sliceDg.txt_y_width.setText(
                    self.txt_xzslice_width.text())
                self.u2.plot.sliceDg.radio_yvalue.setChecked(True)
                self.u2.plot.sliceDg.ckb_sliceX.setCheckState(
                    self.cb_xzslice_bin.checkState())
                self.u2.plot.sliceDg.txt_xbin.setText(
                    self.txt_xzslice_bin.text())
                self.u2.plot.sliceDg.OnApply()
                self.u2.plot.OnSliceMPlot("ax_top")
            else:
                # 連続してスライス
                center_v = float(self.txt_xzslice_center.text())
                center_c = center_v
                while((center_c * (1.0 - EPCILON)) <= center_to):
                    self.u2.plot.sliceDg.txt_y_center.setText(
                        "{}".format(center_c))
                    self.u2.plot.sliceDg.txt_y_width.setText(
                        self.txt_xzslice_width.text())
                    self.u2.plot.sliceDg.radio_yvalue.setChecked(True)
                    self.u2.plot.sliceDg.ckb_sliceX.setCheckState(
                        self.cb_xzslice_bin.checkState())
                    self.u2.plot.sliceDg.txt_xbin.setText(
                        self.txt_xzslice_bin.text())
                    self.u2.plot.sliceDg.OnApply()
                    self.u2.plot.OnSliceMPlot("ax_top")
                    center_c += center_step
                # 最初の設定値に戻す
                self.txt_xzslice_center.setText("{}".format(center_v))
        """
        if self.rd_xzslice_value.isChecked():
            self.u2.plot.sliceDg.txt_y_center.setText(self.txt_xzslice_center.text())
            self.u2.plot.sliceDg.txt_y_width.setText(self.txt_xzslice_width.text())
            self.u2.plot.sliceDg.radio_yvalue.setChecked(True)
        else:
            self.u2.plot.sliceDg.txt_y_start.setText(self.txt_xzslice_start.text())
            self.u2.plot.sliceDg.txt_y_end.setText(self.txt_xzslice_end.text())
            self.u2.plot.sliceDg.radio_yrange.setChecked(True)
        """
        # u2dplotへ反映
        if self.u2.plot.sliceDg.radio_xvalue.isChecked():
            if self.u2.plot.sliceDg.txt_x_center.text() == "":
                xbin = self.u2.plot.data[1][0]
                self.u2.plot.sliceDg.txt_x_center.setText(
                    "{0:.3f}".format(xbin.mean()))
                self.u2.plot.sliceDg.txt_x_width.setText("0.0")
        else:
            if self.u2.plot.sliceDg.txt_x_start.text() == "":
                xbin = self.u2.plot.data[1][0]
                self.u2.plot.sliceDg.txt_x_start.setText(
                    "{0:.3f}".format(xbin.mean()))
                self.u2.plot.sliceDg.txt_x_end.setText(
                    "{0:.3f}".format(xbin.mean()))
        """
        self.u2.plot.sliceDg.OnApply()

        self.u2.plot.sliceDg.ckb_sliceX.setCheckState( self.cb_xzslice_bin.checkState() )
        self.u2.plot.sliceDg.txt_xbin.setText( self.txt_xzslice_bin.text() )

        self.u2.plot.OnSliceMPlot("ax_top")
        """
        return

    #########################################
    def OnSlice1dClear(self):
        """
        Clear X-Z 1D plots
        """
        logging.debug("M2PP::OnSlice1dClear")
        sender_name = self.sender().objectName()
        if self.u2 is not None:
            if self.u2.plot is not None:
                if sender_name == "btXZSlice1dclear":
                    if (self.u2.plot.mp_top is not None) and (self.u2.plot.mp_top.plot.IsAliveComm()):
                        self.u2.plot.mp_top.Remove(0)
                else:
                    if (self.u2.plot.mp_right is not None) and (self.u2.plot.mp_right.plot.IsAliveComm()):
                        self.u2.plot.mp_right.Remove(0)

    #########################################
    def OnYZSlice1d(self):
        """
        指定値によるY-Z 1Dスライスボタン
        """
        logging.debug("M2PP::OnYZSlice1d")
        if self.rd_yzslice_range.isChecked():  # 範囲を指定した場合
            self.u2.plot.sliceDg.radio_xrange.setChecked(True)
            yz_delta = 0
            try:
                yz_delta = float(self.txt_yzslice_delta.text())
            except:
                yz_delta = 0
            if yz_delta <= 0.0:
                yz_delta = 0.0
                self.txt_yzslice_delta.setText("{}".format(0.0))
            if yz_delta == 0:  # スライス幅が0のとき
                # 単独スライスを行う
                self.u2.plot.sliceDg.txt_x_start.setText(
                    self.txt_yzslice_start.text())
                self.u2.plot.sliceDg.txt_x_end.setText(
                    self.txt_yzslice_end.text())
                self.u2.plot.sliceDg.ckb_sliceY.setCheckState(
                    self.cb_yzslice_bin.checkState())
                self.u2.plot.sliceDg.txt_ybin.setText(
                    self.txt_yzslice_bin.text())
                self.u2.plot.sliceDg.OnApply()
                self.u2.plot.OnSliceMPlot("ax_right")
            else:  # スライス幅が指定されていた場合
                # 連続してスライス
                yz_start = float(self.txt_yzslice_start.text())
                yz_end = float(self.txt_yzslice_end.text())
                if (yz_end - yz_start) < yz_delta:
                    yz_delta = yz_end - yz_start
                xval = yz_start
                while(xval <= yz_end):
                    # それぞれの範囲でスライス
                    self.u2.plot.sliceDg.txt_x_start.setText("{}".format(xval))
                    self.u2.plot.sliceDg.txt_x_end.setText("{}".format(xval + yz_delta))
                    self.u2.plot.sliceDg.ckb_sliceY.setCheckState(
                        self.cb_yzslice_bin.checkState())
                    self.u2.plot.sliceDg.txt_ybin.setText(
                        self.txt_yzslice_bin.text())
                    self.u2.plot.sliceDg.OnApply()
                    self.u2.plot.OnSliceMPlot("ax_right")
                    xval += yz_delta
                # 最初の設定値に戻す
                self.txt_yzslice_start.setText("{}".format(yz_start))
                self.txt_yzslice_end.setText("{}".format(yz_end))
        else:  # 中心と幅で指定した場合
            isSingleSlice = False
            # 連続スライス用のパラメータが設定されているか
            try:
                center_to = float(self.txt_yzslice_center_to.text())
                center_step = float(self.txt_yzslice_center_step.text())
            except:
                isSingleSlice = True
            if isSingleSlice:
                # 単独スライスを行う
                self.u2.plot.sliceDg.txt_x_center.setText(
                    self.txt_yzslice_center.text())
                self.u2.plot.sliceDg.txt_x_width.setText(
                    self.txt_yzslice_width.text())
                self.u2.plot.sliceDg.radio_xvalue.setChecked(True)
                self.u2.plot.sliceDg.ckb_sliceY.setCheckState(
                    self.cb_yzslice_bin.checkState())
                self.u2.plot.sliceDg.txt_ybin.setText(
                    self.txt_yzslice_bin.text())
                self.u2.plot.sliceDg.OnApply()
                self.u2.plot.OnSliceMPlot("ax_right")
            else:
                # 連続してスライス
                center_v = float(self.txt_yzslice_center.text())
                center_c = center_v
                while((center_c * (1.0 - EPCILON)) <= center_to):
                    self.u2.plot.sliceDg.txt_x_center.setText(
                        "{}".format(center_c))
                    self.u2.plot.sliceDg.txt_x_width.setText(
                        self.txt_yzslice_width.text())
                    self.u2.plot.sliceDg.radio_xvalue.setChecked(True)
                    self.u2.plot.sliceDg.ckb_sliceY.setCheckState(
                        self.cb_yzslice_bin.checkState())
                    self.u2.plot.sliceDg.txt_ybin.setText(
                        self.txt_yzslice_bin.text())
                    self.u2.plot.sliceDg.OnApply()
                    self.u2.plot.OnSliceMPlot("ax_right")
                    center_c += center_step
                # 最初の設定値に戻す
                self.txt_yzslice_center.setText("{}".format(center_v))
        """
        if self.rd_yzslice_value.isChecked():
            self.u2.plot.sliceDg.txt_x_center.setText(self.txt_yzslice_center.text())
            self.u2.plot.sliceDg.txt_x_width.setText(self.txt_yzslice_width.text())
            self.u2.plot.sliceDg.radio_xvalue.setChecked(True)
        else:
            self.u2.plot.sliceDg.txt_x_start.setText(self.txt_yzslice_start.text())
            self.u2.plot.sliceDg.txt_x_end.setText(self.txt_yzslice_end.text())
            self.u2.plot.sliceDg.radio_xrange.setChecked(True)
        """
        # u2dplotへ反映
        if self.u2.plot.sliceDg.radio_yvalue.isChecked():
            if self.u2.plot.sliceDg.txt_y_center.text() == "":
                ybin = self.u2.plot.data[2].T[0]
                self.u2.plot.sliceDg.txt_y_center.setText(
                    "{0:.3f}".format(ybin.mean()))
                self.u2.plot.sliceDg.txt_y_width.setText("0.0")
        else:
            if self.u2.plot.sliceDg.txt_y_start.text() == "":
                ybin = self.u2.plot.data[2].T[0]
                self.u2.plot.sliceDg.txt_y_start.setText(
                    "{0:.3f}".format(ybin.mean()))
                self.u2.plot.sliceDg.txt_y_end.setText(
                    "{0:.3f}".format(ybin.mean()))
        """
        self.u2.plot.sliceDg.OnApply()

        self.u2.plot.sliceDg.ckb_sliceY.setCheckState( self.cb_yzslice_bin.checkState() )
        self.u2.plot.sliceDg.txt_ybin.setText( self.txt_yzslice_bin.text() )

        self.u2.plot.OnSliceMPlot("ax_right")
        """
        return

    #########################################
    def OnDiagonal1d(self):
        """
        ドラッグ＆ドロップした始点と終点で1Dスライスする

        """
        logging.debug("M2PP::OnDIagonal1d")
        # GUIから値を取り出し、スライス範囲として設定する
        x0 = float(self.txt_diagonal_sp_x.text())
        y0 = float(self.txt_diagonal_sp_y.text())
        x1 = float(self.txt_diagonal_ep_x.text())
        y1 = float(self.txt_diagonal_ep_y.text())
        self.u2.plot.SetSliceRegionToDialog((x0, y0, x1, y1))

        # Diagonal Sliceのためのパラメータを設定する
        width = float(self.txt_diagonal_width.text())
        binning = float(self.txt_diagonal_binning.text())
        params = self.ifi.GetProperty('params')
        params.diagonalSliceInfo = [width, binning]

        # Diagonal Sliceを実行する
        self.u2.plot.OnDiagonalSlice()

        # X-Z Sliceや Y-Z Sliceに反映する
        self.u2.plot.sliceDg.OnApply()
        # この時 y0とy1が入れ替わる可能性があるので元に戻す
        # x0とx1は入れ替わるのが仕様
        self.txt_diagonal_sp_y.setText("{0:.3f}".format(y0))
        self.txt_diagonal_ep_y.setText("{0:.3f}".format(y1))

    #########################################
    def _ApplySliceParamsToSliceDlg(self, which="all"):
        """
        メインパネルのSlice情報を u2dplotのSliceDialogに反映させる

        @param which (string) どのスライス情報か（"all","x","y"）
        @param None
        """
        if self.u2.plot is None:
            return
        flag = which.lower()
        if flag not in ["all", "x", "y"]:
            return False
        if flag == "x" or flag == "all":  # XZ-slice panel
            if self.rd_xzslice_value.isChecked():
                self.u2.plot.sliceDg.txt_y_center.setText(
                    self.txt_xzslice_center.text())
                self.u2.plot.sliceDg.txt_y_width.setText(
                    self.txt_xzslice_width.text())
                self.u2.plot.sliceDg.radio_yvalue.setChecked(True)
            else:
                self.u2.plot.sliceDg.txt_y_start.setText(
                    self.txt_xzslice_start.text())
                self.u2.plot.sliceDg.txt_y_end.setText(
                    self.txt_xzslice_end.text())
                self.u2.plot.sliceDg.radio_yrange.setChecked(True)

            if self.u2.plot.sliceDg.radio_xvalue.isChecked():
                if self.u2.plot.sliceDg.txt_x_center.text() == "":
                    xbin = self.u2.plot.data[1][0]
                    self.u2.plot.sliceDg.txt_x_center.setText(
                        "{0:.3f}".format(xbin.mean()))
                    self.u2.plot.sliceDg.txt_x_width.setText("0.0")
            else:
                if self.u2.plot.sliceDg.txt_x_start.text() == "":
                    xbin = self.u2.plot.data[1][0]
                    self.u2.plot.sliceDg.txt_x_start.setText(
                        "{0:.3f}".format(xbin.mean()))
                    self.u2.plot.sliceDg.txt_x_end.setText(
                        "{0:.3f}".format(xbin.mean()))
        if flag == "y" or flag == "all":  # YZ-slice panel
            if self.rd_yzslice_value.isChecked():
                self.u2.plot.sliceDg.txt_x_center.setText(
                    self.txt_yzslice_center.text())
                self.u2.plot.sliceDg.txt_x_width.setText(
                    self.txt_yzslice_width.text())
                self.u2.plot.sliceDg.radio_xvalue.setChecked(True)
            else:
                self.u2.plot.sliceDg.txt_x_start.setText(
                    self.txt_yzslice_start.text())
                self.u2.plot.sliceDg.txt_x_end.setText(
                    self.txt_yzslice_end.text())
                self.u2.plot.sliceDg.radio_xrange.setChecked(True)

            if self.u2.plot.sliceDg.radio_yvalue.isChecked():
                if self.u2.plot.sliceDg.txt_y_center.text() == "":
                    ybin = self.u2.plot.data[2].T[0]
                    self.u2.plot.sliceDg.txt_y_center.setText(
                        "{0:.3f}".format(ybin.mean()))
                    self.u2.plot.sliceDg.txt_y_width.setText("0.0")
            else:
                if self.u2.plot.sliceDg.txt_y_start.text() == "":
                    ybin = self.u2.plot.data[2].T[0]
                    self.u2.plot.sliceDg.txt_y_start.setText(
                        "{0:.3f}".format(ybin.mean()))
                    self.u2.plot.sliceDg.txt_y_end.setText(
                        "{0:.3f}".format(ybin.mean()))

        self.u2.plot.sliceDg.OnApply()
        return True

    #########################################
    def OnXZSlice2d(self):
        """
        指定値によるX-Z 2Dスライスボタン
        """
        logging.debug("M2PP::OnXZSlice2d")
        self._ApplySliceParamsToSliceDlg(which="all")

        if float(self.txt_xzslice_width.text()) == 0.0:
            # event.xdata, event.ydataは表示上の値
            if not self.u2.IsTransposed():
                xdata = float(self.txt_yzslice_center.text())
                ydata = float(self.txt_xzslice_center.text())
                self._OnM2PlotPlus(xdata, ydata, isXaxis=True)
            else:
                xdata = float(self.txt_xzslice_center.text())
                ydata = float(self.txt_yzslice_center.text())
                self._OnM2PlotPlus(xdata, ydata, isXaxis=False)
        else:
            if not self.u2.IsTransposed():
                values = (float(self.txt_yzslice_start.text()),
                          float(self.txt_xzslice_start.text()),
                          float(self.txt_yzslice_end.text()),
                          float(self.txt_xzslice_end.text())
                          )
                plot_type = "X"
            else:
                values = (float(self.txt_xzslice_start.text()),
                          float(self.txt_yzslice_start.text()),
                          float(self.txt_xzslice_end.text()),
                          float(self.txt_yzslice_end.text())
                          )
                plot_type = "Y"
            self._OnM2PlotPlusArea(plot_type, values)

    #########################################
    def OnYZSlice2d(self):
        """
        指定値によるX-Z 2Dスライスボタン
        """
        logging.debug("M2PP::OnYZSlice2d")
        self._ApplySliceParamsToSliceDlg(which="all")

        if float(self.txt_yzslice_width.text()) == 0.0:
            # event.xdata, event.ydataは表示上の値
            if not self.u2.IsTransposed():
                xdata = float(self.txt_yzslice_center.text())
                ydata = float(self.txt_xzslice_center.text())
                self._OnM2PlotPlus(xdata, ydata, isXaxis=False)
            else:
                xdata = float(self.txt_xzslice_center.text())
                ydata = float(self.txt_yzslice_center.text())
                self._OnM2PlotPlus(xdata, ydata, isXaxis=True)
        else:
            if not self.u2.IsTransposed():
                values = (float(self.txt_yzslice_start.text()),
                          float(self.txt_xzslice_start.text()),
                          float(self.txt_yzslice_end.text()),
                          float(self.txt_xzslice_end.text())
                          )
                plot_type = "Y"
            else:
                values = (float(self.txt_xzslice_start.text()),
                          float(self.txt_yzslice_start.text()),
                          float(self.txt_xzslice_end.text()),
                          float(self.txt_yzslice_end.text())
                          )
                plot_type = "X"
            # print("#[inamura 190227] OnYZSlice2d values=",values)
            self._OnM2PlotPlusArea(plot_type, values)

    ##########################################################
    def OnRadioButtonAS(self, *args):
        """
        [inamura 190226]
        """
        self.rb_isSumSlice.setChecked(not self.rb_isAveSlice.isChecked())
        params = self.ifi.GetProperty('params')
        params.slice_ave_mode = bool(self.rb_isAveSlice.isChecked())
        self.UpdatePlotParams()

    ##########################################################
    def OnRadioButtonSS(self, *args):
        """
        [inamura 190226]
        """
        self.rb_isAveSlice.setChecked(not self.rb_isSumSlice.isChecked())
        params = self.ifi.GetProperty('params')
        params.slice_ave_mode = bool(self.rb_isAveSlice.isChecked())
        self.UpdatePlotParams()

    #########################################
    def OnM2PlotPlusArea(self, sender_name):
        """
        選択された領域のデータをM2PlotPlusで表示

        @param sender_name (string) 対応するメニューオブジェクトの名前
        @retval None
        """
        # "X axis 2D" or "Y axis 2D"
        if sender_name in ["actionX_axis_2D_context"]:
            plot_type = "X"
        elif sender_name in ["actionY_axis_2D_context"]:
            plot_type = "Y"
        else:
            return

        # 以降はcall_sliceから一部借用
        # 最後に選択された領域の座標を得る
        values = self.u2.plot._last_slice_drag_values[:]
        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]
        else:
            return

        params = self.ifi.GetProperty('params')
        if params.transPosition:
            _values = list(values)
            values = (_values[1], _values[0], _values[3], _values[2])
            if plot_type == "X":
                plot_type = "Y"
            else:
                plot_type = "X"

        self._OnM2PlotPlusArea(plot_type, values)
    #########################################

    def _OnM2PlotPlusArea(self, plot_type, values):
        """
        ドラッグ&ドロップした領域におけるスライスとM2PlotPlus表示
        #[inamura 190228]
        @param plot_type (str) X or Y
        @param values (tupple of coordinates) 矩形選択の対角線の座標 (x0,y0,x1,y1)
        @retval None
        """
        params = self.ifi.GetProperty('params')
        # Key
        # [20170620, TI] TODO: ykeyがNoneなことはない？
        _ykey = str(self.converter.ykey)
        _xkey = str(self.converter.xkey)
        _rkey = str(self.converter.rkey)
        _intKey = str(self.converter.intKey)

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

        # bin数、データ数
        n_x_plot = len(xbin)  # プロットX軸区切り数
        n_x_data = self.data.PutSize()  # データECM中のECA数 or ECA中のEC数
        if self.converter._eca is not None:
            n_x_data = self.converter._eca.PutSize()

        # plot_index: 表示binでのindex, data_index: 読み込みデータでのindex
        # if (n_x_plot - 1) == n_x_data: # 散布データ [20170610 TI] TODO: Falseの場合を考える
        if (n_x_plot - 1) == n_x_data or self.converter.isInelasticPowder:
            if values[0] <= xbin[0]:
                plot_index_x0 = 0  # 最小のbinをさしたものとみなす
            elif values[0] >= xbin[-1]:
                plot_index_x0 = n_x_data - 1  # 最大のbinを指したものとみなす
            else:
                plot_index_x0 = np.searchsorted(
                    xbin, values[0]) - 1  # xbinでのindex
            if len(values) == 4:
                # plot_index_x1 = np.searchsorted(xbin, values[2]) - 1 # xbinでのindex
                if values[2] <= xbin[0]:
                    plot_index_x1 = 0
                elif values[2] >= xbin[-1]:
                    plot_index_x1 = n_x_data
                else:
                    plot_index_x1 = np.searchsorted(
                        xbin, values[2]) - 1  # xbinでのindex
            else:
                plot_index_x1 = None

        plot_index_y0 = np.searchsorted(ybin, values[1]) - 1  # ybinでのindex
        if len(values) == 4:
            plot_index_y1 = np.searchsorted(ybin, values[3]) - 1  # ybinでのindex
        else:
            plot_index_y1 = None
        # 借用ここまで

        # print( "#[inamura 190226] plot_index_x0 = {}".format(plot_index_x0) )
        # print( "#[inamura 190226] plot_index_x1 = {}".format(plot_index_x1) )
        # print( "#[inamura 190226] plot_index_y0 = {}".format(plot_index_y0) )
        # print( "#[inamura 190226] plot_index_y1 = {}".format(plot_index_y1) )

        # スライスの作成
        ret_eca = None
        AE = mm.AverageElementContainerMatrix(self.data)
        if plot_type == "X":  # X axis 2D
            ret_eca = Manyo.ElementContainerArray()
            # Detector方向へのループ
            for i in range(self.data.PutSize()):
                det_v = Manyo.MakeUInt4Vector()
                pix_v = Manyo.MakeUInt4Vector()
                # Pixel方向へのループ（範囲指定）
                for j in range(plot_index_y0, (plot_index_y1 + 1)):
                    pv = self.converter.slicer.PutDetectMapIndex(i, j)
                    if (pv[0] != -1) and pv[1] != -1:
                        det_v.append(i)
                        pix_v.append(pv[1])
                AE.SetPoints(det_v, pix_v)
                # 計算
                if params.slice_ave_mode:
                    ret_ec = AE.GetAverage()
                else:
                    ret_ec = AE.GetSum()
                masked_flag = ret_ec.PutHeaderPointer().PutInt4("MASKED")
                # ヘッダ調整（中央のPixelのヘッダを流用）
                y_center_index = int((plot_index_y0 + plot_index_y1) / 2)
                hh = self.data(i, y_center_index).PutHeader()
                hh.OverWrite("MASKED", masked_flag)
                ret_ec.InputHeader(hh)
                ret_eca.Add(ret_ec)
        else:  # Y axis 2D
            ret_eca = Manyo.ElementContainerArray()
            # Pixel方向へのループ
            for i in range(self.data(0).PutSize()):
                det_v = Manyo.MakeUInt4Vector()
                pix_v = Manyo.MakeUInt4Vector()
                # Detector方向へのループ（範囲指定）
                for j in range(plot_index_x0, (plot_index_x1 + 1)):
                    pv = self.converter.slicer.PutDetectMapIndex(j, i)
                    if (pv[0] != -1) and pv[1] != -1:
                        det_v.append(pv[0])
                        pix_v.append(i)
                AE.SetPoints(det_v, pix_v)
                # 計算
                if params.slice_ave_mode:
                    ret_ec = AE.GetAverage()
                else:
                    ret_ec = AE.GetSum()
                masked_flag = ret_ec.PutHeaderPointer().PutInt4("MASKED")
                # ヘッダ変更（中央のDetectorのヘッダを流用,"PIXEL"の追加）
                x_center_index = int((plot_index_x0 + plot_index_x1) / 2)
                hh = self.data(x_center_index, i).PutHeader()
                hh.OverWrite("MASKED", masked_flag)
                if hh.CheckKey("PIXEL") == 0:
                    hh.Add("PIXEL", i)
                else:
                    hh.OverWrite("PIXEL", i)
                ret_ec.InputHeader(hh)
                ret_eca.Add(ret_ec)

        del AE
        # 表示
        p = m2cui.M2PlotPlusCui()
        p.ChangeData(ret_eca)
        # p.ShowData(xkey=,ykey="-",rkey="-",r_min=0.0, r_max=0.0)
        if plot_type == "X":
            p.SetCurrentKey(self._currentXKey)
        elif plot_type == "Y":
            p.SetCurrentKey(self._currentYKey)

    #########################################
    def OnM2PlotPlus(self):
        """
        ECMの一部をM2PlotPlus表示

        """
        isXaxis = True
        sender_name = self.sender().objectName()
        if sender_name in ["actionX_axis_2D", "actionY_axis_2D"]:  # メニュー呼び出し
            rname, color, values, isSelected = self.u2.GetSelectedRegInfo()  # 選択領域情報 # 転置で変化しない
            if rname in ["Point"]:
                xdata = values[0]
                ydata = values[1]
            else:
                logging.info('Select a "Point" to use this funtion.')
                return
        else:  # コンテキストメニュー呼び出し
            if self.u2.plot.last_clicked_point is None:
                # print("#[inamura 190222] self.last_clicked_point = None")
                # [inamura 190222] 本来、選択領域をSummation/Averageするべき。ペンディング。
                # print("#[inamura 190222] _last_slice_drag_values = ",self.u2.plot._last_slice_drag_values)
                self.OnM2PlotPlusArea(sender_name)
                return
            event = self.u2.plot._r_click_event
            ax = event.inaxes  # 呼び出しAxes
            gid = ax.get_gid()  # 呼び出しAxesのGroup ID。ax_top or ax_right
            if gid is not None:
                return
            # event.xdata, event.ydataは表示上の値
            if not self.u2.IsTransposed():
                # xdata = event.xdata
                # ydata = event.ydata
                xdata = self.u2.plot.last_clicked_point[0]
                ydata = self.u2.plot.last_clicked_point[1]
            else:
                # xdata = event.ydata
                # ydata = event.xdata
                xdata = self.u2.plot.last_clicked_point[1]
                ydata = self.u2.plot.last_clicked_point[0]
        if "Y_axis_2D" in sender_name:
            if not self.u2.IsTransposed():
                isXaxis = False
        elif "X_axis_2D" in sender_name:
            if self.u2.IsTransposed():
                isXaxis = False

        self._OnM2PlotPlus(xdata, ydata, isXaxis)
    #########################################

    def _OnM2PlotPlus(self, xdata, ydata, isXaxis):
        """
        クリックした点におけるスライスとM2PlotPlus表示
        #[inamura 190228]
        @param xdata (float) クリック点のX座標
        @param ydata (float) クリック点のY座標
        @param isXaxis (bool) 実データに対するスライス方向がX(PDS方向)かどうか
        @retval None
        """
        # 表示軸ndarray取り出し # 値は転置で変化しない
        xbin = self.u2.plot.data[1][0]
        ybin = self.u2.plot.data[2].T[0]

        n_x_plot = len(xbin)  # プロットX軸区切り数
        plot_index_x = int(np.searchsorted(xbin, xdata)) - 1  # xbinでのindex
        n_x_data = self.data.PutSize()  # データECM中のECA数 or ECA中のEC数
        # ECM/ECAでのindex
        data_index_x = self.converter.indices_sort[plot_index_x]
        if isinstance(self.data, Manyo.ElementContainerArray):
            return
        else:
            n_y_plot = len(ybin)  # プロットy軸区切り数
            n_y_data = self.data(0).PutSize()  # データECM中のECA中のEC数
            if (n_y_plot - 1) == n_y_data:
                plot_index_y = int(np.searchsorted(ybin, ydata)) - 1
            pv = self.converter.slicer.PutDetectMapIndex(
                plot_index_x, plot_index_y)
            if len(pv) == 0:
                raise PlotException(
                    'Common', 'C001', ("Range over", "D2Frame:OnMonuseUp"))
            elif pv[0] == -1 or pv[1] == -1:
                print("#[inamura 190228] OnM2PlotPlus detector at ({},{}) must be ignored.".format(
                    plot_index_x, plot_index_y))
                return
            else:
                cbR = self.findChild(QtWidgets.QComboBox, "cbR")
                rkey = str(cbR.currentText())
                p = m2cui.M2PlotPlusCui()
                if isXaxis:
                    _eca = Manyo.ElementContainerArray()
                    for i in range(self.data.PutSize()):
                        _eca.Add(self.data(i, pv[1]))
                    p.ChangeData(_eca)
                    del _eca
                    cbX = self.findChild(QtWidgets.QComboBox, "cbX")
                    xkey = str(cbX.currentText())
                    if xkey == "Index":
                        xkey = "-"
                    p.ShowData(xkey, rkey, "-", 0.0, 0.0)
                    msg = "X axis 2D at Y = {0}".format(ydata)
                else:
                    p.ChangeData(self.data.Put(pv[0]))
                    cbY = self.findChild(QtWidgets.QComboBox, "cbY")
                    ykey = str(cbY.currentText())
                    if ykey == "Index":
                        ykey = "-"
                    p.ShowData(ykey, rkey, "-", 0.0, 0.0)
                    msg = "Y axis 2D at X = {0}".format(xdata)
                self.statusbar.showMessage(msg)

    #########################################
    def _GetIntKeys(self, ecobj):
        """EC, ECAのヘッダーより、マスクを除く整数キーを取得

        Parameters:
            ecobj (ECA or EC): ヘッダを取り出すECA, EC

        Returns:
            list of strings: キーのリスト
        """
        keys = []
        units = []
        # ヘッダを取得
        head = ecobj.PutHeaderPointer()
        # ヘッダストリングを取得
        hdump = head.DumpToString()
        # 整数型のキーを取得
        inth_num = int(hdump.split('#,#')[0])
        inth = hdump.split('#,#')[1]
        inth_v = inth.split('\\,')
        if len(inth_v) != inth_num:
            inth_v = inth.split(',')
        for key in inth_v:
            if key != "MASKED" and key != "None" and key != "isHistogram":
                keys.append(key)
                units.append("")
        return keys, units

    ######################################
    def _GetDoubleKeys(self, ecobj):
        """EC, ECAのヘッダーより、Doubleキーを取得

        Parameters:
            ecobj (ECA or EC): ヘッダを取り出すECA, EC

        Returns:
            list of strings: キーのリスト
        """
        keys = []
        units = []
        # ヘッダを取得
        head = ecobj.PutHeaderPointer()
        # ヘッダストリングを取得
        hdump = head.DumpToString()
        # Double型のキーを取得
        doubleh_num = int(hdump.split('#,#')[3])
        doubleh = hdump.split('#,#')[4]
        doubleh_v = doubleh.split('\\,')
        if len(doubleh_v) != doubleh_num:
            doubleh_v = doubleh.split(',')
        for key in doubleh_v:
            if key != "None":
                keys.append(key)
                units.append("")
                if key == "Xaxis":
                    if head.CheckKey("Xunit") == 1:
                        units[-1] = head.PutString("Xunit")
                if head.CheckKey("_UNIT_" + key) == 1:
                    units[-1] = head.PutString("_UNIT_" + key)

        return keys, units

    ######################################
    def _GetVecKeys(self, ec, getAllKeys=False):
        """ECより、vector のキーを取得(強度とエラーのキーを除く)

        Parameters:
            ecobj (EC): ヘッダを取り出すECA, EC

        Returns:
            list of strings: キーのリスト
        """
        # ベクターの全キーを取得
        vkeys = ec.PutKeysList()

        # X, Y, Er のキーを取得
        xkey = ec.PutXKey()
        ykey = ec.PutYKey()
        ekey = ec.PutEKey()

        # X, Y, Erのキーについては先頭に並ぶようにする。
        if getAllKeys:
            keys = [ykey, ekey, xkey]
            units = [ec.PutUnit(ykey), ec.PutUnit(ekey), ec.PutUnit(xkey)]
        else:
            keys = [xkey]
            units = [ec.PutUnit(xkey)]

        # X, Y, Er 以外のキーを追加
        for key in vkeys:
            if key != xkey and key != ykey and key != ekey:
                keys.append(key)
                units.append("")

        return keys, units

    #######################################
    def CopyKeyToLabel(self):
        """キーCombobox変更時にラベルにコピー

        """
        if self.sender().objectName() == "cbX":
            self.txt_label_x.setText(str(self.cbX.currentText()))
            self.txt_unit_x.setText(
                str(self.cbX_units[self.cbX.currentIndex()]))
        elif self.sender().objectName() == "cbY":
            self.txt_label_y.setText(str(self.cbY.currentText()))
            self.txt_unit_y.setText(
                str(self.cbY_units[self.cbY.currentIndex()]))

    #######################################
    def UpdateLabels(self):
        """プロットラベル更新

        """
        xlabel = self.txt_label_x.text()
        ylabel = self.txt_label_y.text()
        xunit = self.txt_unit_x.text()
        yunit = self.txt_unit_y.text()
        if self.u2 is not None:
            self.u2.SetLabels(xlabel, ylabel)
            self.u2.SetUnits(xunit, yunit)

    ##########################################################
    # プロット情報パネル関連
    ##########################################################
    def PlotParamsPanelTurnOn(self, flag):
        """
        プロット情報パネルのオン・オフ
        @param flag (bool) True:On, False:Off
        @retval None
        """
        self.groupBox_int.setEnabled(flag)
        self.btIntApply.setEnabled(flag)
        self.groupBox_xscale.setEnabled(flag)
        self.groupBox_yscale.setEnabled(flag)
        self.groupBox_slice.setEnabled(flag)
        self.btXZSlice2d.setEnabled(flag)
        self.btYZSlice2d.setEnabled(flag)
        # 2D Plotボタンは、ElementContainerMatrixデータの時のみ有効
        if self.converter.CheckInelasticPowderData(self.data) or isinstance(self.data, Manyo.ElementContainerArray):
            self.btXZSlice2d.setEnabled(False)
            self.btYZSlice2d.setEnabled(False)
        # FindPlotterボタンも連動
        self.btFindPlt.setEnabled(flag)

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

    def OnPlotParamsApply(self):
        """
        Applyボタンが押された時の処理
        @param None
        @retval None
        """
        self.UpdatePlotParams(False)

    #########################################
    def OnCheckAutoInt(self):
        """
        Inteinsty:Auto Scaleチェックボックスが変更された時の処理
        @param None
        @retval None
        """
        if self.chk_int_auto_range.checkState() == QtCore.Qt.Checked:
            self.SetIntState(True)
        else:
            self.SetIntState(False)
        self.UpdatePlotParams()

    #########################################
    def SetIntState(self, flag):
        params = self.ifi.GetProperty('params')
        self.txt_int_min.setEnabled(not flag)
        self.txt_int_max.setEnabled(not flag)
        self.label_int_range.setEnabled(not flag)
        self.label_int_range_h.setEnabled(not flag)
        params.autoRange = flag

        if params.range is not None:
            if flag:
                tmp_array = np.array(self.u2.plot.data[0])
                masked_arr = np.ma.masked_where(tmp_array >= MASKVALUE, tmp_array)
                params.range = (self.u2.plot.data[0].min(), float(masked_arr.max()))
            # stR0 = "%.3f" % params.range[0]
            # stR1 = "%.3f" % params.range[1]
            stR0 = "%g" % params.range[0]
            stR1 = "%g" % params.range[1]
            self.txt_int_min.setText(stR0)
            self.txt_int_max.setText(stR1)

    #########################################
    def OnCheckIntLog(self):
        """
        Inteinsty:Log Scaleチェックボックスが変更された時の処理
        @param None
        @retval None
        """
        params = self.ifi.GetProperty('params')
        if self.chk_int_log.checkState() == QtCore.Qt.Checked:
            params.logScale = True
        else:
            params.logScale = False
        self.UpdatePlotParams()

    #########################################
    def OnCheckSmooth(self):
        """
        Inteinsty:Smoothingチェックボックスが変更された時の処理
        @param None
        @retval None
        """
        params = self.ifi.GetProperty('params')
        if self.chk_smooth.checkState() == QtCore.Qt.Checked:
            params.smoothing = [True, int(self.txt_smooth_win.text()), int(
                self.txt_smooth_tim.text())]
        else:
            params.smoothing = [False, 1.0, 1.0]
        self.UpdatePlotParams()

    #########################################
    def OnCheckXAutoRange(self):
        """
        XScale:Auto Scaleチェックボックスが変更された時の処理
        @param None
        @retval None
        """
        params = self.ifi.GetProperty('params')
        if self.chk_xscale_auto_range.checkState() == QtCore.Qt.Checked:
            self.txt_xscale_min.setEnabled(False)
            self.txt_xscale_max.setEnabled(False)
            self.label_xscale_range.setEnabled(False)
            self.label_xscale_h.setEnabled(False)
            params.xscale.autoRange = True
            params.xscale.range = (self.u2.plot.data[1].min(), self.u2.plot.data[1].max())
        else:
            self.txt_xscale_min.setEnabled(True)
            self.txt_xscale_max.setEnabled(True)
            self.label_xscale_range.setEnabled(True)
            self.label_xscale_h.setEnabled(True)
            params.xscale.autoRange = False
            self.txt_xscale_min.setText("%g" % (params.xscale.range[0]))
            self.txt_xscale_max.setText("%g" % (params.xscale.range[1]))
        self.UpdatePlotParams()

    #########################################
    def OnCheckYAutoRange(self):
        """
        YScale:Auto Scaleチェックボックスが変更された時の処理
        @param None
        @retval None
        """
        params = self.ifi.GetProperty('params')
        if self.chk_yscale_auto_range.checkState() == QtCore.Qt.Checked:
            self.txt_yscale_min.setEnabled(False)
            self.txt_yscale_max.setEnabled(False)
            self.label_yscale_range.setEnabled(False)
            self.label_yscale_h.setEnabled(False)
            params.yscale.autoRange = True
            params.yscale.range = (self.u2.plot.data[2].min(), self.u2.plot.data[2].max())
        else:
            self.txt_yscale_min.setEnabled(True)
            self.txt_yscale_max.setEnabled(True)
            self.label_yscale_range.setEnabled(True)
            self.label_yscale_h.setEnabled(True)
            params.yscale.autoRange = False
            self.txt_yscale_min.setText("%g" % (params.yscale.range[0]))
            self.txt_yscale_max.setText("%g" % (params.yscale.range[1]))
        self.UpdatePlotParams()

    #########################################
    def OnCheckXLog(self):
        """
        XScale:Log Scaleチェックボックスが変更された時の処理
        @param None
        @retval None
        """
        params = self.ifi.GetProperty('params')
        if self.chk_xscale_log.checkState() == QtCore.Qt.Checked:
            params.xscale.logScale = True
        else:
            params.xscale.logScale = False
        self.UpdatePlotParams()

    #########################################
    def OnCheckYLog(self):
        """
        YScale:Log Scaleチェックボックスが変更された時の処理
        @param None
        @retval None
        """
        params = self.ifi.GetProperty('params')
        if self.chk_yscale_log.checkState() == QtCore.Qt.Checked:
            params.yscale.logScale = True
        else:
            params.yscale.logScale = False
        self.UpdatePlotParams()

    #########################################
    def OnCheckXInv(self):
        """
        XScale:Inverted Scaleチェックボックスが変更された時の処理
        @param None
        @retval None
        """
        params = self.ifi.GetProperty('params')
        if self.chk_xscale_inv.checkState() == QtCore.Qt.Checked:
            params.xscale.inversion = True
        else:
            params.xscale.inversion = False
        self.UpdatePlotParams()

    #########################################
    def OnCheckYInv(self):
        """
        YScale:Inverted Scaleチェックボックスが変更された時の処理
        @param None
        @retval None
        """
        params = self.ifi.GetProperty('params')
        if self.chk_yscale_inv.checkState() == QtCore.Qt.Checked:
            params.yscale.inversion = True
        else:
            params.yscale.inversion = False
        self.UpdatePlotParams()

    #########################################
    def UpdatePlotParams(self, isParamChanged=True):
        """
        プロット情報を用いてu2dplotの更新を行う
        @param isParamChanged (bool) 更新を行うかどうか
        @retval None
        """
        params = self.ifi.GetProperty('params')
        if self.chk_int_auto_range.checkState() != QtCore.Qt.Checked:
            int_min = float(self.txt_int_min.text())
            int_max = float(self.txt_int_max.text())
            params.range = (int_min, int_max)
            isParamChanged = True

        if self.chk_smooth.checkState() == QtCore.Qt.Checked:
            params.smoothing = [True, int(self.txt_smooth_win.text()), int(
                self.txt_smooth_tim.text())]
            isParamChanged = True

        if self.chk_xscale_auto_range.checkState() != QtCore.Qt.Checked:
            try:
                scale_min = float(self.txt_xscale_min.text())
                scale_max = float(self.txt_xscale_max.text())
                params.xscale.range = (scale_min, scale_max)
                isParamChanged = True
            except:
                pass
        if self.chk_yscale_auto_range.checkState() != QtCore.Qt.Checked:
            try:
                scale_min = float(self.txt_yscale_min.text())
                scale_max = float(self.txt_yscale_max.text())
                params.yscale.range = (scale_min, scale_max)
                isParamChanged = True
            except:
                pass

        # Set current plot window size to params
        self.u2.plot.GetWindowSizeParams()

        if isParamChanged:
            self.ifi.NotifyEvent(self, 'change_params')

    #########################################
    def InitPlotParamsPanel(self):
        """
        プロット情報パネルを初期化する
        @param None
        @retval None
        """
        self.PlotParamsPanelTurnOn(True)
        params = self.ifi.GetProperty('params')
        # Intensity
        if params.autoRange:
            self.chk_int_auto_range.setCheckState(QtCore.Qt.Checked)
            self.SetIntState(True)
        else:
            self.chk_int_auto_range.setCheckState(QtCore.Qt.Unchecked)
            self.SetIntState(False)

        if params.logScale:
            self.chk_int_log.setCheckState(QtCore.Qt.Checked)
        else:
            self.chk_int_log.setCheckState(QtCore.Qt.Unchecked)

        if params.smoothing[0]:
            self.chk_smooth.setCheckState(QtCore.Qt.Checked)
        else:
            self.chk_smooth.setCheckState(QtCore.Qt.Unchecked)
        self.txt_smooth_win.setText("%d" % (params.smoothing[1]))
        self.txt_smooth_tim.setText("%d" % (params.smoothing[2]))

        # X Scale
        if params.xscale is not None:
            if params.xscale.autoRange:
                self.chk_xscale_auto_range.setCheckState(QtCore.Qt.Checked)
            else:
                self.chk_xscale_auto_range.setCheckState(QtCore.Qt.Unchecked)
            if params.xscale.range is not None:
                self.txt_xscale_min.setText("%g" % (params.xscale.range[0]))
                self.txt_xscale_max.setText("%g" % (params.xscale.range[1]))
            if params.xscale.logScale:
                self.chk_xscale_log.setCheckState(QtCore.Qt.Checked)
            else:
                self.chk_xscale_log.setCheckState(QtCore.Qt.Unchecked)
            if params.xscale.inversion:
                self.chk_xscale_inv.setCheckState(QtCore.Qt.Checked)
            else:
                self.chk_xscale_inv.setCheckState(QtCore.Qt.Unchecked)

            self.txt_xzslice_center.setText("{0:.3f}".format(0.0))
            self.txt_xzslice_width.setText("{0:.3f}".format(0.0))
            self.txt_xzslice_start.setText("{0:.3f}".format(0.0))
            self.txt_xzslice_end.setText("{0:.3f}".format(0.0))

        # Y Scale
        if params.yscale is not None:
            if params.yscale.autoRange:
                self.chk_yscale_auto_range.setCheckState(QtCore.Qt.Checked)
            else:
                self.chk_yscale_auto_range.setCheckState(QtCore.Qt.Unchecked)
            if params.yscale.range is not None:
                self.txt_yscale_min.setText("%g" % (params.yscale.range[0]))
                self.txt_yscale_max.setText("%g" % (params.yscale.range[1]))
            if params.yscale.logScale:
                self.chk_yscale_log.setCheckState(QtCore.Qt.Checked)
            else:
                self.chk_yscale_log.setCheckState(QtCore.Qt.Unchecked)
            if params.yscale.inversion:
                self.chk_yscale_inv.setCheckState(QtCore.Qt.Checked)
            else:
                self.chk_yscale_inv.setCheckState(QtCore.Qt.Unchecked)

            self.txt_yzslice_center.setText("{0:.3f}".format(0.0))
            self.txt_yzslice_width.setText("{0:.3f}".format(0.0))
            self.txt_yzslice_start.setText("{0:.3f}".format(0.0))
            self.txt_yzslice_end.setText("{0:.3f}".format(0.0))

        # Diagonal (Mouse Dragging path) info
        self.txt_diagonal_sp_x.setText(
            "{0:.3f}".format(params.mouseDragPath[0][0]))
        self.txt_diagonal_sp_y.setText(
            "{0:.3f}".format(params.mouseDragPath[0][1]))
        self.txt_diagonal_ep_x.setText(
            "{0:.3f}".format(params.mouseDragPath[1][0]))
        self.txt_diagonal_ep_y.setText(
            "{0:.3f}".format(params.mouseDragPath[1][1]))
        self.txt_diagonal_width.setText(
            "{0:.3f}".format(params.diagonalSliceInfo[0]))
        self.txt_diagonal_binning.setText(
            "{0:.3f}".format(params.diagonalSliceInfo[1]))

        # If DetectMap mode, bank separators are shown.
        if self.converter.xkey is None and self.converter.ykey is None:
            if not params.bankseparator:
                params.bankseparator = True
                self.ifi.NotifyEvent(self, 'change_params')
        else:
            if params.bankseparator:
                params.bankseparator = False
                self.ifi.NotifyEvent(self, 'change_params')

        # If data is the inelastic powder data, turn on the only x bin checkbox.
        self.cb_xzslice_bin.setEnabled(False)
        self.cb_yzslice_bin.setEnabled(False)
        self.txt_xzslice_bin.setEnabled(False)
        self.txt_yzslice_bin.setEnabled(False)
        if self.converter.isInelasticPowder or isinstance(self.data, Manyo.ElementContainerArray):
            self.cb_xzslice_bin.setEnabled(True)
            self.cb_yzslice_bin.setEnabled(True)

        # Ave/Sum raiobuttons
        self.rb_isAveSlice.setChecked(params.slice_ave_mode)
        self.rb_isSumSlice.setChecked(not params.slice_ave_mode)

    #########################################
    def OnNotifyAutoSlice(self, eventSrc, evt, data):
        """
        u2dplotのAutoSliceイベントで実行され、X-Zスライス、Y-Zスライス情報を
        プロット情報パネルに反映する
        @param eventSrc
        @param evt
        @param data
        @retval None
        """
        if len(data) == 3:
            x0, y0, flag = data
            data = [x0, y0]
        elif len(data) == 5:
            x0, y0, x1, y1, flag = data
            data = [x0, y0, x1, y1]
        else:
            pass

        if len(data) == 2:
            self.txt_xzslice_center.setText("{0:.3f}".format(data[1]))
            self.txt_xzslice_width.setText("0.0")
            self.txt_xzslice_start.setText("{0:.3f}".format(data[1]))
            self.txt_xzslice_end.setText("{0:.3f}".format(data[1]))
            self.txt_yzslice_center.setText("{0:.3f}".format(data[0]))
            self.txt_yzslice_width.setText("0.0")
            self.txt_yzslice_start.setText("{0:.3f}".format(data[0]))
            self.txt_yzslice_end.setText("{0:.3f}".format(data[0]))
        else:
            x0, y0, x1, y1 = data
            # if x0 > x1:
            #    x0, x1 = x1, x0
            # if y0 > y1:
            #    y0, y1 = y1, y0
            center = (y0 + y1) * 0.5
            # width = (y1-y0)*0.5
            width = abs((y1 - y0) * 0.5)
            self.txt_xzslice_center.setText("{0:.3f}".format(center))
            self.txt_xzslice_width.setText("{0:.3f}".format(width))
            self.txt_xzslice_start.setText("{0:.3f}".format(y0))
            self.txt_xzslice_end.setText("{0:.3f}".format(y1))

            center = (x0 + x1) * 0.5
            # width = (x1-x0)*0.5
            width = abs((x1 - x0) * 0.5)
            self.txt_yzslice_center.setText("{0:.3f}".format(center))
            self.txt_yzslice_width.setText("{0:.3f}".format(width))
            self.txt_yzslice_start.setText("{0:.3f}".format(x0))
            self.txt_yzslice_end.setText("{0:.3f}".format(x1))

        # Diagonal (Mouse Dragging path) info
        params = self.ifi.GetProperty('params')
        self.txt_diagonal_sp_x.setText(
            "{0:.3f}".format(params.mouseDragPath[0][0]))
        self.txt_diagonal_sp_y.setText(
            "{0:.3f}".format(params.mouseDragPath[0][1]))
        self.txt_diagonal_ep_x.setText(
            "{0:.3f}".format(params.mouseDragPath[1][0]))
        self.txt_diagonal_ep_y.setText(
            "{0:.3f}".format(params.mouseDragPath[1][1]))
        self.txt_diagonal_width.setText(
            "{0:.3f}".format(params.diagonalSliceInfo[0]))
        self.txt_diagonal_binning.setText(
            "{0:.3f}".format(params.diagonalSliceInfo[1]))

        # Slice bin info
        self.cb_xzslice_bin.setCheckState(
            self.u2.plot.sliceDg.ckb_sliceX.checkState())
        self.cb_yzslice_bin.setCheckState(
            self.u2.plot.sliceDg.ckb_sliceY.checkState())
        self.txt_xzslice_bin.setText(self.u2.plot.sliceDg.txt_xbin.text())
        self.txt_yzslice_bin.setText(self.u2.plot.sliceDg.txt_ybin.text())

    #########################################
    def OnNotifyChangePrms(self, eventSrc, evt, data):
        """update view parameters on Main panel
        @param eventSrc
        @param evt
        @param data
        @retval None
        """
        self.InitPlotParamsPanel()

    #########################################
    def OnNotifyU2DClose(self, eventSrc, evtType, dat=None):
        """
        u2dplotのcloseイベント発生時に
        プロット情報パネルをオフにする
        @param eventSrc
        @param evt
        @param data
        @retval None
        """
        self.PlotParamsPanelTurnOn(False)

    ##########################################################
    # Listner functions for CUI
    ##########################################################

    def OnNotifyChangeData(self, wid, evt, value):
        """
        データ変更のイベント処理
        @param  wid イベント発生元のインスタンス
        @param  evt イベントタイプ
        @param  value イベントの値
        @retval 無し
        """
        self.isReady = False
        if self.data is not None:
            del self.data

        self.data = value

        self.findChild(QAction, "actionShow").setEnabled(True)
        try:
            if self.cb_currentIndexChanged_connected:
                self.cbX.currentIndexChanged.disconnect(self.CopyKeyToLabel)
                self.cbY.currentIndexChanged.disconnect(self.CopyKeyToLabel)
        except RuntimeWarning:
            pass
        self._currentXKey = None
        self._currentYKey = None
        _m2pp_x_key = None
        _m2pp_y_key = None
        _m2pp_rng_key = None
        xlabel = None
        ylabel = None
        self.RefreshAxisCombobox()
        if self.converter.CheckInelasticPowderData(self.data):
            self.TurnEnabledCombobox(False)
            self.txt_label_x.setEnabled(False)
            self.txt_label_y.setEnabled(False)
            self.txt_unit_x.setEnabled(False)
            self.txt_unit_y.setEnabled(False)
            xlabel = "|Q|"
            ylabel = "Energy Transfer"
            xunit = "1/A"
            yunit = "meV"
        else:
            self.TurnEnabledCombobox(True)
            # [inamura 181106]
            if isinstance(self.data, Manyo.ElementContainerArray):
                self.findChild(QtWidgets.QGroupBox,
                               "SumRangePanel").setEnabled(False)
                self.cb_DetMapMode.setEnabled(False)
            else:
                self.cb_DetMapMode.setEnabled(True)
                self.cb_DetMapMode.setCheckState(QtCore.Qt.Unchecked)
            self.txt_label_x.setEnabled(True)
            self.txt_label_y.setEnabled(True)
            self.txt_unit_x.setEnabled(True)
            self.txt_unit_y.setEnabled(True)
            if xlabel is None:
                xlabel = str(self.cbX.currentText())
                xunit = str(self.cbX_units[self.cbX.currentIndex()])
            if ylabel is None:
                ylabel = str(self.cbY.currentText())
                yunit = str(self.cbY_units[self.cbY.currentIndex()])
            # dataのHeaderにM2PP_*_KEYでStringがあれば、*Keyにそれらを設定
            if self.data.PutHeaderPointer().PutKeyLocation("M2PP_X_KEY") == 3:
                _m2pp_x_key = self.data.PutHeaderPointer().PutString("M2PP_X_KEY")
            if self.data.PutHeaderPointer().PutKeyLocation("M2PP_Y_KEY") == 3:
                _m2pp_y_key = self.data.PutHeaderPointer().PutString("M2PP_Y_KEY")
            if self.data.PutHeaderPointer().PutKeyLocation("M2PP_RNG_KEY") == 3:
                _m2pp_rng_key = self.data.PutHeaderPointer().PutString("M2PP_RNG_KEY")
        # データ読込時Labelを更新
        self.txt_label_x.setText(xlabel)
        self.txt_label_y.setText(ylabel)
        self.txt_unit_x.setText(xunit)
        self.txt_unit_y.setText(yunit)

        # Combobox更新があるためこのタイミングでconnectする
        self.cbX.currentIndexChanged.connect(self.CopyKeyToLabel)
        self.cbY.currentIndexChanged.connect(self.CopyKeyToLabel)
        self.cb_currentIndexChanged_connected = True

        # data.HeaderのM2PP_*_KEYを反映
        if _m2pp_x_key is not None:
            _idx_x_key = self.cbX.findText(_m2pp_x_key)
            if _idx_x_key != -1:
                self.cbX.setCurrentIndex(_idx_x_key)
                logging.info("M2PP_X_KEY {0} was set.".format(_m2pp_x_key))
            else:
                logging.info(
                    "M2PP_X_KEY {0} was not found in the combobox.".format(_m2pp_x_key))
        if _m2pp_y_key is not None:
            _idx_y_key = self.cbY.findText(_m2pp_y_key)
            if _idx_y_key != -1:
                self.cbY.setCurrentIndex(_idx_y_key)
                logging.info("M2PP_Y_KEY {0} was set.".format(_m2pp_y_key))
            else:
                logging.info(
                    "M2PP_Y_KEY {0} was not found in the combobox.".format(_m2pp_y_key))
        if _m2pp_rng_key is not None:
            _idx_rng_key = self.cbR.findText(_m2pp_rng_key)
            if _idx_rng_key != -1:
                self.cbR.setCurrentIndex(_idx_rng_key)
                logging.info("M2PP_RNG_KEY {0} was set.".format(_m2pp_rng_key))
            else:
                logging.info(
                    "M2PP_RNG_KEY {0} was not found in the combobox.".format(_m2pp_rng_key))

        self.statusbar.showMessage("Data load complete")
        self.showButton.setEnabled(True)
        self.isReady = True

    ##########################################################
    def OnNotifyDetectMapMode(self, wid, evt, value):
        """DetectMapモードの指定
        @param  wid イベント発生元のインスタンス
        @param  evt イベントタイプ
        @param  value イベントの値 ["TRUE"] or ["FALSE"]
        @retval 無し
        """
        if value[0] == "TRUE":
            self.cb_DetMapMode.setCheckState(QtCore.Qt.Checked)
        else:
            self.cb_DetMapMode.setCheckState(QtCore.Qt.Unchecked)

    ##########################################################
    def OnNotifyShowData(self, wid, evt, value):
        """
        データ表示のイベント処理
        @param  wid イベント発生元のインスタンス
        @param  evt イベントタイプ
        @param  value イベントの値
        @retval 無し
        """
        self.isReady = False
        xkey = value[0]
        ykey = value[1]
        rkey = value[2]
        rmin = value[3]
        rmax = value[4]

        if xkey != "-":
            cb = self.findChild(QtWidgets.QComboBox, "cbX")
            xkey_i = cb.findText(xkey)
            if xkey_i < 0:
                logging.warning(
                    "ShowData >> Not found XKey = {0}".format(xkey))
                return
            else:
                cb.setCurrentIndex(xkey_i)

        if ykey != "-":
            cb = self.findChild(QtWidgets.QComboBox, "cbY")
            ykey_i = cb.findText(ykey)
            if ykey_i < 0:
                logging.warning(
                    "ShowData >> Not found YKey = {0}".format(ykey))
                return
            else:
                cb.setCurrentIndex(ykey_i)
        """
        if zkey!="-":
            cb = self.findChild(QtWidgets.QComboBox, "cbZ")
            zkey_i = cb.findText(zkey)
            if zkey_i<0:
                logging.warning("ShowData >> Not found ZKey= {0}".format(zkey))
                return
            else:
                cb.setCurrentIndex(zkey_i)
        """
        if rkey != "-":
            cb = self.findChild(QtWidgets.QComboBox, "cbR")
            rkey_i = cb.findText(rkey)
            if rkey_i < 0:
                logging.warning(
                    "ShowData >> Not found RKey = {0}".format(rkey))
                return
            else:
                cb.setCurrentIndex(rkey_i)

        if rmin != 0.0 or rmax != 0.0:
            r0 = self.findChild(QtWidgets.QLineEdit, "txtR0")
            r1 = self.findChild(QtWidgets.QLineEdit, "txtR1")
            r0.setText("%g" % rmin)
            r1.setText("%g" % rmax)

        self.OnShow()
        self.isReady = True

    ##########################################################
    def OnNotifySetCurrentKey(self, wid, evt, value):
        """
        プロットキーコンボボックスのキーを設定
        @param  wid イベント発生元のインスタンス
        @param  evt イベントタイプ
        @param  value イベントの値
        @retval 無し
        """
        idx = self.cbX.findText(value[0])
        self.cbX.setCurrentIndex(idx)

    ##########################################################
    def OnNotifyTurnModePlotOnly(self, wid, evt, value):
        """
        Turn on/off combo boxes of keys and Open button
        @param  wid イベント発生元のインスタンス
        @param  evt イベントタイプ
        @param  value イベントの値
        @retval 無し
        """
        if value not in [True, False]:
            return
        flag = not value
        self.TurnEnabledCombobox(flag)
        self.findChild(QtWidgets.QPushButton, "openButton").setEnabled(flag)

    ##########################################################
    def OnNotifySetLabels(self, wid, evt, value):
        """
        ラベル変更イベント処理
        @param  wid イベント発生元のインスタンス
        @param  evt イベントタイプ
        @param  value イベントの値
        @retval 無し
        """
        self.isReady = False
        try:
            xlabel = value[0]
            ylabel = value[1]
        except:
            return
        # self.u2.SetLabels(xlabel,ylabel)
        xlabel = xlabel.replace(STRING_TO_REPLACE_SPACE, " ")
        ylabel = ylabel.replace(STRING_TO_REPLACE_SPACE, " ")
        self.txt_label_x.setText(xlabel)
        self.txt_label_y.setText(ylabel)
        self.UpdateLabels()
        self.isReady = True

    ##########################################################
    def OnNotifySetUnits(self, wid, evt, value):
        """
        単位変更イベント処理
        @param  wid イベント発生元のインスタンス
        @param  evt イベントタイプ
        @param  value イベントの値
        @retval 無し
        """
        self.isReady = False
        try:
            xunit = value[0]
            yunit = value[1]
        except:
            return
        xunit = xunit.replace(STRING_TO_REPLACE_SPACE, " ")
        yunit = yunit.replace(STRING_TO_REPLACE_SPACE, " ")
        self.txt_unit_x.setText(xunit)
        self.txt_unit_y.setText(yunit)
        self.UpdateLabels()
        self.isReady = True

    ##########################################################
    def OnNotifySetTitles(self, wid, evt, value):
        """
        タイトルとコメントの設定
        @param  wid イベント発生元のインスタンス
        @param  evt イベントタイプ
        @param  value イベントの値 value[0]:str:Title, value[1]:str:Comment, value[2]:bool:replace initial title and comment
        @retval 無し
        """
        self.isReady = False
        changeInitTitle = False
        try:
            title = value[0]
            comment = value[1]
            if len(value) > 2:
                if type(value[2]) == bool:
                    changeInitTitle = value[2]
        except:
            return
        title = title.replace(STRING_TO_REPLACE_SPACE, " ")
        title = title.replace(STRING_TO_REPLACE_LF, "\n")
        comment = comment.replace(STRING_TO_REPLACE_SPACE, " ")
        comment = comment.replace(STRING_TO_REPLACE_LF, "\n")
        self.u2.SetTitles(title, comment)
        if changeInitTitle or self.initial_viewParams_Title == "":
            self.initial_viewParams_Title = title
            self.u2.plot.initial_viewParams_Title = title
        if changeInitTitle or self.initial_viewParams_Comment == "":
            self.initial_viewParams_Comment = comment
            self.u2.plot.initial_viewParams_Comment = comment
        self.isReady = True

    #########################################################
    def OnNotifySmoothing(self, wid, evt, value):
        """
        スムージング設定
        @param  wid イベント発生元のインスタンス
        @param  evt イベントタイプ
        @param  value イベントの値
        @retval None
        """
        self.isReady = False
        try:
            if value[0].upper() == "TRUE":
                isSmooth = True
            else:
                isSmooth = False
            windowVal = int(value[1])
            timesVal = int(value[2])
        except:
            return
        # self.u2.SetSmooth( isSmooth, windowVal )
        if isSmooth:
            self.chk_smooth.setCheckState(QtCore.Qt.Checked)
            self.txt_smooth_win.setText("{:d}".format(windowVal))
            self.txt_smooth_tim.setText("{:d}".format(timesVal))
        else:
            self.chk_smooth.setCheckState(QtCore.Qt.Unchecked)
        self.OnCheckSmooth()
        self.isReady = True

    #########################################################
    def OnNotifyLogScale(self, wid, evt, value):
        """Setting Log scale

        @param wid   the instance of this event publisher
        @param evt   the event
        @param value the value list of this event [<Axis>,<TRUE/FALSE>]
        @retval None
        """
        self.isReady = False
        axis = value[0].upper()
        chk = None
        if axis == "Z":
            chk = self.chk_int_log
        elif axis == "Y":
            chk = self.chk_yscale_log
        elif axis == "X":
            chk = self.chk_xscale_log
        else:
            return

        try:
            if value[1].upper() == "TRUE":
                logScale = True
            else:
                logScale = False
        except:
            return
        if logScale:
            chk.setCheckState(QtCore.Qt.Checked)
        else:
            chk.setCheckState(QtCore.Qt.Unchecked)
        self.isReady = True

    #########################################################
    def OnNotifyAutoScale(self, wid, evt, value):
        """Setting Auto scale

        @param wid   the instance of this event publisher
        @param evt   the event
        @param value the value list of this event [<Axis>,<TRUE/FALSE>] or [<Axis>,<ON/OFF>]
        @retval None
        """
        self.isReady = False
        axis = value[0].upper()
        chk_this = None
        if axis == "Z":
            chk_this = self.chk_int_auto_range
        elif axis == "Y":
            chk_this = self.chk_yscale_auto_range
        elif axis == "X":
            chk_this = self.chk_xscale_auto_range
        else:
            return

        if value[1].upper() in ["ON", "TRUE"]:
            autoScale = True
        elif value[1].upper() in ["OFF", "FALSE"]:
            autoScale = False
        elif value[1].upper() == "TURN":
            if chk_this.checkState() == QtCore.Qt.Checked:
                autoScale = False
            else:
                autoScale = True
        else:
            print("ERROR : Invalid SetScale argument {} (ON/OFF/TURN)".format(value[1]))
            return

        if autoScale:
            chk_this.setCheckState(QtCore.Qt.Checked)
        else:
            chk_this.setCheckState(QtCore.Qt.Unchecked)
        self.isReady = True

    #########################################################
    def OnNotifyAxisInversion(self, wid, evt, value):
        """Setting Axis-Inversion

        @param wid   the instance of this event publisher
        @param evt   the event
        @param value the value list of this event [<Axis>,<TRUE/FALSE>]
        @retval None
        """
        self.isReady = False
        axis = value[0].upper()
        chk_this = None
        if axis == "X":
            chk_this = self.chk_xscale_inv
        elif axis == "Y":
            chk_this = self.chk_yscale_inv
        else:
            return

        is_invert = None
        if value[1].upper() == "TRUE":
            is_invert = True
        elif value[1].upper() == "FALSE":
            is_invert = False
        else:
            if chk_this.checkState() == QtCore.Qt.Checked:
                is_invert = False
            else:
                is_invert = True

        if is_invert:
            chk_this.setCheckState(QtCore.Qt.Checked)
        else:
            chk_this.setCheckState(QtCore.Qt.Unchecked)
        self.isReady = True

    #########################################################
    def OnNotifyAxisScale(self, wid, evt, value):
        """Setting scale range

        @param wid   the instance of this event publisher
        @param evt   the event
        @param value the value list of this event [<Axis>,<min>,<max>]
        @retval None
        """
        self.isReady = False
        ax_dic = {"X":1, "Y":2, "Z":0}
        try:
            axis = value[0].upper()
            if value[1].upper() == "NONE":
                min_v = self.u2.plot.data[ax_dic[axis]].min()
            else:
                min_v = float(value[1])
            if value[2].upper() == "NONE":
                max_v = self.u2.plot.data[ax_dic[axis]].max()
            else:
                max_v = float(value[2])
            if max_v < min_v:
                tmp = max_v
                max_v = min_v
                min_v = tmp
        except:
            return
        txt_min = None
        txt_max = None
        if axis == "Z":
            txt_min = self.txt_int_min
            txt_max = self.txt_int_max
        elif axis == "Y":
            txt_min = self.txt_yscale_min
            txt_max = self.txt_yscale_max
        elif axis == "X":
            txt_min = self.txt_xscale_min
            txt_max = self.txt_xscale_max
        txt_min.setText("{:g}".format(min_v))
        txt_max.setText("{:g}".format(max_v))
        self.UpdatePlotParams(False)
        self.isReady = True

    #########################################################
    def OnNotifySetWindowSize(self, wid, evt, value):
        """
        ウィンドウサイズ設定 [inamura 181113]
        @param  wid イベント発生元のインスタンス
        @param  evt イベントタイプ
        @param  value イベントの値
        @retval None
        """
        self.isReady = False
        try:
            width = int(value[0])
            height = int(value[1])
        except:
            return
        self.u2.SetWindowSize(width, height)
        self.isReady = True

    #########################################################
    def OnNotifySetWindowTitle(self, wid, evt, value):
        """
        ウィンドウタイトル設定 [inamura 190125]]
        @param  wid イベント発生元のインスタンス
        @param  evt イベントタイプ
        @param  value イベントの値
        @retval None
        """
        title = "M2Plot+ (%s)" % (str(value[0]))
        if QtCore.__version__ < '5.0.0':
            self.setWindowTitle(QtWidgets.QApplication.translate(
                "MainWindow", title, None, QtGui.QApplication.UnicodeUTF8))
        else:
            self.setWindowTitle(QtWidgets.QApplication.translate(
                "MainWindow", title, None, -1))

    ##########################################################
    def OnNotifySetSliceMethod(self, wid, evt, value):
        """
        Slice Mode設定 [inamura 190226]]
        @param  wid イベント発生元のインスタンス
        @param  evt イベントタイプ
        @param  value イベントの値
        @retval None
        """
        self.isReady = False
        try:
            if value[0].upper() == "TRUE":
                isAve = True
            else:
                isAve = False
        except:
            return
        self.u2.SetSliceMethod(isAve)
        self.rb_isAveSlice.setChecked(isAve)
        self.rb_isSumSlice.setChecked(not isAve)
        self.isReady = True

    ###################################################
    def PutMousePointInfo(self, event):
        """
        マウス位置情報作成
        @param   event イベント情報
        @retval (str) マウス位置情報
        """
        strTx = self.u2.plot.PutMousePointInfo(event)
        if strTx == "":
            return strTx
        gid = event.inaxes.get_gid()
        if gid is None:
            if self.u2.IsTransposed():
                tmp = event.xdata
                event.xdata = event.ydata
                event.ydata = tmp
            if self.ifi.GetProperty('params').detectmapmode:
                plot_index_x = np.searchsorted(
                    self.u2.plot.data[1][0], event.xdata) - 1
                if plot_index_x < len(self.sorted_ecm_idx):
                    data_index_x = self.sorted_ecm_idx[plot_index_x]
                    plot_index_y = np.searchsorted(
                        self.u2.plot.data[2].T[0], event.ydata) - 1
                    if plot_index_y < len(self.pixel_infos[data_index_x]):
                        strTx_dm = "DetectMap: DETID-Pixel: {3:4d} -{4:4d}  2theta: {0:+08.3f}  Azim: {1:+08.3f}  L2: {2:08.2f}".format(
                            *self.pixel_infos[data_index_x][plot_index_y])
                        ind_int = strTx.find("Int=")
                        if ind_int > 0:
                            strTx_dm += "  {}".format(strTx[ind_int:])
                        strTx = strTx_dm
            if self.converter.isInelasticPowder:
                plot_index_y = np.searchsorted(
                    self.u2.plot.data[2].T[0], event.ydata) - 1
                trajectry_index = np.searchsorted(
                    self.u2.plot.data[1][plot_index_y], event.xdata) - 1
                if trajectry_index >= 0 and trajectry_index < len(self.pixel_infos):
                    strTx += "  2theta: {0:+08.3f}  ".format(
                        self.pixel_infos[trajectry_index][0])
        return strTx

    ###################################################
    def OnMouseMove(self, event):
        """
        マウス-ポインタ移動イベント処理
        @param   event イベント情報
        @retval 無し
        """
        # u2dplotが閉じられていれば無視する
        if self.u2.plot is None:
            return
        strTx = self.PutMousePointInfo(event)
        self.u2.plot.infotxt.showMessage(strTx)
        # matplotlib 3.9以上では、パン処理中、プロッタの軸範囲の変更を追随させる必要があるため
        if MATPLOTLIB_VER >= "030900":
            if self.u2.plot.toolbar._actions['pan'].isChecked():
                self.u2.plot.d2.ax.set_xlim(self.u2.plot.d2.regAxes.get_xlim())
                self.u2.plot.d2.ax.set_ylim(self.u2.plot.d2.regAxes.get_ylim())

    ##########################################################
    def EraseDummyContainerArray(self, data):
        """
        ElementContainerMatrixに不要な（空の）Arrayがあれば省く
        DetectorMapで形を整えるために空のArrayを差し込まれたECMを修正する
        @param data (ElementContainerMatrix)
        @retval None
        """
        ind = 0
        while(True):
            if data(ind).PutSize() == 0:
                data.EraseElement(ind)
            else:
                ind += 1
            if data.PutSize() == ind:
                break

    ##########################################################
    def MakePixelInfos(self, xkey):
        """
        DetectorMap時用ピクセル情報を作成

        Parameters:
            xkey (str or None) X軸指定キー
        """
        _idx2det_ids = []
        _pixel_infos = []
        self.sorted_ecm_idx = []
        n_x_data = self.data.PutSize()
        n_y_data = self.data(0).PutSize()
        for i in range(n_x_data):
            if xkey is not None:
                _idx2det_ids.append(
                    self.data(i).PutHeaderPointer().PutInt4(xkey))
            _infos = []
            for j in range(n_y_data):
                ech = self.data(i, j).PutHeaderPointer()
                L2 = 0.0
                posi_x = 0.0
                polar_ang = 0.0
                azim_ang = 0.0
                detId = 0
                if ech.CheckKey("PixelPolarAngle") == 1:
                    angP = ech.PutDoubleVector("PixelPolarAngle")
                    polar_ang = angP[0]
                if ech.CheckKey("PixelAzimAngle") == 1:
                    angA = ech.PutDoubleVector("PixelAzimAngle")
                    azim_ang = angA[0]
                if ech.CheckKey("PixelPosition") == 1:
                    posi = ech.PutDoubleVector("PixelPosition")
                    posi_x = posi[0]
                    L2 = np.sqrt((posi[0] * posi[0]) + (posi[1] * posi[1]) + (posi[2] * posi[2]))
                if np.isnan(azim_ang):
                    if posi_x >= 0.0:
                        azim_ang = 0.0
                    else:
                        azim_ang = 180.0
                if ech.CheckKey("DETID") == 1:
                    detId = ech.PutInt4("DETID")
                _infos.append((polar_ang, azim_ang, L2, detId, j))
            _pixel_infos.append(tuple(_infos))
        self.pixel_infos = tuple(_pixel_infos)
        if xkey is not None:
            self.sorted_ecm_idx = np.argsort(_idx2det_ids)
        else:
            self.sorted_ecm_idx = range(n_x_data)

        return

    ##########################################################
    def MakePixelInfosWithBankGap(self):
        """
        DetectorMap with Gap時用ピクセル情報を作成

        """
        if self.data.PutHeaderPointer().CheckKey("BANKIDLIST") == 0:
            self.MakePixelInfos("Index")
            return

        bankIdVect = self.data.PutHeaderPointer().PutInt4Vector("BANKIDLIST")
        bankSizeVect = self.data.PutHeaderPointer().PutInt4Vector("BANKSIZELIST")

        _idx2det_ids = []
        _pixel_infos = []

        n_y_data = self.data(0).PutSize()
        _infos_empty = []
        for i in range(n_y_data):
            # ( <PolarAngle>, <AzimAngle>, <L2> )
            _infos_empty.append((0.0, 0.0, 0.0, 0, 0))

        if bankIdVect.size() != bankSizeVect.size():
            raise UserWarning("ERROR : invalid Bank Id List in given data.")

        indexInMap = 0
        for i in range(bankIdVect.size()):
            bankId = bankIdVect[i]
            for j in range(bankSizeVect[i]):
                indexInBank = -1
                for k in range(self.data.PutSize()):
                    hh = self.data(k).PutHeaderPointer()
                    if hh.PutInt4("BANKID") == bankId and hh.PutInt4("INDEXINBANK") == j:
                        indexInBank = k

                if indexInBank != -1:
                    _infos = []
                    for k in range(n_y_data):
                        ech = self.data(indexInBank, k).PutHeaderPointer()
                        L2 = 0.0
                        posi_x = 0.0
                        polar_ang = 0.0
                        azim_ang = 0.0
                        detId = 0
                        if ech.CheckKey("PixelPolarAngle") == 1:
                            angP = ech.PutDoubleVector("PixelPolarAngle")
                            polar_ang = angP[0]
                        if ech.CheckKey("PixelAzimAngle") == 1:
                            angA = ech.PutDoubleVector("PixelAzimAngle")
                            azim_ang = angA[0]
                        if ech.CheckKey("PixelPosition") == 1:
                            posi = ech.PutDoubleVector("PixelPosition")
                            posi_x = posi[0]
                            L2 = np.sqrt((posi[0] * posi[0]) + (posi[1] * posi[1]) + (posi[2] * posi[2]))
                        if np.isnan(azim_ang):
                            if posi_x >= 0.0:
                                azim_ang = 0.0
                            else:
                                azim_ang = 180.0
                        if ech.CheckKey("DETID") == 1:
                            detId = ech.PutInt4("DETID")
                        _infos.append((polar_ang, azim_ang, L2, detId, k))
                    _pixel_infos.append(tuple(_infos))
                else:
                    _pixel_infos.append(tuple(_infos_empty[:]))

                _idx2det_ids.append(indexInMap)
                indexInMap += 1

            if i != (bankIdVect.size() - 1):
                _pixel_infos.append(tuple(_infos_empty[:]))
                _idx2det_ids.append(indexInMap)
                indexInMap += 1

        self.pixel_infos = tuple(_pixel_infos)

        self.sorted_ecm_idx = _idx2det_ids
        return

    ##########################################################
    def MakePixelInfosForInelaPowder(self):
        """
        DetectorMap時用ピクセル情報を作成

        Parameters:
            xkey (str or None) X軸指定キー
        """
        self.sorted_ecm_idx = []
        self.pixel_infos = []
        n_traj_data = self.data(0).PutSize()
        for i in range(n_traj_data):
            self.sorted_ecm_idx.append(i)
            self.pixel_infos.append([-1])
            hh = self.data(0, i).PutHeaderPointer()
            if hh.CheckKey("PolarAngle") == 0:
                continue
            self.pixel_infos[-1] = [float(hh.PutDouble("PolarAngle"))]

        return

    ##########################################################
    def OnNotifySaveAsText(self, obj, command, params):
        """
        Save as Text
        """
        if len(params) != 5:
            raise UserWarning("SaveAsText parameters are invalid.")
        fileName = str(params[0])
        try:
            dQ = float(params[1])
            isIgnoreMask = False
            if params[2].upper() == "TRUE":
                isIgnoreMask = True
            msk = False
            if params[3].upper() == "TRUE":
                msk = True
            val = float(params[4])
            maskinfo = [msk, val]
        except:
            raise UserWarning("SaveAsText parameters are invalid.")
        FIO = M2PlotPlusTextFileIO(self)
        FIO.Save(fileName, dQ, isIgnoreMask, maskinfo)

    ##########################################################
    def OnNotifyClose(self, *arg):
        """
        Catch close event from IFEvtProp
        """
        self.closeEvent()

    ##########################################################
    def GetRunNo(self):
        """Get the run number
        Returns:
            string: run number
        """
        try:
            hh = self.data.PutHeaderPointer()
        except:
            logging.warning(
                "Cannot get any run number. There is no header in data.")
        runno = ""
        if hh.CheckKey("RUNNUMBER"):
            runno = hh.PutString("RUNNUMBER")
        return runno

    ##########################################################
    def GetIncidentEnergy(self):
        """Get the incident energy
        Returns:
            0.0: Not found Ei
            float: incident energy
        """
        try:
            hh = self.data.PutHeaderPointer()
        except:
            logging.warning(
                "Cannot get any run number. There is no header in data.")

        if hh.CheckKey("Ei"):
            return hh.PutDouble("Ei")
        return 0.0

    ##########################################################
    def closeEvent(self, event=None):
        """
        Catch window close event
        @event event
        """
        logging.debug("M2PlotPlus::closeEvent")
        # self.ifi.NotifyEvent(self, 'u2dclosed')
        self.ifi.NotifyEvent(self, 'close_u2dplot')  # [inamura 181001]
        self.ifi_mine.NotifyEvent(self, 'u2dclosed')
        if event is not None:
            event.accept()
        else:
            self.close()
        logging.info("M2PlotPlus closing")

#######################################
#  CuiIF
#######################################


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

    def __init__(self, order=None):
        """
        コンストラクタ
        @param  order    プロッタの起動順序
        @retval 無し
        """
        if order is not None:
            self.ifi = IFEvtProp(order)

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

        # 2次元プロッタ画面の起動
        self.plot = M2PlotPlus(None, None, plotNum)

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

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

        # コマンドとその実行関数登録
        self.functions = {"changedata": self.ChangeData,  # Add cui functions in this dictionary
                          "detectmapmode": self.SetChangeParams,
                          "showdata": self.ShowData,
                          "setlabels": self.SetChangeParams,
                          "setunits": self.SetChangeParams,
                          "settitles": self.SetChangeParams,
                          "setsmooth": self.SetChangeParams,
                          "setlogscale": self.SetChangeParams,
                          "setaxisinversion": self.SetChangeParams,
                          "setautoscale": self.SetChangeParams,
                          "setaxisscale": self.SetChangeParams,
                          "setwindowsize": self.SetChangeParams,
                          "setslicemethod": self.SetChangeParams,
                          "setcurrentkey": self.SetChangeParams,
                          "saveastext": self.SetChangeParams,
                          "setwindowtitle": self.SetWindowTitle,
                          "close": self.OnNotifyClose}

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

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

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

    # Add cui functions below
    def ChangeData(self, args):
        """
        データ変更イベント発行
        @param  args コマンドと引数のタプル
        @retval 無し
        """
        logging.debug("M2PPCuiIF:ChangeData")
        # デシリアライズ
        crr = Manyo.ReadSerializationFileBinary(str(args[1]))
        # 元データがArrayであれば
        if int(args[2]) == 1:
            mat = Manyo.ElementContainerArray()
            crr.Load(mat)
            del crr
        else:
            mat = Manyo.ElementContainerMatrix()
            crr.Load(mat)
            del crr
        # デシリアライズ失敗?
        if mat is None:
            # 否定応答を返信
            return "NACK\n"
        # データ変更イベント発行
        self.ifi.NotifyEvent(self, args[0], mat)

    ###################################################
    def ShowData(self, args):
        """
        データ表示イベント発行
        @param args コマンドと引数のタプル
        @retval 無し
        """
        params = args[1:4]  # xkey,ykey,rkey
        params.append(float(args[4]))  # rmin
        params.append(float(args[5]))  # rmax
        self.ifi.NotifyEvent(self, args[0], params)

    ###################################################
    def SetChangeParams(self, args):
        """
        params変更イベント発行
        @param args コマンドと引数のタプル
        @retval 無し
        """
        params = args[1:]
        self.ifi.NotifyEvent(self, args[0], params)

    ###################################################
    def SetWindowTitle(self, args):
        """
        """
        params = args[1:]
        self.plot.ifi_mine.NotifyEvent(self, args[0], params)


def call_slice(eventSrc, eventType, values):
    """
    マウスイベントからのEcsClipper呼び出し用コールバック関数
    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]
    """
    noPixel = False
    logging.debug("---- Slice & draw ----")
    logging.debug("Selected region: {0}".format(values))
    slice_ave_mode = True
    # _slicing_prms_*_strはスライス情報表示用の文字列
    if len(values) == 2:
        _slicing_prms_right_str = "X: {0:.3f}".format(values[0])
        _slicing_prms_top_str = "Y: {0:.3f}".format(values[1])
    if len(values) == 3:
        if type(values[2]) == bool:
            slice_ave_mode = values[2]
        values = values[:-1]
        _slicing_prms_right_str = "X: {0:.3f}".format(values[0])
        _slicing_prms_top_str = "Y: {0:.3f}".format(values[1])
    if len(values) == 5:
        if type(values[4]) == bool:
            slice_ave_mode = values[4]
        values = values[:-1]
        _slicing_prms_right_str = "X: {0:.3f}({1:.3f} - {2:.3f})".format((values[0] + values[2]) * 0.5, values[0], values[2])
        _slicing_prms_top_str = "Y: {0:.3f}({1:.3f} - {2:.3f})".format((values[1] + values[3]) * 0.5, values[1], values[3])
    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]
        _slicing_prms_right_str = "X: {0:.3f}({1:.3f} - {2:.3f})".format((values[0] + values[2]) * 0.5, values[0], values[2])
        _slicing_prms_top_str = "Y: {0:.3f}({1:.3f} - {2:.3f})".format((values[1] + values[3]) * 0.5, values[1], values[3])

    parent = eventSrc.parentWidget()  # eventSrcはD2Frame。parentはM2PlotPlus

    # マウス位置情報からデータ座標を計算し置き換える
    values = list(values)
    values[0] = eventSrc.CalcLogScaleValueFromEvent(eventSrc.params.xscale, values[0])
    values[1] = eventSrc.CalcLogScaleValueFromEvent(eventSrc.params.yscale, values[1])
    if len(values) == 4:
        values[2] = eventSrc.CalcLogScaleValueFromEvent(eventSrc.params.xscale, values[2])
        values[3] = eventSrc.CalcLogScaleValueFromEvent(eventSrc.params.yscale, values[3])

    if eventSrc.params.transPosition:
        _values = list(values)
        if len(values) == 4:
            values = [_values[1], _values[0], _values[3], _values[2]]
        else:
            values = [_values[1], _values[0]]

    # スライス情報を表示
    if len(eventSrc.d2.ax_right.texts) == 0:
        eventSrc.d2.ax_right.text(0, 1.02, _slicing_prms_right_str,
                                  fontsize=6, transform=eventSrc.d2.ax_right.transAxes)
    else:
        eventSrc.d2.ax_right.texts[0].set_text(_slicing_prms_right_str)
    if len(eventSrc.d2.ax_top.texts) == 0:
        eventSrc.d2.ax_top.text(0, 1.05, _slicing_prms_top_str,
                                fontsize=6, transform=eventSrc.d2.ax_top.transAxes)
    else:
        eventSrc.d2.ax_top.texts[0].set_text(_slicing_prms_top_str)

    # Key
    _ykey = parent.converter.ykey  # [20170620, TI] TODO: ykeyがNoneなことはない？
    _xkey = parent.converter.xkey
    _intKey = parent.converter.intKey
    logging.debug("Keys: {0}, {1}, {2}".format(_xkey, _ykey, _intKey))

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

    # bin数、データ数
    n_x_plot = len(xbin)  # プロットX軸区切り数
    n_x_data = parent.data.PutSize()  # データECM中のECA数 or ECA中のEC数
    if parent.converter._eca is not None:
        n_x_data = parent.converter._eca.PutSize()

    # 上下限の外をポイントした場合にTrue
    lower_boundary_x = False
    upper_boundary_x = False
    lower_boundary_y = False
    upper_boundary_y = False

    # plot_index: 表示binでのindex, data_index: 読み込みデータでのindex
    # if (n_x_plot - 1) == n_x_data: # 散布データ [20170610 TI] TODO: Falseの場合を考える
    if parent.converter.isInelasticPowder:
        xbin_m = np.array(eventSrc.data[1])
        if values[0] <= xbin_m.min():
            plot_index_x0 = xbin_m.min()
            lower_boundary_x = True
        elif values[0] > xbin_m.max():
            plot_index_x0 = xbin_m.max()
            upper_boundary_x = True
        else:
            plot_index_x0 = values[0]
        if len(values) == 4:
            plot_index_x1 = values[2]
        else:
            plot_index_x1 = values[0]
    elif (n_x_plot - 1) == n_x_data:
        if values[0] <= xbin[0]:
            plot_index_x0 = 0  # 最小のbinをさしたものとみなす
            lower_boundary_x = True
        elif values[0] >= xbin[-1]:
            plot_index_x0 = n_x_data - 1  # 最大のbinを指したものとみなす
            upper_boundary_x = True
        else:
            plot_index_x0 = np.searchsorted(xbin, values[0]) - 1  # xbinでのindex
        if len(values) == 4:
            # plot_index_x1 = np.searchsorted(xbin, values[2]) - 1 # xbinでのindex
            if values[2] <= xbin[0]:
                plot_index_x1 = 0
            elif values[2] >= xbin[-1]:
                plot_index_x1 = n_x_data - 1
            else:
                plot_index_x1 = np.searchsorted(xbin, values[2]) - 1  # xbinでのindex
        else:
            plot_index_x1 = None

    plot_index_y0 = np.searchsorted(ybin, values[1]) - 1  # ybinでのindex
    if plot_index_y0 < 0:
        plot_index_y0 = 0
    if len(values) == 4:
        plot_index_y1 = np.searchsorted(ybin, values[3]) - 1  # ybinでのindex
    else:
        plot_index_y1 = None

    logging.debug("indices 0: {0} {1}".format(plot_index_x0, plot_index_y0))
    logging.debug("indices 1: {0} {1}".format(plot_index_x1, plot_index_y1))
    xbin_w, ybin_w = parent.u2.plot.sliceDg.PutBins()
    if parent.converter.isInelasticPowder:
        if len(values) == 2:
            plot_index_y1 = plot_index_y0
        draw_powder_slice(parent.data, eventSrc, (_xkey, _ykey, _intKey),
                          (plot_index_x0, plot_index_y0,
                           plot_index_x1, plot_index_y1),
                          (xbin, ybin, xbin_w, ybin_w), len(values) == 2, slice_ave_mode, values)
    # if isinstance(parent.data, Manyo.ElementContainerArray):
    elif isinstance(parent.data, Manyo.ElementContainerArray):
        if len(values) == 2:
            plot_index_y1 = plot_index_y0
        draw_clipper_slice(parent.data, eventSrc, (_xkey, _ykey, _intKey),
                           (plot_index_x0, plot_index_y0,
                            plot_index_x1, plot_index_y1),
                           (xbin, ybin, xbin_w, ybin_w), len(values) == 2, slice_ave_mode, values)
    elif isinstance(parent.data, Manyo.ElementContainerMatrix):
        if len(values) == 2:
            plot_index_x1 = plot_index_x0
            plot_index_y1 = plot_index_y0
        draw_clipper_slice(parent.converter._eca, eventSrc, (_xkey, _ykey, _intKey),
                           (plot_index_x0, plot_index_y0,
                            plot_index_x1, plot_index_y1),
                           (xbin, ybin, xbin_w, ybin_w), len(values) == 2, slice_ave_mode, values)
    elif isinstance(parent.data, numpy.ndarray):
        values.append(slice_ave_mode)
        call_ndarray_slice(eventSrc, eventType, values)
    else:
        return
    eventSrc.canvas.draw()
    return


def draw_clipper_slice(data, d2frame, keys, indices, bins, isPoint=False, isAve=True, values=None):
    """Manyo.MLF.MlfArraySlicerによるスライスの描画

    Parameters:
        data (ECA)
        d2frame (D2Frame)
        keys (Tuple[str, str, str]) xkey, ykey, intkey
        indices (Tuple[int, int, int, int]) x0, y0, x1, y1のindex
        bins (Tuple(ndarray, ndarray)) xbin, ybin
        isPoint (bool) ポイント指定であるか
        isAve (bool) Average or Summation
    """
    logging.debug("---- draw_clipper_slice ----")
    parent = d2frame.parentWidget()
    noPixel = False
    clip_region = [0.0, 0.0, 0.0, 0.0]  # [x0, y0, x1, y1] for clipper
    # clip = mm.MlfArraySlicer(data)
    clip = parent.converter.arraySlicer
    clip.ClearClipRegion()
    # Y - Intensity
    # [20170621 TI] TODO: _xkeyがNoneで_ykeyがEC.SetKeysされているもの以外の場合を検討する必要性
    # [20170610 TI] TODO: X順序が変わっている場合について考える
    data_index_x0 = parent.converter.indices_sort[indices[0]]  # ECM/ECAでのindex
    data_index_x1 = 0.0
    if indices[2] is not None:
        data_index_x0 = parent.converter.indices_sort[indices[0] + 1]
        # ECM/ECAでのindex
        data_index_x1 = parent.converter.indices_sort[indices[2]]
    logging.debug(
        "---- data_index_x0, data_index_x1 = {}, {}".format(data_index_x0, data_index_x1))
    if isPoint or (indices[2] - indices[0] == 0):
        _ec = data.Put(data_index_x0)
        if bins[3] > 0.0:  # If X bin width is set
            vx_ec = _ec.PutX()
            vx_new = mm.PutVectorAsBinCenterZero(
                vx_ec.front(), vx_ec.back(), bins[3])
            _ec = _ec.Averaging(vx_new)
        _xarray = np.array(_ec.PutYList())
        _xarray_right = np.ma.masked_where(_xarray >= MASKVALUE, _xarray)
        if isinstance(parent.data, Manyo.ElementContainerArray):
            _yarray_right = _ec.ReduceColumnList(keys[1])
            if (len(_xarray_right) - 1) == len(_yarray_right):  # YKEYのベクターサイズがEC.PutY()のサイズと同じ場合
                _yarray_right = _ec.PutList(keys[1])
        else:
            if keys[1] is None:  # Indexによる表示
                if _ec.isHist():  # ECがヒストグラム
                    _yarray_right = np.array(
                        _ec.ReduceColumnList(_ec.PutXKey()))
                else:           # ECが散布データ
                    _yarray_right = np.array(_ec.PutXList())
            else:  # [20170919 TI] TODO: この場合が未検証 Reduceしないのが良さそう？
                _yarray_right = _ec.ReduceColumnList(keys[1])
                if (len(_xarray_right) - 1) == len(_yarray_right):  # YKEYのベクターサイズがEC.PutY()のサイズと同じ場合
                    _yarray_right = _ec.PutList(keys[1])
        if isPoint or (values is None):
            clip.SetHeaderToEC(_ec, float(
                bins[0][indices[0]]), float(bins[0][indices[0]]))
        else:
            clip.SetHeaderToEC(_ec, float(values[0]), float(values[2]))
        parent._sliced_ec_right = _ec
        # del _ec
    else:
        clip_region[1] = float(bins[1][0])  # Y軸最小値
        clip_region[3] = float(bins[1][-1])  # Y軸最大値
        if keys[0] is not None:
            if keys[1] is None:
                clip.SetAxes(keys[0], "index")
            else:
                clip.SetAxes(keys[0], keys[1])
            clip_region[0] = float(bins[0][indices[0] + 1])  # X軸　選択ビンの左端
            clip_region[2] = float(bins[0][indices[2] + 1])  # X軸　選択ビンの右端
        else:
            loc = data(0).PutHeaderPointer().PutKeyLocation("XRANGE")
            if loc == 5:  # PlaneSlicer処理済み
                clip_region[0] = float(
                    data(data_index_x0).PutHeaderPointer().PutDoubleVector("XRANGE")[0])
                clip_region[2] = float(
                    data(data_index_x1).PutHeaderPointer().PutDoubleVector("XRANGE")[1])
            else:
                clip_region[0] = float(indices[0] + 1)
                clip_region[2] = float(indices[2] + 1)
        logging.debug(
            "---- Y-Intensity clip_region x0, x1= {},{}".format(clip_region[0], [2]))
        logging.debug(
            "---- Y-Intensity clip_region y0, y1= {},{}".format(clip_region[1], [3]))
        clip.SetClipRegion(*clip_region)
        # rtn = clip.CutAlongY(False)
        rtn = clip.CutAlongY(isAve)
        _ec = rtn.Put(0)
        if bins[3] > 0.0:  # If X bin width is set
            vx_ec = _ec.PutX()
            vx_new = mm.PutVectorAsBinCenterZero(
                vx_ec.front(), vx_ec.back(), bins[3])
            _ec = _ec.Averaging(vx_new)
        _xarray = np.array(_ec.PutYList())
        _xarray_right = np.ma.masked_where(_xarray >= MASKVALUE, _xarray)
        if _ec.isHist():  # ヒストグラムデータの場合
            _yarray_right = _ec.ReduceColumnList(_ec.PutXKey())
        else:               # 散布データの場合
            _yarray_right = _ec.PutXList()
        clip.ClearClipRegion()
        if values is not None:
            clip.SetHeaderToEC(_ec, float(values[0]), float(values[2]))
        parent._sliced_ec_right = _ec
        del rtn
    # X - Intensity
    if isPoint or (indices[3] - indices[1] == 0):
        clip_region[1] = bins[1][indices[1]]
        clip_region[3] = bins[1][indices[1]]
    else:
        clip_region[1] = bins[1][indices[1]]  # Y軸　選択ビンの下端
        clip_region[3] = bins[1][indices[3]]  # Y軸　選択ビンの上端
    if keys[0] is not None:
        if keys[1] is None:
            clip.SetAxes(keys[0], "index")
        else:
            clip.SetAxes(keys[0], keys[1])
        clip_region[0] = bins[0][0]  # X軸最小値
        clip_region[2] = bins[0][-1]  # X軸最大値
    else:
        loc = data(0).PutHeaderPointer().PutKeyLocation("XRANGE")
        if loc == 5:  # PlaneSlicer処理済み
            clip_region[0] = data(
                0).PutHeaderPointer().PutDoubleVector("XRANGE")[0]
            clip_region[2] = data(data.PutSize() - 1).PutHeaderPointer().PutDoubleVector("XRANGE")[1]
        else:
            clip_region[0] = 0
            clip_region[2] = len(bins[0]) - 1
    logging.debug(
        "---- X-Intensity clip_region x0, x1= {},{}".format(clip_region[0], [2]))
    logging.debug(
        "---- X-Intensity clip_region y0, y1= {},{}".format(clip_region[1], [3]))
    clip.SetClipRegion(*clip_region)
    # rtn = clip.CutAlongX(False)
    rtn = clip.CutAlongX(isAve)
    _ec = rtn.Put(0)
    if bins[2] > 0.0:  # If Y bin width is set
        vx_ec = _ec.PutX()
        vx_new = mm.PutVectorAsBinCenterZero(
            vx_ec.front(), vx_ec.back(), bins[2])
        _ec = _ec.Averaging(vx_new)
    _yarray = np.array(_ec.PutYList())
    _yarray_top = np.ma.masked_where(_yarray >= MASKVALUE, _yarray)
    if keys[0] is not None:
        _xarray_top = _ec.ReduceColumnList(_ec.PutXKey())
    else:
        # _xarray_top = np.arange(len(bins[0]) - 1)
        _xarray_top = np.arange(len(_ec.PutXList()) - 1)
        if bins[2] > 0.0:
            _xarray_top = _xarray_top * bins[2]
    if values is None or isPoint:
        pass
    else:
        clip.SetHeaderToEC(_ec, float(values[1]), float(values[3]))
    parent._sliced_ec_top = _ec
    del rtn
    # del clip

    if d2frame.params.transPosition:
        _xarray_right, _yarray_right, _xarray_top, _yarray_top = _yarray_top, _xarray_top, _yarray_right, _xarray_right
    # Y-Intensity slice
    if len(d2frame.d2.ax_right.lines) == 0:
        d2frame.d2.ax_right.plot(_xarray_right, _yarray_right)
    else:
        d2frame.d2.ax_right.lines[0].set_ydata(_yarray_right)
        d2frame.d2.ax_right.lines[0].set_xdata(_xarray_right)
        d2frame.d2.ax_right.set_xlim(
            (_xarray_right.min(), _xarray_right.max()))
    # 強度と軸のログスケールの対応
    if d2frame.d2.params.logScale:
        d2frame.d2.ax_right.set_xscale('log')
    if d2frame.d2.params.yscale.logScale:
        d2frame.d2.ax_right.set_yscale('log')
    d2frame.d2.ax_right.set_ylim(d2frame.d2.ax.get_ylim())

    # X-Intensity slice
    if len(d2frame.d2.ax_top.lines) == 0:
        d2frame.d2.ax_top.plot(_xarray_top, _yarray_top)
    else:
        d2frame.d2.ax_top.lines[0].set_xdata(_xarray_top)
        d2frame.d2.ax_top.lines[0].set_ydata(_yarray_top)
        d2frame.d2.ax_top.set_ylim((_yarray_top.min(), _yarray_top.max()))
    # 強度と軸のログスケールの対応
    if d2frame.d2.params.logScale:
        d2frame.d2.ax_top.set_yscale('log')
    if d2frame.d2.params.xscale.logScale:
        d2frame.d2.ax_top.set_xscale('log')
    d2frame.d2.ax_top.set_xlim(d2frame.d2.ax.get_xlim())
    return


def draw_powder_slice(data, d2frame, keys, indices, bins, isPoint=False, isAve=True, values=None):
    """Manyo.MLF.MlfArraySlicerによるスライスの描画

    Parameters:
        data (ECA)
        d2frame (D2Frame)
        keys (Tuple[str, str, str]) xkey, ykey, intkey
        indices (Tuple[int, int, int, int]) x0, y0, x1, y1のindex
        bins (Tuple(ndarray, ndarray)) xbin, ybin
        isPoint (bool) ポイント指定であるか
        isAve (bool) Average or Summation
    """
    parent = d2frame.parentWidget()
    noPixel = False
    clip_region = [0.0, 0.0, 0.0, 0.0]  # [x0, y0, x1, y1] for clipper
    # clip = mm.MlfArraySlicer(data)
    clip = parent.converter.arraySlicer
    clip.ClearClipRegion()
    # Y - Intensity
    clip_region[0] = indices[0]
    clip_region[1] = bins[1][0]  # Y軸最小値
    clip_region[3] = bins[1][-1]  # Y軸最大値
    if isPoint or (indices[2] - indices[0] == 0):
        clip_region[2] = indices[0]
    else:
        clip_region[2] = indices[2]

    clip.SetClipRegion(*clip_region)
    # rtn = clip.CutAlongY(False)
    rtn = clip.CutAlongY(isAve)
    clip.ClearClipRegion()
    ec = rtn.Put(0)
    if bins[3] > 0.0:  # If Y bin width is set
        vx_ec = ec.PutX()
        vx_new = mm.PutVectorAsBinCenterZero(
            vx_ec.front(), vx_ec.back(), bins[3])
        ec = ec.Averaging(vx_new)
    _xarray = np.array(ec.PutYList())
    _xarray_right = np.ma.masked_where(_xarray >= MASKVALUE, _xarray)
    _yarray_right = ec.ReduceColumnList(ec.PutXKey())
    if isPoint or (values is None):
        pass
    else:
        clip.SetHeaderToEC(ec, float(values[0]), float(values[2]))
    parent._sliced_ec_right = ec
    del rtn

    # X - Intensity
    # clip_region[0] = bins[0][0] # X軸最小値
    # clip_region[2] = bins[0][-1] # X軸最大値
    clip_region[0] = -1.0  # X軸最小値
    clip_region[2] = -1.0  # X軸最大値
    if isPoint or (indices[3] - indices[1] == 0):
        clip_region[1] = bins[1][indices[1]]
        clip_region[3] = bins[1][indices[1]]
    else:
        clip_region[1] = bins[1][indices[1]]  # Y軸　選択ビンの下端
        clip_region[3] = bins[1][indices[3]]  # Y軸　選択ビンの上端

    clip.SetClipRegion(*clip_region)
    # rtn = clip.CutAlongX(False)
    clip.SetQbin(bins[2])
    rtn = clip.CutAlongX(isAve)
    _yarray = np.array(rtn(0).PutYList())
    _yarray_top = np.ma.masked_where(_yarray >= MASKVALUE, _yarray)
    _xarray_top = rtn(0).ReduceColumnList(rtn(0).PutXKey())
    ec2 = rtn.Put(0)
    if isPoint or (values is None):
        pass
    else:
        clip.SetHeaderToEC(ec2, float(values[1]), float(values[3]))
    parent._sliced_ec_top = ec2
    del rtn
    # del clip

    if d2frame.params.transPosition:
        _xarray_right, _yarray_right, _xarray_top, _yarray_top = _yarray_top, _xarray_top, _yarray_right, _xarray_right
    if len(d2frame.d2.ax_right.lines) == 0:
        d2frame.d2.ax_right.plot(_xarray_right, _yarray_right)
    else:
        d2frame.d2.ax_right.lines[0].set_ydata(_yarray_right)
        d2frame.d2.ax_right.lines[0].set_xdata(_xarray_right)
        d2frame.d2.ax_right.set_xlim(
            (_xarray_right.min(), _xarray_right.max()))
    d2frame.d2.ax_right.set_ylim(d2frame.d2.ax.get_ylim())

    if len(d2frame.d2.ax_top.lines) == 0:
        d2frame.d2.ax_top.plot(_xarray_top, _yarray_top)
    else:
        d2frame.d2.ax_top.lines[0].set_xdata(_xarray_top)
        d2frame.d2.ax_top.lines[0].set_ydata(_yarray_top)
        d2frame.d2.ax_top.set_ylim((_yarray_top.min(), _yarray_top.max()))
    d2frame.d2.ax_top.set_xlim(d2frame.d2.ax.get_xlim())
    return


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

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

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

    # 引数無しの場合は、テスト用のスクリプト
    else:
        FORMAT = "[%(levelno)s] %(asctime)s: %(message)s"
        DATE_FORMAT = "%Y-%m-%d %H:%M:%S"
        home = expanduser("~")
        path = os.path.join(home, 'ana', 'log')
        if os.path.exists(path):
            filepath = os.path.join(path, 'M2PlotPlus.log')
        elif "UTSUSEMI_USR_DIR" in os.environ:  # If executed with Utsusemi
            path = os.environ["UTSUSEMI_USR_DIR"]
            filepath = os.path.join(path, 'M2PlotPlus.log')
        else:
            path = os.getcwd()
            filepath = os.path.join(path, 'M2PlotPlus.log')
        if os.access(path, os.W_OK):
            logging.getLogger('matplotlib.font_manager').disabled = True
            logger = logging.getLogger()
            logger.setLevel(logging.DEBUG)
            handler = logging.handlers.TimedRotatingFileHandler(
                filepath, when='D', interval=10, backupCount=3)
            handler.setFormatter(logging.Formatter(
                fmt=FORMAT, datefmt=DATE_FORMAT))
            logger.addHandler(handler)

        # Hi-resolution Display for windows
        if hasattr(QtCore.Qt, 'AA_EnableHighDpiScaling'):
            QtWidgets.QApplication.setAttribute(
                QtCore.Qt.AA_EnableHighDpiScaling, True)
        app = QtWidgets.QApplication(sys.argv)
        # Set Default Font Size to (default 14)
        deffont = app.font()
        if "UTSUSEMI_DEFAULT_FONTSIZE" in os.environ:
            deffontsize = int(os.environ["UTSUSEMI_DEFAULT_FONTSIZE"])
            deffont.setPointSize(deffontsize)
        else:
            deffont.setPointSize(10)
        app.setFont(deffont)
        main_window = M2PlotPlus(None)
        # main_window.show()
    if PYSIDEVER == 6:
        sys.exit(app.exec())
    else:
        sys.exit(app.exec_())
