diff --git a/xmidas/css/darkStyle.css b/xmidas/css/darkStyle.css
index a5e9ddb..ea2c89f 100644
--- a/xmidas/css/darkStyle.css
+++ b/xmidas/css/darkStyle.css
@@ -1,68 +1,68 @@
-QWidget {
-background-color: rgb(60, 60, 60);
-color: rgb(255, 255, 255);
-font: 10pt "Segoe UI";
-}
-
-QPushButton {
-background-color: rgb(175, 236, 255);
-color: rgb(255, 5,0);
-}
-
-QSlider::groove:horizontal {
-border: 1px solid #bbb;
-background: white;
-height: 10px;
-border-radius: 4px;
-}
-
-QSlider::sub-page:horizontal {
-background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
- stop: 0 #66e, stop: 1 #bbf);
-background: qlineargradient(x1: 0, y1: 0.2, x2: 1, y2: 1,
- stop: 0 #bbf, stop: 1 #55f);
-border: 1px solid #777;
-height: 10px;
-border-radius: 4px;
-}
-
-QSlider::add-page:horizontal {
-background: #fff;
-border: 1px solid #777;
-height: 10px;
-border-radius: 4px;
-}
-
-QSlider::handle:horizontal {
-background: qlineargradient(x1:0, y1:0, x2:1, y2:1,
- stop:0 #eee, stop:1 #ccc);
-border: 1px solid #777;
-width: 13px;
-margin-top: -2px;
-margin-bottom: -2px;
-border-radius: 4px;
-}
-
-QSlider::handle:horizontal:hover {
-background: qlineargradient(x1:0, y1:0, x2:1, y2:1,
- stop:0 #fff, stop:1 #ddd);
-border: 1px solid #444;
-border-radius: 2px;
-}
-
-QSlider::sub-page:horizontal:disabled {
-background: #bbb;
-border-color: #999;
-}
-
-QSlider::add-page:horizontal:disabled {
-background: #eee;
-border-color: #999;
-}
-
-QSlider::handle:horizontal:disabled {
-background: #eee;
-border: 1px solid #aaa;
-border-radius: 4px;
-}
-
+QWidget {
+background-color: rgb(60, 60, 60);
+color: rgb(255, 255, 255);
+font: 10pt "Segoe UI";
+}
+
+QPushButton {
+background-color: rgb(175, 236, 255);
+color: rgb(255, 5,0);
+}
+
+QSlider::groove:horizontal {
+border: 1px solid #bbb;
+background: white;
+height: 10px;
+border-radius: 4px;
+}
+
+QSlider::sub-page:horizontal {
+background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
+ stop: 0 #66e, stop: 1 #bbf);
+background: qlineargradient(x1: 0, y1: 0.2, x2: 1, y2: 1,
+ stop: 0 #bbf, stop: 1 #55f);
+border: 1px solid #777;
+height: 10px;
+border-radius: 4px;
+}
+
+QSlider::add-page:horizontal {
+background: #fff;
+border: 1px solid #777;
+height: 10px;
+border-radius: 4px;
+}
+
+QSlider::handle:horizontal {
+background: qlineargradient(x1:0, y1:0, x2:1, y2:1,
+ stop:0 #eee, stop:1 #ccc);
+border: 1px solid #777;
+width: 13px;
+margin-top: -2px;
+margin-bottom: -2px;
+border-radius: 4px;
+}
+
+QSlider::handle:horizontal:hover {
+background: qlineargradient(x1:0, y1:0, x2:1, y2:1,
+ stop:0 #fff, stop:1 #ddd);
+border: 1px solid #444;
+border-radius: 2px;
+}
+
+QSlider::sub-page:horizontal:disabled {
+background: #bbb;
+border-color: #999;
+}
+
+QSlider::add-page:horizontal:disabled {
+background: #eee;
+border-color: #999;
+}
+
+QSlider::handle:horizontal:disabled {
+background: #eee;
+border: 1px solid #aaa;
+border-radius: 4px;
+}
+
diff --git a/xmidas/css/defaultStyle.css b/xmidas/css/defaultStyle.css
index 981a787..11c2467 100644
--- a/xmidas/css/defaultStyle.css
+++ b/xmidas/css/defaultStyle.css
@@ -1,72 +1,72 @@
-
-QWidget {
-font: 10pt "Segoe UI";
-}
-
-QPushButton {
-background-color: rgb(175, 236, 255);
-color: rgb(255, 5,0);
-font: 10pt "Segoe UI";
-}
-
-QLabel {
-font: 10pt "Segoe UI";
-}
-
-QSlider::groove:horizontal {
-border: 1px solid #bbb;
-background: white;
-height: 10px;
-border-radius: 4px;
-}
-
-QSlider::sub-page:horizontal {
-background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
- stop: 0 #66e, stop: 1 #bbf);
-background: qlineargradient(x1: 0, y1: 0.2, x2: 1, y2: 1,
- stop: 0 #bbf, stop: 1 #55f);
-border: 1px solid #777;
-height: 10px;
-border-radius: 4px;
-}
-
-QSlider::add-page:horizontal {
-background: #fff;
-border: 1px solid #777;
-height: 10px;
-border-radius: 4px;
-}
-
-QSlider::handle:horizontal {
-background: qlineargradient(x1:0, y1:0, x2:1, y2:1,
- stop:0 #eee, stop:1 #ccc);
-border: 1px solid #777;
-width: 13px;
-margin-top: -2px;
-margin-bottom: -2px;
-border-radius: 4px;
-}
-
-QSlider::handle:horizontal:hover {
-background: qlineargradient(x1:0, y1:0, x2:1, y2:1,
- stop:0 #fff, stop:1 #ddd);
-border: 1px solid #444;
-border-radius: 2px;
-}
-
-QSlider::sub-page:horizontal:disabled {
-background: #bbb;
-border-color: #999;
-}
-
-QSlider::add-page:horizontal:disabled {
-background: #eee;
-border-color: #999;
-}
-
-QSlider::handle:horizontal:disabled {
-background: #eee;
-border: 1px solid #aaa;
-border-radius: 4px;
-}
-
+
+QWidget {
+font: 10pt "Segoe UI";
+}
+
+QPushButton {
+background-color: rgb(175, 236, 255);
+color: rgb(255, 5,0);
+font: 10pt "Segoe UI";
+}
+
+QLabel {
+font: 10pt "Segoe UI";
+}
+
+QSlider::groove:horizontal {
+border: 1px solid #bbb;
+background: white;
+height: 10px;
+border-radius: 4px;
+}
+
+QSlider::sub-page:horizontal {
+background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
+ stop: 0 #66e, stop: 1 #bbf);
+background: qlineargradient(x1: 0, y1: 0.2, x2: 1, y2: 1,
+ stop: 0 #bbf, stop: 1 #55f);
+border: 1px solid #777;
+height: 10px;
+border-radius: 4px;
+}
+
+QSlider::add-page:horizontal {
+background: #fff;
+border: 1px solid #777;
+height: 10px;
+border-radius: 4px;
+}
+
+QSlider::handle:horizontal {
+background: qlineargradient(x1:0, y1:0, x2:1, y2:1,
+ stop:0 #eee, stop:1 #ccc);
+border: 1px solid #777;
+width: 13px;
+margin-top: -2px;
+margin-bottom: -2px;
+border-radius: 4px;
+}
+
+QSlider::handle:horizontal:hover {
+background: qlineargradient(x1:0, y1:0, x2:1, y2:1,
+ stop:0 #fff, stop:1 #ddd);
+border: 1px solid #444;
+border-radius: 2px;
+}
+
+QSlider::sub-page:horizontal:disabled {
+background: #bbb;
+border-color: #999;
+}
+
+QSlider::add-page:horizontal:disabled {
+background: #eee;
+border-color: #999;
+}
+
+QSlider::handle:horizontal:disabled {
+background: #eee;
+border: 1px solid #aaa;
+border-radius: 4px;
+}
+
diff --git a/xmidas/css/modern.css b/xmidas/css/modern.css
index 1bc5d20..a949b73 100644
--- a/xmidas/css/modern.css
+++ b/xmidas/css/modern.css
@@ -1,289 +1,289 @@
-/* /////////////////////////////////////////////////////////////////////////////////////////////////
-
-SET APP STYLESHEET - FULL STYLES HERE
-DARK THEME - DRACULA COLOR BASED
-
-///////////////////////////////////////////////////////////////////////////////////////////////// */
-
-QWidget{
- background-color: rgb(23,23,37);
- color: rgb(255, 255, 200);
- font: 10pt "Segoe UI";
-}
-
-
-
-/* /////////////////////////////////////////////////////////////////////////////////////////////////
-Tooltip */
-QToolTip {
- color: #ffffff;
- background-color: rgba(33, 37, 43, 180);
- border: 1px solid rgb(44, 49, 58);
- background-image: none;
- background-position: left center;
- background-repeat: no-repeat;
- border: none;
- border-left: 2px solid rgb(255, 121, 198);
- text-align: left;
- padding-left: 8px;
- margin: 0px;
-}
-
-
-QPushButton {
- background-color: rgb(210, 210, 98);
- color: rgb(23,23,37);
- border: none;
- border-radius: 5px;
- padding: 4px;
-}
-QPushButton:hover {
- background-color: rgb(211, 100, 211);
-}
-QPushButton:pressed {
- background-color: rgb(189, 147, 249);
- color: rgb(255, 255, 255);
-}
-
-
-QTabWidget {
- color: rgb(44, 0, 0);
-}
-QTabWidget::item{
- color: rgb(24, 0, 0);
-}
-QTabBar::tab {
- color:rgb(24, 0, 0);
-}
-
-QLineEdit {
- background-color: rgb(33, 37, 43);
- border-radius: 5px;
- border: 2px solid rgb(33, 37, 43);
- padding-left: 10px;
- color: rgb(255,255,255);
- selection-color: rgb(255, 255, 255);
- selection-background-color: rgb(255, 121, 198);
-}
-QLineEdit:hover {
- border: 2px solid rgb(64, 71, 88);
-}
-QLineEdit:focus {
- border: 2px solid rgb(91, 101, 124);
-}
-
-/* /////////////////////////////////////////////////////////////////////////////////////////////////
-PlainTextEdit */
-QPlainTextEdit {
- background-color: rgb(27, 29, 35);
- border-radius: 5px;
- padding: 10px;
- selection-color: rgb(255, 255, 255);
- selection-background-color: rgb(255, 121, 198);
-}
-QPlainTextEdit QScrollBar:vertical {
- width: 8px;
- }
-QPlainTextEdit QScrollBar:horizontal {
- height: 8px;
- }
-QPlainTextEdit:hover {
- border: 2px solid rgb(64, 71, 88);
-}
-QPlainTextEdit:focus {
- border: 2px solid rgb(91, 101, 124);
-}
-
-/* /////////////////////////////////////////////////////////////////////////////////////////////////
-ScrollBars */
-QScrollBar:horizontal {
- border: none;
- background: rgb(52, 59, 72);
- height: 8px;
- margin: 0px 21px 0 21px;
- border-radius: 0px;
-}
-QScrollBar::handle:horizontal {
- background: rgb(189, 147, 249);
- min-width: 25px;
- border-radius: 4px
-}
-QScrollBar::add-line:horizontal {
- border: none;
- background: rgb(55, 63, 77);
- width: 20px;
- border-top-right-radius: 4px;
- border-bottom-right-radius: 4px;
- subcontrol-position: right;
- subcontrol-origin: margin;
-}
-QScrollBar::sub-line:horizontal {
- border: none;
- background: rgb(55, 63, 77);
- width: 20px;
- border-top-left-radius: 4px;
- border-bottom-left-radius: 4px;
- subcontrol-position: left;
- subcontrol-origin: margin;
-}
-QScrollBar::up-arrow:horizontal, QScrollBar::down-arrow:horizontal
-{
- background: none;
-}
-QScrollBar::add-page:horizontal, QScrollBar::sub-page:horizontal
-{
- background: none;
-}
- QScrollBar:vertical {
- border: none;
- background: rgb(52, 59, 72);
- width: 8px;
- margin: 21px 0 21px 0;
- border-radius: 0px;
- }
- QScrollBar::handle:vertical {
- background: rgb(189, 147, 249);
- min-height: 25px;
- border-radius: 4px
- }
- QScrollBar::add-line:vertical {
- border: none;
- background: rgb(55, 63, 77);
- height: 20px;
- border-bottom-left-radius: 4px;
- border-bottom-right-radius: 4px;
- subcontrol-position: bottom;
- subcontrol-origin: margin;
- }
- QScrollBar::sub-line:vertical {
- border: none;
- background: rgb(55, 63, 77);
- height: 20px;
- border-top-left-radius: 4px;
- border-top-right-radius: 4px;
- subcontrol-position: top;
- subcontrol-origin: margin;
- }
- QScrollBar::up-arrow:vertical, QScrollBar::down-arrow:vertical {
- background: none;
- }
-
- QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical {
- background: none;
- }
-
-
-QRadioButton::indicator {
- border: 3px solid rgb(52, 59, 72);
- width: 15px;
- height: 15px;
- border-radius: 10px;
- background: rgb(44, 4, 0);
-}
-QRadioButton::indicator:hover {
- border: 3px solid rgb(58, 66, 81);
-}
-QRadioButton::indicator:checked {
- background: 3px solid rgb(0, 255, 0);
- border: 3px solid rgb(255, 252, 255);
-}
-
-QCheckBox::indicator {
- border: 3px solid rgb(52, 59, 72);
- width: 15px;
- height: 15px;
- border-radius: 10px;
- background: rgb(44, 4, 0);
-}
-QCheckBox::indicator:hover {
- border: 3px solid rgb(58, 66, 81);
-}
-QCheckBox::indicator:checked {
- background: 3px solid rgb(0, 255, 0);
- border: 3px solid rgb(255, 252, 255);
-}
-
-/* /////////////////////////////////////////////////////////////////////////////////////////////////
-ComboBox */
-QComboBox{
- background-color: rgb(138, 138, 138);
- color: rgb(79, 27, 79);
- border-radius: 5px;
- border: 2px solid rgb(33, 37, 43);
- padding: 5px;
- padding-left: 10px;
-}
-QComboBox:hover{
- border: 2px solid rgb(64, 71, 88);
-}
-QComboBox::drop-down {
- subcontrol-origin: padding;
- subcontrol-position: top right;
- width: 25px;
- border-left-width: 3px;
- border-left-color: rgba(39, 44, 54, 150);
- border-left-style: solid;
- border-top-right-radius: 3px;
- border-bottom-right-radius: 3px;
- background-image: url(:/icons/images/icons/cil-arrow-bottom.png);
- background-position: center;
- background-repeat: no-reperat;
- }
-QComboBox QAbstractItemView {
- color: rgb(255, 121, 198);
- background-color: rgb(33, 37, 43);
- padding: 10px;
- selection-background-color: rgb(39, 44, 54);
-}
-
-/* /////////////////////////////////////////////////////////////////////////////////////////////////
-Sliders */
-QSlider::groove:horizontal {
- border-radius: 5px;
- height: 10px;
- margin: 0px;
- background-color: rgb(52, 59, 72);
-}
-QSlider::groove:horizontal:hover {
- background-color: rgb(55, 62, 76);
-}
-QSlider::handle:horizontal {
- background-color: rgb(189, 147, 249);
- border: none;
- height: 10px;
- width: 10px;
- margin: 0px;
- border-radius: 5px;
-}
-QSlider::handle:horizontal:hover {
- background-color: rgb(195, 155, 255);
-}
-QSlider::handle:horizontal:pressed {
- background-color: rgb(255, 121, 198);
-}
-
-QSlider::groove:vertical {
- border-radius: 5px;
- width: 10px;
- margin: 0px;
- background-color: rgb(52, 59, 72);
-}
-QSlider::groove:vertical:hover {
- background-color: rgb(55, 62, 76);
-}
-QSlider::handle:vertical {
- background-color: rgb(189, 147, 249);
- border: none;
- height: 10px;
- width: 10px;
- margin: 0px;
- border-radius: 5px;
-}
-QSlider::handle:vertical:hover {
- background-color: rgb(195, 155, 255);
-}
-QSlider::handle:vertical:pressed {
- background-color: rgb(255, 121, 198);
-}
-
-
+/* /////////////////////////////////////////////////////////////////////////////////////////////////
+
+SET APP STYLESHEET - FULL STYLES HERE
+DARK THEME - DRACULA COLOR BASED
+
+///////////////////////////////////////////////////////////////////////////////////////////////// */
+
+QWidget{
+ background-color: rgb(23,23,37);
+ color: rgb(255, 255, 200);
+ font: 10pt "Segoe UI";
+}
+
+
+
+/* /////////////////////////////////////////////////////////////////////////////////////////////////
+Tooltip */
+QToolTip {
+ color: #ffffff;
+ background-color: rgba(33, 37, 43, 180);
+ border: 1px solid rgb(44, 49, 58);
+ background-image: none;
+ background-position: left center;
+ background-repeat: no-repeat;
+ border: none;
+ border-left: 2px solid rgb(255, 121, 198);
+ text-align: left;
+ padding-left: 8px;
+ margin: 0px;
+}
+
+
+QPushButton {
+ background-color: rgb(210, 210, 98);
+ color: rgb(23,23,37);
+ border: none;
+ border-radius: 5px;
+ padding: 4px;
+}
+QPushButton:hover {
+ background-color: rgb(211, 100, 211);
+}
+QPushButton:pressed {
+ background-color: rgb(189, 147, 249);
+ color: rgb(255, 255, 255);
+}
+
+
+QTabWidget {
+ color: rgb(44, 0, 0);
+}
+QTabWidget::item{
+ color: rgb(24, 0, 0);
+}
+QTabBar::tab {
+ color:rgb(24, 0, 0);
+}
+
+QLineEdit {
+ background-color: rgb(33, 37, 43);
+ border-radius: 5px;
+ border: 2px solid rgb(33, 37, 43);
+ padding-left: 10px;
+ color: rgb(255,255,255);
+ selection-color: rgb(255, 255, 255);
+ selection-background-color: rgb(255, 121, 198);
+}
+QLineEdit:hover {
+ border: 2px solid rgb(64, 71, 88);
+}
+QLineEdit:focus {
+ border: 2px solid rgb(91, 101, 124);
+}
+
+/* /////////////////////////////////////////////////////////////////////////////////////////////////
+PlainTextEdit */
+QPlainTextEdit {
+ background-color: rgb(27, 29, 35);
+ border-radius: 5px;
+ padding: 10px;
+ selection-color: rgb(255, 255, 255);
+ selection-background-color: rgb(255, 121, 198);
+}
+QPlainTextEdit QScrollBar:vertical {
+ width: 8px;
+ }
+QPlainTextEdit QScrollBar:horizontal {
+ height: 8px;
+ }
+QPlainTextEdit:hover {
+ border: 2px solid rgb(64, 71, 88);
+}
+QPlainTextEdit:focus {
+ border: 2px solid rgb(91, 101, 124);
+}
+
+/* /////////////////////////////////////////////////////////////////////////////////////////////////
+ScrollBars */
+QScrollBar:horizontal {
+ border: none;
+ background: rgb(52, 59, 72);
+ height: 8px;
+ margin: 0px 21px 0 21px;
+ border-radius: 0px;
+}
+QScrollBar::handle:horizontal {
+ background: rgb(189, 147, 249);
+ min-width: 25px;
+ border-radius: 4px
+}
+QScrollBar::add-line:horizontal {
+ border: none;
+ background: rgb(55, 63, 77);
+ width: 20px;
+ border-top-right-radius: 4px;
+ border-bottom-right-radius: 4px;
+ subcontrol-position: right;
+ subcontrol-origin: margin;
+}
+QScrollBar::sub-line:horizontal {
+ border: none;
+ background: rgb(55, 63, 77);
+ width: 20px;
+ border-top-left-radius: 4px;
+ border-bottom-left-radius: 4px;
+ subcontrol-position: left;
+ subcontrol-origin: margin;
+}
+QScrollBar::up-arrow:horizontal, QScrollBar::down-arrow:horizontal
+{
+ background: none;
+}
+QScrollBar::add-page:horizontal, QScrollBar::sub-page:horizontal
+{
+ background: none;
+}
+ QScrollBar:vertical {
+ border: none;
+ background: rgb(52, 59, 72);
+ width: 8px;
+ margin: 21px 0 21px 0;
+ border-radius: 0px;
+ }
+ QScrollBar::handle:vertical {
+ background: rgb(189, 147, 249);
+ min-height: 25px;
+ border-radius: 4px
+ }
+ QScrollBar::add-line:vertical {
+ border: none;
+ background: rgb(55, 63, 77);
+ height: 20px;
+ border-bottom-left-radius: 4px;
+ border-bottom-right-radius: 4px;
+ subcontrol-position: bottom;
+ subcontrol-origin: margin;
+ }
+ QScrollBar::sub-line:vertical {
+ border: none;
+ background: rgb(55, 63, 77);
+ height: 20px;
+ border-top-left-radius: 4px;
+ border-top-right-radius: 4px;
+ subcontrol-position: top;
+ subcontrol-origin: margin;
+ }
+ QScrollBar::up-arrow:vertical, QScrollBar::down-arrow:vertical {
+ background: none;
+ }
+
+ QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical {
+ background: none;
+ }
+
+
+QRadioButton::indicator {
+ border: 3px solid rgb(52, 59, 72);
+ width: 15px;
+ height: 15px;
+ border-radius: 10px;
+ background: rgb(44, 4, 0);
+}
+QRadioButton::indicator:hover {
+ border: 3px solid rgb(58, 66, 81);
+}
+QRadioButton::indicator:checked {
+ background: 3px solid rgb(0, 255, 0);
+ border: 3px solid rgb(255, 252, 255);
+}
+
+QCheckBox::indicator {
+ border: 3px solid rgb(52, 59, 72);
+ width: 15px;
+ height: 15px;
+ border-radius: 10px;
+ background: rgb(44, 4, 0);
+}
+QCheckBox::indicator:hover {
+ border: 3px solid rgb(58, 66, 81);
+}
+QCheckBox::indicator:checked {
+ background: 3px solid rgb(0, 255, 0);
+ border: 3px solid rgb(255, 252, 255);
+}
+
+/* /////////////////////////////////////////////////////////////////////////////////////////////////
+ComboBox */
+QComboBox{
+ background-color: rgb(138, 138, 138);
+ color: rgb(79, 27, 79);
+ border-radius: 5px;
+ border: 2px solid rgb(33, 37, 43);
+ padding: 5px;
+ padding-left: 10px;
+}
+QComboBox:hover{
+ border: 2px solid rgb(64, 71, 88);
+}
+QComboBox::drop-down {
+ subcontrol-origin: padding;
+ subcontrol-position: top right;
+ width: 25px;
+ border-left-width: 3px;
+ border-left-color: rgba(39, 44, 54, 150);
+ border-left-style: solid;
+ border-top-right-radius: 3px;
+ border-bottom-right-radius: 3px;
+ background-image: url(:/icons/images/icons/cil-arrow-bottom.png);
+ background-position: center;
+ background-repeat: no-reperat;
+ }
+QComboBox QAbstractItemView {
+ color: rgb(255, 121, 198);
+ background-color: rgb(33, 37, 43);
+ padding: 10px;
+ selection-background-color: rgb(39, 44, 54);
+}
+
+/* /////////////////////////////////////////////////////////////////////////////////////////////////
+Sliders */
+QSlider::groove:horizontal {
+ border-radius: 5px;
+ height: 10px;
+ margin: 0px;
+ background-color: rgb(52, 59, 72);
+}
+QSlider::groove:horizontal:hover {
+ background-color: rgb(55, 62, 76);
+}
+QSlider::handle:horizontal {
+ background-color: rgb(189, 147, 249);
+ border: none;
+ height: 10px;
+ width: 10px;
+ margin: 0px;
+ border-radius: 5px;
+}
+QSlider::handle:horizontal:hover {
+ background-color: rgb(195, 155, 255);
+}
+QSlider::handle:horizontal:pressed {
+ background-color: rgb(255, 121, 198);
+}
+
+QSlider::groove:vertical {
+ border-radius: 5px;
+ width: 10px;
+ margin: 0px;
+ background-color: rgb(52, 59, 72);
+}
+QSlider::groove:vertical:hover {
+ background-color: rgb(55, 62, 76);
+}
+QSlider::handle:vertical {
+ background-color: rgb(189, 147, 249);
+ border: none;
+ height: 10px;
+ width: 10px;
+ margin: 0px;
+ border-radius: 5px;
+}
+QSlider::handle:vertical:hover {
+ background-color: rgb(195, 155, 255);
+}
+QSlider::handle:vertical:pressed {
+ background-color: rgb(255, 121, 198);
+}
+
+
diff --git a/xmidas/main.py b/xmidas/main.py
index 3185d3c..c2c2236 100644
--- a/xmidas/main.py
+++ b/xmidas/main.py
@@ -1,4299 +1,4019 @@
-# -*- coding: utf-8 -*-
-
-# Author: Ajith Pattammattel
-# First Version on:06-23-2020
-
-import argparse
-import logging
-import sys
-import webbrowser
-import traceback
-import os
-import json
-import h5py
-import scipy.stats as stats
-import numpy as np
-import pandas as pd
-import tifffile as tf
-import pyqtgraph as pg
-import pyqtgraph.exporters
-import scipy.optimize as opt
-import sklearn.decomposition as sd
-import sklearn.cluster as sc
-
-from pyqtgraph import plot
-from itertools import combinations
-from scipy.stats import linregress
-from scipy.signal import savgol_filter
-from skimage.transform import resize
-from skimage import filters
-from sklearn import linear_model
-from larch.xafs import preedge
-from pystackreg import StackReg
-from packaging import version
-
-from PyQt5 import QtWidgets, QtCore, QtGui, uic, QtTest
-from PyQt5.QtGui import QMovie
-from PyQt5.QtWidgets import QMessageBox, QFileDialog, QApplication
-from PyQt5.QtCore import QObject, pyqtSignal, pyqtSlot, QRunnable, QThreadPool, PYQT_VERSION_STR
-
-from . import __version__
-
-# from MultiChannel import *
-
-logger = logging.getLogger()
-try:
- import cv2 # noqa: F401
-except Exception:
- logger.warning("openCV module not found")
- pass
-if hasattr(QtCore.Qt, "AA_EnableHighDpiScaling"):
- QtWidgets.QApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling, True)
-
-if hasattr(QtCore.Qt, "AA_UseHighDpiPixmaps"):
- QtWidgets.QApplication.setAttribute(QtCore.Qt.AA_UseHighDpiPixmaps, True)
-
-ui_path = os.path.dirname(os.path.abspath(__file__))
-
-# global settings for pyqtgraph plot and image colormaps
-pg.setConfigOption("imageAxisOrder", "row-major")
-cmap_names = ["CET-L13", "CET-L14", "CET-L15"]
-cmap_combo = combinations(cmap_names, 2)
-cmap_label1 = ["red", "green", "blue"]
-cmap_label2 = ["yellow", "magenta", "cyan"]
-cmap_dict = {}
-for i, name in zip(cmap_names, cmap_label1):
- cmap_dict[name] = pg.colormap.get(i).getLookupTable(alpha=True)
-
-for i, name in zip(cmap_combo, cmap_label2):
- cmap_dict[name] = pg.colormap.get(i[0]).getLookupTable(alpha=True) + pg.colormap.get(i[1]).getLookupTable(
- alpha=True
- )
- cmap_dict[name][:, 3] = 255
-
- grey = (
- pg.colormap.get("CET-L13").getLookupTable(alpha=True)
- + pg.colormap.get("CET-L14").getLookupTable(alpha=True)
- + pg.colormap.get("CET-L15").getLookupTable(alpha=True)
- )
-
- grey[:, 3] = 255
- cmap_dict["grey"] = grey
-
-
-class jsonEncoder(json.JSONEncoder):
- def default(self, obj):
- if isinstance(obj, np.integer):
- return int(obj)
- elif isinstance(obj, np.floating):
- return float(obj)
- elif isinstance(obj, np.ndarray):
- return obj.tolist()
- else:
- return super(jsonEncoder, self).default(obj)
-
-
-class midasWindow(QtWidgets.QMainWindow):
- def __init__(self, im_stack=None, energy=[], refs=[]):
- super(midasWindow, self).__init__()
- uic.loadUi(os.path.join(ui_path, "uis/midasMainwindow.ui"), self)
- self.im_stack = im_stack
- self.energy = energy
- self.refs = refs
- self.loaded_tranform_file = []
- self.image_roi2_flag = False
- self.refStackAvailable = False
- self.isAReload = False
- self.plotWidth = 2
- self.stackStatusDict = {}
-
- self.plt_colors = [
- "g",
- "r",
- "c",
- "m",
- "y",
- "w",
- "b",
- pg.mkPen(70, 5, 80),
- pg.mkPen(255, 85, 130),
- pg.mkPen(0, 85, 130),
- pg.mkPen(255, 170, 60),
- ] * 3
- # window style
- self.actionDarkMode.triggered.connect(self.darkMode)
- self.actionDefault.triggered.connect(self.defaultMode)
- self.actionModern.triggered.connect(self.modernMode)
-
- # self.setToolTipsVisible(True)
- for menuItem in self.findChildren(QtWidgets.QMenu):
- menuItem.setToolTipsVisible(True)
-
- # plotview options
- self.actionWhite.triggered.connect(lambda: self.spectrum_view.setBackground("w"))
- self.actionRed.triggered.connect(lambda: self.spectrum_view.setBackground("r"))
- self.actionYellow.triggered.connect(lambda: self.spectrum_view.setBackground("y"))
- self.actionBlue.triggered.connect(lambda: self.spectrum_view.setBackground("b"))
- self.actionBlack.triggered.connect(lambda: self.spectrum_view.setBackground((0, 0, 0)))
-
- self.actn1.triggered.connect(lambda: self.setPlotLineWidth(int(self.actn1.text())))
- self.actn2.triggered.connect(lambda: self.setPlotLineWidth(int(self.actn2.text())))
- self.actn3.triggered.connect(lambda: self.setPlotLineWidth(int(self.actn3.text())))
- self.actn4.triggered.connect(lambda: self.setPlotLineWidth(int(self.actn4.text())))
- self.actn5.triggered.connect(lambda: self.setPlotLineWidth(int(self.actn5.text())))
- self.actn6.triggered.connect(lambda: self.setPlotLineWidth(int(self.actn6.text())))
- self.actn8.triggered.connect(lambda: self.setPlotLineWidth(int(self.actn8.text())))
- self.actn10.triggered.connect(lambda: self.setPlotLineWidth(int(self.actn10.text())))
-
- self.actionOpen_Image_Data.triggered.connect(self.browse_file)
- self.actionOpen_Multiple_Files.triggered.connect(self.createVirtualStack)
- self.actionSave_as.triggered.connect(lambda: self.save_stack())
- self.actionExit.triggered.connect(lambda: QApplication.closeAllWindows())
- self.actionOpen_in_GitHub.triggered.connect(self.open_github_link)
- self.actionLoad_Energy.triggered.connect(self.select_elist)
- self.menuFile.setToolTipsVisible(True)
-
- # Accessories
- self.actionOpen_Mask_Gen.triggered.connect(self.openMaskMaker)
- self.actionMultiColor.triggered.connect(self.openMultiColorWindow)
-
- # calculations
- self.pb_transpose_stack.clicked.connect(lambda: self.threadMaker(self.transposeStack))
- self.pb_swapXY_stack.clicked.connect(lambda: self.threadMaker(self.swapStackXY))
- self.pb_reset_img.clicked.connect(self.reloadImageStack)
- self.pb_crop.clicked.connect(self.crop_to_dim)
- self.pb_crop.clicked.connect(self.view_stack)
- self.sb_scaling_factor.valueChanged.connect(self.view_stack)
- self.pb_ref_xanes.clicked.connect(self.select_ref_file)
- self.pb_elist_xanes.clicked.connect(self.select_elist)
-
- # batchjobs
- self.actionPlotAllCorrelations.triggered.connect(self.plotCorrelationsAllCombinations)
-
- [
- uis.valueChanged.connect(self.replot_image)
- for uis in [self.hs_smooth_size, self.hs_nsigma, self.hs_bg_threshold]
- ]
-
- [
- uis.stateChanged.connect(self.replot_image)
- for uis in [self.cb_remove_bg, self.cb_remove_outliers, self.cb_smooth, self.cb_norm, self.cb_log]
- ]
-
- [
- uis.stateChanged.connect(self.view_stack)
- for uis in [self.cb_remove_edges, self.cb_upscale, self.cb_rebin]
- ]
-
- # ToolBar
- self.actionStack_Info.triggered.connect(self.displayStackInfo)
- self.actionSave_Image.triggered.connect(self.save_disp_img)
- self.actionExport_Stack.triggered.connect(lambda: self.save_stack())
-
- # ROI background
- self.actionSubtract_ROI_BG.triggered.connect(lambda: self.threadMaker(self.removeROIBGStack))
-
- # alignment
- self.pb_load_align_ref.clicked.connect(self.loadAlignRefImage)
- self.pb_loadAlignTranform.clicked.connect(self.importAlignTransformation)
- self.pb_saveAlignTranform.clicked.connect(self.exportAlignTransformation)
- self.pb_alignStack.clicked.connect(lambda: self.threadMaker(self.stackRegistration))
- # self.pb_alignStack.clicked.connect(self.stackRegistration)
-
- # save_options
- self.actionSave_Sum_Image.triggered.connect(lambda: self.save_stack(method="sum"))
- self.actionSave_Mean_Image.triggered.connect(lambda: self.save_stack(method="mean"))
- self.pb_save_disp_spec.clicked.connect(self.save_disp_spec)
- self.actionSave_Energy_List.triggered.connect(self.saveEnergyList)
- self.pb_show_roi.clicked.connect(self.getROIMask)
- self.pb_addToCollector.clicked.connect(self.addSpectrumToCollector)
- self.pb_collect_clear.clicked.connect(lambda: self.spectrum_view_collect.clear())
- self.pb_saveCollectorPlot.clicked.connect(self.saveCollectorPlot)
-
- # XANES Normalization
- self.pb_apply_xanes_norm.clicked.connect(self.nomalizeLiveSpec)
- self.pb_auto_Eo.clicked.connect(self.findEo)
- self.pb_xanes_norm_vals.clicked.connect(self.initNormVals)
- self.pb_apply_norm_to_stack.clicked.connect(lambda: self.threadMaker(self.normalizeStack))
- self.actionExport_Norm_Params.triggered.connect(self.exportNormParams)
- self.actionImport_Norm_Params.triggered.connect(self.importNormParams)
-
- # Analysis
- self.pb_pca_scree.clicked.connect(self.pca_scree_)
- self.pb_calc_components.clicked.connect(self.calc_comp_)
- self.pb_kmeans_elbow.clicked.connect(self.kmeans_elbow)
- self.pb_calc_cluster.clicked.connect(self.clustering_)
- self.pb_xanes_fit.clicked.connect(self.fast_xanes_fitting)
- self.pb_plot_refs.clicked.connect(self.plt_xanes_refs)
-
- self.show()
-
- self.threadpool = QThreadPool()
- print(f"Multithreading with maximum {self.threadpool.maxThreadCount()} threads")
-
- # View Options
- def darkMode(self):
- self.centralwidget.setStyleSheet(open(os.path.join(ui_path, "css/darkStyle.css")).read())
-
- def defaultMode(self):
- self.centralwidget.setStyleSheet(open(os.path.join(ui_path, "css/defaultStyle.css")).read())
-
- def modernMode(self):
- self.centralwidget.setStyleSheet(open(os.path.join(ui_path, "css/modern.css")).read())
-
- def setPlotLineWidth(self, width_input):
- self.plotWidth = width_input
- try:
- self.update_spectrum()
- except Exception:
- pass
-
- def openMultiColorWindow(self):
- self.multicolorwindow = MultiChannelWindow()
- self.multicolorwindow.show()
-
- def openMaskMaker(self):
- self.mask_window = MaskSpecViewer(xanes_stack=self.displayedStack, energy=self.energy)
- self.mask_window.show()
-
- def open_github_link(self):
- webbrowser.open("https://github.com/pattammattel/NSLS-II-MIDAS/wiki")
-
- def threadMaker(self, funct):
- # Pass the function to execute
- worker = Worker(funct) # Any other args, kwargs are passed to the run function
- self.loadSplashScreen()
- worker.signals.start.connect(self.splash.startAnimation)
- worker.signals.result.connect(self.print_output)
-
- list(
- map(
- worker.signals.finished.connect,
- [
- self.thread_complete,
- self.splash.stopAnimation,
- self.update_stack_info,
- self.update_spectrum,
- self.update_image_roi,
- ],
- )
- )
-
- # Execute
- self.threadpool.start(worker)
-
- # File Loading
-
- def createVirtualStack(self):
- """User can load multiple/series of tiff images with same shape.
- The 'self.load_stack()' recognizes 'self.filename as list and create the stack.
- """
- self.energy = []
- filter = "TIFF (*.tiff);;TIF (*.tif);;all_files (*)"
- file_name = QFileDialog()
- file_name.setFileMode(QFileDialog.ExistingFiles)
- names = file_name.getOpenFileNames(self, "Open files", " ", filter)
- if names[0]:
-
- self.file_name = names[0]
- self.load_stack()
-
- else:
- self.statusbar_main.showMessage("No file has selected")
- pass
-
- def load_stack(self):
-
- """load the image data from the selected file.
- If the the choice is for multiple files stack will be created in a loop.
- If single h5 file is selected the unpacking will be done with 'get_xrf_data' function in StackCalcs.
- From the h5 the program can recognize the beamline. The exported stack will be normalized to I0.
-
- If the single tiff file is choosen tf.imread() is used.
-
- The output 'self.im_stack' is the unmodified data file
- """
-
- self.log_warning = False # for the Qmessage box in cb_log
- self.image_roi2_flag = False
- self.cb_log.setChecked(False)
- self.cb_remove_edges.setChecked(False)
- self.cb_norm.setChecked(False)
- self.cb_smooth.setChecked(False)
- self.cb_remove_outliers.setChecked(False)
- self.cb_remove_bg.setChecked(False)
- self.cb_rebin.setChecked(False)
- self.cb_upscale.setChecked(False)
- self.sb_xrange1.setValue(0)
- self.sb_yrange1.setValue(0)
- self.sb_zrange1.setValue(0)
-
- self.menuMask.setEnabled(True)
- self.actionLoad_Energy.setEnabled(True)
- self.actionSave_Energy_List.setEnabled(True)
- self.actionSave_as.setEnabled(True)
-
- self.sb_zrange2.setMaximum(99999)
- self.sb_xrange2.setMaximum(99999)
- self.sb_yrange2.setMaximum(99999)
-
- self.statusbar_main.showMessage("Loading.. please wait...")
-
- if isinstance(self.file_name, list):
-
- all_images = []
-
- for im_file in self.file_name:
- img = tf.imread(im_file)
- all_images.append(img) # row major image
- self.im_stack = np.dstack(all_images).transpose((2, 0, 1))
- self.avgIo = 1 # I0 is only applicable to XRF h5 files
- self.sb_zrange2.setValue(self.im_stack.shape[0])
-
- else:
-
- if self.file_name.endswith(".h5"):
- self.im_stack, mono_e, bl_name, self.avgIo = get_xrf_data(self.file_name)
- self.statusbar_main.showMessage(f"Data from {bl_name}")
- self.sb_zrange2.setValue(mono_e / 10)
- self.energy = []
-
- elif self.file_name.endswith(".tiff") or self.file_name.endswith(".tif"):
- self.im_stack_ = tf.imread(self.file_name)
- if self.im_stack_.ndim == 2:
- self.im_stack = self.im_stack_.reshape(1, self.im_stack_.shape[0], self.im_stack_.shape[1])
-
- else:
- self.im_stack = self.im_stack_
- self.sb_zrange2.setValue(self.im_stack.shape[0])
- self.autoEnergyLoader()
- self.energyUnitCheck()
- self.avgIo = 1
-
- else:
- logger.error("Unknown data format")
-
- """ Fill the stack dimensions to the GUI and set the image dimensions as max values.
- This prevent user from choosing higher image dimensions during a resizing event"""
-
- logger.info(f" loaded stack with {np.shape(self.im_stack)} from the file")
-
- try:
- logger.info(f" Transposed to shape: {np.shape(self.im_stack)}")
- self.init_dimZ, self.init_dimY, self.init_dimX = self.im_stack.shape
- # Remove any previously set max value during a reload
-
- self.sb_xrange2.setValue(self.init_dimX)
- self.sb_yrange2.setValue(self.init_dimY)
-
- except UnboundLocalError:
- logger.error("No file selected")
- pass
-
- self.view_stack()
- logger.info("Stack displayed correctly")
- self.update_stack_info()
-
- logger.info(f"completed image shape {np.shape(self.im_stack)}")
-
- try:
- self.statusbar_main.showMessage(f"Loaded: {self.file_name}")
-
- except AttributeError:
- self.statusbar_main.showMessage("New Stack is made from selected tiffs")
- pass
-
- def browse_file(self):
- """To open a file widow and choose the data file.
- The filename will be used to load data using 'rest and load stack' function"""
-
- filename = QFileDialog().getOpenFileName(
- self, "Select image data", "", "image file(*.hdf *.h5 *tiff *tif )"
- )
- self.file_name = str(filename[0])
-
- # if user decides to cancel the file window gui returns to original state
- if self.file_name:
- self.disconnectImageActions()
- self.isAReload = False
- self.load_stack()
-
- else:
- self.statusbar_main.showMessage("No file has selected")
- pass
-
- def autoEnergyLoader(self):
-
- dir_, filename_ = os.path.split(self.file_name)
- self.efilePath_name = os.path.join(dir_, os.path.splitext(filename_)[0] + ".txt")
- self.efilePath_log = os.path.join(dir_, "maps_log_tiff.txt")
-
- if os.path.isfile(self.efilePath_name):
- self.efilePath = self.efilePath_name
- self.efileLoader()
- self.statusbar_main.showMessage(f"Energy File detected {self.efilePath}")
-
- elif os.path.isfile(self.efilePath_log):
- self.efilePath = self.efilePath_log
- self.efileLoader()
- self.statusbar_main.showMessage(f"Energy File detected {self.efilePath}")
-
- else:
- self.efilePath = False
- self.efileLoader()
-
- def update_stack_info(self):
- z, y, x = np.shape(self.displayedStack)
- self.sb_zrange2.setMaximum(z + self.sb_zrange1.value())
- self.sb_xrange2.setValue(x)
- self.sb_xrange2.setMaximum(x)
- self.sb_yrange2.setValue(y)
- self.sb_yrange2.setMaximum(y)
- logger.info("Stack info has been updated")
-
- # Image Transformations
-
- def crop_to_dim(self):
- self.x1, self.x2 = self.sb_xrange1.value(), self.sb_xrange2.value()
- self.y1, self.y2 = self.sb_yrange1.value(), self.sb_yrange2.value()
- self.z1, self.z2 = self.sb_zrange1.value(), self.sb_zrange2.value()
-
- try:
- self.displayedStack = remove_nan_inf(
- self.displayedStack[self.z1 : self.z2, self.y1 : self.y2, self.x1 : self.x2]
- )
- except Exception:
- self.displayedStack = remove_nan_inf(
- self.im_stack[self.z1 : self.z2, self.y1 : self.y2, self.x1 : self.x2]
- )
-
- def transpose_stack(self):
- self.displayedStack = self.displayedStack.T
- self.update_spectrum()
- self.update_spec_image_roi()
-
- # Alignement
-
- def loadAlignRefImage(self):
- filename = QFileDialog().getOpenFileName(self, "Image Data", "", "*.tiff *.tif")
- file_name = str(filename[0])
- self.alignRefImage = tf.imread(file_name)
- assert self.alignRefImage.shape == self.displayedStack.shape, "Image dimensions do not match"
- self.refStackAvailable = True
- self.rb_alignRefVoid.setChecked(False)
- self.change_color_on_load(self.pb_load_align_ref)
-
- def stackRegistration(self):
-
- self.transformations = {
- "TRANSLATION": StackReg.TRANSLATION,
- "RIGID_BODY": StackReg.RIGID_BODY,
- "SCALED_ROTATION": StackReg.SCALED_ROTATION,
- "AFFINE": StackReg.AFFINE,
- "BILINEAR": StackReg.BILINEAR,
- }
-
- self.transformType = self.transformations[self.cb_alignTransform.currentText()]
- self.alignReferenceImage = self.cb_alignRef.currentText()
- self.alignRefStackVoid = self.rb_alignRefVoid.isChecked()
- self.alignMaxIter = self.sb_maxIterVal.value()
-
- if self.cb_use_tmatFile.isChecked():
-
- if len(self.loaded_tranform_file) > 0:
-
- self.displayedStack = align_with_tmat(
- self.displayedStack, tmat_file=self.loaded_tranform_file, transformation=self.transformType
- )
- logger.info("Aligned to the tranform File")
-
- else:
- logger.error("No Tranformation File Loaded")
-
- elif self.cb_iterAlign.isChecked():
-
- if not self.refStackAvailable:
- self.alignRefImage = self.displayedStack
- else:
- pass
-
- self.displayedStack = align_stack_iter(
- self.displayedStack,
- ref_stack_void=False,
- ref_stack=self.alignRefImage,
- transformation=self.transformType,
- method=("previous", "first"),
- max_iter=self.alignMaxIter,
- )
-
- else:
- if not self.refStackAvailable:
- self.alignRefImage = self.displayedStack
-
- else:
- pass
-
- self.displayedStack, self.tranform_file = align_stack(
- self.displayedStack,
- ref_image_void=True,
- ref_stack=self.alignRefImage,
- transformation=self.transformType,
- reference=self.alignReferenceImage,
- )
- logger.info("New Tranformation file available")
- self.im_stack = self.displayedStack
-
- def exportAlignTransformation(self):
- file_name = QFileDialog().getSaveFileName(
- self, "Save Transformation File", "TranformationMatrix.npy", "text file (*.npy)"
- )
- if file_name[0]:
- np.save(file_name[0], self.tranform_file)
- else:
- pass
-
- def importAlignTransformation(self):
- file_name = QFileDialog().getOpenFileName(self, "Open Transformation File", " ", "text file (*.npy)")
- if file_name[0]:
- self.loaded_tranform_file = np.load(file_name[0])
- self.cb_use_tmatFile.setChecked(True)
- logger.info("Tranformation File Loaded")
- else:
- pass
-
- def loadSplashScreen(self):
- self.splash = LoadingScreen()
-
- px = self.geometry().x()
- py = self.geometry().y()
- ph = self.geometry().height()
- pw = self.geometry().width()
- dw = self.splash.width()
- dh = self.splash.height()
- new_x, new_y = px + (0.5 * pw) - dw, py + (0.5 * ph) - dh
- self.splash.setGeometry(new_x, new_y, dw, dh)
-
- self.splash.show()
-
- def reloadImageStack(self):
- self.isAReload = True
- self.load_stack()
-
- def update_stack(self):
- self.displayedStack = self.im_stack
- self.crop_to_dim()
-
- if self.cb_rebin.isChecked():
- self.cb_upscale.setChecked(False)
- self.sb_scaling_factor.setEnabled(True)
- self.displayedStack = resize_stack(self.displayedStack, scaling_factor=self.sb_scaling_factor.value())
- self.update_stack_info()
-
- elif self.cb_upscale.isChecked():
- self.cb_rebin.setChecked(False)
- self.sb_scaling_factor.setEnabled(True)
- self.displayedStack = resize_stack(
- self.displayedStack, upscaling=True, scaling_factor=self.sb_scaling_factor.value()
- )
- self.update_stack_info()
-
- if self.cb_remove_outliers.isChecked():
- self.hs_nsigma.setEnabled(True)
- nsigma = self.hs_nsigma.value() / 10
- self.displayedStack = remove_hot_pixels(self.displayedStack, NSigma=nsigma)
- self.label_nsigma.setText(str(nsigma))
- logger.info(f"Removing Outliers with NSigma {nsigma}")
-
- elif self.cb_remove_outliers.isChecked() is False:
- self.hs_nsigma.setEnabled(False)
-
- if self.cb_remove_edges.isChecked():
- self.displayedStack = remove_edges(self.displayedStack)
- logger.info(f"Removed edges, new shape {self.displayedStack.shape}")
- self.update_stack_info()
-
- if self.cb_remove_bg.isChecked():
- self.hs_bg_threshold.setEnabled(True)
- logger.info("Removing background")
- bg_threshold = self.hs_bg_threshold.value()
- self.label_bg_threshold.setText(str(bg_threshold) + "%")
- self.displayedStack = clean_stack(self.displayedStack, auto_bg=False, bg_percentage=bg_threshold)
-
- elif self.cb_remove_bg.isChecked() is False:
- self.hs_bg_threshold.setEnabled(False)
-
- if self.cb_log.isChecked():
-
- self.displayedStack = remove_nan_inf(np.log10(self.displayedStack))
- logger.info("Log Stack is in use")
-
- if self.cb_smooth.isChecked():
- self.hs_smooth_size.setEnabled(True)
- window = self.hs_smooth_size.value()
- if window % 2 == 0:
- window = +1
- self.smooth_winow_size.setText("Window size: " + str(window))
- self.displayedStack = smoothen(self.displayedStack, w_size=window)
- logger.info("Spectrum Smoothening Applied")
-
- elif self.cb_smooth.isChecked() is False:
- self.hs_smooth_size.setEnabled(False)
-
- if self.cb_norm.isChecked():
- logger.info("Normalizing spectra")
- self.displayedStack = normalize(self.displayedStack, norm_point=-1)
-
- logger.info("Updated image is in use")
-
- # ImageView
-
- def view_stack(self):
-
- if not self.im_stack.ndim == 3:
- raise ValueError("stack should be an ndarray with ndim == 3")
- else:
- self.update_stack()
- # self.StackUpdateThread()
-
- try:
- self.image_view.removeItem(self.image_roi_math)
- except Exception:
- pass
-
- (self.dim1, self.dim2, self.dim3) = self.displayedStack.shape
- self.image_view.setImage(self.displayedStack)
- self.image_view.ui.menuBtn.hide()
- self.image_view.ui.roiBtn.hide()
- self.image_view.setPredefinedGradient("viridis")
- self.image_view.setCurrentIndex(self.dim1 // 2)
- if len(self.energy) == 0:
- self.energy = np.arange(self.z1, self.z2) * 10
- logger.info("Arbitary X-axis used in the plot for XANES")
- self.sz = np.max(
- [int(self.dim2 * 0.1), int(self.dim3 * 0.1)]
- ) # size of the roi set to be 10% of the image area
-
- self.stack_center = self.energy[len(self.energy) // 2]
- self.stack_width = (self.energy.max() - self.energy.min()) // 10
- self.spec_roi = pg.LinearRegionItem(
- values=(self.stack_center - self.stack_width, self.stack_center + self.stack_width)
- )
-
- # a second optional ROI for calculations follow
- self.image_roi_math = pg.PolyLineROI(
- [[0, 0], [0, self.sz], [self.sz, self.sz], [self.sz, 0]],
- pos=(int(self.dim3 // 3), int(self.dim2 // 3)),
- pen="r",
- closed=True,
- removable=True,
- )
-
- self.spec_roi_math = pg.LinearRegionItem(
- values=(self.stack_center - self.stack_width - 10, self.stack_center + self.stack_width - 10),
- pen="r",
- brush=QtGui.QColor(0, 255, 200, 50),
- )
- self.spec_lo_m_idx = self.spec_hi_m_idx = 0
-
- self.setImageROI()
- self.update_spectrum()
- self.update_image_roi()
-
- if not self.isAReload:
- # image connections
- self.image_view.mousePressEvent = self.getPointSpectrum
- self.spec_roi.sigRegionChanged.connect(self.update_image_roi)
- self.spec_roi_math.sigRegionChangeFinished.connect(self.spec_roi_calc)
- self.pb_apply_spec_calc.clicked.connect(self.spec_roi_calc)
- self.rb_math_roi.clicked.connect(self.update_spectrum)
- self.pb_add_roi_2.clicked.connect(self.math_img_roi_flag)
- self.image_roi_math.sigRegionChangeFinished.connect(self.image_roi_calc)
- self.pb_apply_img_calc.clicked.connect(self.image_roi_calc)
-
- [
- rbs.clicked.connect(self.setImageROI)
- for rbs in [self.rb_poly_roi, self.rb_elli_roi, self.rb_rect_roi, self.rb_line_roi, self.rb_circle_roi]
- ]
-
- def disconnectImageActions(self):
- for btns in [self.pb_apply_spec_calc, self.rb_math_roi, self.pb_add_roi_2, self.pb_apply_img_calc]:
- try:
- btns.disconnect()
- except Exception:
- pass
-
- def select_elist(self):
- self.energyFileChooser()
- self.efileLoader()
- self.energyUnitCheck()
- self.view_stack()
-
- def efileLoader(self):
-
- if self.efilePath:
-
- if str(self.efilePath).endswith("log_tiff.txt"):
- self.energy = energy_from_logfile(logfile=str(self.efilePath))
- logger.info("Log file from pyxrf processing")
-
- else:
- self.energy = np.loadtxt(str(self.efilePath))
- self.change_color_on_load(self.pb_elist_xanes)
- logger.info("Energy file loaded")
-
- else:
- self.statusbar_main.showMessage("No Energy List Selected, Setting Arbitary Axis")
- self.energy = np.arange(self.im_stack.shape[0])
- logger.info("Arbitary Energy Axis")
-
- # assert len(self.energy) == self.dim1, "Number of Energy Points is not equal to stack length"
-
- def energyUnitCheck(self):
-
- if np.max(self.energy) < 100:
- self.cb_kev_flag.setChecked(True)
- self.energy *= 1000
-
- else:
- self.cb_kev_flag.setChecked(False)
-
- def select_ref_file(self):
- self.pb_xanes_fit.setEnabled(True)
- self.ref_names = []
- file_name = QFileDialog().getOpenFileName(self, "Open reference file", "", "text file (*.txt *.nor)")
- if file_name[0]:
- if file_name[0].endswith(".nor"):
- self.refs, self.ref_names = create_df_from_nor_try2(athenafile=str(file_name[0]))
- self.change_color_on_load(self.pb_ref_xanes)
-
- elif file_name[0].endswith(".txt"):
- self.refs = pd.read_csv(str(file_name[0]), header=None, delim_whitespace=True)
- self.change_color_on_load(self.pb_ref_xanes)
-
- else:
- logger.error("No file selected")
- pass
-
- self.plt_xanes_refs()
-
- def plt_xanes_refs(self):
-
- try:
- self.ref_plot.close()
- except Exception:
- pass
-
- self.ref_plot = plot(title="Reference Standards")
- self.ref_plot.setLabel("bottom", "Energy")
- self.ref_plot.setLabel("left", "Intensity")
- self.ref_plot.addLegend()
-
- for n in range(np.shape(self.refs)[1]):
-
- if not n == 0:
- self.ref_plot.plot(
- self.refs.values[:, 0],
- self.refs.values[:, n],
- pen=pg.mkPen(self.plt_colors[n - 1], width=self.plotWidth),
- name=self.ref_names[n],
- )
-
- def getPointSpectrum(self, event):
- if event.type() == QtCore.QEvent.MouseButtonDblClick:
- if event.button() == QtCore.Qt.LeftButton:
- self.xpixel = int(self.image_view.view.mapSceneToView(event.pos()).x()) - 1
- zlim, ylim, xlim = self.displayedStack.shape
-
- if self.xpixel > xlim:
- self.xpixel = xlim - 1
-
- self.ypixel = int(self.image_view.view.mapSceneToView(event.pos()).y()) - 1
- if self.ypixel > ylim:
- self.ypixel = ylim - 1
- self.spectrum_view.addLegend()
- self.point_spectrum = self.displayedStack[:, self.ypixel, self.xpixel]
- self.spectrum_view.plot(
- self.xdata,
- self.point_spectrum,
- clear=True,
- pen=pg.mkPen(pg.mkColor(0, 0, 255, 255), width=self.plotWidth),
- symbol="o",
- symbolSize=6,
- symbolBrush="r",
- name=f"Point Spectrum; x= {self.xpixel}, y= {self.ypixel}",
- )
-
- self.spectrum_view.addItem(self.spec_roi)
-
- self.statusbar_main.showMessage(f"{self.xpixel} and {self.ypixel}")
-
- def setImageROI(self):
-
- self.lineROI = pg.LineSegmentROI([[int(self.dim3 // 2), int(self.dim2 // 2)], [self.sz, self.sz]], pen="r")
-
- self.rectROI = pg.RectROI(
- [int(self.dim3 // 2), int(self.dim2 // 2)],
- [self.sz, self.sz],
- pen="w",
- maxBounds=QtCore.QRectF(0, 0, self.dim3, self.dim2),
- )
-
- self.rectROI.addTranslateHandle([0, 0], [2, 2])
- self.rectROI.addRotateHandle([0, 1], [2, 2])
-
- self.ellipseROI = pg.EllipseROI(
- [int(self.dim3 // 2), int(self.dim2 // 2)],
- [self.sz, self.sz],
- pen="w",
- maxBounds=QtCore.QRectF(0, 0, self.dim3, self.dim2),
- )
-
- self.circleROI = pg.CircleROI(
- [int(self.dim3 // 2), int(self.dim2 // 2)],
- [self.sz, self.sz],
- pen="w",
- maxBounds=QtCore.QRectF(0, 0, self.dim3, self.dim2),
- ) # pos and size
-
- self.polyLineROI = pg.PolyLineROI(
- [[0, 0], [0, self.sz], [self.sz, self.sz], [self.sz, 0]],
- pos=(int(self.dim3 // 2), int(self.dim2 // 2)),
- maxBounds=QtCore.QRectF(0, 0, self.dim3, self.dim2),
- closed=True,
- removable=True,
- )
-
- self.rois = {
- "rb_line_roi": self.lineROI,
- "rb_rect_roi": self.rectROI,
- "rb_circle_roi": self.circleROI,
- "rb_elli_roi": self.ellipseROI,
- "rb_poly_roi": self.polyLineROI,
- }
-
- button_name = self.sender()
-
- if button_name.objectName() in self.rois.keys():
- self.roi_preference = button_name.objectName()
-
- else:
- self.roi_preference = "rb_rect_roi" # default
-
- try:
- self.image_view.removeItem(self.image_roi)
-
- except Exception:
- pass
-
- # ROI settings for image, used polyline roi with non rectangular shape
-
- self.image_roi = self.rois[self.roi_preference]
- self.image_view.addItem(self.image_roi)
- self.image_roi.sigRegionChanged.connect(self.update_spectrum)
-
- def replot_image(self):
- self.update_stack()
- self.update_spectrum()
- self.update_image_roi()
-
- def update_spec_roi_values(self):
- self.stack_center = int(self.energy[len(self.energy) // 2])
- self.stack_width = int((self.energy.max() - self.energy.min()) * 0.05)
- self.spec_roi.setBounds([self.xdata[0], self.xdata[-1]]) # if want to set bounds for the spec roi
- self.spec_roi_math.setBounds([self.xdata[0], self.xdata[-1]])
-
- def update_spectrum(self):
-
- # set x-axis values; array taken from energy values, if clipped z box values will update the array
- self.xdata = self.energy[self.sb_zrange1.value() : self.sb_zrange2.value()]
-
- # get the cropped stack from ROI region; pyqtgraph function is used
- self.roi_img_stk = self.image_roi.getArrayRegion(
- self.displayedStack, self.image_view.imageItem, axes=(1, 2)
- )
-
- posx, posy = self.image_roi.pos()
- self.le_roi.setText(str(int(posx)) + ":" + str(int(posy)))
-
- # display the ROI features in the line edit boxes
- if self.roi_img_stk.ndim == 3:
- sizex, sizey = self.roi_img_stk.shape[1], self.roi_img_stk.shape[2]
- self.le_roi_size.setText(str(sizex) + "," + str(sizey))
- self.mean_spectra = get_mean_spectra(self.roi_img_stk)
-
- elif self.roi_img_stk.ndim == 2:
- sizex, sizey = self.roi_img_stk.shape[0], self.roi_img_stk.shape[1]
- self.le_roi_size.setText(str(sizex) + "," + str(sizey))
- self.mean_spectra = self.roi_img_stk.mean(-1)
-
- self.spectrum_view.addLegend()
-
- try:
- self.spectrum_view.plot(
- self.xdata,
- self.mean_spectra,
- pen=pg.mkPen(pg.mkColor(5, 255, 5, 255), width=self.plotWidth),
- clear=True,
- symbol="o",
- symbolSize=6,
- symbolBrush="r",
- name="ROI Spectrum",
- )
- except Exception:
- self.spectrum_view.plot(
- self.mean_spectra,
- clear=True,
- pen=pg.mkPen(pg.mkColor(5, 255, 5, 255), width=self.plotWidth),
- symbol="o",
- symbolSize=6,
- symbolBrush="r",
- name="ROI Spectrum",
- )
-
- if self.energy[-1] > 1000:
- self.e_unit = "eV"
- else:
- self.e_unit = "keV"
-
- self.spectrum_view.setLabel("bottom", "Energy", self.e_unit)
- self.spectrum_view.setLabel("left", "Intensity", "A.U.")
- self.spectrum_view.addItem(self.spec_roi)
- self.update_spec_roi_values()
- self.math_roi_flag()
-
- def update_image_roi(self):
- self.spec_lo, self.spec_hi = self.spec_roi.getRegion()
- self.spec_lo_idx = (np.abs(self.energy - self.spec_lo)).argmin()
- self.spec_hi_idx = (np.abs(self.energy - self.spec_hi)).argmin()
- self.le_spec_roi.setText(str(int(self.spec_lo)) + ":" + str(int(self.spec_hi)))
- self.le_spec_roi_size.setText(str(int(self.spec_hi - self.spec_lo)))
- self.update_spec_roi_values()
- self.stackIndexToNames()
-
- try:
- if int(self.spec_lo_idx) == int(self.spec_hi_idx):
- self.disp_img = self.displayedStack[int(self.spec_hi_idx), :, :]
-
- else:
- self.disp_img = self.displayedStack[int(self.spec_lo_idx) : int(self.spec_hi_idx), :, :].mean(0)
-
- self.image_view.setImage(self.disp_img)
- self.statusbar_main.showMessage(f"Image Display is {self.corrImg1}")
- except Exception:
- logger.warning("Indices are out of range; Image cannot be created")
- pass
-
- def set_spec_roi(self):
- self.spec_lo_, self.spec_hi_ = int(self.sb_roi_spec_s.value()), int(self.sb_roi_spec_e.value())
- self.spec_lo_idx_ = (np.abs(self.energy - self.spec_lo_)).argmin()
- self.spec_hi_idx_ = (np.abs(self.energy - self.spec_hi_)).argmin()
- self.spec_roi.setRegion((self.xdata[self.spec_lo_idx_], self.xdata[self.spec_hi_idx_]))
- self.update_image_roi()
-
- def math_roi_flag(self):
- if self.rb_math_roi.isChecked():
- self.rb_math_roi.setStyleSheet("color : green")
- self.spectrum_view.addItem(self.spec_roi_math)
- else:
- self.spectrum_view.removeItem(self.spec_roi_math)
-
- def spec_roi_calc(self):
-
- self.spec_lo_m, self.spec_hi_m = self.spec_roi_math.getRegion()
- self.spec_lo_m_idx = (np.abs(self.energy - self.spec_lo_m)).argmin()
- self.spec_hi_m_idx = (np.abs(self.energy - self.spec_hi_m)).argmin()
-
- if int(self.spec_lo_idx) == int(self.spec_hi_idx):
- self.img1 = self.displayedStack[int(self.spec_hi_idx), :, :]
-
- else:
- self.img1 = self.displayedStack[int(self.spec_lo_idx) : int(self.spec_hi_idx), :, :].mean(0)
-
- if int(self.spec_lo_m_idx) == int(self.spec_hi_m_idx):
- self.img2 = self.displayedStack[int(self.spec_hi_m_idx), :, :]
-
- else:
- self.img2 = self.displayedStack[int(self.spec_lo_m_idx) : int(self.spec_hi_m_idx), :, :].mean(0)
-
- if self.cb_roi_operation.currentText() == "Correlation Plot":
- self.correlation_plot()
-
- else:
- calc = {"Divide": np.divide, "Subtract": np.subtract, "Add": np.add}
- self.disp_img = remove_nan_inf(calc[self.cb_roi_operation.currentText()](self.img1, self.img2))
- self.image_view.setImage(self.disp_img)
-
- def math_img_roi_flag(self):
-
- button_name = self.sender().text()
- logger.info(f"{button_name}")
- if button_name == "Add ROI_2":
- self.image_view.addItem(self.image_roi_math)
- self.pb_add_roi_2.setText("Remove ROI_2")
- self.image_roi2_flag = 1
- elif button_name == "Remove ROI_2":
- self.image_view.removeItem(self.image_roi_math)
- self.pb_add_roi_2.setText("Add ROI_2")
- self.image_roi2_flag = 0
-
- else:
- pass
- logger.error("Unknown signal for second ROI")
-
- def image_roi_calc(self):
-
- if self.image_roi2_flag == 1:
- self.calc = {"Divide": np.divide, "Subtract": np.subtract, "Add": np.add}
- self.update_spec_image_roi()
- else:
- logger.error("No ROI2 found")
- return
-
- def update_spec_image_roi(self):
-
- self.math_roi_reg = self.image_roi_math.getArrayRegion(
- self.displayedStack, self.image_view.imageItem, axes=(1, 2)
- )
- if self.math_roi_reg.ndim == 3:
-
- self.math_roi_spectra = get_mean_spectra(self.math_roi_reg)
-
- elif self.roi_img_stk.ndim == 2:
- self.math_roi_spectra = self.math_roi_reg.mean(-1)
-
- if self.cb_img_roi_action.currentText() in self.calc.keys():
-
- calc_spec = self.calc[self.cb_img_roi_action.currentText()](self.mean_spectra, self.math_roi_spectra)
- self.spectrum_view.addLegend()
- self.spectrum_view.plot(
- self.xdata,
- calc_spec,
- clear=True,
- pen=pg.mkPen("m", width=2),
- name=self.cb_img_roi_action.currentText() + "ed",
- )
- self.spectrum_view.plot(self.xdata, self.math_roi_spectra, pen=pg.mkPen("y", width=2), name="ROI2")
- self.spectrum_view.plot(self.xdata, self.mean_spectra, pen=pg.mkPen("g", width=2), name="ROI1")
-
- elif self.cb_img_roi_action.currentText() == "Compare":
- self.spectrum_view.plot(
- self.xdata, self.math_roi_spectra, pen=pg.mkPen("y", width=2), clear=True, name="ROI2"
- )
- self.spectrum_view.plot(self.xdata, self.mean_spectra, pen=pg.mkPen("g", width=2), name="ROI1")
-
- self.spectrum_view.addItem(self.spec_roi)
-
- def displayStackInfo(self):
-
- try:
-
- if isinstance(self.file_name, list):
- info = f"Folder; {os.path.dirname(self.file_name[0])} \n"
- for n, name in enumerate(self.file_name):
- info += f"{n}: {os.path.basename(name)} \n"
-
- # info = f'Stack order; {[name for name in enumerate(self.file_name)]}'
- else:
- info = f"Stack; {self.file_name}"
-
- self.infoWindow = StackInfo(str(info))
- self.infoWindow.show()
-
- except AttributeError:
- self.statusbar_main.showMessage("Warning: No Image Data Loaded")
-
- def stackIndexToNames(self):
- # create list of tiff file names for virtutal stack for plot axes
- self.elemFileName = []
-
- if isinstance(self.file_name, list):
- for name in self.file_name:
- self.elemFileName.append(os.path.basename(name).split(".")[0])
-
- logger.info(f" Virtual Stack - list of image names; {self.elemFileName}")
-
- # if the roi focus on one frame, Note that this slicing excludes the last index
- if int(self.spec_lo_idx) == int(self.spec_hi_idx):
- self.corrImg1 = str(self.elemFileName[int(self.spec_lo_idx)])
- else:
- self.corrImg1 = self.elemFileName[int(self.spec_lo_idx) : int(self.spec_hi_idx)]
- if len(self.corrImg1) > 1:
- self.corrImg1 = f"Sum of {self.corrImg1} "
-
- if int(self.spec_lo_m_idx) == int(self.spec_hi_m_idx):
- self.corrImg2 = str(self.elemFileName[int(self.spec_lo_m_idx)])
-
- else:
- self.corrImg2 = self.elemFileName[int(self.spec_lo_m_idx) : int(self.spec_hi_m_idx)]
-
- if len(self.corrImg2) > 1:
- self.corrImg2 = f"Sum of {self.corrImg2}"
-
- logger.info(
- f"Correlation stack {int(self.spec_lo_idx)}:{int(self.spec_hi_idx)} with "
- f"{int(self.spec_lo_m_idx)}:{int(self.spec_hi_m_idx)}"
- )
-
- logger.info(f" Virtual Stack; corrlation plot of {self.corrImg1} vs {self.corrImg2}")
- else:
- self.corrImg1 = (
- f" Sum of {os.path.basename(self.file_name).split('.')[0]}_{int(self.spec_lo_idx)} "
- f"to {int(self.spec_hi_idx)}"
- )
- self.corrImg2 = (
- f" Sum of {os.path.basename(self.file_name).split('.')[0]}_{int(self.spec_lo_m_idx)} "
- f"to {int(self.spec_hi_m_idx)}"
- )
- # logger.info(f" corrlation plot of {self.corrImg1} vs {self.corrImg2}")
-
- def correlation_plot(self):
- self.stackIndexToNames()
-
- self.statusbar_main.showMessage(f"Correlation of {self.corrImg1} with {self.corrImg2}")
-
- if self.rb_roiRegionOnly.isChecked():
- self.roi_mask = self.image_roi.getArrayRegion(
- self.displayedStack, self.image_view.imageItem, axes=(1, 2)
- )
- self.roi_img1 = np.mean(self.roi_mask[int(self.spec_lo_idx) : int(self.spec_hi_idx)], axis=0)
- self.roi_img2 = np.mean(self.roi_mask[int(self.spec_lo_m_idx) : int(self.spec_hi_m_idx)], axis=0)
- self.scatter_window = ScatterPlot(
- self.roi_img1, self.roi_img2, (str(self.corrImg1), str(self.corrImg2))
- )
-
- else:
-
- self.scatter_window = ScatterPlot(self.img1, self.img2, (str(self.corrImg1), str(self.corrImg2)))
-
- # ph = self.geometry().height()
- # pw = self.geometry().width()
- # px = self.geometry().x()
- # py = self.geometry().y()
- # dw = self.scatter_window.width()
- # dh = self.scatter_window.height()
- # self.scatter_window.setGeometry(px+0.65*pw, py + ph - 2*dh-5, dw, dh)
- self.scatter_window.show()
-
- def plotCorrelationsAllCombinations(self):
-
- self.stackIndexToNames()
- allElemCombNum = list(combinations(np.arange(len(self.elemFileName)), 2))
-
- self.scW1 = self.scW2 = self.scW3 = self.scW4 = self.scW5 = None
- self.scW6 = self.scW7 = self.scW8 = self.scW9 = self.scW10 = None
-
- self.scWindowList = [
- self.scW1,
- self.scW2,
- self.scW3,
- self.scW4,
- self.scW5,
- self.scW6,
- self.scW7,
- self.scW8,
- self.scW9,
- self.scW10,
- ]
- self.scWindowDict = {
- 1: self.scW1,
- 2: self.scW2,
- 3: self.scW3,
- 4: self.scW4,
- 5: self.scW5,
- 6: self.scW6,
- 7: self.scW7,
- 8: self.scW8,
- 9: self.scW9,
- 10: self.scW10,
- }
-
- if len(allElemCombNum) > len(self.scWindowDict):
-
- reply = QMessageBox.warning(
- self,
- "Plot Window Limit",
- f"The number of combination exceeds "
- f"maxiumum number of "
- f"plot windows. First {len(self.scWindowDict)} "
- f"combinations will be plotted. \n Proceed?",
- QMessageBox.Yes | QMessageBox.No,
- QMessageBox.No,
- )
-
- if reply == QMessageBox.Yes:
-
- for i, pair in enumerate(allElemCombNum):
- im1 = self.displayedStack[pair[0]]
- im2 = self.displayedStack[pair[1]]
- im1Name = self.elemFileName[pair[0]]
- im2Name = self.elemFileName[pair[1]]
-
- self.scWindowDict[i] = ScatterPlot(im1, im2, (str(im1Name), str(im2Name)))
- self.scWindowDict[i].show()
-
- if reply == QMessageBox.No:
- return
-
- def getROIMask(self):
- self.roi_mask = self.image_roi.getArrayRegion(self.displayedStack, self.image_view.imageItem, axes=(1, 2))
- self.newWindow = singleStackViewer(self.roi_mask)
- self.newWindow.show()
-
- def save_stack(self, method="raw"):
-
- # self.update_stack()
- file_name = QFileDialog().getSaveFileName(
- self, "Save image data", "image_data.tiff", "image file(*tiff *tif )"
- )
- if file_name[0]:
- if method == "raw":
-
- tf.imsave(str(file_name[0]), self.displayedStack)
- logger.info(f"Updated Image Saved: {str(file_name[0])}")
- self.statusbar_main.showMessage(f"Updated Image Saved: {str(file_name[0])}")
- elif method == "sum":
- tf.imsave(str(file_name[0]), np.sum(self.displayedStack, axis=0))
-
- elif method == "mean":
- tf.imsave(str(file_name[0]), np.mean(self.displayedStack, axis=0))
-
- else:
- self.statusbar_main.showMessage("Saving cancelled")
- logger.info(f"Save failed: {str(file_name[0])}")
- pass
-
- def save_disp_img(self):
- file_name = QFileDialog().getSaveFileName(self, "Save image data", "image.tiff", "image file(*tiff *tif )")
- if file_name[0]:
- tf.imsave(str(file_name[0]), self.disp_img)
- self.statusbar_main.showMessage(f"Image Saved to {str(file_name[0])}")
- logger.info(f"Updated Image Saved: {str(file_name[0])}")
-
- else:
- logger.error("No file to save")
- self.statusbar_main.showMessage("Saving cancelled")
- pass
-
- def getLivePlotData(self):
- try:
-
- data = np.squeeze([c.getData() for c in self.spectrum_view.plotItem.curves])
- # print(np.shape(data))
- if data.ndim == 2:
- self.mu_ = data[1]
- self.e_ = data[0]
- elif data.ndim == 3:
- e_mu = data[0, :, :]
- self.mu_ = e_mu[1]
- self.e_ = e_mu[0]
-
- else:
- logger.error(f" Data shape of {data.ndim} is not supported")
- pass
- except AttributeError:
- logger.error("No data loaded")
- pass
-
- def addSpectrumToCollector(self):
- self.getLivePlotData()
- self.spectrum_view_collect.plot(self.e_, self.mu_, name="ROI Spectrum")
- self.spectrum_view_collect.setLabel("bottom", "Energy", self.e_unit)
- self.spectrum_view_collect.setLabel("left", "Intensity", "A.U.")
-
- def findEo(self):
- try:
- self.getLivePlotData()
- e0_init = self.e_[np.argmax(np.gradient(self.mu_))]
- self.dsb_norm_Eo.setValue(e0_init)
-
- except AttributeError:
- logger.error("No data loaded")
- pass
-
- def initNormVals(self):
- self.getLivePlotData()
- e0_init = self.e_[np.argmax(np.gradient(self.mu_))]
- pre1, pre2, post1, post2 = xanesNormalization(
- self.e_, self.mu_, e0=e0_init, step=None, nnorm=1, nvict=0, guess=True
- )
- self.dsb_norm_pre1.setValue(pre1)
- self.dsb_norm_pre2.setValue(pre2)
- self.dsb_norm_post1.setValue(post1)
- self.dsb_norm_post2.setValue(post2)
- self.dsb_norm_Eo.setValue(e0_init)
-
- def getNormParams(self):
- self.getLivePlotData()
- eo_ = self.dsb_norm_Eo.value()
- pre1_, pre2_ = self.dsb_norm_pre1.value(), self.dsb_norm_pre2.value()
- norm1_, norm2_ = self.dsb_norm_post1.value(), self.dsb_norm_post2.value()
- norm_order = self.sb_norm_order.value()
-
- return eo_, pre1_, pre2_, norm1_, norm2_, norm_order
-
- def exportNormParams(self):
- self.xanesNormParam = {}
- eo_, pre1_, pre2_, norm1_, norm2_, norm_order = self.getNormParams()
- self.xanesNormParam["E0"] = eo_
- self.xanesNormParam["pre1"] = pre1_
- self.xanesNormParam["pre2"] = pre2_
- self.xanesNormParam["post1"] = norm1_
- self.xanesNormParam["post2"] = norm2_
- self.xanesNormParam["norm_order"] = norm_order
-
- file_name = QtWidgets.QFileDialog().getSaveFileName(
- self, "Save XANES Norm Params", "xanes_norm_params.csv", "csv file(*csv)"
- )
-
- if file_name[0]:
-
- pd.DataFrame(self.xanesNormParam, index=[0]).to_csv(file_name[0])
-
- else:
- pass
-
- def importNormParams(self):
-
- file_name = QtWidgets.QFileDialog().getOpenFileName(
- self, "Open a XANES Norm File", "", "csv file(*csv);;all_files (*)"
- )
-
- if file_name[0]:
- xanesNormParam = pd.read_csv(file_name[0])
- self.dsb_norm_Eo.setValue(xanesNormParam["E0"])
- self.dsb_norm_pre1.setValue(xanesNormParam["pre1"])
- self.dsb_norm_pre2.setValue(xanesNormParam["pre2"])
- self.dsb_norm_post1.setValue(xanesNormParam["post1"])
- self.dsb_norm_post2.setValue(xanesNormParam["post2"])
- self.sb_norm_order.setValue(xanesNormParam["norm_order"])
-
- def nomalizeLiveSpec(self):
- eo_, pre1_, pre2_, norm1_, norm2_, norm_order = self.getNormParams()
- self.spectrum_view.clear()
-
- pre_line, post_line, normXANES = xanesNormalization(
- self.e_,
- self.mu_,
- e0=eo_,
- step=None,
- nnorm=norm_order,
- nvict=0,
- pre1=pre1_,
- pre2=pre2_,
- norm1=norm1_,
- norm2=norm2_,
- )
-
- names = np.array(("Spectrum", "Pre", "Post"))
- data_array = np.array((self.mu_, pre_line, post_line))
- colors = np.array(("c", "r", "m"))
-
- for data, clr, name in zip(data_array, colors, names):
- self.spectrum_view.plot(self.e_, data, pen=pg.mkPen(clr, width=self.plotWidth), name=name)
-
- self.spectrum_view_norm.plot(
- self.e_, normXANES, clear=True, pen=pg.mkPen(self.plt_colors[-1], width=self.plotWidth)
- )
- self.spectrum_view_norm.setLabel("bottom", "Energy", self.e_unit)
- self.spectrum_view_norm.setLabel("left", "Norm. Intensity", "A.U.")
-
- def normalizeStack(self):
- self.getLivePlotData()
- eo_, pre1_, pre2_, norm1_, norm2_, norm_order = self.getNormParams()
-
- self.im_stack = self.displayedStack = xanesNormStack(
- self.e_,
- self.displayedStack,
- e0=eo_,
- step=None,
- nnorm=norm_order,
- nvict=0,
- pre1=pre1_,
- pre2=pre2_,
- norm1=norm1_,
- norm2=norm2_,
- )
- # self.im_stack = self.displayedStack
-
- def transposeStack(self):
- self.im_stack = self.displayedStack = np.transpose(self.displayedStack, (2, 1, 0))
-
- def swapStackXY(self):
- self.im_stack = self.displayedStack = np.transpose(self.displayedStack, (0, 2, 1))
-
- def removeROIBGStack(self):
- self.displayedStack = subtractBackground(self.displayedStack, self.mean_spectra)
-
- def resetCollectorSpec(self):
- pass
-
- def saveCollectorPlot(self):
- exporter = pg.exporters.CSVExporter(self.spectrum_view_collect.plotItem)
- exporter.parameters()["columnMode"] = "(x,y,y,y) for all plots"
- file_name = QFileDialog().getSaveFileName(self, "save spectra", "", "spectra (*csv)")
- if file_name[0]:
- exporter.export(str(file_name[0]) + ".csv")
- else:
- self.statusbar_main.showMessage("Saving cancelled")
- pass
-
- def save_disp_spec(self):
-
- exporter = pg.exporters.CSVExporter(self.spectrum_view.plotItem)
- exporter.parameters()["columnMode"] = "(x,y,y,y) for all plots"
- file_name = QFileDialog().getSaveFileName(self, "save spectrum", "", "spectra (*csv)")
- if file_name[0]:
- exporter.export(str(file_name[0]) + ".csv")
- else:
- self.statusbar_main.showMessage("Saving cancelled")
- pass
-
- def saveEnergyList(self):
- file_name = QFileDialog().getSaveFileName(self, "save energy list", "energy_list.txt", "text file (*txt)")
- if file_name[0]:
- np.savetxt(file_name[0], self.xdata, fmt="%.4f")
- else:
- pass
-
- def pca_scree_(self):
- logger.info("Process started..")
- self.update_stack()
- pca_scree(self.displayedStack)
- logger.info("Process complete")
-
- def calc_comp_(self):
-
- logger.info("Process started..")
-
- # self.update_stack()
- n_components = self.sb_ncomp.value()
- method_ = self.cb_comp_method.currentText()
-
- ims, comp_spec, decon_spec, decomp_map = decompose_stack(
- self.displayedStack, decompose_method=method_, n_components_=n_components
- )
-
- self._new_window3 = ComponentViewer(ims, self.xdata, comp_spec, decon_spec, decomp_map)
- self._new_window3.show()
-
- logger.info("Process complete")
-
- def kmeans_elbow(self):
- logger.info("Process started..")
- # self.update_stack()
-
- with pg.BusyCursor():
- try:
- kmeans_variance(self.displayedStack)
- logger.info("Process complete")
- except OverflowError:
- pass
- logger.error("Overflow Error, values are too long")
-
- def kmeans_elbow_Thread(self):
- # Pass the function to execute
- worker = Worker(self.kmeans_elbow) # Any other args, kwargs are passed to the run function
- worker.signals.result.connect(self.print_output)
- worker.signals.finished.connect(self.thread_complete)
- # Execute
- self.threadpool.start(worker)
-
- def clustering_(self):
-
- logger.info("Process started..")
- # self.update_stack()
- method_ = self.cb_clust_method.currentText()
-
- decon_images, X_cluster, decon_spectra = cluster_stack(
- self.displayedStack,
- method=method_,
- n_clusters_=self.sb_ncluster.value(),
- decomposed=False,
- decompose_method=self.cb_comp_method.currentText(),
- decompose_comp=self.sb_ncomp.value(),
- )
-
- self._new_window4 = ClusterViewer(decon_images, self.xdata, X_cluster, decon_spectra)
- self._new_window4.show()
-
- logger.info("Process complete")
-
- def change_color_on_load(self, button_name):
- button_name.setStyleSheet("background-color : rgb(0,150,0);" "color: rgb(255,255,255)")
-
- def energyFileChooser(self):
- file_name = QFileDialog().getOpenFileName(self, "Open energy list", "", "text file (*.txt)")
- self.efilePath = file_name[0]
-
- def fast_xanes_fitting(self):
-
- self._new_window5 = XANESViewer(self.displayedStack, self.xdata, self.refs, self.ref_names)
- self._new_window5.show()
-
- # Thread Signals
-
- def print_output(self, s):
- print(s)
-
- def thread_complete(self):
- print("THREAD COMPLETE!")
-
- def closeEvent(self, event):
- reply = QMessageBox.question(
- self,
- "Window Close",
- "Are you sure you want to close?",
- QMessageBox.Yes | QMessageBox.No,
- QMessageBox.No,
- )
-
- if reply == QMessageBox.Yes:
- event.accept()
- QApplication.closeAllWindows()
- else:
- event.ignore()
-
-
-class WorkerSignals(QObject):
- """
- Defines the signals available from a running worker thread.
- Supported signals are:
- - finished: No data
- - error:`tuple` (exctype, value, traceback.format_exc() )
- - result: `object` data returned from processing, anything
- - progress: `tuple` indicating progress metadata
- """
-
- start = pyqtSignal()
- finished = pyqtSignal()
- error = pyqtSignal(tuple)
- result = pyqtSignal(object)
-
-
-class Worker(QRunnable):
- """
- Worker thread
- Inherits from QRunnable to handler worker thread setup, signals and wrap-up.
- """
-
- def __init__(self, fn, *args, **kwargs):
- super(Worker, self).__init__()
- # Store constructor arguments (re-used for processing)
- self.fn = fn
- self.args = args
- self.kwargs = kwargs
- self.signals = WorkerSignals()
-
- @pyqtSlot()
- def run(self):
- """
- Initialise the runner function with passed args, kwargs.
- """
- # Retrieve args/kwargs here; and fire processing using them
- self.signals.start.emit()
- try:
- result = self.fn(*self.args, **self.kwargs)
- except Exception:
- traceback.print_exc()
- exctype, value = sys.exc_info()[:2]
- self.signals.error.emit((exctype, value, traceback.format_exc()))
- else:
- self.signals.result.emit(result) # Return the result of the processing
- finally:
- self.signals.finished.emit() # Done
-
-
-class singleStackViewer(QtWidgets.QMainWindow):
- def __init__(self, img_stack, gradient="viridis"):
- super(singleStackViewer, self).__init__()
-
- # Load the UI Page
- uic.loadUi(os.path.join(ui_path, "uis/singleStackView.ui"), self)
-
- self.image_view.ui.menuBtn.hide()
- self.image_view.ui.roiBtn.hide()
-
- self.img_stack = img_stack
- self.gradient = gradient
- self.image_view.setPredefinedGradient(gradient)
-
- if self.img_stack.ndim == 3:
- self.dim1, self.dim3, self.dim2 = img_stack.shape
- elif self.img_stack.ndim == 2:
- self.dim3, self.dim2 = img_stack.shape
- self.dim1 = 1
- self.hs_img_stack.setMaximum(self.dim1 - 1)
- self.hs_img_stack.setValue(np.round(self.dim1 / 2))
- self.displayStack()
-
- # connections
- self.hs_img_stack.valueChanged.connect(self.displayStack)
- self.actionSave.triggered.connect(self.saveImageStackAsTIFF)
-
- def displayStack(self):
- im_index = self.hs_img_stack.value()
- if self.img_stack.ndim == 2:
- self.image_view.setImage(self.img_stack)
- else:
- self.image_view.setImage(self.img_stack[im_index])
- self.label_img_count.setText(f"{im_index + 1}/{self.dim1}")
-
- def saveImageStackAsTIFF(self):
- file_name = QFileDialog().getSaveFileName(self, "", "", "*.tiff;;*.tif")
- if file_name[0]:
- if self.img_stack.ndim == 3:
- tf.imsave(str(file_name[0]), np.float32(self.img_stack.transpose(0, 2, 1)))
- elif self.img_stack.ndim == 2:
- tf.imsave(str(file_name[0]), np.float32(self.img_stack.T))
- else:
- pass
-
-
-class ComponentViewer(QtWidgets.QMainWindow):
- def __init__(self, comp_stack, energy, comp_spectra, decon_spectra, decomp_map):
- super(ComponentViewer, self).__init__()
-
- # Load the UI Page
- uic.loadUi(os.path.join(ui_path, "uis/ComponentView.ui"), self)
- self.centralwidget.setStyleSheet(open(os.path.join(ui_path, "css/defaultStyle.css")).read())
-
- self.comp_stack = comp_stack
- self.energy = energy
- self.comp_spectra = comp_spectra
- self.decon_spectra = decon_spectra
- self.decomp_map = decomp_map
-
- (self.dim1, self.dim3, self.dim2) = self.comp_stack.shape
- self.hs_comp_number.setMaximum(self.dim1 - 1)
-
- self.image_view.setImage(self.comp_stack)
- self.image_view.setPredefinedGradient("viridis")
- self.image_view.ui.menuBtn.hide()
- self.image_view.ui.roiBtn.hide()
-
- self.image_view2.setImage(self.decomp_map)
- self.image_view2.setPredefinedGradient("bipolar")
- self.image_view2.ui.menuBtn.hide()
- self.image_view2.ui.roiBtn.hide()
-
- # connection
- self.update_image()
- self.pb_show_all.clicked.connect(self.show_all_spec)
- self.hs_comp_number.valueChanged.connect(self.update_image)
- self.actionSave.triggered.connect(self.save_comp_data)
- self.pb_openScatterPlot.clicked.connect(self.openScatterPlot)
- self.pb_showMultiColor.clicked.connect(self.generateMultiColorView)
-
- def update_image(self):
- im_index = self.hs_comp_number.value()
- self.spectrum_view.setLabel("bottom", "Energy")
- self.spectrum_view.setLabel("left", "Intensity", "A.U.")
- self.spectrum_view.plot(self.energy, self.decon_spectra[:, im_index], clear=True)
- self.component_view.setLabel("bottom", "Energy")
- self.component_view.setLabel("left", "Weight", "A.U.")
- self.component_view.plot(self.energy, self.comp_spectra[:, im_index], clear=True)
- self.label_comp_number.setText(f"{im_index + 1}/{self.dim1}")
- # self.image_view.setCurrentIndex(im_index-1)
- self.image_view.setImage(self.comp_stack[im_index])
-
- def openScatterPlot(self):
- self.scatter_window = ComponentScatterPlot(self.comp_stack, self.comp_spectra)
-
- # ph = self.geometry().height()
- # pw = self.geometry().width()
- # px = self.geometry().x()
- # py = self.geometry().y()
- # dw = self.scatter_window.width()
- # dh = self.scatter_window.height()
- # self.scatter_window.setGeometry(px+0.65*pw, py + ph - 2*dh-5, dw, dh)
- self.scatter_window.show()
-
- def show_all_spec(self):
- self.spectrum_view.clear()
- self.plt_colors = ["g", "b", "r", "c", "m", "y", "w"] * 10
- offsets = np.arange(0, 2, 0.2)
- self.spectrum_view.addLegend()
- for ii in range(self.decon_spectra.shape[1]):
- self.spectrum_view.plot(
- self.energy,
- (self.decon_spectra[:, ii] / self.decon_spectra[:, ii].max()) + offsets[ii],
- pen=self.plt_colors[ii],
- name="component" + str(ii + 1),
- )
-
- def save_comp_data(self):
- file_name = QFileDialog().getSaveFileName(self, "", "", "data(*tiff *tif *txt *png )")
- if file_name[0]:
- tf.imsave(
- str(file_name[0]) + "_components.tiff", np.float32(self.comp_stack.transpose(0, 2, 1)), imagej=True
- )
- tf.imsave(str(file_name[0]) + "_component_masks.tiff", np.float32(self.decomp_map.T), imagej=True)
- np.savetxt(str(file_name[0]) + "_deconv_spec.txt", self.decon_spectra)
- np.savetxt(str(file_name[0]) + "_component_spec.txt", self.comp_spectra)
- else:
- pass
-
- def generateMultiColorView(self):
- self.multichanneldict = {}
-
- for n, (colorName, image) in enumerate(zip(cmap_dict.keys(), self.comp_stack.transpose(0, 1, 2))):
- low, high = np.min(image), np.max(image)
- self.multichanneldict[f"Image {n + 1}"] = {
- "ImageName": f"Image {n + 1}",
- "ImageDir": ".",
- "Image": image,
- "Color": colorName,
- "CmapLimits": (low, high),
- "Opacity": 1.0,
- }
- self.muli_color_window = MultiChannelWindow(image_dict=self.multichanneldict)
- self.muli_color_window.show()
-
- # add energy column
-
-
-class ClusterViewer(QtWidgets.QMainWindow):
- def __init__(self, decon_images, energy, X_cluster, decon_spectra):
- super(ClusterViewer, self).__init__()
-
- # Load the UI Page
- uic.loadUi(os.path.join(ui_path, "uis/ClusterView.ui"), self)
- self.centralwidget.setStyleSheet(open(os.path.join(ui_path, "css/defaultStyle.css")).read())
-
- self.decon_images = decon_images
- self.energy = energy
- self.X_cluster = X_cluster
- self.decon_spectra = decon_spectra
- (self.dim1, self.dim3, self.dim2) = self.decon_images.shape
- self.hsb_cluster_number.setMaximum(self.dim1 - 1)
- self.X_cluster = X_cluster
-
- self.image_view.setImage(self.decon_images, autoHistogramRange=True, autoLevels=True)
- self.image_view.setPredefinedGradient("viridis")
- self.image_view.ui.menuBtn.hide()
- self.image_view.ui.roiBtn.hide()
-
- self.cluster_view.setImage(self.X_cluster, autoHistogramRange=True, autoLevels=True)
- self.cluster_view.setPredefinedGradient("bipolar")
- self.cluster_view.ui.histogram.hide()
- self.cluster_view.ui.menuBtn.hide()
- self.cluster_view.ui.roiBtn.hide()
-
- # connection
- self.update_display()
- self.hsb_cluster_number.valueChanged.connect(self.update_display)
- self.actionSave.triggered.connect(self.save_clust_data)
- self.pb_show_all_spec.clicked.connect(self.showAllSpec)
- self.pb_showMultiColor.clicked.connect(self.generateMultiColorView)
-
- def update_display(self):
- im_index = self.hsb_cluster_number.value()
- self.component_view.setLabel("bottom", "Energy")
- self.component_view.setLabel("left", "Intensity", "A.U.")
- self.component_view.plot(self.energy, self.decon_spectra[:, im_index], clear=True)
- # self.image_view.setCurrentIndex(im_index-1)
- self.image_view.setImage(self.decon_images[im_index])
- self.label_comp_number.setText(f"{im_index + 1}/{self.dim1}")
-
- def save_clust_data(self):
- file_name = QFileDialog().getSaveFileName(self, "", "", "data(*tiff *tif *txt *png )")
- if file_name[0]:
-
- tf.imsave(
- str(file_name[0]) + "_cluster.tiff", np.float32(self.decon_images.transpose(0, 2, 1)), imagej=True
- )
- tf.imsave(str(file_name[0]) + "_cluster_map.tiff", np.float32(self.X_cluster.T), imagej=True)
- np.savetxt(str(file_name[0]) + "_deconv_spec.txt", self.decon_spectra)
-
- else:
- logger.error("Saving Cancelled")
- self.statusbar.showMessage("Saving Cancelled")
- pass
-
- def showAllSpec(self):
- self.component_view.clear()
- self.plt_colors = ["g", "b", "r", "c", "m", "y", "w"] * 10
- offsets = np.arange(0, 2, 0.2)
- self.component_view.addLegend()
- for ii in range(self.decon_spectra.shape[1]):
- self.component_view.plot(
- self.energy,
- (self.decon_spectra[:, ii] / self.decon_spectra[:, ii].max()) + offsets[ii],
- pen=self.plt_colors[ii],
- name="cluster" + str(ii + 1),
- )
-
- def generateMultiColorView(self):
- self.multichanneldict = {}
-
- for n, (colorName, image) in enumerate(zip(cmap_dict.keys(), self.decon_images.transpose(0, 1, 2))):
- low, high = np.min(image), np.max(image)
- self.multichanneldict[f"Image {n + 1}"] = {
- "ImageName": f"Image {n + 1}",
- "ImageDir": ".",
- "Image": image,
- "Color": colorName,
- "CmapLimits": (low, high),
- "Opacity": 1.0,
- }
- self.muli_color_window = MultiChannelWindow(image_dict=self.multichanneldict)
- self.muli_color_window.show()
-
-
-class XANESViewer(QtWidgets.QMainWindow):
- def __init__(self, im_stack=None, e_list=None, refs=None, ref_names=None):
- super(XANESViewer, self).__init__()
-
- uic.loadUi(os.path.join(ui_path, "uis/XANESViewer.ui"), self)
- self.centralwidget.setStyleSheet(open(os.path.join(ui_path, "css/defaultStyle.css")).read())
-
- self.im_stack = im_stack
- self.e_list = e_list
- self.refs = refs
- self.ref_names = ref_names
- self.selected = self.ref_names
- self.fitResultDict = {}
- self.fit_method = self.cb_xanes_fit_model.currentText()
- self.alphaForLM = self.dsb_alphaForLM.value()
-
- self.decon_ims, self.rfactor, self.coeffs_arr = xanes_fitting(
- self.im_stack, self.e_list, self.refs, method=self.fit_method, alphaForLM=self.alphaForLM
- )
-
- (self.dim1, self.dim2, self.dim3) = self.im_stack.shape
- self.cn = int(self.dim2 // 2)
- self.sz = np.max([int(self.dim2 * 0.15), int(self.dim3 * 0.15)])
- self.image_roi = pg.RectROI(
- [int(self.dim3 // 2), int(self.dim2 // 2)],
- [self.sz, self.sz],
- pen="w",
- maxBounds=QtCore.QRectF(0, 0, self.dim3, self.dim2),
- )
-
- self.image_roi.addTranslateHandle([0, 0], [2, 2])
- self.image_roi.addRotateHandle([0, 1], [2, 2])
-
- # self.image_roi = pg.PolyLineROI([[0, 0], [0, self.sz], [self.sz, self.sz], [self.sz, 0]],
- # pos=(int(self.dim2 // 2), int(self.dim3 // 2)),
- # maxBounds=QtCore.QRect(0, 0, self.dim3, self.dim2), closed=True)
- # self.image_roi.addTranslateHandle([self.sz // 2, self.sz // 2], [2, 2])
-
- self.stack_center = int(self.dim1 // 2)
- self.stack_width = int(self.dim1 * 0.05)
- # self.image_view.setCurrentIndex(self.stack_center)
-
- self.image_view.addItem(self.image_roi)
- self.xdata = self.e_list + self.sb_e_shift.value()
-
- self.scrollBar_setup()
- self.display_image_data()
- self.display_references()
- self.update_spectrum()
-
- # connections
- self.sb_e_shift.valueChanged.connect(self.update_spectrum)
- self.pb_re_fit.clicked.connect(self.re_fit_xanes)
- self.pb_edit_refs.clicked.connect(self.choose_refs)
- self.image_roi.sigRegionChanged.connect(self.update_spectrum)
- self.hsb_xanes_stk.valueChanged.connect(self.display_image_data)
- self.hsb_chem_map.valueChanged.connect(self.display_image_data)
- self.pb_showMultiColor.clicked.connect(self.generateMultiColorView)
- self.pb_showCompSpec.clicked.connect(self.showComponentXANES)
-
- # menu
- self.actionSave_Chem_Map.triggered.connect(self.save_chem_map)
- self.actionSave_R_factor_Image.triggered.connect(self.save_rfactor_img)
- self.actionSave_Live_Fit_Data.triggered.connect(self.pg_export_spec_fit)
- self.actionExport_Fit_Stats.triggered.connect(self.exportFitResults)
- self.actionExport_Ref_Plot.triggered.connect(self.pg_export_references)
-
- def scrollBar_setup(self):
- self.hsb_xanes_stk.setValue(self.stack_center)
- self.hsb_xanes_stk.setMaximum(self.dim1 - 1)
- self.hsb_chem_map.setValue(0)
- self.hsb_chem_map.setMaximum(self.decon_ims.shape[-1] - 1)
-
- def display_image_data(self):
-
- self.image_view.setImage(self.im_stack[self.hsb_xanes_stk.value()])
- self.image_view.ui.menuBtn.hide()
- self.image_view.ui.roiBtn.hide()
- self.image_view.setPredefinedGradient("viridis")
-
- self.image_view_maps.setImage(self.decon_ims.transpose(2, 0, 1)[self.hsb_chem_map.value()])
- self.image_view_maps.setPredefinedGradient("bipolar")
- self.image_view_maps.ui.menuBtn.hide()
- self.image_view_maps.ui.roiBtn.hide()
-
- def display_references(self):
-
- self.inter_ref = interploate_E(self.refs, self.xdata)
- self.plt_colors = ["c", "m", "y", "w"] * 10
- self.spectrum_view_refs.addLegend()
- for ii in range(self.inter_ref.shape[0]):
- if len(self.selected) != 0:
- self.spectrum_view_refs.plot(
- self.xdata,
- self.inter_ref[ii],
- pen=pg.mkPen(self.plt_colors[ii], width=2),
- name=self.selected[1:][ii],
- )
- else:
- self.spectrum_view_refs.plot(
- self.xdata,
- self.inter_ref[ii],
- pen=pg.mkPen(self.plt_colors[ii], width=2),
- name="ref" + str(ii + 1),
- )
-
- def choose_refs(self):
- "Interactively exclude some standards from the reference file"
- self.ref_edit_window = RefChooser(
- self.ref_names,
- self.im_stack,
- self.e_list,
- self.refs,
- self.sb_e_shift.value(),
- self.cb_xanes_fit_model.currentText(),
- )
- self.ref_edit_window.show()
- # self.rf_plot = pg.plot(title="RFactor Tracker")
-
- # connections
- self.ref_edit_window.choosenRefsSignal.connect(self.update_refs)
- self.ref_edit_window.fitResultsSignal.connect(self.plotFitResults)
-
- def update_refs(self, list_):
- self.selected = list_ # list_ is the signal from ref chooser
- self.update_spectrum()
- self.re_fit_xanes()
-
- def update_spectrum(self):
-
- self.roi_img = self.image_roi.getArrayRegion(self.im_stack, self.image_view.imageItem, axes=(1, 2))
- sizex, sizey = self.roi_img.shape[1], self.roi_img.shape[2]
- posx, posy = self.image_roi.pos()
- self.roi_info.setText(f"ROI_Pos: {int(posx)},{int(posy)} ROI_Size: {sizex},{sizey}")
-
- self.xdata1 = self.e_list + self.sb_e_shift.value()
- self.ydata1 = get_sum_spectra(self.roi_img)
- self.fit_method = self.cb_xanes_fit_model.currentText()
-
- if len(self.selected) != 0:
-
- self.inter_ref = interploate_E(self.refs[self.selected], self.xdata1)
- stats, coeffs = xanes_fitting_1D(
- self.ydata1,
- self.xdata1,
- self.refs[self.selected],
- method=self.fit_method,
- alphaForLM=self.alphaForLM,
- )
-
- else:
- self.inter_ref = interploate_E(self.refs, self.xdata1)
- stats, coeffs = xanes_fitting_1D(
- self.ydata1, self.xdata1, self.refs, method=self.fit_method, alphaForLM=self.alphaForLM
- )
-
- self.fit_ = np.dot(coeffs, self.inter_ref)
- pen = pg.mkPen("g", width=1.5)
- pen2 = pg.mkPen("r", width=1.5)
- # pen3 = pg.mkPen("y", width=1.5)
- self.spectrum_view.addLegend()
- self.spectrum_view.setLabel("bottom", "Energy")
- self.spectrum_view.setLabel("left", "Intensity", "A.U.")
- self.spectrum_view.plot(self.xdata1, self.ydata1, pen=pen, name="Data", clear=True)
- self.spectrum_view.plot(self.xdata1, self.fit_, name="Fit", pen=pen2)
-
- for n, (coff, ref, plt_clr) in enumerate(zip(coeffs, self.inter_ref, self.plt_colors)):
-
- if len(self.selected) != 0:
-
- self.spectrum_view.plot(self.xdata1, np.dot(coff, ref), name=self.selected[1:][n], pen=plt_clr)
- else:
- self.spectrum_view.plot(self.xdata1, np.dot(coff, ref), name="ref" + str(n + 1), pen=plt_clr)
- # set the rfactor value to the line edit slot
- self.results = (
- f"Coefficients: {coeffs} \n"
- f"R-Factor: {stats['R_Factor']}, R-Square: {stats['R_Square']},\n "
- f"Chi-Square: {stats['Chi_Square']}, "
- f"Reduced Chi-Square: {stats['Reduced Chi_Square']}"
- )
-
- self.fit_results.setText(self.results)
-
- def re_fit_xanes(self):
- if len(self.selected) != 0:
- self.decon_ims, self.rfactor, self.coeffs_arr = xanes_fitting(
- self.im_stack,
- self.e_list + self.sb_e_shift.value(),
- self.refs[self.selected],
- method=self.cb_xanes_fit_model.currentText(),
- alphaForLM=self.alphaForLM,
- )
- else:
- # if non athena file with no header is loaded no ref file cannot be edited
- self.decon_ims, self.rfactor, self.coeffs_arr = xanes_fitting(
- self.im_stack,
- self.e_list + self.sb_e_shift.value(),
- self.refs,
- method=self.cb_xanes_fit_model.currentText(),
- alphaForLM=self.alphaForLM,
- )
-
- # rfactor is a list of all spectra so take the mean
- self.rfactor_mean = np.mean(self.rfactor)
- self.image_view_maps.setImage(self.decon_ims.transpose(2, 0, 1))
- self.scrollBar_setup()
-
- def plotFitResults(self, decon_ims, rfactor_mean, coeff_array):
- # upadte the chem maps and scrollbar params
- self.image_view_maps.setImage(decon_ims.transpose(2, 0, 1))
- # self.hsb_chem_map.setValue(0)
- # self.hsb_chem_map.setMaximum(decon_ims.shape[-1]-1)
-
- # set the rfactor value to the line edit slot
- self.le_r_sq.setText(f"{rfactor_mean :.4f}")
-
- def showComponentXANES(self):
- compNum = self.hsb_chem_map.value()
- currentComp = self.decon_ims.transpose(2, 0, 1)[compNum]
- currentCompMask = currentComp > 0
- yData = applyMaskGetMeanSpectrum(self.im_stack, currentCompMask)
- xanes_comp_plot = pg.plot(
- self.e_list + self.sb_e_shift.value(),
- yData,
- title=f"Component_{compNum}",
- pen=pg.mkPen("y", width=2, style=QtCore.Qt.DotLine),
- symbol="o",
- )
- xanes_comp_plot.setLabel("bottom", "Energy (keV)")
- xanes_comp_plot.setLabel("left", "Intensity")
-
- def generateMultiColorView(self):
- self.multichanneldict = {}
-
- for n, (colorName, image) in enumerate(zip(cmap_dict.keys(), self.decon_ims.transpose((2, 0, 1)))):
- low, high = np.min(image), np.max(image)
- self.multichanneldict[f"Image {n + 1}"] = {
- "ImageName": f"Image {n + 1}",
- "ImageDir": ".",
- "Image": image,
- "Color": colorName,
- "CmapLimits": (low, high),
- "Opacity": 1.0,
- }
- self.muli_color_window = MultiChannelWindow(image_dict=self.multichanneldict)
- self.muli_color_window.show()
-
- def save_chem_map(self):
- file_name = QFileDialog().getSaveFileName(self, "save image", "chemical_map.tiff", "image data (*tiff)")
- if file_name[0]:
- tf.imsave(str(file_name[0]), np.float32(self.decon_ims.transpose(2, 0, 1)), imagej=True)
- else:
- logger.error("No file to save")
- pass
-
- def save_rfactor_img(self):
- file_name = QFileDialog().getSaveFileName(self, "save image", "r-factor_map.tiff", "image data (*tiff)")
- if file_name[0]:
- tf.imsave(str(file_name[0]), np.float32(self.rfactor), imagej=True)
- else:
- logger.error("No file to save")
- pass
-
- def save_spec_fit(self):
- try:
- to_save = np.column_stack([self.xdata1, self.ydata1, self.fit_])
- file_name = QFileDialog().getSaveFileName(self, "save spectrum", "", "spectrum and fit (*txt)")
- if file_name[0]:
- np.savetxt(str(file_name[0]) + ".txt", to_save)
- else:
- pass
- except Exception:
- logger.error("No file to save")
- pass
-
- def pg_export_spec_fit(self):
-
- exporter = pg.exporters.CSVExporter(self.spectrum_view.plotItem)
- exporter.parameters()["columnMode"] = "(x,y,y,y) for all plots"
- file_name = QFileDialog().getSaveFileName(self, "save spectrum", "", "spectrum and fit (*csv)")
- if file_name[0]:
- exporter.export(str(file_name[0]) + ".csv")
- else:
- pass
-
- def pg_export_references(self):
-
- exporter = pg.exporters.CSVExporter(self.spectrum_view_refs.plotItem)
- exporter.parameters()["columnMode"] = "(x,y,y,y) for all plots"
- file_name = QFileDialog().getSaveFileName(
- self, "save references", "xanes_references.csv", "column data (*csv)"
- )
- if file_name[0]:
- exporter.export(str(file_name[0]))
- else:
- pass
-
- def exportFitResults(self):
- file_name = QFileDialog().getSaveFileName(self, "save txt", "xanes_1D_fit_results.txt", "txt data (*txt)")
- if file_name[0]:
- with open(file_name[0], "w") as file:
- file.write(self.results)
- else:
- pass
-
-
-class RefChooser(QtWidgets.QMainWindow):
- choosenRefsSignal: pyqtSignal = QtCore.pyqtSignal(list)
- fitResultsSignal: pyqtSignal = QtCore.pyqtSignal(np.ndarray, float, np.ndarray)
-
- def __init__(self, ref_names, im_stack, e_list, refs, e_shift, fit_model):
- super(RefChooser, self).__init__()
- uic.loadUi(os.path.join(ui_path, "uis/RefChooser.ui"), self)
- self.centralwidget.setStyleSheet(open(os.path.join(ui_path, "css/defaultStyle.css")).read())
- self.ref_names = ref_names
- self.refs = refs
- self.im_stack = im_stack
- self.e_list = e_list
- self.e_shift = e_shift
- self.fit_model = fit_model
-
- self.all_boxes = []
- self.rFactorList = []
-
- self.displayCombinations()
-
- # selection become more apparent than default with red-ish color
- self.tableWidget.setStyleSheet("background-color: white; selection-background-color: rgb(200,0,0);")
-
- # add a line to the plot to walk through the table. Note that the table is not sorted
- self.selectionLine = pg.InfiniteLine(
- pos=1, angle=90, pen=pg.mkPen("m", width=2.5), movable=True, bounds=None, label="Move Me!"
- )
- self.stat_view.setLabel("bottom", "Fit ID")
- self.stat_view.setLabel("left", "Reduced Chi^2")
-
- for n, i in enumerate(self.ref_names):
- self.cb_i = QtWidgets.QCheckBox(self.ref_box_frame)
- if n == 0:
- self.cb_i.setChecked(True)
- self.cb_i.setEnabled(False)
- self.cb_i.setObjectName(i)
- self.cb_i.setText(i)
- self.gridLayout_2.addWidget(self.cb_i, n, 0, 1, 1)
- self.cb_i.toggled.connect(self.enableApply)
- self.all_boxes.append(self.cb_i)
-
- # connections
- self.pb_apply.clicked.connect(self.clickedWhichAre)
- self.pb_combo.clicked.connect(self.tryAllCombo)
- self.actionExport_Results_csv.triggered.connect(self.exportFitResults)
- self.selectionLine.sigPositionChanged.connect(self.updateFitWithLine)
- self.tableWidget.itemSelectionChanged.connect(self.updateWithTableSelection)
- # self.stat_view.scene().sigMouseClicked.connect(self.moveSelectionLine)
- self.stat_view.mouseDoubleClickEvent = self.moveSelectionLine
- self.sb_max_combo.valueChanged.connect(self.displayCombinations)
- # self.pb_sort_with_r.clicked.connect(lambda: self.tableWidget.sortItems(3, QtCore.Qt.AscendingOrder))
- self.pb_sort_with_r.clicked.connect(self.sortTable)
- self.cb_sorter.currentTextChanged.connect(self.sortTable)
-
- # def clickedWhich(self):
- # button_name = self.sender()
-
- def populateChecked(self):
- self.onlyCheckedBoxes = []
- for names in self.all_boxes:
- if names.isChecked():
- self.onlyCheckedBoxes.append(names.objectName())
-
- QtCore.pyqtSlot()
-
- def clickedWhichAre(self):
- self.populateChecked()
- self.choosenRefsSignal.emit(self.onlyCheckedBoxes)
-
- def generateRefList(self, ref_list, maxCombo, minCombo=1):
-
- """
- Creates a list of reference combinations for xanes fitting
-
- Paramaters;
-
- ref_list (list): list of ref names from the header
- maxCombo (int): maximum number of ref lists in combination
- minCombo (int): min number of ref lists in combination
-
- returns;
-
- 1. int: length of total number of combinations
- 2. list: all the combinations
-
- """
-
- if not maxCombo > len(ref_list):
-
- iter_list = []
- while minCombo < maxCombo + 1:
- iter_list += list(combinations(ref_list, minCombo))
- minCombo += 1
- return len(iter_list), iter_list
-
- else:
- raise ValueError(" Maximum numbinations cannot be larger than number of list items")
-
- def displayCombinations(self):
- niter, self.iter_list = self.generateRefList(self.ref_names[1:], self.sb_max_combo.value())
- self.label_nComb.setText(str(niter) + " Combinations")
-
- @QtCore.pyqtSlot()
- def tryAllCombo(self):
- # empty list to to keep track and plot of reduced chi2 of all the fits
- self.rfactor_list = []
-
- # create dataframe for the table
- self.df = pd.DataFrame(
- columns=["Fit Number", "References", "Coefficients", "R-Factor", "R^2", "chi^2", "red-chi^2", "Score"]
- )
-
- # df columns is the header for the table widget
- self.tableWidget.setHorizontalHeaderLabels(self.df.columns)
- # self.iter_list = list(combinations(self.ref_names[1:],self.sb_max_combo.value()))
-
- niter, self.iter_list = self.generateRefList(self.ref_names[1:], self.sb_max_combo.value())
- tot_combo = len(self.iter_list)
- for n, refs in enumerate(self.iter_list):
- self.statusbar.showMessage(f"{n + 1}/{tot_combo}")
- selectedRefs = list((str(self.ref_names[0]),) + refs)
- self.fit_combo_progress.setValue((n + 1) * 100 / tot_combo)
- self.stat, self.coeffs_arr = xanes_fitting_Binned(
- self.im_stack, self.e_list + self.e_shift, self.refs[selectedRefs], method=self.fit_model
- )
-
- self.rfactor_list.append(self.stat["Reduced Chi_Square"])
- self.stat_view.plot(
- x=np.arange(n + 1),
- y=self.rfactor_list,
- clear=True,
- title="Reduced Chi^2",
- pen=pg.mkPen("y", width=2, style=QtCore.Qt.DotLine),
- symbol="o",
- )
-
- # arbitary number to rank the best fit
- fit_score = (self.stat["R_Square"] + np.sum(self.coeffs_arr)) / (
- self.stat["R_Factor"] + self.stat["Reduced Chi_Square"]
- )
-
- resultsDict = {
- "Fit Number": n,
- "References": str(selectedRefs[1:]),
- "Coefficients": str(np.around(self.coeffs_arr, 4)),
- "Sum of Coefficients": str(np.around(np.sum(self.coeffs_arr), 4)),
- "R-Factor": self.stat["R_Factor"],
- "R^2": self.stat["R_Square"],
- "chi^2": self.stat["Chi_Square"],
- "red-chi^2": self.stat["Reduced Chi_Square"],
- "Score": np.around(fit_score, 4),
- }
-
- self.df = pd.concat([self.df, pd.DataFrame([resultsDict])], ignore_index=True)
-
- self.dataFrametoQTable(self.df)
- QtTest.QTest.qWait(0.1) # hepls with real time plotting
-
- self.stat_view.addItem(self.selectionLine)
-
- def dataFrametoQTable(self, df_: pd.DataFrame):
- nRows = len(df_.index)
- nColumns = len(df_.columns)
- self.tableWidget.setRowCount(nRows)
- self.tableWidget.setColumnCount(nColumns)
- self.tableWidget.setHorizontalHeaderLabels(df_.columns)
-
- for i in range(nRows):
- for j in range(nColumns):
- cell = QtWidgets.QTableWidgetItem(str(df_.values[i][j]))
- self.tableWidget.setItem(i, j, cell)
-
- # set the property of the table view. Size policy to make the contents justified
- self.tableWidget.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.AdjustToContents)
- self.tableWidget.resizeColumnsToContents()
-
- def exportFitResults(self):
- file_name = QFileDialog().getSaveFileName(self, "save csv", "xanes_fit_results_log.csv", "txt data (*csv)")
- if file_name[0]:
- with open(str(file_name[0]), "w") as fp:
- self.df.to_csv(fp)
- else:
- pass
-
- def selectTableAndCheckBox(self, x):
- nSelection = int(round(x))
- self.tableWidget.selectRow(nSelection)
- fit_num = int(self.tableWidget.item(nSelection, 0).text())
- refs_selected = self.iter_list[fit_num]
-
- # reset all the checkboxes to uncheck state, except the energy
- for checkstate in self.findChildren(QtWidgets.QCheckBox):
- if checkstate.isEnabled():
- checkstate.setChecked(False)
-
- for cb_names in refs_selected:
- checkbox = self.findChild(QtWidgets.QCheckBox, name=cb_names)
- checkbox.setChecked(True)
-
- def updateFitWithLine(self):
- pos_x, pos_y = self.selectionLine.pos()
- x = self.df.index[self.df[str("Fit Number")] == np.round(pos_x)][0]
- self.selectTableAndCheckBox(x)
-
- def updateWithTableSelection(self):
- x = self.tableWidget.currentRow()
- self.selectTableAndCheckBox(x)
-
- def moveSelectionLine(self, event):
- if event.button() == QtCore.Qt.LeftButton:
- Pos = self.stat_view.plotItem.vb.mapSceneToView(event.pos())
- self.selectionLine.setPos(Pos.x())
-
- def sortTable(self):
- sorter_dict = {
- "R-Factor": "R-Factor",
- "R-Square": "R^2",
- "Chi-Square": "chi^2",
- "Reduced Chi-Square": "red-chi^2",
- "Fit Number": "Fit Number",
- }
- sorter = sorter_dict[self.cb_sorter.currentText()]
- self.df = self.df.sort_values(sorter, ignore_index=True)
- self.dataFrametoQTable(self.df)
-
- def enableApply(self):
-
- """ """
- self.populateChecked()
- if len(self.onlyCheckedBoxes) > 1:
- self.pb_apply.setEnabled(True)
- else:
- self.pb_apply.setEnabled(False)
-
-
-class ScatterPlot(QtWidgets.QMainWindow):
- def __init__(self, img1, img2, nameTuple):
- super(ScatterPlot, self).__init__()
-
- uic.loadUi(os.path.join(ui_path, "uis/ScatterView.ui"), self)
- self.centralwidget.setStyleSheet(open(os.path.join(ui_path, "css/defaultStyle.css")).read())
- self.clearPgPlot()
- self.w1 = self.scatterViewer.addPlot()
- self.img1 = img1
- self.img2 = img2
- self.nameTuple = nameTuple
- x, y = np.shape(self.img1)
- self.s1 = pg.ScatterPlotItem(size=2, pen=pg.mkPen(None), brush=pg.mkBrush(255, 255, 0, 255))
- # print(self.s1)
-
- # create three polyline ROIs for masking
- Xsize = self.img1.max() / 6
- Ysize = self.img2.max() / 6
-
- self.scatter_mask = pg.PolyLineROI(
- [[0, 0], [0, Ysize], [Xsize / 2, Ysize * 1.5], [Xsize, Ysize], [Xsize, 0]],
- pos=None,
- pen=pg.mkPen("r", width=2),
- hoverPen=pg.mkPen("w", width=2),
- closed=True,
- removable=True,
- )
-
- self.scatter_mask2 = pg.PolyLineROI(
- [
- [Xsize * 1.2, 0],
- [Xsize * 1.2, Ysize * 2],
- [Xsize * 2, Ysize * 2],
- [Xsize * 3, Ysize],
- [Xsize * 2, 0],
- ],
- pos=None,
- pen=pg.mkPen("g", width=2),
- hoverPen=pg.mkPen("w", width=2),
- closed=True,
- removable=True,
- )
- self.scatter_mask3 = pg.PolyLineROI(
- [
- [Xsize * 2.5, 0],
- [Xsize * 2.5, Ysize],
- [Xsize * 4, Ysize],
- [Xsize * 4, 0],
- [Xsize * 3.7, Ysize * -0.5],
- ],
- pos=None,
- pen=pg.mkPen("c", width=2),
- hoverPen=pg.mkPen("w", width=2),
- closed=True,
- removable=True,
- )
-
- self.fitScatter = self.fitScatter2 = self.fitScatter3 = None
-
- self.rois = {
- "ROI 1": (self.scatter_mask, self.rb_roi1.isChecked(), self.fitScatter),
- "ROI 2": (self.scatter_mask2, self.rb_roi2.isChecked(), self.fitScatter2),
- "ROI 3": (self.scatter_mask3, self.rb_roi3.isChecked(), self.fitScatter3),
- }
-
- self.windowNames = {"ROI 1": self.fitScatter, "ROI 2": self.fitScatter2, "ROI 3": self.fitScatter3}
-
- self.s1.setData(self.img1.flatten(), self.img2.flatten())
- self.w1.setLabel("bottom", self.nameTuple[0], "counts")
- self.label_img1.setText(self.nameTuple[0])
- self.w1.setLabel("left", self.nameTuple[1], "counts")
- self.label_img2.setText(self.nameTuple[1])
- self.w1.addItem(self.s1)
-
- self.image_view.setImage(self.img1)
- self.image_view.ui.menuBtn.hide()
- self.image_view.ui.roiBtn.hide()
- self.image_view.setPredefinedGradient("thermal")
-
- self.image_view2.setImage(self.img2)
- self.image_view2.ui.menuBtn.hide()
- self.image_view2.ui.roiBtn.hide()
- self.image_view2.setPredefinedGradient("thermal")
-
- # connections
- self.actionSave_Plot.triggered.connect(self.pg_export_correlation)
- self.actionSave_Images.triggered.connect(self.tiff_export_images)
- # self.pb_define_mask.clicked.connect(lambda:self.createMask(self.scatter_mask))
- self.pb_define_mask.clicked.connect(self.addMultipleROIs)
- # self.pb_apply_mask.clicked.connect(lambda:self.getMaskRegion(self.scatter_mask))
- self.pb_apply_mask.clicked.connect(self.applyMultipleROIs)
- self.pb_clear_mask.clicked.connect(self.clearMultipleROIs)
- self.pb_compositeScatter.clicked.connect(self.createCompositeScatter)
- [rbs.clicked.connect(self.updateROIDict) for rbs in [self.rb_roi1, self.rb_roi2, self.rb_roi3]]
-
- def pg_export_correlation(self):
-
- exporter = pg.exporters.CSVExporter(self.w1)
- exporter.parameters()["columnMode"] = "(x,y,y,y) for all plots"
- file_name = QFileDialog().getSaveFileName(self, "save correlation", "", "spectrum and fit (*csv)")
- if file_name[0]:
- exporter.export(str(file_name[0]) + ".csv")
- self.statusbar.showMessage(f"Data saved to {str(file_name[0])}")
- else:
- pass
-
- def tiff_export_images(self):
- file_name = QFileDialog().getSaveFileName(self, "save images", "", "spectrum and fit (*tiff)")
- if file_name[0]:
- tf.imsave(str(file_name[0]) + ".tiff", np.dstack([self.img1, self.img2]).T)
- self.statusbar.showMessage(f"Images saved to {str(file_name[0])}")
- else:
- pass
-
- def createMask(self, ROIName):
-
- try:
- self.w1.removeItem(ROIName)
- except Exception:
- pass
- self.w1.addItem(ROIName)
-
- def clearMask(self, ROIName):
- self.w1.removeItem(ROIName)
-
- def clearPgPlot(self):
- try:
- self.masked_img.close()
- except Exception:
- pass
-
- def getMaskRegion(self, ROIName, generateSeperateWindows=True):
-
- """filter scatterplot points using polylineROI region"""
-
- # Ref : https://stackoverflow.com/questions/57719303/how-to-map-mouse-position-on-a-scatterplot
-
- # get the roi region:QPaintPathObject
- roiShape = self.rois[ROIName][0].mapToItem(self.s1, self.rois[ROIName][0].shape())
-
- # get data in the scatter plot
- scatterData = np.array(self.s1.getData())
-
- # generate a binary mask for points inside or outside the roishape
- selected = [roiShape.contains(QtCore.QPointF(pt[0], pt[1])) for pt in scatterData.T]
-
- # reshape the mask to image dimensions
- self.mask2D = np.reshape(selected, (self.img1.shape))
-
- # get masked image1
- self.maskedImage = self.mask2D * self.img1
-
- # get rid of the (0,0) values in the masked array
- self.xData, self.yData = np.compress(selected, scatterData[0]), np.compress(selected, scatterData[1])
-
- # linear regeression of the filtered X,Y data
- result = linregress(self.xData, self.yData)
-
- # Pearson's correlation of the filtered X,Y data
- pr, pp = stats.pearsonr(self.xData, self.yData)
-
- # apply the solved equation to xData to generate the fit line
- self.yyData = result.intercept + result.slope * self.xData
-
- # Prepare strings for fit results and stats
- self.fitLineEqn = (
- f" y = x*{result.slope :.3e} + {result.intercept :.3e}, "
- "R^2 = {result.rvalue**2 :.3f}, r = {pr :.3f}\n"
- )
- FitStats1 = f" Slope Error = {result.stderr :.3e}, Intercept Error = {result.intercept_stderr :.3e}\n"
- FitStats2 = f" Pearson’s correlation coefficient = {pr :.3f}"
- refs = "\n\n ***References****\n\n scipy.stats.linregress, scipy.stats.pearsonr "
- fitStats = (
- f"\n ***{ROIName} Fit Results***\n\n" + " Equation: " + self.fitLineEqn + FitStats1 + FitStats2 + refs
- )
-
- # generate new window to plot the results
-
- if generateSeperateWindows:
- self.windowNames[ROIName] = MaskedScatterPlotFit(
- [self.xData, self.yData],
- [self.xData, self.yyData],
- self.mask2D,
- self.maskedImage,
- fitStats,
- self.fitLineEqn,
- self.nameTuple,
- )
- self.windowNames[ROIName].show()
-
- """
- from scipy.linalg import lstsq
- M = xData[:, np.newaxis]**[0, 1] #use >1 for polynomial fits
- p, res, rnk, s = lstsq(M, yData)
- yyData = p[0] + p[1]*xData
- """
-
- def updateROIDict(self):
- self.rois = {
- "ROI 1": (self.scatter_mask, self.rb_roi1.isChecked()),
- "ROI 2": (self.scatter_mask2, self.rb_roi2.isChecked()),
- "ROI 3": (self.scatter_mask3, self.rb_roi3.isChecked()),
- }
-
- def applyMultipleROIs(self):
- with pg.BusyCursor():
- self.updateROIDict()
- for key in self.rois.keys():
- if self.rois[key][1]:
- self.getMaskRegion(key)
- else:
- pass
-
- def addMultipleROIs(self):
- self.updateROIDict()
- for key in self.rois.keys():
- if self.rois[key][1]:
- self.createMask(self.rois[key][0])
- else:
- self.clearMask(self.rois[key][0])
-
- def clearMultipleROIs(self):
- self.updateROIDict()
- for key in self.rois.keys():
- if not self.rois[key][1]:
- self.clearMask(self.rois[key][0])
- else:
- pass
-
- def createCompositeScatter(self):
-
- points = []
- fitLine = []
- masks = []
- roiFitEqn = {}
-
- self.updateROIDict()
- for n, key in enumerate(self.rois.keys()):
- if self.rois[key][1]:
- self.getMaskRegion(key, generateSeperateWindows=False)
- points.append(np.column_stack([self.xData, self.yData]))
- fitLine.append(np.column_stack([self.xData, self.yyData]))
- masks.append(self.mask2D)
- roiFitEqn[key] = self.fitLineEqn
- else:
- pass
-
- logger.info(f" fitline shape: {np.shape(fitLine)}")
- logger.info(f" points shape: {np.shape(points)}")
- logger.info(f" maks shape: {np.shape(masks)}")
- self.compositeScatterWindow = CompositeScatterPlot(
- np.array(points), np.array(fitLine), np.array(masks), roiFitEqn, self.nameTuple
- )
- self.compositeScatterWindow.show()
-
- def _createCompositeScatter(self):
- self.scatterColors = ["w", "c", "y", "k", "m"]
- points = []
- fitLine = []
-
- self.updateROIDict()
- for n, key in enumerate(self.rois.keys()):
- if self.rois[key][1]:
- self.getMaskRegion(key, generateSeperateWindows=False)
-
- for x, y, yy in zip(self.xData, self.yData, self.yyData):
-
- points.append(
- {
- "pos": (x, y),
- "data": "id",
- "size": 3,
- "pen": pg.mkPen(None),
- "brush": self.scatterColors[n],
- }
- )
- fitLine.extend(np.column_stack((self.xData, self.yyData)))
- else:
- pass
-
- logger.info(f" fitline shape: {np.shape(fitLine)}")
- self.compositeScatterWindow = CompositeScatterPlot(points, np.array(fitLine))
- self.compositeScatterWindow.show()
-
- def getROIParams(self):
- print(np.array(self.scatter_mask.getSceneHandlePositions()))
-
-
-class MaskedScatterPlotFit(QtWidgets.QMainWindow):
- def __init__(self, scatterData, fitData, mask, maskedImage, fitString, fitEquation, nameTuple):
- super(MaskedScatterPlotFit, self).__init__()
-
- uic.loadUi(os.path.join(ui_path, "uis/maskedScatterPlotFit.ui"), self)
- self.centralwidget.setStyleSheet(open(os.path.join(ui_path, "css/defaultStyle.css")).read())
- self.scatterData = scatterData
- self.fitData = fitData
- self.mask = mask
- self.maskedImage = maskedImage
- self.fitString = fitString
- self.fitEquation = fitEquation
- self.nameTuple = nameTuple
-
- # set the graphicslayoutwidget in the ui as canvas
- self.canvas = self.scatterViewer.addPlot()
- self.canvas.addLegend()
- self.canvas.setLabel("bottom", self.nameTuple[0], "counts")
- self.canvas.setLabel("left", self.nameTuple[1], "counts")
- self.gb_maskedImage1.setTitle(f" Masked {self.nameTuple[0]}")
-
- # generate a scatter plot item
- self.scattered = pg.ScatterPlotItem(size=3.5, pen=pg.mkPen(None), brush=pg.mkBrush(5, 214, 255, 200))
-
- # set scatter plot data
- self.scattered.setData(scatterData[0], scatterData[1], name="Data")
-
- # set z value negative to show scatter data behind the fit line
- self.scattered.setZValue(-10)
-
- # add scatter plot to the canvas
- self.canvas.addItem(self.scattered)
-
- # generate plotitem for fit line
- self.fitLinePlot = pg.PlotDataItem(pen=pg.mkPen(pg.mkColor(220, 20, 60), width=3.3))
-
- # set line plot data
- self.fitLinePlot.setData(fitData[0], fitData[1], name="Linear Fit")
-
- # add line plot to the canvas
- self.canvas.addItem(self.fitLinePlot)
-
- # display Mask
- self.imageView_mask.setImage(self.mask)
- self.imageView_mask.ui.menuBtn.hide()
- self.imageView_mask.ui.roiBtn.hide()
- self.imageView_mask.setPredefinedGradient("plasma")
-
- # display masked Image
- self.imageView_maskedImage.setImage(self.maskedImage)
- self.imageView_maskedImage.ui.menuBtn.hide()
- self.imageView_maskedImage.ui.roiBtn.hide()
- self.imageView_maskedImage.setPredefinedGradient("viridis")
-
- # display Fit stats
- self.text_fit_results.setPlainText(fitString)
- self.canvas.setTitle(self.fitEquation, color="r")
-
- # connections
- self.pb_copy_results.clicked.connect(self.copyFitResults)
- self.pb_save_results.clicked.connect(self.saveFitResults)
- self.actionSave_Plot.triggered.connect(self.pg_export_correlation)
- self.actionSaveMask.triggered.connect(self.saveMask)
- self.actionSaveMaskedImage.triggered.connect(self.saveImage)
-
- def saveFitResults(self):
- S__File = QFileDialog.getSaveFileName(self, "save txt", "correlationPlotFit.txt", "txt data (*txt)")
-
- Text = self.text_fit_results.toPlainText()
- if S__File[0]:
- with open(S__File[0], "w") as file:
- file.write(Text)
-
- def copyFitResults(self):
- self.text_fit_results.selectAll()
- self.text_fit_results.copy()
- self.statusbar.showMessage("text copied to clipboard")
-
- def pg_export_correlation(self):
-
- exporter = pg.exporters.CSVExporter(self.canvas)
- exporter.parameters()["columnMode"] = "(x,y,y,y) for all plots"
- file_name = QFileDialog().getSaveFileName(
- self, "save correlation", "scatterData.csv", "spectrum and fit (*csv)"
- )
- if file_name[0]:
- exporter.export(str(file_name[0]))
- self.statusbar.showMessage(f"Data saved to {str(file_name[0])}")
- else:
- pass
-
- def saveImage(self):
-
- file_name = QFileDialog().getSaveFileName(self, "Save image data", "image.tiff", "image file(*tiff *tif )")
- if file_name[0]:
- tf.imsave(str(file_name[0]), self.maskedImage)
- self.statusbar.showMessage(f"Data saved to {str(file_name[0])}")
- else:
- self.statusbar.showMessage("Saving cancelled")
- pass
-
- def saveMask(self):
-
- file_name = QFileDialog().getSaveFileName(self, "Save image data", "mask.tiff", "image file(*tiff *tif )")
- if file_name[0]:
- tf.imsave(str(file_name[0]), self.mask)
- self.statusbar.showMessage(f"Data saved to {str(file_name[0])}")
- else:
- self.statusbar.showMessage("Saving cancelled")
- pass
-
-
-class ComponentScatterPlot(QtWidgets.QMainWindow):
- def __init__(self, decomp_stack, specs):
- super(ComponentScatterPlot, self).__init__()
-
- uic.loadUi(os.path.join(ui_path, "uis/ComponentScatterPlot.ui"), self)
- self.centralwidget.setStyleSheet(open(os.path.join(ui_path, "css/defaultStyle.css")).read())
- self.w1 = self.scatterViewer.addPlot()
- self.decomp_stack = decomp_stack
- self.specs = specs
- (self.dim1, self.dim3, self.dim2) = self.decomp_stack.shape
- # fill the combonbox depending in the number of components for scatter plot
- for n, combs in enumerate(combinations(np.arange(self.dim1), 2)):
- self.cb_scatter_comp.addItem(str(combs))
- self.cb_scatter_comp.setItemData(n, combs)
-
- self.s1 = pg.ScatterPlotItem(size=3, pen=pg.mkPen(None), brush=pg.mkBrush(255, 255, 0, 120))
-
- self.setImageAndScatterPlot()
- # connections
- self.actionSave_Plot.triggered.connect(self.pg_export_correlation)
- self.actionSave_Images.triggered.connect(self.tiff_export_images)
- self.pb_updateComponents.clicked.connect(self.setImageAndScatterPlot)
- self.pb_define_mask.clicked.connect(self.createMask)
- self.pb_apply_mask.clicked.connect(self.getMaskRegion)
- self.pb_reset_mask.clicked.connect(self.resetMask)
- self.pb_addALine.clicked.connect(lambda: self.createMask(Line=True))
-
- def setImageAndScatterPlot(self):
-
- try:
- self.s1.clear()
- except Exception:
- pass
-
- comp_tuple = self.cb_scatter_comp.currentData()
- self.img1, self.img2 = self.decomp_stack[comp_tuple[0]], self.decomp_stack[comp_tuple[-1]]
- self.image_view.setImage(self.decomp_stack[comp_tuple[0]])
- self.image_view.ui.menuBtn.hide()
- self.image_view.ui.roiBtn.hide()
- self.image_view.setPredefinedGradient("bipolar")
-
- self.image_view2.setImage(self.decomp_stack[comp_tuple[-1]])
- self.image_view2.ui.menuBtn.hide()
- self.image_view2.ui.roiBtn.hide()
- self.image_view2.setPredefinedGradient("bipolar")
-
- points = []
- for i, j in zip(self.img1.flatten(), self.img2.flatten()):
-
- points.append(
- {
- "pos": (i, j),
- "data": "id",
- "size": 5,
- "pen": pg.mkPen(None),
- "brush": pg.mkBrush(255, 255, 0, 160),
- }
- )
-
- self.s1.addPoints(points)
- self.w1.addItem(self.s1)
- # self.s1.setData(self.specs[:, comp_tuple[0]], self.specs[:, comp_tuple[-1]])
- self.w1.setLabel("bottom", f"PC{comp_tuple[0]+1}")
- self.w1.setLabel("left", f"PC{comp_tuple[-1]+1}")
- self.label_im1.setText(f"PC{comp_tuple[0]+1}")
- self.label_im2.setText(f"PC{comp_tuple[-1]+1}")
-
- def createMask(self, Line=False):
-
- self.size = self.img1.max() / 10
- self.pos = int(self.img1.mean())
-
- if Line:
- self.lineROI = pg.LineSegmentROI(
- [0, 1],
- pos=(self.pos, self.pos),
- pen=pg.mkPen("r", width=4),
- hoverPen=pg.mkPen("g", width=4),
- removable=True,
- )
- self.w1.addItem(self.lineROI)
-
- else:
-
- self.scatter_mask = pg.PolyLineROI(
- [[0, 0], [0, self.size], [self.size, self.size], [self.size, 0]],
- pos=(self.pos, self.pos),
- pen=pg.mkPen("r", width=4),
- hoverPen=pg.mkPen("g", width=4),
- closed=True,
- removable=True,
- )
-
- self.w1.addItem(self.scatter_mask)
-
- def resetMask(self):
- self.clearMask()
- self.createMask()
-
- def clearMask(self):
- try:
- self.w1.removeItem(self.scatter_mask)
- except AttributeError:
- pass
-
- def clearPgPlot(self):
- try:
- self.masked_img.close()
- except Exception:
- pass
-
- def getMaskRegion(self):
-
- # Ref : https://stackoverflow.com/questions/57719303/how-to-map-mouse-position-on-a-scatterplot
-
- roiShape = self.scatter_mask.mapToItem(self.s1, self.scatter_mask.shape())
- self._points = list()
- logger.info("Building Scatter Plot Window; Please wait..")
- for i in range(len(self.img1.flatten())):
- self._points.append(QtCore.QPointF(self.img1.flatten()[i], self.img2.flatten()[i]))
-
- selected = [roiShape.contains(pt) for pt in self._points]
- img_selected = np.reshape(selected, (self.img1.shape))
-
- self.masked_img = singleStackViewer(img_selected * self.img1, gradient="bipolar")
- self.masked_img.show()
-
- def pg_export_correlation(self):
-
- exporter = pg.exporters.CSVExporter(self.w1)
- exporter.parameters()["columnMode"] = "(x,y,y,y) for all plots"
- file_name = QFileDialog().getSaveFileName(self, "save correlation", "", "spectrum and fit (*csv)")
- if file_name[0]:
- exporter.export(str(file_name[0]) + ".csv")
- self.statusbar.showMessage(f"Data saved to {str(file_name[0])}")
- else:
- pass
-
- def tiff_export_images(self):
- file_name = QFileDialog().getSaveFileName(self, "save images", "", "spectrum and fit (*tiff)")
- if file_name[0]:
- tf.imsave(str(file_name[0]) + ".tiff", np.dstack([self.img1, self.img2]).T)
- self.statusbar.showMessage(f"Images saved to {str(file_name[0])}")
- else:
- pass
-
-
-class LoadingScreen(QtWidgets.QSplashScreen):
- def __init__(self):
- super(LoadingScreen, self).__init__()
- uic.loadUi(os.path.join(ui_path, "uis/animationWindow.ui"), self)
- self.setWindowOpacity(0.65)
- self.movie = QMovie("uis/animation.gif")
- self.label.setMovie(self.movie)
-
- def mousePressEvent(self, event):
- # disable default "click-to-dismiss" behaviour
- pass
-
- def startAnimation(self):
- self.movie.start()
- self.show()
-
- def stopAnimation(self):
- self.movie.stop()
- self.hide()
-
-
-class CompositeScatterPlot(QtWidgets.QMainWindow):
- def __init__(self, scatterPoints, fitLine, maskImages, fitEquations, nameTuple):
- super(CompositeScatterPlot, self).__init__()
-
- uic.loadUi(os.path.join(ui_path, "uis/multipleScatterFit.ui"), self)
- self.centralwidget.setStyleSheet(open(os.path.join(ui_path, "css/defaultStyle.css")).read())
-
- self.scatterPoints = scatterPoints
- self.fitLine = fitLine
- self.scatterColors = ["r", (0, 115, 0), (4, 186, 186), "c", "w", "k"]
- self.fitColors = ["b", "r", "m", "k", "b"]
- self.roiNames = list(fitEquations.keys())
- self.fitEqns = list(fitEquations.values())
- self.nameTuple = nameTuple
- self.maskImages = maskImages
-
- # self.scatterViewer.setBackground('w')
- # set the graphicslayoutwidget in the ui as canvas
- self.canvas = self.scatterViewer.addPlot()
- self.canvas.addLegend()
- self.canvas.setLabel("bottom", self.nameTuple[0], "counts")
- self.canvas.setLabel("left", self.nameTuple[1], "counts")
-
- # connections
- self.actionExport.triggered.connect(self.exportData)
- self.actionSave_as_PNG.triggered.connect(self.exportAsPNG)
- self.actionGenerate_MultiColor_Mask.triggered.connect(self.generateMultiColorView)
- self.actionWhite.triggered.connect(lambda: self.scatterViewer.setBackground("w"))
- self.actionBlack.triggered.connect(lambda: self.scatterViewer.setBackground("k"))
-
- with pg.BusyCursor():
-
- for arr, fitline, clr, fitClr, rname, feqn in zip(
- self.scatterPoints, self.fitLine, self.scatterColors, self.fitColors, self.roiNames, self.fitEqns
- ):
-
- sctrPoints = []
- for pt in arr:
- sctrPoints.append(
- {"pos": (pt[0], pt[1]), "data": "id", "size": 3, "pen": pg.mkPen(None), "brush": clr}
- )
-
- # generate a scatter plot item
- self.scattered = pg.ScatterPlotItem(size=4.5, pen=clr, brush=pg.mkBrush(5, 214, 255, 200))
- # set scatter plot data
- self.scattered.setPoints(sctrPoints, name=rname)
-
- # set z value negative to show scatter data behind the fit line
- self.scattered.setZValue(-10)
-
- # add scatter plot to the canvas
- self.canvas.addItem(self.scattered)
-
- # generate plotitem for fit line
- self.fitLinePlot = pg.PlotDataItem(pen=pg.mkPen(fitClr, width=4.5))
-
- # set line plot data
- self.fitLinePlot.setData(fitline, name=feqn)
-
- # add line plot to the canvas
- self.canvas.addItem(self.fitLinePlot)
-
- def generateMultiColorView(self):
- self.multichanneldict = {}
-
- for n, (colorName, image, rname) in enumerate(zip(cmap_dict.keys(), self.maskImages, self.roiNames)):
- low, high = np.min(image), np.max(image)
- self.multichanneldict[rname] = {
- "ImageName": rname,
- "ImageDir": ".",
- "Image": image,
- "Color": colorName,
- "CmapLimits": (low, high),
- "Opacity": 1.0,
- }
-
- # print( self.multichanneldict)
- self.muli_color_window = MultiChannelWindow(image_dict=self.multichanneldict)
- self.muli_color_window.show()
-
- def exportData(self):
-
- exporter = pg.exporters.CSVExporter(self.canvas)
- # exporter.parameters()['columnMode'] = '(x,y,y,y) for all plots'
- file_name = QFileDialog().getSaveFileName(self, "Save CSV Data", "scatter.csv", "image file (*csv)")
- if file_name[0]:
- exporter.export(str(file_name[0]))
- self.statusbar.showMessage(f"Data saved to {str(file_name[0])}")
- else:
- pass
-
- def exportAsPNG(self):
- file_name = QtWidgets.QFileDialog().getSaveFileName(
- self, "Save Image", "image.png", "PNG(*.png);; TIFF(*.tiff);; JPG(*.jpg)"
- )
- exporter = pg.exporters.ImageExporter(self.canvas)
-
- if file_name[0]:
- exporter.export(str(file_name[0]))
- self.statusbar.showMessage(f"Image saved to {str(file_name[0])}")
- else:
- pass
-
-
-class MaskSpecViewer(QtWidgets.QMainWindow):
- def __init__(self, xanes_stack=None, xrf_map=None, energy=[]):
- super(MaskSpecViewer, self).__init__()
- uic.loadUi(os.path.join(ui_path, "uis/MaskedView.ui"), self)
-
- self.xanes_stack = xanes_stack
- self.xrf_map = xrf_map
- self.energy = energy
- self.xrf_map = self.xanes_stack[-1]
- self.view_data()
-
- # connections
- self.sldr_xrf_low.valueChanged.connect(self.create_mask)
- self.sldr_xrf_high.valueChanged.connect(self.create_mask)
- self.pb_apply_mask.clicked.connect(self.apply_mask_to_xanes)
- self.pb_export_mask.clicked.connect(self.export_mask)
- self.pb_import_mask.clicked.connect(self.import_a_mask)
- self.actionLoad_Energy_List.triggered.connect(self.load_energy)
- self.actionLoad_XANES_Stack.triggered.connect(self.load_xanes_stack)
- self.actionLoad_XRF_Map.triggered.connect(self.load_xrf_map)
-
- def view_data(self):
-
- self.xanes_view.setImage(self.xanes_stack)
- self.xanes_view.ui.menuBtn.hide()
- self.xanes_view.ui.roiBtn.hide()
- (self.dim1, self.dim3, self.dim2) = self.xanes_stack.shape
- self.xanes_view.setPredefinedGradient("viridis")
- self.xanes_view.setCurrentIndex(self.dim1 // 2)
- self.statusbar.showMessage("One image from the XANES stack is used as mask")
- self.xrf_view.setImage(self.xrf_map)
- self.xrf_view.ui.menuBtn.hide()
- self.xrf_view.ui.roiBtn.hide()
- self.xrf_view.setPredefinedGradient("viridis")
-
- self.mask_view.ui.menuBtn.hide()
- self.mask_view.ui.roiBtn.hide()
-
- def create_mask(self):
- self.threshold_low = np.around(self.sldr_xrf_low.value() * 0.01, 3)
- self.threshold_high = np.around(self.sldr_xrf_high.value() * 0.01, 3)
- self.sldr_xrf_low.setMaximum(self.sldr_xrf_high.value() + 1)
- self.sldr_xrf_high.setMinimum(self.sldr_xrf_low.value() + 1)
- self.norm_xrf_map = remove_nan_inf(self.xrf_map) / remove_nan_inf(self.xrf_map.max())
- self.norm_xrf_map[self.norm_xrf_map < self.threshold_low] = 0
- self.norm_xrf_map[self.norm_xrf_map > self.threshold_high] = 0
- self.xrf_view.setImage(self.norm_xrf_map)
- self.le_sldr_vals.setText(str(self.threshold_low) + " to " + str(self.threshold_high))
- self.statusbar.showMessage("New Threshold Applied")
- self.xrf_mask = np.where(self.norm_xrf_map > 0, self.norm_xrf_map, 0)
- self.xrf_mask[self.xrf_mask > 0] = 1
- self.mask_view.setImage(self.xrf_mask)
-
- def load_xanes_stack(self):
- """loading a new xanes stack"""
- filename = QFileDialog().getOpenFileName(self, "Select image data", "", "image file(*tiff *tif )")
- self.file_name = str(filename[0])
- self.xanes_stack = tf.imread(self.file_name).transpose(0, 2, 1)
- self.view_data()
-
- def load_energy(self):
- """To load energy list that will be used for plotting the spectra.
- number of stack should match length of energy list"""
-
- file_name = QFileDialog().getOpenFileName(self, "Open energy list", "", "text file (*.txt)")
-
- try:
- self.energy = np.loadtxt(str(file_name[0]))
- logger.info("Energy file loaded")
- assert len(self.energy) == self.dim1
- self.view_data()
-
- except OSError:
- logger.error("No File selected")
- pass
-
- def load_xrf_map(self):
- """To xrf map for masking. If 3D mean will be taken"""
-
- filename = QFileDialog().getOpenFileName(self, "Select image data", "", "image file(*tiff *tif )")
- self.xrf_file_name = str(filename[0])
- self.xrf_map = tf.imread(self.xrf_file_name)
- if self.xrf_map.ndim == 3:
- self.xrf_map = self.xrf_map.mean(0).T
-
- else:
- self.xrf_map = self.xrf_map.T
-
- assert (
- self.dim3,
- self.dim2,
- ) == self.xrf_map.shape, f"Unexpected image dimensions: {self.xrf_map.shape} vs {(self.dim2,self.dim3)}"
-
- self.view_data()
- self.create_mask()
-
- def apply_mask_to_xanes(self):
-
- """Generates a mask with 0 and 1 from the choosen threshold and multply with the xanes stack.
- A spectrum will be generated from the new masked stack"""
-
- self.masked_xanes = self.xanes_stack * self.xrf_mask
- self.xanes_view.setImage(self.masked_xanes)
- self.xanes_view.setCurrentIndex(self.dim1 // 2)
- self.statusbar.showMessage("Mask Applied to XANES")
- self.mask_spec = get_mean_spectra(self.masked_xanes)
-
- if len(self.energy) != 0:
- self.xdata = self.energy
- else:
- self.xdata = np.arange(0, self.dim1)
- self.statusbar.showMessage("No Energy List Available; Integer values are used for plotting")
-
- self.spectrum_view.plot(self.xdata, self.mask_spec, clear=True)
-
- def import_a_mask(self):
- filename = QFileDialog().getOpenFileName(self, "Select image data", "", "image file(*tiff *tif )")
- xrf_file_name = str(filename[0])
- self.xrf_mask = tf.imread(xrf_file_name).T
- self.statusbar.showMessage("A New Mask Imported")
- self.mask_view.setImage(self.xrf_mask)
- self.apply_mask_to_xanes()
-
- def export_mask(self):
- try:
- file_name = QFileDialog().getSaveFileName(self, "Save image data", "", "image file(*tiff *tif )")
- tf.imsave(str(file_name[0]) + ".tiff", self.xrf_mask.T)
- logger.info(f"Updated Image Saved: {str(file_name[0])}")
- self.statusbar.showMessage("Mask Exported")
- except Exception:
- logger.error("No file to save")
- pass
-
-
-class StackInfo(QtWidgets.QMainWindow):
- def __init__(self, text_to_write: str = " "):
- super(StackInfo, self).__init__()
- uic.loadUi(os.path.join(ui_path, "uis/log.ui"), self)
-
- self.text_to_write = text_to_write
- self.pte_run_cmd.setPlainText(self.text_to_write)
-
- # connections
- self.pb_save_cmd.clicked.connect(self.save_file)
- self.pb_clear_cmd.clicked.connect(self.clear_text)
-
- def save_file(self):
- S__File = QFileDialog.getSaveFileName(None, "SaveFile", "/", "txt Files (*.txt)")
-
- Text = self.pte_run_cmd.toPlainText()
- if S__File[0]:
- with open(S__File[0], "w") as file:
- file.write(Text)
-
- def clear_text(self):
- self.pte_run_cmd.clear()
-
-
-class MultiChannelWindow(QtWidgets.QMainWindow):
- def __init__(self, image_dict=None):
- super(MultiChannelWindow, self).__init__()
- if image_dict is None:
- image_dict = {}
- uic.loadUi(os.path.join(ui_path, "uis/mutlichannel.ui"), self)
-
- self.canvas = self.img_view.addPlot(title="")
- self.canvas.getViewBox().invertY(True)
- self.canvas.setAspectLocked(True)
- self.cb_choose_color.addItems([i for i in cmap_dict.keys()])
-
- self.image_dict = image_dict
- self.buildFromDictionary()
-
- # connections
- self.actionLoad.triggered.connect(self.createMuliColorAndList)
- self.actionLoad_Stack.triggered.connect(self.createMuliColorAndList)
- self.cb_choose_color.currentTextChanged.connect(self.updateImageDictionary)
- self.pb_update_low_high.clicked.connect(self.updateImageDictionary)
- self.listWidget.itemClicked.connect(self.editImageProperties)
- self.listWidget.itemDoubleClicked.connect(self.showOneImageOnly)
- self.pb_show_selected.clicked.connect(self.showOneImageOnly)
- self.pb_show_all.clicked.connect(self.showAllItems)
- self.actionLoad_State_File.triggered.connect(self.importState)
- self.actionSave_State.triggered.connect(self.exportState)
- self.actionSave_View.triggered.connect(self.saveImage)
-
- def buildFromDictionary(self):
- if self.image_dict is not None:
- self.createMultiColorView(self.image_dict)
- self.displayImageNames(self.image_dict)
- else:
- pass
-
- def generateImageDictionary(self):
- """Creates a dictionary contains image path, color scheme chosen, throshold limits etc.
- when user edits the parameters dictionary will be updated and unwrapped for display later.
- This dictionary is saved as json file while saving the state. Two image loading options are possible.
- User can either select multiple 2D array images or one 3D array (stack)"""
-
- clickedAction = self.sender()
-
- if clickedAction.text() == "Load Images":
- # multiple images are selected
- self.loadMultipleImageFiles()
-
- elif clickedAction.text() == "Load Stack":
- # an image stack is selected
- self.loadAsStack()
-
- def loadMultipleImageFiles(self):
-
- filter = "TIFF (*.tiff);;TIF (*.tif)"
- QtWidgets.QFileDialog().setFileMode(QtWidgets.QFileDialog.ExistingFiles)
- # choose mutliple tiff files
- names = QtWidgets.QFileDialog().getOpenFileNames(self, "Open files", " ", filter)
- if names[0]:
- self.image_dict = {}
- # select the file directory. Image files are expected to be in the same folder
- self.imageDir = os.path.dirname(names[0][0])
-
- # create the dictionary
- for colorName, image in zip(cmap_dict.keys(), names[0]):
- # squeeze to allow with pseudo 3D axis from some tomo recon (eg. 1, 100,100 array)
- im_array = np.squeeze(tf.imread(image))
- # set values for thresholding as image min and max
- low, high = np.min(im_array), np.max(im_array)
- # name of the tiff file is chosen as key for the dictionary,
- # inner keys are properties set for that image
- im_name = os.path.basename(image)
- # construct the dictionary
- self.image_dict[f"{os.path.basename(image)}"] = {
- "ImageName": im_name,
- "ImageDir": self.imageDir,
- "Image": im_array,
- "Color": colorName,
- "CmapLimits": (low, high),
- "Opacity": 1.0,
- }
- else:
- pass
-
- def loadAsStack(self):
- """construct the dictionary with image +number as the key.
- All other steps are similar to the loadMultipleImageFiles function"""
-
- filter = "TIFF (*.tiff);;TIF (*.tif)"
- file_name = QtWidgets.QFileDialog().getOpenFileName(
- self, "Open a Stack", "", "TIFF(*tiff *tif);;all_files (*)", filter
- )
- if file_name[0]:
- self.imageDir = os.path.dirname(file_name[0])
- self.image_dict = {}
- im_stack = np.squeeze(tf.imread(file_name[0]))
- # asset the file is a stack
- assert im_stack.ndim == 3, "Not a stack"
- # construct the dictionary
- for n, (colorName, image) in enumerate(zip(cmap_dict.keys(), im_stack)):
- low, high = np.min(image), np.max(image)
- self.image_dict[f"Image {n+1}"] = {
- "ImageName": f"Image {n+1}",
- "ImageDir": self.imageDir,
- "Image": image,
- "Color": colorName,
- "CmapLimits": (low, high),
- "Opacity": 1.0,
- }
-
- def loadAnImage(self, image, colormap, cmap_limits, opacity=1):
- """load single image and colorbar to the widget. This function will be looped for
- multiple images later
- """
- # get pg image item
- img = pg.ImageItem()
- # add image to the graphicsview widget
- self.canvas.addItem(img)
- # set the color map
- cmap = pg.ColorMap(pos=np.linspace(0, 1, len(colormap)), color=colormap)
- # image = np.squeeze(tf.imread(image_path))
- # set image to the image item with cmap
- img.setImage(np.array(image), lut=cmap.getLookupTable(), opacity=opacity)
-
- # set colorbar for thresholding
- bar = pg.ColorBarItem(values=cmap_limits, cmap=cmap, limits=(0, None), orientation="vertical")
- bar.setImageItem(img)
- # set composition mode to plus for overlaying
- img.setCompositionMode(QtGui.QPainter.CompositionMode_Plus)
-
- def createMultiColorView(self, image_dictionary):
- """Function creates multi color image view by taking image
- data and parameters from the dictionary"""
-
- # clear the plots and list in case of re-loading
- self.canvas.clear()
- self.listWidget.clear()
-
- # display individual images in for loop
- for path_and_color in image_dictionary.values():
- self.loadAnImage(
- path_and_color["Image"],
- cmap_dict[path_and_color["Color"]],
- path_and_color["CmapLimits"],
- path_and_color["Opacity"],
- )
-
- def showOneImageOnly(self):
- editItem = self.listWidget.currentItem()
- editRow = self.listWidget.currentRow()
- for i in range(self.listWidget.count()):
- if self.listWidget.item(i) == editItem:
- editItemName = self.listWidget.item(i).text().split(",")[0]
- self.image_dict[editItemName]["Opacity"] = 1
-
- elif self.listWidget.item(i) != editItem:
- editItemName = self.listWidget.item(i).text().split(",")[0]
- self.image_dict[editItemName]["Opacity"] = 0
-
- self.createMultiColorView(self.image_dict)
- self.displayImageNames(self.image_dict)
- self.listWidget.setCurrentRow(editRow)
-
- def showAllItems(self):
- # editItem = self.listWidget.currentItem()
- editRow = self.listWidget.currentRow()
- for i in range(self.listWidget.count()):
- editItemName = self.listWidget.item(i).text().split(",")[0]
- self.image_dict[editItemName]["Opacity"] = 1
-
- self.createMultiColorView(self.image_dict)
- self.displayImageNames(self.image_dict)
- self.listWidget.setCurrentRow(editRow)
-
- def displayImageNames(self, image_dictionary):
- """Populate the list widget table with image name and color used to plot,
- using image dictionary input"""
-
- for im_name, vals in image_dictionary.items():
- self.listWidget.addItem(f"{im_name},{vals['Color']}")
- self.listWidget.setCurrentRow(0)
-
- def createMuliColorAndList(self):
- """Finally Load Images and poplulate the list widget from the dictionary"""
- with pg.BusyCursor(): # gives the circle showing gui is doing something
- self.generateImageDictionary()
- if self.image_dict:
- self.createMultiColorView(self.image_dict)
- self.displayImageNames(self.image_dict)
-
- else:
- pass
-
- def sliderSetUp(self, im_array):
- """Setting the slider min and max from image values"""
-
- low = (np.min(im_array) / np.max(im_array)) * 100
- self.sldr_low.setMaximum(100)
- self.sldr_low.setMinimum(low)
- self.sldr_high.setMaximum(100)
- self.sldr_high.setMinimum(low)
-
- def editImageProperties(self, item):
- """function to control the assigned properties such as color,
- threshold limits, opacity etc of a single image selected using the list widget item"""
-
- editItem = item.text()
- # get the dictionary key from item text
- editItemName = editItem.split(",")[0]
- editItemColor = editItem.split(",")[1]
- im_array = self.image_dict[editItemName]["Image"]
- self.sliderSetUp(im_array)
- setValLow = (self.image_dict[editItemName]["CmapLimits"][0] * 100) / np.max(im_array)
- setValHigh = (self.image_dict[editItemName]["CmapLimits"][1] * 100) / np.max(im_array)
- setOpacity = self.image_dict[editItemName]["Opacity"] * 100
- self.sldr_low.setValue(int(setValLow))
- self.sldr_high.setValue(int(setValHigh))
- self.sldr_opacity.setValue(int(setOpacity))
- self.low_high_vals.setText(f"low:{self.sldr_low.value()}," f"high:{self.sldr_high.value()}")
- self.cb_choose_color.setCurrentText(editItemColor)
-
- def updateImageDictionary(self):
- newColor = self.cb_choose_color.currentText()
- editItem = self.listWidget.currentItem().text()
- editRow = self.listWidget.currentRow()
- editItemName = editItem.split(",")[0]
- self.imageDir = self.image_dict[editItemName]["ImageDir"]
- im_array = self.image_dict[editItemName]["Image"]
- self.sliderSetUp(im_array)
- cmap_limits = (
- self.sldr_low.value() * np.max(im_array) / 100,
- self.sldr_high.value() * np.max(im_array) / 100,
- )
- self.low_high_vals.setText(f"low:{cmap_limits[0]:.3f},high:{cmap_limits[1]:.3f}")
- opacity = self.sldr_opacity.value() / 100
- self.opacity_val.setText(str(opacity))
- self.image_dict[editItemName] = {
- "ImageName": editItemName,
- "ImageDir": self.imageDir,
- "Image": im_array,
- "Color": newColor,
- "CmapLimits": cmap_limits,
- "Opacity": opacity,
- }
-
- self.createMultiColorView(self.image_dict)
- self.displayImageNames(self.image_dict)
- self.listWidget.setCurrentRow(editRow)
-
- def exportState(self):
-
- file_name = QtWidgets.QFileDialog().getSaveFileName(
- self, "Save Current State", "multicolor_params.json", "json file(*json)"
- )
- """
- for val in self.image_dict.values():
- val['CmapLimits'] = json.dumps(str(val['CmapLimits']))
- """
-
- if file_name[0]:
-
- with open(f"{file_name[0]}", "w") as fp:
- json.dump(self.image_dict, fp, indent=4, cls=jsonEncoder)
-
- else:
- pass
-
- def importState(self):
- file_name = QtWidgets.QFileDialog().getOpenFileName(
- self, "Open a State File", "", "json file(*json);;all_files (*)"
- )
- if file_name[0]:
- with open(file_name[0], "r") as fp:
- self.image_dict = json.load(fp)
-
- self.createMultiColorView(self.image_dict)
- self.displayImageNames(self.image_dict)
- else:
- pass
-
- def saveImage(self):
- file_name = QtWidgets.QFileDialog().getSaveFileName(
- self, "Save Image", "multicolor_image.png", "PNG(*.png);; TIFF(*.tiff);; JPG(*.jpg)"
- )
- exporter = pg.exporters.ImageExporter(self.canvas.getViewBox())
- exporter.export(file_name[0])
-
-
-""" Helper Functions"""
-
-
-def get_xrf_data(h="h5file"):
- """
- get xrf stack from h5 data generated at NSLS-II beamlines
-
- Arguments:
- h5/hdf5 file
-
- Returns:
- norm_xrf_stack - xrf stack image normalized with Io
- mono_e - excitation enegy used for xrf
- beamline - identity of the beamline
- Io_avg - an average Io value, used before taking log
-
- """
-
- f = h5py.File(h, "r")
-
- if list(f.keys())[0] == "xrfmap":
- logger.info("Data from HXN/TES/SRX")
- beamline = f["xrfmap/scan_metadata"].attrs["scan_instrument_id"]
-
- try:
-
- beamline_scalar = {"HXN": 2, "SRX": 0, "TES": 0}
-
- if beamline in beamline_scalar.keys():
-
- Io = np.array(f["xrfmap/scalers/val"])[:, :, beamline_scalar[beamline]]
- raw_xrf_stack = np.array(f["xrfmap/detsum/counts"])
- norm_xrf_stack = raw_xrf_stack
- Io_avg = int(remove_nan_inf(Io).mean())
- else:
- logger.error("Unknown Beamline Scalar")
- except Exception:
- logger.warning("Unknown Scalar: Raw Detector count in use")
- norm_xrf_stack = np.array(f["xrfmap/detsum/counts"])
-
- elif list(f.keys())[0] == "xrmmap":
- logger.info("Data from XFM")
- beamline = "XFM"
- raw_xrf_stack = np.array(f["xrmmap/mcasum/counts"])
- Io = np.array(f["xrmmap/scalars/I0"])
- norm_xrf_stack = raw_xrf_stack
- Io_avg = int(remove_nan_inf(Io).mean())
-
- else:
- logger.error("Unknown Data Format")
-
- try:
- mono_e = int(f["xrfmap/scan_metadata"].attrs["instrument_mono_incident_energy"] * 1000)
- logger.info("Excitation energy was taken from the h5 data")
-
- except Exception:
- mono_e = 12000
- logger.info(f"Unable to get Excitation energy from the h5 data; using default value {mono_e} KeV")
-
- return remove_nan_inf(norm_xrf_stack.transpose((2, 0, 1))), mono_e + 1500, beamline, Io_avg
-
-
-def remove_nan_inf(im):
- im = np.array(im, dtype=np.float32)
- im[np.isnan(im)] = 0
- im[np.isinf(im)] = 0
- return im
-
-
-def rebin_image(im, bin_factor):
- arrx, arry = np.shape(im)
- if arrx / bin_factor != int or arrx / bin_factor != int:
- logger.error("Invalid Binning")
-
- else:
- shape = (arrx / bin_factor, arry / bin_factor)
- return im.reshape(shape).mean(-1).mean(1)
-
-
-def remove_hot_pixels(image_array, NSigma=5):
- image_array = remove_nan_inf(image_array)
- a, b, c = np.shape(image_array)
- img_stack2 = np.zeros((a, b, c))
- for i in range(a):
- im = image_array[i, :, :]
- im[abs(im) > np.std(im) * NSigma] = im.mean()
- img_stack2[i, :, :] = im
- return img_stack2
-
-
-def smoothen(image_array, w_size=5):
- a, b, c = np.shape(image_array)
- spec2D_Matrix = np.reshape(image_array, (a, (b * c)))
- smooth2D_Matrix = savgol_filter(spec2D_Matrix, w_size, w_size - 2, axis=0)
- return remove_nan_inf(np.reshape(smooth2D_Matrix, (a, b, c)))
-
-
-def resize_stack(image_array, upscaling=False, scaling_factor=2):
- en, im1, im2 = np.shape(image_array)
-
- if upscaling:
- im1_ = im1 * scaling_factor
- im2_ = im2 * scaling_factor
- img_stack_resized = resize(image_array, (en, im1_, im2_))
-
- else:
- im1_ = int(im1 / scaling_factor)
- im2_ = int(im2 / scaling_factor)
- img_stack_resized = resize(image_array, (en, im1_, im2_))
-
- return img_stack_resized
-
-
-def normalize(image_array, norm_point=-1):
- norm_stack = image_array / image_array[norm_point]
- return remove_nan_inf(norm_stack)
-
-
-def remove_edges(image_array):
- # z, x, y = np.shape(image_array)
- return image_array[:, 1:-1, 1:-1]
-
-
-def background_value(image_array):
- img = image_array.mean(0)
- img_h = img.mean(0)
- img_v = img.mean(1)
- h = np.gradient(img_h)
- v = np.gradient(img_v)
- bg = np.min([img_h[h == h.max()], img_v[v == v.max()]])
- return bg
-
-
-def background_subtraction(img_stack, bg_percentage=10):
- img_stack = remove_nan_inf(img_stack)
- a, b, c = np.shape(img_stack)
- ref_image = np.reshape(img_stack.mean(0), (b * c))
- bg_ratio = int((b * c) * 0.01 * bg_percentage)
- bg_ = np.max(sorted(ref_image)[0:bg_ratio])
- bged_img_stack = img_stack - bg_[:, np.newaxis, np.newaxis]
- return bged_img_stack
-
-
-def background_subtraction2(img_stack, bg_percentage=10):
- img_stack = remove_nan_inf(img_stack)
- a, b, c = np.shape(img_stack)
- bg_ratio = int((b * c) * 0.01 * bg_percentage)
- bged_img_stack = img_stack.copy()
-
- for n, img in enumerate(img_stack):
- bg_ = np.max(sorted(img.flatten())[0:bg_ratio])
- print(bg_)
- bged_img_stack[n] = img - bg_
-
- return remove_nan_inf(bged_img_stack)
-
-
-def background1(img_stack):
- img = img_stack.sum(0)
- img_h = img.mean(0)
- img_v = img.mean(1)
- h = np.gradient(img_h)
- v = np.gradient(img_v)
- bg = np.min([img_h[h == h.max()], img_v[v == v.max()]])
- return bg
-
-
-def get_sum_spectra(image_array):
- spec = np.sum(image_array, axis=(1, 2))
- return spec
-
-
-def get_mean_spectra(image_array):
- spec = np.mean(image_array, axis=(1, 2))
- return spec
-
-
-def flatten_(image_array):
- z, x, y = np.shape(image_array)
- flat_array = np.reshape(image_array, (x * y, z))
- return flat_array
-
-
-def image_to_pandas(image_array):
- a, b, c = np.shape(image_array)
- im_array = np.reshape(image_array, ((b * c), a))
- a, b = im_array.shape
- df = pd.DataFrame(
- data=im_array[:, :], columns=["e" + str(i) for i in range(b)], index=["s" + str(i) for i in range(a)]
- )
- return df
-
-
-def image_to_pandas2(image_array):
- a, b, c = np.shape(image_array)
- im_array = np.reshape(image_array, (a, (b * c)))
- a, b = im_array.shape
- df = pd.DataFrame(
- data=im_array[:, :], index=["e" + str(i) for i in range(a)], columns=["s" + str(i) for i in range(b)]
- )
- return df
-
-
-def neg_log(image_array):
- absorb = -1 * np.log(image_array)
- return remove_nan_inf(absorb)
-
-
-def clean_stack(img_stack, auto_bg=False, bg_percentage=5):
- a, b, c = np.shape(img_stack)
-
- if auto_bg is True:
- bg_ = background1(img_stack)
-
- else:
- sum_spec = (img_stack.sum(1)).sum(1)
- ref_stk_num = np.where(sum_spec == sum_spec.max())[-1]
-
- ref_image = np.reshape(img_stack[ref_stk_num], (b * c))
- bg_ratio = int((b * c) * 0.01 * bg_percentage)
- bg_ = np.max(sorted(ref_image)[0:bg_ratio])
-
- bg = np.where(img_stack[ref_stk_num] > bg_, img_stack[ref_stk_num], 0)
- bg2 = np.where(bg < bg_, bg, 1)
-
- bged_img_stack = img_stack * bg2
-
- return remove_nan_inf(bged_img_stack)
-
-
-def subtractBackground(im_stack, bg_region):
- if bg_region.ndim == 3:
- bg_region_ = np.mean(bg_region, axis=(1, 2))
-
- elif bg_region.ndim == 2:
- bg_region_ = np.mean(bg_region, axis=1)
-
- else:
- bg_region_ = bg_region
-
- return im_stack - bg_region_[:, np.newaxis, np.newaxis]
-
-
-def classify(img_stack, correlation="Pearson"):
- img_stack_ = img_stack
- a, b, c = np.shape(img_stack_)
- norm_img_stack = normalize(img_stack_)
- f = np.reshape(norm_img_stack, (a, (b * c)))
-
- max_x, max_y = np.where(norm_img_stack.sum(0) == (norm_img_stack.sum(0)).max())
- ref = norm_img_stack[:, int(max_x), int(max_y)]
- corr = np.zeros(len(f.T))
- for s in range(len(f.T)):
- if correlation == "Kendall":
- r, p = stats.kendalltau(ref, f.T[s])
- elif correlation == "Pearson":
- r, p = stats.pearsonr(ref, f.T[s])
-
- corr[s] = r
-
- cluster_image = np.reshape(corr, (b, c))
- return (cluster_image**3), img_stack_
-
-
-def correlation_kmeans(img_stack, n_clusters, correlation="Pearson"):
- img, bg_image = classify(img_stack, correlation)
- img[np.isnan(img)] = -99999
- X = img.reshape((-1, 1))
- k_means = sc.KMeans(n_clusters)
- k_means.fit(X)
-
- X_cluster = k_means.labels_
- X_cluster = X_cluster.reshape(img.shape) + 1
-
- return X_cluster
-
-
-def cluster_stack(
- im_array, method="KMeans", n_clusters_=4, decomposed=False, decompose_method="PCA", decompose_comp=2
-):
- a, b, c = im_array.shape
-
- if method == "Correlation-Kmeans":
-
- X_cluster = correlation_kmeans(im_array, n_clusters_, correlation="Pearson")
-
- else:
-
- methods = {
- "MiniBatchKMeans": sc.MiniBatchKMeans,
- "KMeans": sc.KMeans,
- "MeanShift": sc.MeanShift,
- "Spectral Clustering": sc.SpectralClustering,
- "Affinity Propagation": sc.AffinityPropagation,
- }
-
- if decomposed:
- im_array = denoise_with_decomposition(im_array, method_=decompose_method, n_components=decompose_comp)
-
- flat_array = np.reshape(im_array, (a, (b * c)))
- init_cluster = methods[method](n_clusters=n_clusters_)
- init_cluster.fit(np.transpose(flat_array))
- X_cluster = init_cluster.labels_.reshape(b, c) + 1
-
- decon_spectra = np.zeros((a, n_clusters_))
- decon_images = np.zeros((n_clusters_, b, c))
-
- for i in range(n_clusters_):
- mask_i = np.where(X_cluster == (i + 1), X_cluster, 0)
- spec_i = get_sum_spectra(im_array * mask_i)
- decon_spectra[:, i] = spec_i
- decon_images[i] = im_array.sum(0) * mask_i
-
- return decon_images, X_cluster, decon_spectra
-
-
-def kmeans_variance(im_array):
- a, b, c = im_array.shape
- flat_array = np.reshape(im_array, (a, (b * c)))
- var = np.arange(24)
- clust_n = np.arange(24) + 2
-
- for clust in var:
- init_cluster = sc.KMeans(n_clusters=int(clust + 2))
- init_cluster.fit(np.transpose(flat_array))
- var_ = init_cluster.inertia_
- var[clust] = np.float64(var_)
-
- kmeans_var_plot = pg.plot(
- clust_n, var, title="KMeans Variance", pen=pg.mkPen("y", width=2, style=QtCore.Qt.DotLine), symbol="o"
- )
- kmeans_var_plot.setLabel("bottom", "Cluster Number")
- kmeans_var_plot.setLabel("left", "Sum of squared distances")
-
-
-def pca_scree(im_stack):
- new_image = im_stack.transpose(2, 1, 0)
- x, y, z = np.shape(new_image)
- img_ = np.reshape(new_image, (x * y, z))
- pca = sd.PCA(z)
- pca.fit(img_)
- # var = pca.explained_variance_ratio_
- var = pca.singular_values_
-
- pca_scree_plot = pg.plot(
- var[:24], title="PCA Scree Plot", pen=pg.mkPen("y", width=2, style=QtCore.Qt.DotLine), symbol="o"
- )
- pca_scree_plot.addLine(y=0)
- pca_scree_plot.setLabel("bottom", "Component Number")
- pca_scree_plot.setLabel("left", "Singular Values")
-
-
-def decompose_stack(im_stack, decompose_method="PCA", n_components_=3):
- new_image = im_stack.transpose(2, 1, 0)
- x, y, z = np.shape(new_image)
- img_ = np.reshape(new_image, (x * y, z))
- methods_dict = {
- "PCA": sd.PCA,
- "IncrementalPCA": sd.IncrementalPCA,
- "NMF": sd.NMF,
- "FastICA": sd.FastICA,
- "DictionaryLearning": sd.MiniBatchDictionaryLearning,
- "FactorAnalysis": sd.FactorAnalysis,
- "TruncatedSVD": sd.TruncatedSVD,
- }
-
- _mdl = methods_dict[decompose_method](n_components=n_components_)
-
- ims = (_mdl.fit_transform(img_).reshape(x, y, n_components_)).transpose(2, 1, 0)
- spcs = _mdl.components_.transpose()
- decon_spetra = np.zeros((z, n_components_))
- decom_map = np.zeros((ims.shape))
-
- for i in range(n_components_):
- f = ims.copy()[i]
- f[f < 0] = 0
- spec_i = ((new_image.T * f).sum(1)).sum(1)
- decon_spetra[:, i] = spec_i
-
- f[f > 0] = i + 1
- decom_map[i] = f
- decom_map = decom_map.sum(0)
-
- return np.float32(ims), spcs, decon_spetra, decom_map
-
-
-def denoise_with_decomposition(img_stack, method_="PCA", n_components=4):
- new_image = img_stack.transpose(2, 1, 0)
- x, y, z = np.shape(new_image)
- img_ = np.reshape(new_image, (x * y, z))
-
- methods_dict = {
- "PCA": sd.PCA,
- "IncrementalPCA": sd.IncrementalPCA,
- "NMF": sd.NMF,
- "FastICA": sd.FastICA,
- "DictionaryLearning": sd.DictionaryLearning,
- "FactorAnalysis": sd.FactorAnalysis,
- "TruncatedSVD": sd.TruncatedSVD,
- }
-
- decomposed = methods_dict[method_](n_components=n_components)
-
- ims = (decomposed.fit_transform(img_).reshape(x, y, n_components)).transpose(2, 1, 0)
- ims[ims < 0] = 0
- ims[ims > 0] = 1
- mask = ims.sum(0)
- mask[mask > 1] = 1
- # mask = uniform_filter(mask)
- filtered = img_stack * mask
- # plt.figure()
- # plt.imshow(filtered.sum(0))
- # plt.title('background removed')
- # plt.show()
- return remove_nan_inf(filtered)
-
-
-def interploate_E(refs, e):
- n = np.shape(refs)[1]
- refs = np.array(refs)
- ref_e = refs[:, 0]
- ref = refs[:, 1:n]
- all_ref = []
- for i in range(n - 1):
- ref_i = np.interp(e, ref_e, ref[:, i])
- all_ref.append(ref_i)
- return np.array(all_ref)
-
-
-def getStats(spec, fit, num_refs=2):
- stats = {}
-
- r_factor = (np.sum(spec - fit) ** 2) / np.sum(spec**2)
- stats["R_Factor"] = np.around(r_factor, 5)
-
- y_mean = np.sum(spec) / len(spec)
- SS_tot = np.sum((spec - y_mean) ** 2)
- SS_res = np.sum((spec - fit) ** 2)
- r_square = 1 - (SS_res / SS_tot)
- stats["R_Square"] = np.around(r_square, 4)
-
- chisq = np.sum((spec - fit) ** 2)
- stats["Chi_Square"] = np.around(chisq, 5)
-
- red_chisq = chisq / (len(spec) - num_refs)
- stats["Reduced Chi_Square"] = red_chisq
-
- return stats
-
-
-def xanes_fitting_1D(spec, e_list, refs, method="NNLS", alphaForLM=0.01):
- """Linear combination fit of image data with reference standards"""
-
- int_refs = interploate_E(refs, e_list)
-
- if method == "NNLS":
- coeffs, r = opt.nnls(int_refs.T, spec)
-
- elif method == "LASSO":
- lasso = linear_model.Lasso(positive=True, alpha=alphaForLM) # lowering alpha helps with 1D fits
- fit_results = lasso.fit(int_refs.T, spec)
- coeffs = fit_results.coef_
-
- elif method == "RIDGE":
- ridge = linear_model.Ridge(alpha=alphaForLM)
- fit_results = ridge.fit(int_refs.T, spec)
- coeffs = fit_results.coef_
-
- fit = coeffs @ int_refs
- stats = getStats(spec, fit, num_refs=np.min(np.shape(int_refs.T)))
-
- return stats, coeffs
-
-
-def xanes_fitting(im_stack, e_list, refs, method="NNLS", alphaForLM=0.1, binStack=False):
- """Linear combination fit of image data with reference standards"""
-
- if binStack:
- im_stack = resize_stack(im_stack, scaling_factor=4)
-
- en, im1, im2 = np.shape(im_stack)
- im_array = im_stack.reshape(en, im1 * im2)
- coeffs_arr = []
- r_factor_arr = []
- # lasso = linear_model.Lasso(positive=True, alpha=alphaForLM)
- for n, i in enumerate(range(im1 * im2)):
- stats, coeffs = xanes_fitting_1D(im_array[:, i], e_list, refs, method=method, alphaForLM=alphaForLM)
- coeffs_arr.append(coeffs)
- r_factor_arr.append(stats["R_Factor"])
-
- abundance_map = np.reshape(coeffs_arr, (im1, im2, -1))
- r_factor_im = np.reshape(r_factor_arr, (im1, im2))
-
- return abundance_map, r_factor_im, np.mean(coeffs_arr, axis=0)
-
-
-def xanes_fitting_Line(im_stack, e_list, refs, method="NNLS", alphaForLM=0.05):
- """Linear combination fit of image data with reference standards"""
- en, im1, im2 = np.shape(im_stack)
- im_array = np.mean(im_stack, 2)
- coeffs_arr = []
- meanStats = {"R_Factor": 0, "R_Square": 0, "Chi_Square": 0, "Reduced Chi_Square": 0}
-
- for i in range(im1):
- stats, coeffs = xanes_fitting_1D(im_array[:, i], e_list, refs, method=method, alphaForLM=alphaForLM)
- coeffs_arr.append(coeffs)
- for key in stats.keys():
- meanStats[key] += stats[key]
-
- for key, vals in meanStats.items():
- meanStats[key] = np.around((vals / im1), 5)
-
- return meanStats, np.mean(coeffs_arr, axis=0)
-
-
-def xanes_fitting_Binned(im_stack, e_list, refs, method="NNLS", alphaForLM=0.05):
- """Linear combination fit of image data with reference standards"""
-
- im_stack = resize_stack(im_stack, scaling_factor=10)
- # use a simple filter to find threshold value
- val = filters.threshold_otsu(im_stack[-1])
- en, im1, im2 = np.shape(im_stack)
- im_array = im_stack.reshape(en, im1 * im2)
- coeffs_arr = []
- meanStats = {"R_Factor": 0, "R_Square": 0, "Chi_Square": 0, "Reduced Chi_Square": 0}
-
- specs_fitted = 0
- total_spec = im1 * im2
- for i in range(total_spec):
- spec = im_array[:, i]
- # do not fit low intensity/background regions
- if spec[-1] > val:
- specs_fitted += 1
- stats, coeffs = xanes_fitting_1D(spec / spec[-1], e_list, refs, method=method, alphaForLM=alphaForLM)
- coeffs_arr.append(coeffs)
- for key in stats.keys():
- meanStats[key] += stats[key]
- else:
- pass
-
- for key, vals in meanStats.items():
- meanStats[key] = np.around((vals / specs_fitted), 6)
- # print(f"{specs_fitted}/{total_spec}")
- return meanStats, np.mean(coeffs_arr, axis=0)
-
-
-def create_df_from_nor(athenafile="fe_refs.nor"):
- """create pandas dataframe from athena nor file, first column
- is energy and headers are sample names"""
-
- refs = np.loadtxt(athenafile)
- n_refs = refs.shape[-1]
- skip_raw_n = n_refs + 6
-
- df = pd.read_table(
- athenafile, delim_whitespace=True, skiprows=skip_raw_n, header=None, usecols=np.arange(0, n_refs)
- )
- df2 = pd.read_table(
- athenafile, delim_whitespace=True, skiprows=skip_raw_n - 1, usecols=np.arange(0, n_refs + 1)
- )
- new_col = df2.columns.drop("#")
- df.columns = new_col
- return df, list(new_col)
-
-
-def create_df_from_nor_try2(athenafile="fe_refs.nor"):
- """create pandas dataframe from athena nor file, first column
- is energy and headers are sample names"""
-
- refs = np.loadtxt(athenafile)
- n_refs = refs.shape[-1]
- df_refs = pd.DataFrame(refs)
-
- df = pd.read_csv(athenafile, header=None)
- new_col = list((str(df.iloc[n_refs + 5].values)).split(" ")[2::2])
- df_refs.columns = new_col
-
- return df_refs, list(new_col)
-
-
-def energy_from_logfile(logfile="maps_log_tiff.txt"):
- df = pd.read_csv(logfile, header=None, delim_whitespace=True, skiprows=9)
- return df[9][df[7] == "energy"].values.astype(float)
-
-
-def xanesNormalization(
- e, mu, e0=7125, step=None, nnorm=2, nvict=0, pre1=None, pre2=-50, norm1=100, norm2=None, guess=False
-):
- if guess:
- result = preedge(e, mu, e0, step=step, nnorm=nnorm, nvict=nvict)
-
- return result["pre1"], result["pre2"], result["norm1"], result["norm2"]
-
- else:
- result = preedge(e, mu, e0, step, nnorm, nvict, pre1, pre2, norm1, norm2)
-
- return result["pre_edge"], result["post_edge"], result["norm"]
-
-
-def xanesNormStack(
- e_list, im_stack, e0=7125, step=None, nnorm=2, nvict=0, pre1=None, pre2=-50, norm1=100, norm2=None
-):
-
- en, im1, im2 = np.shape(im_stack)
- im_array = im_stack.reshape(en, im1 * im2)
- normedStackArray = np.zeros_like(im_array)
-
- for i in range(im1 * im2):
- pre_line, post_line, normXANES = xanesNormalization(
- e_list,
- im_array[:, i],
- e0=e0,
- step=step,
- nnorm=nnorm,
- nvict=nvict,
- pre1=pre1,
- pre2=pre2,
- norm1=norm1,
- norm2=norm2,
- guess=False,
- )
- normedStackArray[:, i] = normXANES
-
- return remove_nan_inf(np.reshape(normedStackArray, (en, im1, im2)))
-
-
-def align_stack(
- stack_img, ref_image_void=True, ref_stack=None, transformation=StackReg.TRANSLATION, reference="previous"
-):
-
- """Image registration flow using pystack reg"""
-
- # all the options are in one function
-
- sr = StackReg(transformation)
-
- if ref_image_void:
- tmats_ = sr.register_stack(stack_img, reference=reference)
-
- else:
- tmats_ = sr.register_stack(ref_stack, reference=reference)
- # out_ref = sr.transform_stack(ref_stack)
-
- out_stk = sr.transform_stack(stack_img, tmats=tmats_)
- return np.float32(out_stk), tmats_
-
-
-def align_simple(stack_img, transformation=StackReg.TRANSLATION, reference="previous"):
-
- sr = StackReg(transformation)
- tmats_ = sr.register_stack(stack_img, reference="previous")
- for i in range(10):
- out_stk = sr.transform_stack(stack_img, tmats=tmats_)
- import time
-
- time.sleep(2)
- return np.float32(out_stk)
-
-
-def align_with_tmat(stack_img, tmat_file, transformation=StackReg.TRANSLATION):
-
- sr = StackReg(transformation)
- out_stk = sr.transform_stack(stack_img, tmats=tmat_file)
- return np.float32(out_stk)
-
-
-def align_stack_iter(
- stack,
- ref_stack_void=True,
- ref_stack=None,
- transformation=StackReg.TRANSLATION,
- method=("previous", "first"),
- max_iter=2,
-):
- if ref_stack_void:
- ref_stack = stack
-
- for i in range(max_iter):
- sr = StackReg(transformation)
- for ii in range(len(method)):
- print(ii, method[ii])
- tmats = sr.register_stack(ref_stack, reference=method[ii])
- ref_stack = sr.transform_stack(ref_stack)
- stack = sr.transform_stack(stack, tmats=tmats)
-
- return np.float32(stack)
-
-
-def applyMaskGetMeanSpectrum(im_stack, mask):
- """A 2d mask to multiply with the 3d xanes stack and returns mean spectrum"""
-
- masked_stack = im_stack * mask
- return get_mean_spectra(masked_stack)
-
-
-def modifyStack(
- raw_stack,
- normalizeStack=False,
- normToPoint=-1,
- applySmooth=False,
- smoothWindowSize=3,
- applyThreshold=False,
- thresholdValue=0,
- removeOutliers=False,
- nSigmaOutlier=3,
- applyTranspose=False,
- transposeVals=(0, 1, 2),
- applyCrop=False,
- cropVals=(0, 1, 2),
- removeEdges=False,
- resizeStack=False,
- upScaling=False,
- binFactor=2,
-):
-
- """A giant function to modify the stack with many possible operations.
- all the changes can be saved to a jason file as a config file. Enabling and
- distabling the sliders is a problem"""
-
- """
- normStack = normalize(raw_stack, norm_point=normToPoint)
- smoothStack = smoothen(raw_stack, w_size= smoothWindowSize)
- thresholdStack = clean_stack(raw_stack, auto_bg=False, bg_percentage = thresholdValue)
- outlierStack = remove_hot_pixels(raw_stack, NSigma=nSigmaOutlier)
- transposeStack = np.transpose(raw_stack, transposeVals)
- croppedStack = raw_stack[cropVals]
- edgeStack = remove_edges(raw_stack)
- binnedStack = resize_stack(raw_stack,upscaling=upScaling,scaling_factor=binFactor)
-
- """
-
- if removeOutliers:
- modStack = remove_hot_pixels(raw_stack, NSigma=nSigmaOutlier)
-
- else:
- modStack = raw_stack
-
- if applyThreshold:
- modStack = clean_stack(modStack, auto_bg=False, bg_percentage=thresholdValue)
-
- else:
- pass
-
- if applySmooth:
- modStack = smoothen(modStack, w_size=smoothWindowSize)
-
- else:
- pass
-
- if applyTranspose:
- modStack = np.transpose(modStack, transposeVals)
-
- else:
- pass
-
- if applyCrop:
- modStack = modStack[cropVals]
-
- else:
- pass
-
- if normalizeStack:
- modStack = normalize(raw_stack, norm_point=normToPoint)
- else:
- pass
-
-
-def start_xmidas():
- def formatter(prog):
- # Set maximum width such that printed help mostly fits in the RTD theme code block (documentation).
- return argparse.RawDescriptionHelpFormatter(prog, max_help_position=20, width=90)
-
- parser = argparse.ArgumentParser(
- description=f"XMidas: v{__version__}",
- formatter_class=formatter,
- )
- parser.parse_args()
-
- logger.setLevel(logging.INFO)
- formatter = logging.Formatter(fmt="%(asctime)s : %(levelname)s : %(message)s")
- stream_handler = logging.StreamHandler()
- stream_handler.setFormatter(formatter)
- stream_handler.setLevel(logging.INFO)
- if logger.hasHandlers():
- logger.handlers.clear()
- logger.addHandler(stream_handler)
-
- if version.parse(PYQT_VERSION_STR) >= version.parse("5.14"):
- QApplication.setAttribute(QtCore.Qt.HighDpiScaleFactorRoundingPolicy.PassThrough)
-
- app = QtWidgets.QApplication(sys.argv)
- # app.setAttribute(QtCore.Qt.AA_Use96Dpi)
- window = midasWindow()
- window.show()
- sys.exit(app.exec_())
-
-
-if __name__ == "__main__":
- start_xmidas()
+# -*- coding: utf-8 -*-
+
+# Author: Ajith Pattammattel
+# First Version on:06-23-2020
+
+import argparse
+import logging
+import sys
+import webbrowser
+import traceback
+import os
+import json
+import scipy.stats as stats
+import numpy as np
+import pandas as pd
+import tifffile as tf
+import pyqtgraph as pg
+import pyqtgraph.exporters
+from glob import glob
+from pyqtgraph import plot
+from itertools import combinations
+from scipy.stats import linregress
+from packaging import version
+
+from PyQt5 import QtWidgets, QtCore, QtGui, uic, QtTest
+from PyQt5.QtGui import QMovie
+from PyQt5.QtWidgets import QMessageBox, QFileDialog, QApplication
+from PyQt5.QtCore import QObject, pyqtSignal, pyqtSlot, QRunnable, QThreadPool, PYQT_VERSION_STR
+
+from utils import *
+
+#from . import __version__
+
+logger = logging.getLogger()
+try:
+ import cv2 # noqa: F401
+except Exception:
+ logger.warning("openCV module not found")
+ pass
+if hasattr(QtCore.Qt, "AA_EnableHighDpiScaling"):
+ QtWidgets.QApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling, True)
+
+if hasattr(QtCore.Qt, "AA_UseHighDpiPixmaps"):
+ QtWidgets.QApplication.setAttribute(QtCore.Qt.AA_UseHighDpiPixmaps, True)
+
+ui_path = os.path.dirname(os.path.abspath(__file__))
+
+# global settings for pyqtgraph plot and image colormaps
+pg.setConfigOption("imageAxisOrder", "row-major")
+cmap_names = ["CET-L13", "CET-L14", "CET-L15"]
+cmap_combo = combinations(cmap_names, 2)
+cmap_label1 = ["red", "green", "blue"]
+cmap_label2 = ["yellow", "magenta", "cyan"]
+cmap_dict = {}
+for i, name in zip(cmap_names, cmap_label1):
+ cmap_dict[name] = pg.colormap.get(i).getLookupTable(alpha=True)
+
+for i, name in zip(cmap_combo, cmap_label2):
+ cmap_dict[name] = pg.colormap.get(i[0]).getLookupTable(alpha=True) + pg.colormap.get(i[1]).getLookupTable(
+ alpha=True
+ )
+ cmap_dict[name][:, 3] = 255
+
+ grey = (
+ pg.colormap.get("CET-L13").getLookupTable(alpha=True)
+ + pg.colormap.get("CET-L14").getLookupTable(alpha=True)
+ + pg.colormap.get("CET-L15").getLookupTable(alpha=True)
+ )
+
+ grey[:, 3] = 255
+ cmap_dict["grey"] = grey
+
+
+class jsonEncoder(json.JSONEncoder):
+ def default(self, obj):
+ if isinstance(obj, np.integer):
+ return int(obj)
+ elif isinstance(obj, np.floating):
+ return float(obj)
+ elif isinstance(obj, np.ndarray):
+ return obj.tolist()
+ else:
+ return super(jsonEncoder, self).default(obj)
+
+
+class midasWindow(QtWidgets.QMainWindow):
+ def __init__(self, im_stack=None, energy=[], refs=[]):
+ super(midasWindow, self).__init__()
+ uic.loadUi(os.path.join(ui_path, "uis/midasMainwindow.ui"), self)
+ self.im_stack = im_stack
+ self.energy = energy
+ self.refs = refs
+ self.loaded_tranform_file = []
+ self.image_roi2_flag = False
+ self.refStackAvailable = False
+ self.isAReload = False
+ self.plotWidth = 2
+ self.stackStatusDict = {}
+
+ self.user_wd = os.path.expanduser("~")
+ # self.user_config_path = os.path.join(ui_path,"user_config.json")
+
+ # if not os.path.exists(self.user_config_path):
+
+ # with open(f"{self.user_config_path}", "w") as fp:
+ # json.dump(self.user_config, fp, indent=4)
+
+ self.plt_colors = [
+ "g",
+ "r",
+ "c",
+ "m",
+ "y",
+ "w",
+ "b",
+ pg.mkPen(70, 5, 80),
+ pg.mkPen(255, 85, 130),
+ pg.mkPen(0, 85, 130),
+ pg.mkPen(255, 170, 60),
+ ] * 3
+ # window style
+ self.actionDarkMode.triggered.connect(self.darkMode)
+ self.actionDefault.triggered.connect(self.defaultMode)
+ self.actionModern.triggered.connect(self.modernMode)
+
+ # self.setToolTipsVisible(True)
+ for menuItem in self.findChildren(QtWidgets.QMenu):
+ menuItem.setToolTipsVisible(True)
+
+ # plotview options
+ self.actionWhite.triggered.connect(lambda: self.spectrum_view.setBackground("w"))
+ self.actionRed.triggered.connect(lambda: self.spectrum_view.setBackground("r"))
+ self.actionYellow.triggered.connect(lambda: self.spectrum_view.setBackground("y"))
+ self.actionBlue.triggered.connect(lambda: self.spectrum_view.setBackground("b"))
+ self.actionBlack.triggered.connect(lambda: self.spectrum_view.setBackground((0, 0, 0)))
+
+ self.actn1.triggered.connect(lambda: self.setPlotLineWidth(int(self.actn1.text())))
+ self.actn2.triggered.connect(lambda: self.setPlotLineWidth(int(self.actn2.text())))
+ self.actn3.triggered.connect(lambda: self.setPlotLineWidth(int(self.actn3.text())))
+ self.actn4.triggered.connect(lambda: self.setPlotLineWidth(int(self.actn4.text())))
+ self.actn5.triggered.connect(lambda: self.setPlotLineWidth(int(self.actn5.text())))
+ self.actn6.triggered.connect(lambda: self.setPlotLineWidth(int(self.actn6.text())))
+ self.actn8.triggered.connect(lambda: self.setPlotLineWidth(int(self.actn8.text())))
+ self.actn10.triggered.connect(lambda: self.setPlotLineWidth(int(self.actn10.text())))
+
+ self.actionOpen_Image_Data.triggered.connect(self.browse_file)
+ self.actionOpen_Multiple_Files.triggered.connect(self.createVirtualStack)
+ self.actionSave_as.triggered.connect(lambda: self.save_stack())
+ self.actionExit.triggered.connect(lambda: QApplication.closeAllWindows())
+ self.actionOpen_in_GitHub.triggered.connect(self.open_github_link)
+ self.actionLoad_Energy.triggered.connect(self.select_elist)
+ self.menuFile.setToolTipsVisible(True)
+
+ # Accessories
+ self.actionOpen_Mask_Gen.triggered.connect(self.openMaskMaker)
+ self.actionMultiColor.triggered.connect(self.openMultiColorWindow)
+
+ # calculations
+ self.pb_transpose_stack.clicked.connect(lambda: self.threadMaker(self.transposeStack))
+ self.pb_swapXY_stack.clicked.connect(lambda: self.threadMaker(self.swapStackXY))
+ self.pb_reset_img.clicked.connect(self.reloadImageStack)
+ self.pb_crop.clicked.connect(self.crop_to_dim)
+ self.pb_apply_crop_to_all.clicked.connect(self.apply_crop_to_all)
+ self.pb_crop.clicked.connect(self.view_stack)
+ self.sb_scaling_factor.valueChanged.connect(self.view_stack)
+ self.pb_ref_xanes.clicked.connect(self.select_ref_file)
+ self.pb_elist_xanes.clicked.connect(self.select_elist)
+
+ # batchjobs
+ self.actionPlotAllCorrelations.triggered.connect(self.plotCorrelationsAllCombinations)
+
+ [
+ uis.valueChanged.connect(self.replot_image)
+ for uis in [self.hs_smooth_size, self.hs_nsigma, self.hs_bg_threshold]
+ ]
+
+ [
+ uis.stateChanged.connect(self.replot_image)
+ for uis in [self.cb_remove_bg, self.cb_remove_outliers, self.cb_smooth, self.cb_norm, self.cb_log]
+ ]
+
+ [
+ uis.stateChanged.connect(self.view_stack)
+ for uis in [self.cb_remove_edges, self.cb_upscale, self.cb_rebin]
+ ]
+
+ # ToolBar
+ self.actionStack_Info.triggered.connect(self.displayStackInfo)
+ self.actionSave_Image.triggered.connect(self.save_disp_img)
+ self.actionExport_Stack.triggered.connect(lambda: self.save_stack())
+
+ # ROI background
+ self.actionSubtract_ROI_BG.triggered.connect(lambda: self.threadMaker(self.removeROIBGStack))
+
+ # alignment
+ self.pb_load_align_ref.clicked.connect(self.loadAlignRefImage)
+ self.pb_loadAlignTranform.clicked.connect(self.importAlignTransformation)
+ self.pb_saveAlignTranform.clicked.connect(self.exportAlignTransformation)
+ self.pb_alignStack.clicked.connect(lambda: self.threadMaker(self.stackRegistration))
+ # self.pb_alignStack.clicked.connect(self.stackRegistration)
+
+ # save_options
+ self.actionSave_Sum_Image.triggered.connect(lambda: self.save_stack(method="sum"))
+ self.actionSave_Mean_Image.triggered.connect(lambda: self.save_stack(method="mean"))
+ self.actionExport_Image_to_CSV.triggered.connect(self.stackToCSV)
+ self.pb_save_disp_spec.clicked.connect(self.save_disp_spec)
+ self.actionSave_Energy_List.triggered.connect(self.saveEnergyList)
+ self.pb_show_roi.clicked.connect(self.getROIMask)
+ self.pb_addToCollector.clicked.connect(self.addSpectrumToCollector)
+ self.pb_collect_clear.clicked.connect(lambda: self.spectrum_view_collect.clear())
+ self.pb_saveCollectorPlot.clicked.connect(self.saveCollectorPlot)
+
+ # XANES Normalization
+ self.pb_apply_xanes_norm.clicked.connect(self.nomalizeLiveSpec)
+ self.pb_auto_Eo.clicked.connect(self.findEo)
+ self.pb_xanes_norm_vals.clicked.connect(self.initNormVals)
+ self.pb_apply_norm_to_stack.clicked.connect(lambda: self.threadMaker(self.normalizeStack))
+ self.actionExport_Norm_Params.triggered.connect(self.exportNormParams)
+ self.actionImport_Norm_Params.triggered.connect(self.importNormParams)
+
+ # Analysis
+ self.pb_pca_scree.clicked.connect(self.pca_scree_)
+ self.pb_calc_components.clicked.connect(self.calc_comp_)
+ self.pb_kmeans_elbow.clicked.connect(self.kmeans_elbow)
+ self.pb_calc_cluster.clicked.connect(self.clustering_)
+ self.pb_xanes_fit.clicked.connect(self.fast_xanes_fitting)
+ self.pb_plot_refs.clicked.connect(self.plt_xanes_refs)
+
+ self.show()
+
+ self.threadpool = QThreadPool()
+ print(f"Multithreading with maximum {self.threadpool.maxThreadCount()} threads")
+
+ # View Options
+ def darkMode(self):
+ self.centralwidget.setStyleSheet(open(os.path.join(ui_path, "css/darkStyle.css")).read())
+
+ def defaultMode(self):
+ self.centralwidget.setStyleSheet(open(os.path.join(ui_path, "css/defaultStyle.css")).read())
+
+ def modernMode(self):
+ self.centralwidget.setStyleSheet(open(os.path.join(ui_path, "css/modern.css")).read())
+
+ def setPlotLineWidth(self, width_input):
+ self.plotWidth = width_input
+ try:
+ self.update_spectrum()
+ except Exception:
+ pass
+
+ def openMultiColorWindow(self):
+ self.multicolorwindow = MultiChannelWindow()
+ self.multicolorwindow.show()
+
+ def openMaskMaker(self):
+ self.mask_window = MaskSpecViewer(xanes_stack=self.displayedStack, energy=self.energy)
+ self.mask_window.show()
+
+ def open_github_link(self):
+ webbrowser.open("https://github.com/pattammattel/NSLS-II-MIDAS/wiki")
+
+ def threadMaker(self, funct):
+ # Pass the function to execute
+ worker = Worker(funct) # Any other args, kwargs are passed to the run function
+ self.loadSplashScreen()
+ worker.signals.start.connect(self.splash.startAnimation)
+ worker.signals.result.connect(self.print_output)
+
+ list(
+ map(
+ worker.signals.finished.connect,
+ [
+ self.thread_complete,
+ self.splash.stopAnimation,
+ self.update_stack_info,
+ self.update_spectrum,
+ self.update_image_roi,
+ self.setImageROI
+ ],
+ )
+ )
+
+ # Execute
+ self.threadpool.start(worker)
+
+
+ # File Loading
+
+ def createVirtualStack(self):
+ """User can load multiple/series of tiff images with same shape.
+ The 'self.load_stack()' recognizes 'self.filename as list and create the stack.
+ """
+ self.energy = []
+ filter = "TIFF (*.tiff);;TIF (*.tif);;all_files (*)"
+ file_name = QFileDialog()
+ file_name.setFileMode(QFileDialog.ExistingFiles)
+ names = file_name.getOpenFileNames(self, "Open files", self.user_wd, filter)
+ if names[0]:
+
+ self.file_name = names[0]
+ self.user_wd = os.path.dirname(self.file_name)
+ self.load_stack()
+
+ else:
+ self.statusbar_main.showMessage("No file has selected")
+ pass
+
+ def load_stack(self):
+
+ """load the image data from the selected file.
+ If the the choice is for multiple files stack will be created in a loop.
+ If single h5 file is selected the unpacking will be done with 'get_xrf_data' function in StackCalcs.
+ From the h5 the program can recognize the beamline. The exported stack will be normalized to I0.
+
+ If the single tiff file is choosen tf.imread() is used.
+
+ The output 'self.im_stack' is the unmodified data file
+ """
+
+ self.log_warning = False # for the Qmessage box in cb_log
+ self.image_roi2_flag = False
+ self.cb_log.setChecked(False)
+ self.cb_remove_edges.setChecked(False)
+ self.cb_norm.setChecked(False)
+ self.cb_smooth.setChecked(False)
+ self.cb_remove_outliers.setChecked(False)
+ self.cb_remove_bg.setChecked(False)
+ self.cb_rebin.setChecked(False)
+ self.cb_upscale.setChecked(False)
+ self.sb_xrange1.setValue(0)
+ self.sb_yrange1.setValue(0)
+ self.sb_zrange1.setValue(0)
+
+ self.menuMask.setEnabled(True)
+ self.actionLoad_Energy.setEnabled(True)
+ self.actionSave_Energy_List.setEnabled(True)
+ self.actionSave_as.setEnabled(True)
+
+ self.sb_zrange2.setMaximum(99999)
+ self.sb_xrange2.setMaximum(99999)
+ self.sb_yrange2.setMaximum(99999)
+
+ self.statusbar_main.showMessage("Loading.. please wait...")
+
+ if isinstance(self.file_name, list):
+
+ all_images = []
+
+ for im_file in self.file_name:
+ img = tf.imread(im_file)
+ all_images.append(img) # row major image
+ self.im_stack = np.dstack(all_images).transpose((2, 0, 1))
+ self.avgIo = 1 # I0 is only applicable to XRF h5 files
+ self.sb_zrange2.setValue(self.im_stack.shape[0])
+
+ else:
+
+ if self.file_name.endswith(".h5"):
+ self.im_stack, mono_e, bl_name, self.avgIo = get_xrf_data(self.file_name)
+ self.statusbar_main.showMessage(f"Data from {bl_name}")
+ self.sb_zrange2.setValue(mono_e / 10)
+ self.energy = []
+
+ elif self.file_name.endswith(".tiff") or self.file_name.endswith(".tif"):
+ self.im_stack_ = tf.imread(self.file_name)
+ if self.im_stack_.ndim == 2:
+ self.im_stack = self.im_stack_.reshape(1, self.im_stack_.shape[0], self.im_stack_.shape[1])
+
+ else:
+ self.im_stack = self.im_stack_
+ self.sb_zrange2.setValue(self.im_stack.shape[0])
+ self.autoEnergyLoader()
+ self.energyUnitCheck()
+ self.avgIo = 1
+
+ else:
+ logger.error("Unknown data format")
+
+ """ Fill the stack dimensions to the GUI and set the image dimensions as max values.
+ This prevent user from choosing higher image dimensions during a resizing event"""
+
+ logger.info(f" loaded stack with {np.shape(self.im_stack)} from the file")
+
+ try:
+ logger.info(f" Transposed to shape: {np.shape(self.im_stack)}")
+ self.init_dimZ, self.init_dimY, self.init_dimX = self.im_stack.shape
+ # Remove any previously set max value during a reload
+
+ self.sb_xrange2.setValue(self.init_dimX)
+ self.sb_yrange2.setValue(self.init_dimY)
+
+ except UnboundLocalError:
+ logger.error("No file selected")
+ pass
+
+ self.view_stack()
+ logger.info("Stack displayed correctly")
+ self.update_stack_info()
+
+ logger.info(f"completed image shape {np.shape(self.im_stack)}")
+
+ try:
+ self.statusbar_main.showMessage(f"Loaded: {self.file_name}")
+
+ except AttributeError:
+ self.statusbar_main.showMessage("New Stack is made from selected tiffs")
+ pass
+
+ def browse_file(self):
+ """To open a file widow and choose the data file.
+ The filename will be used to load data using 'rest and load stack' function"""
+
+ filename = QFileDialog().getOpenFileName(
+ self, "Select image data", self.user_wd, "image file(*.hdf *.h5 *tiff *tif )"
+ )
+ self.file_name = str(filename[0])
+ self.user_wd = os.path.dirname(self.file_name)
+
+ # if user decides to cancel the file window gui returns to original state
+ if self.file_name:
+ self.disconnectImageActions()
+ self.isAReload = False
+ self.load_stack()
+
+ else:
+ self.statusbar_main.showMessage("No file has selected")
+ pass
+
+ def autoEnergyLoader(self):
+
+ dir_, filename_ = os.path.split(self.file_name)
+ self.efilePath_name = os.path.join(dir_, os.path.splitext(filename_)[0] + ".txt")
+ self.efilePath_log = os.path.join(dir_, "maps_log_tiff.txt")
+
+ if os.path.isfile(self.efilePath_name):
+ self.efilePath = self.efilePath_name
+ self.efileLoader()
+ self.statusbar_main.showMessage(f"Energy File detected {self.efilePath}")
+
+ elif os.path.isfile(self.efilePath_log):
+ self.efilePath = self.efilePath_log
+ self.efileLoader()
+ self.statusbar_main.showMessage(f"Energy File detected {self.efilePath}")
+
+ else:
+ self.efilePath = False
+ self.efileLoader()
+
+ def update_stack_info(self):
+ z, y, x = np.shape(self.displayedStack)
+ self.sb_zrange2.setMaximum(z + self.sb_zrange1.value())
+ self.sb_xrange2.setValue(x)
+ self.sb_xrange2.setMaximum(x)
+ self.sb_yrange2.setValue(y)
+ self.sb_yrange2.setMaximum(y)
+ logger.info("Stack info has been updated")
+
+ # Image Transformations
+
+ def crop_to_dim(self):
+ self.x1, self.x2 = self.sb_xrange1.value(), self.sb_xrange2.value()
+ self.y1, self.y2 = self.sb_yrange1.value(), self.sb_yrange2.value()
+ self.z1, self.z2 = self.sb_zrange1.value(), self.sb_zrange2.value()
+
+ try:
+ self.displayedStack = remove_nan_inf(
+ self.displayedStack[self.z1 : self.z2, self.y1 : self.y2, self.x1 : self.x2]
+ )
+ except Exception:
+ self.displayedStack = remove_nan_inf(
+ self.im_stack[self.z1 : self.z2, self.y1 : self.y2, self.x1 : self.x2]
+ )
+
+ def apply_crop_to_all(self):
+ dir_ = os.path.dirname(self.file_name)
+ tiffs = glob(dir_+"/*.tiff")
+
+ self.x1, self.x2 = self.sb_xrange1.value(), self.sb_xrange2.value()
+ self.y1, self.y2 = self.sb_yrange1.value(), self.sb_yrange2.value()
+ self.z1, self.z2 = self.sb_zrange1.value(), self.sb_zrange2.value()
+
+ print(tiffs)
+
+ for fname in tiffs:
+ print(fname)
+ im_array = tf.imread(fname)
+ im_name = os.path.join(dir_,os.path.basename(fname).split('.')[0]+"_cropped.tiff")
+ if np.ndim(im_array) == 3:
+ tf.imwrite(im_name, im_array[self.z1 : self.z2, self.y1 : self.y2, self.x1 : self.x2])
+ logger.info(f"{im_name} saved")
+ elif np.ndim(im_array) == 2:
+ tf.imwrite(im_name, im_array[self.y1 : self.y2, self.x1 : self.x2])
+ logger.info(f"{im_name} saved")
+
+ else:
+ pass
+
+
+ def transpose_stack(self):
+ self.displayedStack = self.displayedStack.T
+ self.update_spectrum()
+ self.update_spec_image_roi()
+
+ # Alignement
+
+ def loadAlignRefImage(self):
+ filename = QFileDialog().getOpenFileName(self, "Image Data", self.user_wd, "*.tiff *.tif")
+ file_name = str(filename[0])
+ self.user_wd = os.path.dirname(file_name)
+ self.alignRefImage = tf.imread(file_name)
+ assert self.alignRefImage.shape == self.displayedStack.shape, "Image dimensions do not match"
+ self.refStackAvailable = True
+ self.rb_alignRefVoid.setChecked(False)
+ self.change_color_on_load(self.pb_load_align_ref)
+
+ def stackRegistration(self):
+
+ self.transformations = {
+ "TRANSLATION": StackReg.TRANSLATION,
+ "RIGID_BODY": StackReg.RIGID_BODY,
+ "SCALED_ROTATION": StackReg.SCALED_ROTATION,
+ "AFFINE": StackReg.AFFINE,
+ "BILINEAR": StackReg.BILINEAR,
+ }
+
+ self.transformType = self.transformations[self.cb_alignTransform.currentText()]
+ self.alignReferenceImage = self.cb_alignRef.currentText()
+ self.alignRefStackVoid = self.rb_alignRefVoid.isChecked()
+ self.alignMaxIter = self.sb_maxIterVal.value()
+
+ if self.cb_use_tmatFile.isChecked():
+
+ if len(self.loaded_tranform_file) > 0:
+
+ self.displayedStack = align_with_tmat(
+ self.displayedStack, tmat_file=self.loaded_tranform_file, transformation=self.transformType
+ )
+ logger.info("Aligned to the tranform File")
+
+ else:
+ logger.error("No Tranformation File Loaded")
+
+ elif self.cb_iterAlign.isChecked():
+
+ if not self.refStackAvailable:
+ self.alignRefImage = self.displayedStack
+ else:
+ pass
+
+ self.displayedStack = align_stack_iter(
+ self.displayedStack,
+ ref_stack_void=False,
+ ref_stack=self.alignRefImage,
+ transformation=self.transformType,
+ method=("previous", "first"),
+ max_iter=self.alignMaxIter,
+ )
+
+ else:
+ if not self.refStackAvailable:
+ self.alignRefImage = self.displayedStack
+
+ else:
+ pass
+
+ self.displayedStack, self.tranform_file = align_stack(
+ self.displayedStack,
+ ref_image_void=True,
+ ref_stack=self.alignRefImage,
+ transformation=self.transformType,
+ reference=self.alignReferenceImage,
+ )
+ logger.info("New Tranformation file available")
+ self.im_stack = self.displayedStack
+
+ def exportAlignTransformation(self):
+
+
+
+ file_name = QFileDialog().getSaveFileName(
+ self,
+ "Save Transformation File",
+ os.path.join(self.user_wd,"TranformationMatrix.npy"),
+ "text file (*.npy)"
+ )
+ if file_name[0]:
+ np.save(file_name[0], self.tranform_file)
+ self.user_wd = os.path.dirname(file_name[0])
+ else:
+ pass
+
+ def importAlignTransformation(self):
+ file_name = QFileDialog().getOpenFileName(self, "Open Transformation File", self.user_wd, "text file (*.npy)")
+ if file_name[0]:
+ self.loaded_tranform_file = np.load(file_name[0])
+ self.cb_use_tmatFile.setChecked(True)
+ self.user_wd = os.path.dirname(file_name[0])
+ logger.info("Transformation File Loaded")
+ else:
+ pass
+
+ def loadSplashScreen(self):
+ self.splash = LoadingScreen()
+
+ px = self.geometry().x()
+ py = self.geometry().y()
+ ph = self.geometry().height()
+ pw = self.geometry().width()
+ dw = self.splash.width()
+ dh = self.splash.height()
+ new_x, new_y = px + (0.5 * pw) - dw, py + (0.5 * ph) - dh
+ self.splash.setGeometry(int(new_x), int(new_y), int(dw), int(dh))
+
+ self.splash.show()
+
+ def reloadImageStack(self):
+ self.isAReload = True
+ self.load_stack()
+
+ def update_stack(self):
+ self.displayedStack = self.im_stack
+ self.crop_to_dim()
+
+ if self.cb_rebin.isChecked():
+ self.cb_upscale.setChecked(False)
+ self.sb_scaling_factor.setEnabled(True)
+ self.displayedStack = resize_stack(self.displayedStack, scaling_factor=self.sb_scaling_factor.value())
+ self.update_stack_info()
+
+ elif self.cb_upscale.isChecked():
+ self.cb_rebin.setChecked(False)
+ self.sb_scaling_factor.setEnabled(True)
+ self.displayedStack = resize_stack(
+ self.displayedStack, upscaling=True, scaling_factor=self.sb_scaling_factor.value()
+ )
+ self.update_stack_info()
+
+ if self.cb_remove_outliers.isChecked():
+ self.hs_nsigma.setEnabled(True)
+ nsigma = self.hs_nsigma.value() / 10
+ self.displayedStack = remove_hot_pixels(self.displayedStack, NSigma=nsigma)
+ self.label_nsigma.setText(str(nsigma))
+ logger.info(f"Removing Outliers with NSigma {nsigma}")
+
+ elif self.cb_remove_outliers.isChecked() is False:
+ self.hs_nsigma.setEnabled(False)
+
+ if self.cb_remove_edges.isChecked():
+ self.displayedStack = remove_edges(self.displayedStack)
+ logger.info(f"Removed edges, new shape {self.displayedStack.shape}")
+ self.update_stack_info()
+
+ if self.cb_remove_bg.isChecked():
+ self.hs_bg_threshold.setEnabled(True)
+ logger.info("Removing background")
+ bg_threshold = self.hs_bg_threshold.value()
+ self.label_bg_threshold.setText(str(bg_threshold) + "%")
+ self.displayedStack = clean_stack(self.displayedStack, auto_bg=False, bg_percentage=bg_threshold)
+
+ elif self.cb_remove_bg.isChecked() is False:
+ self.hs_bg_threshold.setEnabled(False)
+
+ if self.cb_log.isChecked():
+
+ self.displayedStack = remove_nan_inf(np.log10(self.displayedStack))
+ logger.info("Log Stack is in use")
+
+ if self.cb_smooth.isChecked():
+ self.hs_smooth_size.setEnabled(True)
+ window = self.hs_smooth_size.value()
+ if window % 2 == 0:
+ window = +1
+ self.smooth_winow_size.setText("Window size: " + str(window))
+ self.displayedStack = smoothen(self.displayedStack, w_size=window)
+ logger.info("Spectrum Smoothening Applied")
+
+ elif self.cb_smooth.isChecked() is False:
+ self.hs_smooth_size.setEnabled(False)
+
+ if self.cb_norm.isChecked():
+ logger.info("Normalizing spectra")
+ self.displayedStack = normalize(self.displayedStack, norm_point=-1)
+
+ logger.info("Updated image is in use")
+
+ # ImageView
+
+ def view_stack(self):
+
+ if not self.im_stack.ndim == 3:
+ raise ValueError("stack should be an ndarray with ndim == 3")
+ else:
+ self.update_stack()
+ # self.StackUpdateThread()
+
+ try:
+ self.image_view.removeItem(self.image_roi_math)
+ except Exception:
+ pass
+
+ (self.dim1, self.dim2, self.dim3) = self.displayedStack.shape
+ self.image_view.setImage(self.displayedStack)
+ self.image_view.ui.menuBtn.hide()
+ self.image_view.ui.roiBtn.hide()
+ self.image_view.setPredefinedGradient("viridis")
+ self.image_view.setCurrentIndex(self.dim1 // 2)
+ if len(self.energy) == 0:
+ self.energy = np.arange(self.z1, self.z2) * 10
+ logger.info("Arbitary X-axis used in the plot for XANES")
+ self.sz = np.max(
+ [int(self.dim2 * 0.1), int(self.dim3 * 0.1)]
+ ) # size of the roi set to be 10% of the image area
+
+ self.stack_center = self.energy[len(self.energy) // 2]
+ self.stack_width = (self.energy.max() - self.energy.min()) // 10
+ self.spec_roi = pg.LinearRegionItem(
+ values=(self.stack_center - self.stack_width, self.stack_center + self.stack_width)
+ )
+
+ # a second optional ROI for calculations follow
+ self.image_roi_math = pg.PolyLineROI(
+ [[0, 0], [0, self.sz], [self.sz, self.sz], [self.sz, 0]],
+ pos=(int(self.dim3 // 3), int(self.dim2 // 3)),
+ pen="r",
+ closed=True,
+ removable=True,
+ )
+
+ self.spec_roi_math = pg.LinearRegionItem(
+ values=(self.stack_center - self.stack_width - 10, self.stack_center + self.stack_width - 10),
+ pen="r",
+ brush=QtGui.QColor(0, 255, 200, 50),
+ )
+ self.spec_lo_m_idx = self.spec_hi_m_idx = 0
+
+ self.setImageROI()
+ self.update_spectrum()
+ self.update_image_roi()
+
+ if not self.isAReload:
+ # image connections
+ self.image_view.mousePressEvent = self.getPointSpectrum
+ self.pb_apply_spec_calc.clicked.connect(self.spec_roi_calc)
+ self.rb_math_roi.clicked.connect(self.update_spectrum)
+ self.pb_add_roi_2.clicked.connect(self.math_img_roi_flag)
+ self.image_roi_math.sigRegionChangeFinished.connect(self.image_roi_calc)
+ self.pb_apply_img_calc.clicked.connect(self.image_roi_calc)
+
+ self.spec_roi.sigRegionChanged.connect(self.update_image_roi)
+ self.spec_roi_math.sigRegionChangeFinished.connect(self.spec_roi_calc)
+
+ [
+ rbs.clicked.connect(self.setImageROI)
+ for rbs in [self.rb_poly_roi, self.rb_elli_roi, self.rb_rect_roi, self.rb_line_roi, self.rb_circle_roi]
+ ]
+
+ def disconnectImageActions(self):
+ for btns in [self.pb_apply_spec_calc, self.rb_math_roi, self.pb_add_roi_2, self.pb_apply_img_calc]:
+ try:
+ btns.disconnect()
+ except Exception:
+ pass
+
+ def select_elist(self):
+ self.energyFileChooser()
+ self.efileLoader()
+ self.energyUnitCheck()
+ self.view_stack()
+
+ def efileLoader(self):
+
+ if self.efilePath:
+
+ if str(self.efilePath).endswith("log_tiff.txt"):
+ self.energy = energy_from_logfile(logfile=str(self.efilePath))
+ logger.info("Log file from pyxrf processing")
+
+ else:
+ self.energy = np.loadtxt(str(self.efilePath))
+ self.change_color_on_load(self.pb_elist_xanes)
+ logger.info("Energy file loaded")
+
+ else:
+ self.statusbar_main.showMessage("No Energy List Selected, Setting Arbitary Axis")
+ self.energy = np.arange(self.im_stack.shape[0])
+ logger.info("Arbitary Energy Axis")
+
+ # assert len(self.energy) == self.dim1, "Number of Energy Points is not equal to stack length"
+
+ def energyUnitCheck(self):
+
+ if np.max(self.energy) < 100:
+ self.cb_kev_flag.setChecked(True)
+ self.energy *= 1000
+
+ else:
+ self.cb_kev_flag.setChecked(False)
+
+ def select_ref_file(self):
+ self.pb_xanes_fit.setEnabled(True)
+ self.ref_names = []
+ file_name = QFileDialog().getOpenFileName(self, "Open reference file", self.user_wd, "text file (*.csv *.nor)")
+ if file_name[0]:
+ if file_name[0].endswith(".nor"):
+ self.refs, self.ref_names = create_df_from_nor_try2(athenafile=str(file_name[0]))
+ self.change_color_on_load(self.pb_ref_xanes)
+
+ elif file_name[0].endswith(".csv"):
+ self.refs = pd.read_csv(str(file_name[0]))
+ self.ref_names = list(self.refs.keys())
+
+ self.change_color_on_load(self.pb_ref_xanes)
+
+ self.user_wd = os.path.dirname(file_name[0])
+
+ else:
+ logger.error("No file selected")
+ pass
+
+ logger.info(f"{self.refs.shape = }")
+
+ self.plt_xanes_refs()
+
+ def plt_xanes_refs(self):
+
+ try:
+ self.ref_plot.close()
+ except Exception:
+ pass
+
+ self.ref_plot = plot(title="Reference Standards")
+ self.ref_plot.setLabel("bottom", "Energy")
+ self.ref_plot.setLabel("left", "Intensity")
+ self.ref_plot.addLegend()
+
+ for n in range(np.shape(self.refs)[1]):
+
+ if not n == 0:
+ self.ref_plot.plot(
+ self.refs.values[:, 0],
+ self.refs.values[:, n],
+ pen=pg.mkPen(self.plt_colors[n - 1], width=self.plotWidth),
+ name=self.ref_names[n],
+ )
+
+ def getPointSpectrum(self, event):
+ if event.type() == QtCore.QEvent.MouseButtonDblClick:
+ if event.button() == QtCore.Qt.LeftButton:
+ self.xpixel = int(self.image_view.view.mapSceneToView(event.pos()).x()) - 1
+ zlim, ylim, xlim = self.displayedStack.shape
+
+ if self.xpixel > xlim:
+ self.xpixel = xlim - 1
+
+ self.ypixel = int(self.image_view.view.mapSceneToView(event.pos()).y()) - 1
+ if self.ypixel > ylim:
+ self.ypixel = ylim - 1
+ self.spectrum_view.addLegend()
+ self.point_spectrum = self.displayedStack[:, self.ypixel, self.xpixel]
+ self.spectrum_view.plot(
+ self.xdata,
+ self.point_spectrum,
+ clear=True,
+ pen=pg.mkPen(pg.mkColor(0, 0, 255, 255), width=self.plotWidth),
+ symbol="o",
+ symbolSize=6,
+ symbolBrush="r",
+ name=f"Point Spectrum; x= {self.xpixel}, y= {self.ypixel}",
+ )
+
+ self.spectrum_view.addItem(self.spec_roi)
+
+ self.statusbar_main.showMessage(f"{self.xpixel} and {self.ypixel}")
+
+ def setImageROI(self):
+
+ self.lineROI = pg.LineSegmentROI([[int(self.dim3 // 2), int(self.dim2 // 2)], [self.sz, self.sz]], pen="r")
+
+ self.rectROI = pg.RectROI(
+ [int(self.dim3 // 2), int(self.dim2 // 2)],
+ [self.sz, self.sz],
+ pen="w",
+ maxBounds=QtCore.QRectF(0, 0, self.dim3, self.dim2),
+ )
+
+ self.rectROI.addTranslateHandle([0, 0], [2, 2])
+ self.rectROI.addRotateHandle([0, 1], [2, 2])
+
+ self.ellipseROI = pg.EllipseROI(
+ [int(self.dim3 // 2), int(self.dim2 // 2)],
+ [self.sz, self.sz],
+ pen="w",
+ maxBounds=QtCore.QRectF(0, 0, self.dim3, self.dim2),
+ )
+
+ self.circleROI = pg.CircleROI(
+ [int(self.dim3 // 2), int(self.dim2 // 2)],
+ [self.sz, self.sz],
+ pen="w",
+ maxBounds=QtCore.QRectF(0, 0, self.dim3, self.dim2),
+ ) # pos and size
+
+ self.polyLineROI = pg.PolyLineROI(
+ [[0, 0], [0, self.sz], [self.sz, self.sz], [self.sz, 0]],
+ pos=(int(self.dim3 // 2), int(self.dim2 // 2)),
+ maxBounds=QtCore.QRectF(0, 0, self.dim3, self.dim2),
+ closed=True,
+ removable=True,
+ )
+
+ self.rois = {
+ "rb_line_roi": self.lineROI,
+ "rb_rect_roi": self.rectROI,
+ "rb_circle_roi": self.circleROI,
+ "rb_elli_roi": self.ellipseROI,
+ "rb_poly_roi": self.polyLineROI,
+ }
+
+ button_name = self.sender()
+
+ if button_name.objectName() in self.rois.keys():
+ self.roi_preference = button_name.objectName()
+
+ else:
+ self.roi_preference = "rb_rect_roi" # default
+
+ try:
+ self.image_view.removeItem(self.image_roi)
+
+ except Exception:
+ pass
+
+ # ROI settings for image, used polyline roi with non rectangular shape
+
+ self.image_roi = self.rois[self.roi_preference]
+ self.image_view.addItem(self.image_roi)
+ self.image_roi.sigRegionChanged.connect(self.update_spectrum)
+
+ def replot_image(self):
+ self.update_stack()
+ self.update_spectrum()
+ self.update_image_roi()
+
+ def update_spec_roi_values(self):
+ self.stack_center = int(self.energy[len(self.energy) // 2])
+ self.stack_width = int((self.energy.max() - self.energy.min()) * 0.05)
+ self.spec_roi.setBounds([self.xdata[0], self.xdata[-1]]) # if want to set bounds for the spec roi
+ self.spec_roi_math.setBounds([self.xdata[0], self.xdata[-1]])
+
+ def update_spectrum(self):
+
+ # set x-axis values; array taken from energy values, if clipped z box values will update the array
+ self.xdata = self.energy[self.sb_zrange1.value() : self.sb_zrange2.value()]
+
+ # get the cropped stack from ROI region; pyqtgraph function is used
+ self.roi_img_stk = self.image_roi.getArrayRegion(
+ self.displayedStack, self.image_view.imageItem, axes=(1, 2)
+ )
+
+ posx, posy = self.image_roi.pos()
+ self.le_roi.setText(str(int(posx)) + ":" + str(int(posy)))
+
+ # display the ROI features in the line edit boxes
+ if self.roi_img_stk.ndim == 3:
+ sizex, sizey = self.roi_img_stk.shape[1], self.roi_img_stk.shape[2]
+ self.le_roi_size.setText(str(sizex) + "," + str(sizey))
+ self.mean_spectra = get_mean_spectra(self.roi_img_stk)
+
+ elif self.roi_img_stk.ndim == 2:
+ sizex, sizey = self.roi_img_stk.shape[0], self.roi_img_stk.shape[1]
+ self.le_roi_size.setText(str(sizex) + "," + str(sizey))
+ self.mean_spectra = self.roi_img_stk.mean(-1)
+
+ self.spectrum_view.addLegend()
+
+ try:
+ self.spectrum_view.plot(
+ self.xdata,
+ self.mean_spectra,
+ pen=pg.mkPen(pg.mkColor(5, 255, 5, 255), width=self.plotWidth),
+ clear=True,
+ symbol="o",
+ symbolSize=6,
+ symbolBrush="r",
+ name="ROI Spectrum",
+ )
+ except Exception:
+ self.spectrum_view.plot(
+ self.mean_spectra,
+ clear=True,
+ pen=pg.mkPen(pg.mkColor(5, 255, 5, 255), width=self.plotWidth),
+ symbol="o",
+ symbolSize=6,
+ symbolBrush="r",
+ name="ROI Spectrum",
+ )
+
+ if self.energy[-1] > 1000:
+ self.e_unit = "eV"
+ else:
+ self.e_unit = "keV"
+
+ self.spectrum_view.setLabel("bottom", "Energy", self.e_unit)
+ self.spectrum_view.setLabel("left", "Intensity", "A.U.")
+ self.spectrum_view.addItem(self.spec_roi)
+ self.update_spec_roi_values()
+ self.math_roi_flag()
+
+ def update_image_roi(self):
+ self.spec_lo, self.spec_hi = self.spec_roi.getRegion()
+ self.spec_lo_idx = (np.abs(self.energy - self.spec_lo)).argmin()
+ self.spec_hi_idx = (np.abs(self.energy - self.spec_hi)).argmin()
+ self.le_spec_roi.setText(str(int(self.spec_lo)) + ":" + str(int(self.spec_hi)))
+ self.le_spec_roi_size.setText(str(int(self.spec_hi - self.spec_lo)))
+ self.update_spec_roi_values()
+ self.stackIndexToNames()
+
+ try:
+ if int(self.spec_lo_idx) == int(self.spec_hi_idx):
+ self.disp_img = self.displayedStack[int(self.spec_hi_idx), :, :]
+
+ else:
+ self.disp_img = self.displayedStack[int(self.spec_lo_idx) : int(self.spec_hi_idx), :, :].mean(0)
+
+ self.image_view.setImage(self.disp_img)
+ self.statusbar_main.showMessage(f"Image Display is {self.corrImg1}")
+ except Exception:
+ logger.warning("Indices are out of range; Image cannot be created")
+ pass
+
+ def set_spec_roi(self):
+ self.spec_lo_, self.spec_hi_ = int(self.sb_roi_spec_s.value()), int(self.sb_roi_spec_e.value())
+ self.spec_lo_idx_ = (np.abs(self.energy - self.spec_lo_)).argmin()
+ self.spec_hi_idx_ = (np.abs(self.energy - self.spec_hi_)).argmin()
+ self.spec_roi.setRegion((self.xdata[self.spec_lo_idx_], self.xdata[self.spec_hi_idx_]))
+ self.update_image_roi()
+
+ def math_roi_flag(self):
+ if self.rb_math_roi.isChecked():
+ self.rb_math_roi.setStyleSheet("color : green")
+ self.spectrum_view.addItem(self.spec_roi_math)
+ else:
+ self.spectrum_view.removeItem(self.spec_roi_math)
+
+ def spec_roi_calc(self):
+
+ self.spec_lo_m, self.spec_hi_m = self.spec_roi_math.getRegion()
+ self.spec_lo_m_idx = (np.abs(self.energy - self.spec_lo_m)).argmin()
+ self.spec_hi_m_idx = (np.abs(self.energy - self.spec_hi_m)).argmin()
+
+ if int(self.spec_lo_idx) == int(self.spec_hi_idx):
+ self.img1 = self.displayedStack[int(self.spec_hi_idx), :, :]
+
+ else:
+ self.img1 = self.displayedStack[int(self.spec_lo_idx) : int(self.spec_hi_idx), :, :].mean(0)
+
+ if int(self.spec_lo_m_idx) == int(self.spec_hi_m_idx):
+ self.img2 = self.displayedStack[int(self.spec_hi_m_idx), :, :]
+
+ else:
+ self.img2 = self.displayedStack[int(self.spec_lo_m_idx) : int(self.spec_hi_m_idx), :, :].mean(0)
+
+ if self.cb_roi_operation.currentText() == "Correlation Plot":
+ self.correlation_plot()
+
+ else:
+ calc = {"Divide": np.divide, "Subtract": np.subtract, "Add": np.add}
+ self.disp_img = remove_nan_inf(calc[self.cb_roi_operation.currentText()](self.img1, self.img2))
+ self.image_view.setImage(self.disp_img)
+
+ def math_img_roi_flag(self):
+
+ button_name = self.sender().text()
+ logger.info(f"{button_name}")
+ if button_name == "Add ROI_2":
+ self.image_view.addItem(self.image_roi_math)
+ self.pb_add_roi_2.setText("Remove ROI_2")
+ self.image_roi2_flag = 1
+ elif button_name == "Remove ROI_2":
+ self.image_view.removeItem(self.image_roi_math)
+ self.pb_add_roi_2.setText("Add ROI_2")
+ self.image_roi2_flag = 0
+
+ else:
+ pass
+ logger.error("Unknown signal for second ROI")
+
+ def image_roi_calc(self):
+
+ if self.image_roi2_flag == 1:
+ self.calc = {"Divide": np.divide, "Subtract": np.subtract, "Add": np.add}
+ self.update_spec_image_roi()
+ else:
+ logger.error("No ROI2 found")
+ return
+
+ def update_spec_image_roi(self):
+
+ self.math_roi_reg = self.image_roi_math.getArrayRegion(
+ self.displayedStack, self.image_view.imageItem, axes=(1, 2)
+ )
+ if self.math_roi_reg.ndim == 3:
+
+ self.math_roi_spectra = get_mean_spectra(self.math_roi_reg)
+
+ elif self.roi_img_stk.ndim == 2:
+ self.math_roi_spectra = self.math_roi_reg.mean(-1)
+
+ if self.cb_img_roi_action.currentText() in self.calc.keys():
+
+ calc_spec = self.calc[self.cb_img_roi_action.currentText()](self.mean_spectra, self.math_roi_spectra)
+ self.spectrum_view.addLegend()
+ self.spectrum_view.plot(
+ self.xdata,
+ calc_spec,
+ clear=True,
+ pen=pg.mkPen("m", width=2),
+ name=self.cb_img_roi_action.currentText() + "ed",
+ )
+ self.spectrum_view.plot(self.xdata, self.math_roi_spectra, pen=pg.mkPen("y", width=2), name="ROI2")
+ self.spectrum_view.plot(self.xdata, self.mean_spectra, pen=pg.mkPen("g", width=2), name="ROI1")
+
+ elif self.cb_img_roi_action.currentText() == "Compare":
+ self.spectrum_view.plot(
+ self.xdata, self.math_roi_spectra, pen=pg.mkPen("y", width=2), clear=True, name="ROI2"
+ )
+ self.spectrum_view.plot(self.xdata, self.mean_spectra, pen=pg.mkPen("g", width=2), name="ROI1")
+
+ self.spectrum_view.addItem(self.spec_roi)
+
+ def displayStackInfo(self):
+
+ try:
+
+ if isinstance(self.file_name, list):
+ info = f"Folder; {os.path.dirname(self.file_name[0])} \n"
+ for n, name in enumerate(self.file_name):
+ info += f"{n}: {os.path.basename(name)} \n"
+
+ # info = f'Stack order; {[name for name in enumerate(self.file_name)]}'
+ else:
+ info = f"Stack; {self.file_name}"
+
+ self.infoWindow = StackInfo(str(info))
+ self.infoWindow.show()
+
+ except AttributeError:
+ self.statusbar_main.showMessage("Warning: No Image Data Loaded")
+
+ def stackIndexToNames(self):
+ # create list of tiff file names for virtutal stack for plot axes
+ self.elemFileName = []
+
+ if isinstance(self.file_name, list):
+ for name in self.file_name:
+ self.elemFileName.append(os.path.basename(name).split(".")[0])
+
+ logger.info(f" Virtual Stack - list of image names; {self.elemFileName}")
+
+ # if the roi focus on one frame, Note that this slicing excludes the last index
+ if int(self.spec_lo_idx) == int(self.spec_hi_idx):
+ self.corrImg1 = str(self.elemFileName[int(self.spec_lo_idx)])
+ else:
+ self.corrImg1 = self.elemFileName[int(self.spec_lo_idx) : int(self.spec_hi_idx)]
+ if len(self.corrImg1) > 1:
+ self.corrImg1 = f"Sum of {self.corrImg1} "
+
+ if int(self.spec_lo_m_idx) == int(self.spec_hi_m_idx):
+ self.corrImg2 = str(self.elemFileName[int(self.spec_lo_m_idx)])
+
+ else:
+ self.corrImg2 = self.elemFileName[int(self.spec_lo_m_idx) : int(self.spec_hi_m_idx)]
+
+ if len(self.corrImg2) > 1:
+ self.corrImg2 = f"Sum of {self.corrImg2}"
+
+ logger.info(
+ f"Correlation stack {int(self.spec_lo_idx)}:{int(self.spec_hi_idx)} with "
+ f"{int(self.spec_lo_m_idx)}:{int(self.spec_hi_m_idx)}"
+ )
+
+ logger.info(f" Virtual Stack; corrlation plot of {self.corrImg1} vs {self.corrImg2}")
+ else:
+ self.corrImg1 = (
+ f" Sum of {os.path.basename(self.file_name).split('.')[0]}_{int(self.spec_lo_idx)} "
+ f"to {int(self.spec_hi_idx)}"
+ )
+ self.corrImg2 = (
+ f" Sum of {os.path.basename(self.file_name).split('.')[0]}_{int(self.spec_lo_m_idx)} "
+ f"to {int(self.spec_hi_m_idx)}"
+ )
+ # logger.info(f" corrlation plot of {self.corrImg1} vs {self.corrImg2}")
+
+ def stackToCSV(self):
+
+ self.stackIndexToNames()
+ self.imageDf = pd.DataFrame()
+ if len(self.elemFileName) == len(self.displayedStack):
+ for name, image in zip(self.elemFileName, self.displayedStack):
+ self.imageDf[f'{name}'] = image.flatten()
+ # print(self.imageDf.head())
+ else:
+ self.imageDf = image_to_pandas2(self.displayedStack)
+
+ file_name = QFileDialog().getSaveFileName(self,
+ "Save CSV Data",
+ os.path.join(self.user_wd,'image_2DArray.csv'),
+ 'file (*csv)')
+ if file_name[0]:
+ self.imageDf.to_csv(path_or_buf=file_name[0])
+ self.user_wd = os.path.dirname(file_name[0])
+ self.statusbar_main.showMessage(f"Data saved to {str(file_name[0])}")
+ else:
+ pass
+
+ def correlation_plot(self):
+ self.stackIndexToNames()
+
+ self.statusbar_main.showMessage(f"Correlation of {self.corrImg1} with {self.corrImg2}")
+
+ if self.rb_roiRegionOnly.isChecked():
+ self.roi_mask = self.image_roi.getArrayRegion(
+ self.displayedStack, self.image_view.imageItem, axes=(1, 2)
+ )
+ self.roi_img1 = np.mean(self.roi_mask[int(self.spec_lo_idx) : int(self.spec_hi_idx)], axis=0)
+ self.roi_img2 = np.mean(self.roi_mask[int(self.spec_lo_m_idx) : int(self.spec_hi_m_idx)], axis=0)
+ self.scatter_window = ScatterPlot(
+ self.roi_img1, self.roi_img2, (str(self.corrImg1), str(self.corrImg2))
+ )
+
+ else:
+
+ self.scatter_window = ScatterPlot(self.img1, self.img2, (str(self.corrImg1), str(self.corrImg2)))
+
+ self.scatter_window.show()
+
+ def plotCorrelationsAllCombinations(self):
+
+ print("Plotting all correlations")
+ self.stackIndexToNames()
+ allElemCombNum = list(combinations(np.arange(len(self.elemFileName)), 2))
+
+ self.scW1 = self.scW2 = self.scW3 = self.scW4 = self.scW5 = None
+ self.scW6 = self.scW7 = self.scW8 = self.scW9 = self.scW10 = None
+
+ self.scWindowList = [
+ self.scW1,
+ self.scW2,
+ self.scW3,
+ self.scW4,
+ self.scW5,
+ self.scW6,
+ self.scW7,
+ self.scW8,
+ self.scW9,
+ self.scW10,
+ ]
+ self.scWindowDict = {
+ 1: self.scW1,
+ 2: self.scW2,
+ 3: self.scW3,
+ 4: self.scW4,
+ 5: self.scW5,
+ 6: self.scW6,
+ 7: self.scW7,
+ 8: self.scW8,
+ 9: self.scW9,
+ 10: self.scW10,
+ }
+
+ if len(allElemCombNum) > len(self.scWindowDict):
+
+ reply = QMessageBox.warning(
+ self,
+ "Plot Window Limit",
+ f"The number of combination exceeds "
+ f"maxiumum number of "
+ f"plot windows. First {len(self.scWindowDict)} "
+ f"combinations will be plotted. \n Proceed?",
+ QMessageBox.Yes | QMessageBox.No,
+ QMessageBox.No,
+ )
+
+ if reply == QMessageBox.Yes:
+
+ for i, pair in enumerate(allElemCombNum):
+ im1 = self.displayedStack[pair[0]]
+ im2 = self.displayedStack[pair[1]]
+ im1Name = self.elemFileName[pair[0]]
+ im2Name = self.elemFileName[pair[1]]
+
+ self.scWindowDict[i] = ScatterPlot(im1, im2, (str(im1Name), str(im2Name)))
+ self.scWindowDict[i].show()
+
+ if reply == QMessageBox.No:
+ return
+
+ else:
+
+ for i, pair in enumerate(allElemCombNum):
+ im1 = self.displayedStack[pair[0]]
+ im2 = self.displayedStack[pair[1]]
+ im1Name = self.elemFileName[pair[0]]
+ im2Name = self.elemFileName[pair[1]]
+
+ self.scWindowDict[i] = ScatterPlot(im1, im2, (str(im1Name), str(im2Name)))
+ self.scWindowDict[i].show()
+
+ def getROIMask(self):
+ self.roi_mask = self.image_roi.getArrayRegion(self.displayedStack, self.image_view.imageItem, axes=(1, 2))
+ self.newWindow = singleStackViewer(self.roi_mask)
+ self.newWindow.show()
+
+ def save_stack(self, method="raw"):
+
+ # self.update_stack()
+ file_name = QFileDialog().getSaveFileName(
+ self,
+ "Save image data",
+ os.path.join(self.user_wd,"image_data.tiff"),
+ "image file(*tiff *tif )"
+ )
+ if file_name[0]:
+ if method == "raw":
+
+ tf.imsave(str(file_name[0]), self.displayedStack)
+ logger.info(f"Updated Image Saved: {str(file_name[0])}")
+ self.statusbar_main.showMessage(f"Updated Image Saved: {str(file_name[0])}")
+ elif method == "sum":
+ tf.imsave(str(file_name[0]), np.sum(self.displayedStack, axis=0))
+
+ elif method == "mean":
+ tf.imsave(str(file_name[0]), np.mean(self.displayedStack, axis=0))
+
+ self.user_wd = os.path.dirname(file_name[0])
+
+ else:
+ self.statusbar_main.showMessage("Saving cancelled")
+ logger.info(f"Save failed: {str(file_name[0])}")
+ pass
+
+ def save_disp_img(self):
+ file_name = QFileDialog().getSaveFileName(self,
+ "Save image data",
+ os.path.join(self.user_wd,"image.tiff"),
+ "image file(*tiff *tif )")
+ if file_name[0]:
+ tf.imsave(str(file_name[0]), self.disp_img)
+ self.statusbar_main.showMessage(f"Image Saved to {str(file_name[0])}")
+ self.user_wd = os.path.dirname(file_name[0])
+ logger.info(f"Updated Image Saved: {str(file_name[0])}")
+
+ else:
+ logger.error("No file to save")
+ self.statusbar_main.showMessage("Saving cancelled")
+ pass
+
+ def getLivePlotData(self):
+ try:
+
+ data = np.squeeze([c.getData() for c in self.spectrum_view.plotItem.curves])
+ # print(np.shape(data))
+ if data.ndim == 2:
+ self.mu_ = data[1]
+ self.e_ = data[0]
+ elif data.ndim == 3:
+ e_mu = data[0, :, :]
+ self.mu_ = e_mu[1]
+ self.e_ = e_mu[0]
+
+ else:
+ logger.error(f" Data shape of {data.ndim} is not supported")
+ pass
+ except AttributeError:
+ logger.error("No data loaded")
+ pass
+
+ def addSpectrumToCollector(self):
+ self.getLivePlotData()
+ self.spectrum_view_collect.plot(self.e_, self.mu_, name="ROI Spectrum")
+ self.spectrum_view_collect.setLabel("bottom", "Energy", self.e_unit)
+ self.spectrum_view_collect.setLabel("left", "Intensity", "A.U.")
+
+ def findEo(self):
+ try:
+ self.getLivePlotData()
+ e0_init = self.e_[np.argmax(np.gradient(self.mu_))]
+ self.dsb_norm_Eo.setValue(e0_init)
+
+ except AttributeError:
+ logger.error("No data loaded")
+ pass
+
+ def initNormVals(self):
+ self.getLivePlotData()
+ e0_init = self.e_[np.argmax(np.gradient(self.mu_))]
+ pre1, pre2, post1, post2 = xanesNormalization(
+ self.e_,
+ self.mu_,
+ e0=e0_init,
+ step=None,
+ nnorm=1,
+ nvict=0,
+ method= "guess"
+ )
+ self.dsb_norm_pre1.setValue(pre1)
+ self.dsb_norm_pre2.setValue(pre2)
+ self.dsb_norm_post1.setValue(post1)
+ self.dsb_norm_post2.setValue(post2)
+ self.dsb_norm_Eo.setValue(e0_init)
+
+ def getNormParams(self):
+ self.getLivePlotData()
+ eo_ = self.dsb_norm_Eo.value()
+ pre1_, pre2_ = self.dsb_norm_pre1.value(), self.dsb_norm_pre2.value()
+ norm1_, norm2_ = self.dsb_norm_post1.value(), self.dsb_norm_post2.value()
+ norm_order = self.sb_norm_order.value()
+
+ return eo_, pre1_, pre2_, norm1_, norm2_, norm_order
+
+ def exportNormParams(self):
+ self.xanesNormParam = {}
+ eo_, pre1_, pre2_, norm1_, norm2_, norm_order = self.getNormParams()
+ self.xanesNormParam["E0"] = eo_
+ self.xanesNormParam["pre1"] = pre1_
+ self.xanesNormParam["pre2"] = pre2_
+ self.xanesNormParam["post1"] = norm1_
+ self.xanesNormParam["post2"] = norm2_
+ self.xanesNormParam["norm_order"] = norm_order
+
+ file_name = QtWidgets.QFileDialog().getSaveFileName(
+ self,
+ "Save XANES Norm Params",
+ os.path.join(self.user_wd,"xanes_norm_params.csv"),
+ "csv file(*csv)"
+ )
+ if file_name[0]:
+ pd.DataFrame(self.xanesNormParam, index=[0]).to_csv(file_name[0])
+ self.user_wd = os.path.dirname(file_name[0])
+
+ else:
+ pass
+
+ def importNormParams(self):
+
+ file_name = QtWidgets.QFileDialog().getOpenFileName(
+ self, "Open a XANES Norm File", self.user_wd, "csv file(*csv);;all_files (*)"
+ )
+
+ if file_name[0]:
+ xanesNormParam = pd.read_csv(file_name[0])
+ self.dsb_norm_Eo.setValue(xanesNormParam["E0"])
+ self.dsb_norm_pre1.setValue(xanesNormParam["pre1"])
+ self.dsb_norm_pre2.setValue(xanesNormParam["pre2"])
+ self.dsb_norm_post1.setValue(xanesNormParam["post1"])
+ self.dsb_norm_post2.setValue(xanesNormParam["post2"])
+ self.sb_norm_order.setValue(xanesNormParam["norm_order"])
+ self.user_wd = os.path.dirname(file_name[0])
+
+ def nomalizeLiveSpec(self):
+ eo_, pre1_, pre2_, norm1_, norm2_, norm_order = self.getNormParams()
+ self.spectrum_view.clear()
+ colors = np.array(("c", "r", "m"))
+
+ if self.cb_mback.isChecked():
+ f2, normXANES = xanesNormalization(
+ self.e_,
+ self.mu_,
+ e0=eo_,
+ step=None,
+ nnorm=norm_order,
+ nvict=0,
+ pre1=pre1_,
+ pre2=pre2_,
+ norm1=norm1_,
+ norm2=norm2_,
+ useFlattened=self.cb_xanes_flat.isChecked(),
+ method = "mback"
+ )
+
+ names = np.array(("matched mu(E)", "f2"))
+ data_array = np.array((normXANES, f2))
+
+ else:
+ pre_line, post_line, normXANES = xanesNormalization(
+ self.e_,
+ self.mu_,
+ e0=eo_,
+ step=None,
+ nnorm=norm_order,
+ nvict=0,
+ pre1=pre1_,
+ pre2=pre2_,
+ norm1=norm1_,
+ norm2=norm2_,
+ useFlattened=self.cb_xanes_flat.isChecked()
+ )
+
+ names = np.array(("Spectrum", "Pre", "Post"))
+ data_array = np.array((self.mu_, pre_line, post_line))
+
+
+ for data, clr, name in zip(data_array, colors, names):
+ self.spectrum_view.plot(self.e_, data, pen=pg.mkPen(clr, width=self.plotWidth), name=name)
+
+ self.spectrum_view_norm.plot(
+ self.e_, normXANES, clear=True, pen=pg.mkPen(self.plt_colors[-1], width=self.plotWidth))
+
+ self.spectrum_view_norm.setLabel("bottom", "Energy", self.e_unit)
+ self.spectrum_view_norm.setLabel("left", "Norm. Intensity", "A.U.")
+
+ def normalizeStack(self):
+ self.getLivePlotData()
+ eo_, pre1_, pre2_, norm1_, norm2_, norm_order = self.getNormParams()
+
+ self.im_stack = self.displayedStack = xanesNormStack(
+ self.e_,
+ self.displayedStack,
+ e0=eo_,
+ step=None,
+ nnorm=norm_order,
+ nvict=0,
+ pre1=pre1_,
+ pre2=pre2_,
+ norm1=norm1_,
+ norm2=norm2_,
+ useFlattened=self.cb_xanes_flat.isChecked(),
+ ignorePostEdgeNorm=self.cb_xanes_postedge.isChecked()
+ )
+ # self.im_stack = self.displayedStack
+
+ def transposeStack(self):
+ self.im_stack = self.displayedStack = np.transpose(self.displayedStack, (2, 1, 0))
+
+ def swapStackXY(self):
+ self.im_stack = self.displayedStack = np.transpose(self.displayedStack, (0, 2, 1))
+
+ def removeROIBGStack(self):
+ self.displayedStack = subtractBackground(self.displayedStack, self.mean_spectra)
+
+ def resetCollectorSpec(self):
+ pass
+
+ def saveCollectorPlot(self):
+ exporter = pg.exporters.CSVExporter(self.spectrum_view_collect.plotItem)
+ exporter.parameters()["columnMode"] = "(x,y,y,y) for all plots"
+ file_name = QFileDialog().getSaveFileName(self, "save spectra", self.user_wd, "spectra (*csv)")
+ if file_name[0]:
+ exporter.export(str(file_name[0]) + ".csv")
+ self.user_wd = os.path.dirname(file_name[0])
+ else:
+ self.statusbar_main.showMessage("Saving cancelled")
+ pass
+
+ def save_disp_spec(self):
+
+ exporter = pg.exporters.CSVExporter(self.spectrum_view.plotItem)
+ exporter.parameters()["columnMode"] = "(x,y,y,y) for all plots"
+ file_name = QFileDialog().getSaveFileName(self,
+ "save spectrum",
+ os.path.join(self.user_wd,"spectrum.csv"),
+ "spectra (*csv)")
+ if file_name[0]:
+ exporter.export(str(file_name[0]) + ".csv")
+ self.user_wd = os.path.dirname(file_name[0])
+ else:
+ self.statusbar_main.showMessage("Saving cancelled")
+ pass
+
+ def saveEnergyList(self):
+ file_name = QFileDialog().getSaveFileName(self,
+ "save energy list",
+ os.path.join(self.user_wd,"energy_list.txt"),
+ "text file (*txt)")
+ if file_name[0]:
+ np.savetxt(file_name[0], self.xdata, fmt="%.4f")
+ self.user_wd = os.path.dirname(file_name[0])
+ else:
+ pass
+
+ def pca_scree_(self):
+ logger.info("Process started..")
+ self.update_stack()
+ var = pca_scree(self.displayedStack)
+
+ pca_scree_plot = pg.plot(
+ var[:24], title="Scree Plot", pen=pg.mkPen("y", width=2, style=QtCore.Qt.DotLine), symbol="o"
+ )
+ pca_scree_plot.addLine(y=0)
+ pca_scree_plot.setLabel("bottom", "Component Number")
+ pca_scree_plot.setLabel("left", "Singular Values")
+
+ logger.info("Process complete")
+
+ def calc_comp_(self):
+
+ logger.info("Process started..")
+
+ # self.update_stack()
+ n_components = self.sb_ncomp.value()
+ method_ = self.cb_comp_method.currentText()
+
+ ims, comp_spec, decon_spec, decomp_map = decompose_stack(
+ self.displayedStack, decompose_method=method_, n_components_=n_components
+ )
+
+ self._new_window3 = ComponentViewer(ims, self.xdata, comp_spec, decon_spec, decomp_map)
+ self._new_window3.show()
+
+ logger.info("Process complete")
+
+ def kmeans_elbow(self):
+ logger.info("Process started..")
+ # self.update_stack()
+
+ with pg.BusyCursor():
+ try:
+ clust_n, var = kmeans_variance(self.displayedStack)
+ kmeans_var_plot = pg.plot(
+ clust_n, var, title="KMeans Variance", pen=pg.mkPen("y", width=2, style=QtCore.Qt.DotLine),
+ symbol="o"
+ )
+ kmeans_var_plot.setLabel("bottom", "Cluster Number")
+ kmeans_var_plot.setLabel("left", "Sum of squared distances")
+ logger.info("Process complete")
+ except OverflowError:
+ pass
+ logger.error("Overflow Error, values are too long")
+
+ def kmeans_elbow_Thread(self):
+ # Pass the function to execute
+ worker = Worker(self.kmeans_elbow) # Any other args, kwargs are passed to the run function
+ worker.signals.result.connect(self.print_output)
+ worker.signals.finished.connect(self.thread_complete)
+ # Execute
+ self.threadpool.start(worker)
+
+ def clustering_(self):
+
+ logger.info("Process started..")
+ # self.update_stack()
+ method_ = self.cb_clust_method.currentText()
+
+ decon_images, X_cluster, decon_spectra = cluster_stack(
+ self.displayedStack,
+ method=method_,
+ n_clusters_=self.sb_ncluster.value(),
+ decomposed=False,
+ decompose_method=self.cb_comp_method.currentText(),
+ decompose_comp=self.sb_ncomp.value(),
+ )
+
+ self._new_window4 = ClusterViewer(decon_images, self.xdata, X_cluster, decon_spectra)
+ self._new_window4.show()
+
+ logger.info("Process complete")
+
+ def change_color_on_load(self, button_name):
+ button_name.setStyleSheet("background-color : rgb(0,150,0);" "color: rgb(255,255,255)")
+
+ def energyFileChooser(self):
+ file_name = QFileDialog().getOpenFileName(self,
+ "Open energy list",
+ self.user_wd,
+ "text file (*.txt)")
+ self.efilePath = file_name[0]
+
+ def fast_xanes_fitting(self):
+
+ self._new_window5 = XANESViewer(self.displayedStack, self.xdata, self.refs, self.ref_names)
+ self._new_window5.show()
+
+ # Thread Signals
+
+ def print_output(self, s):
+ print(s)
+
+ def thread_complete(self):
+ print("THREAD COMPLETE!")
+
+ def closeEvent(self, event):
+ reply = QMessageBox.question(
+ self,
+ "Window Close",
+ "Are you sure you want to close?",
+ QMessageBox.Yes | QMessageBox.No,
+ QMessageBox.No,
+ )
+
+ if reply == QMessageBox.Yes:
+ event.accept()
+ QApplication.closeAllWindows()
+ else:
+ event.ignore()
+
+
+class WorkerSignals(QObject):
+ """
+ Defines the signals available from a running worker thread.
+ Supported signals are:
+ - finished: No data
+ - error:`tuple` (exctype, value, traceback.format_exc() )
+ - result: `object` data returned from processing, anything
+ - progress: `tuple` indicating progress metadata
+ """
+
+ start = pyqtSignal()
+ finished = pyqtSignal()
+ error = pyqtSignal(tuple)
+ result = pyqtSignal(object)
+
+
+class Worker(QRunnable):
+ """
+ Worker thread
+ Inherits from QRunnable to handler worker thread setup, signals and wrap-up.
+ """
+
+ def __init__(self, fn, *args, **kwargs):
+ super(Worker, self).__init__()
+ # Store constructor arguments (re-used for processing)
+ self.fn = fn
+ self.args = args
+ self.kwargs = kwargs
+ self.signals = WorkerSignals()
+
+ @pyqtSlot()
+ def run(self):
+ """
+ Initialise the runner function with passed args, kwargs.
+ """
+ # Retrieve args/kwargs here; and fire processing using them
+ self.signals.start.emit()
+ try:
+ result = self.fn(*self.args, **self.kwargs)
+ except Exception:
+ traceback.print_exc()
+ exctype, value = sys.exc_info()[:2]
+ self.signals.error.emit((exctype, value, traceback.format_exc()))
+ else:
+ self.signals.result.emit(result) # Return the result of the processing
+ finally:
+ self.signals.finished.emit() # Done
+
+
+class singleStackViewer(QtWidgets.QMainWindow):
+ def __init__(self, img_stack, gradient="viridis"):
+ super(singleStackViewer, self).__init__()
+
+ # Load the UI Page
+ uic.loadUi(os.path.join(ui_path, "uis/singleStackView.ui"), self)
+ self.user_wd = os.path.abspath("~")
+
+ self.image_view.ui.menuBtn.hide()
+ self.image_view.ui.roiBtn.hide()
+
+ self.img_stack = img_stack
+ self.gradient = gradient
+ self.image_view.setPredefinedGradient(gradient)
+
+ if self.img_stack.ndim == 3:
+ self.dim1, self.dim3, self.dim2 = img_stack.shape
+ elif self.img_stack.ndim == 2:
+ self.dim3, self.dim2 = img_stack.shape
+ self.dim1 = 1
+ self.hs_img_stack.setMaximum(self.dim1 - 1)
+ self.hs_img_stack.setValue(np.round(self.dim1 / 2))
+ self.displayStack()
+
+ # connections
+ self.hs_img_stack.valueChanged.connect(self.displayStack)
+ self.actionSave.triggered.connect(self.saveImageStackAsTIFF)
+
+ def displayStack(self):
+ im_index = self.hs_img_stack.value()
+ if self.img_stack.ndim == 2:
+ self.image_view.setImage(self.img_stack)
+ else:
+ self.image_view.setImage(self.img_stack[im_index])
+ self.label_img_count.setText(f"{im_index + 1}/{self.dim1}")
+
+ def saveImageStackAsTIFF(self):
+ file_name = QFileDialog().getSaveFileName(self,
+ "Export Stack",
+ os.path.join(self.user_wd, "image_stack.tiff"),
+ "*.tiff;;*.tif")
+ if file_name[0]:
+ if self.img_stack.ndim == 3:
+ tf.imsave(str(file_name[0]), np.float32(self.img_stack.transpose(0, 2, 1)))
+ elif self.img_stack.ndim == 2:
+ tf.imsave(str(file_name[0]), np.float32(self.img_stack.T))
+
+ self.user_wd = os.path.dirname(file_name[0])
+ else:
+ pass
+
+
+class ComponentViewer(QtWidgets.QMainWindow):
+ def __init__(self, comp_stack, energy, comp_spectra, decon_spectra, decomp_map):
+ super(ComponentViewer, self).__init__()
+
+ # Load the UI Page
+ uic.loadUi(os.path.join(ui_path, "uis/ComponentView.ui"), self)
+ self.centralwidget.setStyleSheet(open(os.path.join(ui_path, "css/defaultStyle.css")).read())
+ self.user_wd = os.path.abspath("~")
+
+ self.comp_stack = comp_stack
+ self.energy = energy
+ self.comp_spectra = comp_spectra
+ self.decon_spectra = decon_spectra
+ self.decomp_map = decomp_map
+
+ (self.dim1, self.dim3, self.dim2) = self.comp_stack.shape
+ self.hs_comp_number.setMaximum(self.dim1 - 1)
+
+ self.image_view.setImage(self.comp_stack)
+ self.image_view.setPredefinedGradient("viridis")
+ self.image_view.ui.menuBtn.hide()
+ self.image_view.ui.roiBtn.hide()
+
+ self.image_view2.setImage(self.decomp_map)
+ self.image_view2.setPredefinedGradient("bipolar")
+ self.image_view2.ui.menuBtn.hide()
+ self.image_view2.ui.roiBtn.hide()
+
+ # connection
+ self.update_image()
+ self.pb_show_all.clicked.connect(self.show_all_spec)
+ self.hs_comp_number.valueChanged.connect(self.update_image)
+ self.actionSave.triggered.connect(self.save_comp_data)
+ self.pb_openScatterPlot.clicked.connect(self.openScatterPlot)
+ self.pb_showMultiColor.clicked.connect(lambda: self.generateMultiColorView(withSpectra=False))
+ self.pb_showMultiImageXANESView.clicked.connect(lambda: self.generateMultiColorView(withSpectra=True))
+
+ def update_image(self):
+ im_index = self.hs_comp_number.value()
+ self.spectrum_view.setLabel("bottom", "Energy")
+ self.spectrum_view.setLabel("left", "Intensity", "A.U.")
+ self.spectrum_view.plot(self.energy, self.decon_spectra[:, im_index], clear=True)
+ self.component_view.setLabel("bottom", "Energy")
+ self.component_view.setLabel("left", "Weight", "A.U.")
+ self.component_view.plot(self.energy, self.comp_spectra[:, im_index], clear=True)
+ self.label_comp_number.setText(f"{im_index + 1}/{self.dim1}")
+ # self.image_view.setCurrentIndex(im_index-1)
+ self.image_view.setImage(self.comp_stack[im_index])
+
+ def openScatterPlot(self):
+ self.scatter_window = ComponentScatterPlot(self.comp_stack, self.comp_spectra)
+
+ # ph = self.geometry().height()
+ # pw = self.geometry().width()
+ # px = self.geometry().x()
+ # py = self.geometry().y()
+ # dw = self.scatter_window.width()
+ # dh = self.scatter_window.height()
+ # self.scatter_window.setGeometry(px+0.65*pw, py + ph - 2*dh-5, dw, dh)
+ self.scatter_window.show()
+
+ def show_all_spec(self):
+ self.spectrum_view.clear()
+ self.plt_colors = ["g", "b", "r", "c", "m", "y", "w"] * 10
+ offsets = np.arange(0, 2, 0.2)
+ self.spectrum_view.addLegend()
+ for ii in range(self.decon_spectra.shape[1]):
+ self.spectrum_view.plot(
+ self.energy,
+ (self.decon_spectra[:, ii] / self.decon_spectra[:, ii].max()) + offsets[ii],
+ pen=self.plt_colors[ii],
+ name="component" + str(ii + 1),
+ )
+
+ def save_comp_data(self):
+ file_name = QFileDialog().getSaveFileName(self, "save all data", self.user_wd, "data(*tiff *tif *txt *png )")
+ if file_name[0]:
+ tf.imsave(
+ str(file_name[0]) + "_components.tiff", np.float32(self.comp_stack.transpose(0, 2, 1)), imagej=True
+ )
+ tf.imsave(str(file_name[0]) + "_component_masks.tiff", np.float32(self.decomp_map.T), imagej=True)
+ np.savetxt(str(file_name[0]) + "_deconv_spec.txt", self.decon_spectra)
+ np.savetxt(str(file_name[0]) + "_component_spec.txt", self.comp_spectra)
+
+ self.user_wd = os.path.dirname(file_name[0])
+ else:
+ pass
+
+ def generateMultiColorView(self, withSpectra=False):
+ self.multichanneldict = {}
+
+ for n, (colorName, image) in enumerate(zip(cmap_dict.keys(), self.comp_stack.transpose(0, 1, 2))):
+ low, high = np.min(image), np.max(image)
+ self.multichanneldict[f'Image {n + 1}'] = {'ImageName': f'Image {n + 1}',
+ 'ImageDir': '.',
+ 'Image': image,
+ 'Color': colorName,
+ 'CmapLimits': (low, high),
+ 'Opacity': 1.0
+ }
+
+ if withSpectra:
+ compXanesSpetraAll = pd.DataFrame()
+ compXanesSpetraAll['Energy'] = self.energy
+
+ for n, spec in enumerate(self.decon_spectra.T):
+ compXanesSpetraAll[f'Component_{n + 1}'] = spec
+
+ self.muli_color_window = MultiXANESWindow(image_dict=self.multichanneldict,
+ spec_df=compXanesSpetraAll)
+ else:
+ self.muli_color_window = MultiChannelWindow(image_dict=self.multichanneldict)
+
+ self.muli_color_window.show()
+
+ # add energy column
+
+
+class ClusterViewer(QtWidgets.QMainWindow):
+ def __init__(self, decon_images, energy, X_cluster, decon_spectra):
+ super(ClusterViewer, self).__init__()
+
+ # Load the UI Page
+ uic.loadUi(os.path.join(ui_path, "uis/ClusterView.ui"), self)
+ self.user_wd = os.path.abspath("~")
+ self.centralwidget.setStyleSheet(open(os.path.join(ui_path, "css/defaultStyle.css")).read())
+
+ self.decon_images = decon_images
+ self.energy = energy
+ self.X_cluster = X_cluster
+ self.decon_spectra = decon_spectra
+ (self.dim1, self.dim3, self.dim2) = self.decon_images.shape
+ self.hsb_cluster_number.setMaximum(self.dim1 - 1)
+ self.X_cluster = X_cluster
+
+ self.image_view.setImage(self.decon_images, autoHistogramRange=True, autoLevels=True)
+ self.image_view.setPredefinedGradient("viridis")
+ self.image_view.ui.menuBtn.hide()
+ self.image_view.ui.roiBtn.hide()
+
+ self.cluster_view.setImage(self.X_cluster, autoHistogramRange=True, autoLevels=True)
+ self.cluster_view.setPredefinedGradient("bipolar")
+ self.cluster_view.ui.histogram.hide()
+ self.cluster_view.ui.menuBtn.hide()
+ self.cluster_view.ui.roiBtn.hide()
+
+ # connection
+ self.update_display()
+ self.hsb_cluster_number.valueChanged.connect(self.update_display)
+ self.actionSave.triggered.connect(self.save_clust_data)
+ self.pb_show_all_spec.clicked.connect(self.showAllSpec)
+ self.pb_showMultiColor.clicked.connect(self.generateMultiColorView)
+
+ def update_display(self):
+ im_index = self.hsb_cluster_number.value()
+ self.component_view.setLabel("bottom", "Energy")
+ self.component_view.setLabel("left", "Intensity", "A.U.")
+ self.component_view.plot(self.energy, self.decon_spectra[:, im_index], clear=True)
+ # self.image_view.setCurrentIndex(im_index-1)
+ self.image_view.setImage(self.decon_images[im_index])
+ self.label_comp_number.setText(f"{im_index + 1}/{self.dim1}")
+
+ def save_clust_data(self):
+ file_name = QFileDialog().getSaveFileName(self, "", "", "data(*tiff *tif *txt *png )")
+ if file_name[0]:
+
+ tf.imsave(
+ str(file_name[0]) + "_cluster.tiff", np.float32(self.decon_images.transpose(0, 2, 1)), imagej=True
+ )
+ tf.imsave(str(file_name[0]) + "_cluster_map.tiff", np.float32(self.X_cluster.T), imagej=True)
+ np.savetxt(str(file_name[0]) + "_deconv_spec.txt", self.decon_spectra)
+
+ else:
+ logger.error("Saving Cancelled")
+ self.statusbar.showMessage("Saving Cancelled")
+ pass
+
+ def showAllSpec(self):
+ self.component_view.clear()
+ self.plt_colors = ["g", "b", "r", "c", "m", "y", "w"] * 10
+ offsets = np.arange(0, 2, 0.2)
+ self.component_view.addLegend()
+ for ii in range(self.decon_spectra.shape[1]):
+ self.component_view.plot(
+ self.energy,
+ (self.decon_spectra[:, ii] / self.decon_spectra[:, ii].max()) + offsets[ii],
+ pen=self.plt_colors[ii],
+ name="cluster" + str(ii + 1),
+ )
+
+ def generateMultiColorView(self):
+ self.multichanneldict = {}
+
+ for n, (colorName, image) in enumerate(zip(cmap_dict.keys(), self.decon_images.transpose(0, 1, 2))):
+ low, high = np.min(image), np.max(image)
+ self.multichanneldict[f"Image {n + 1}"] = {
+ "ImageName": f"Image {n + 1}",
+ "ImageDir": ".",
+ "Image": image,
+ "Color": colorName,
+ "CmapLimits": (low, high),
+ "Opacity": 1.0,
+ }
+ self.muli_color_window = MultiChannelWindow(image_dict=self.multichanneldict)
+ self.muli_color_window.show()
+
+
+class XANESViewer(QtWidgets.QMainWindow):
+ def __init__(self, im_stack=None, e_list=None, refs=None, ref_names=None):
+ super(XANESViewer, self).__init__()
+
+ uic.loadUi(os.path.join(ui_path, "uis/XANESViewer.ui"), self)
+ self.user_wd = os.path.abspath("~")
+ self.centralwidget.setStyleSheet(open(os.path.join(ui_path, "css/defaultStyle.css")).read())
+
+ self.im_stack = im_stack
+ self.e_list = e_list
+ self.refs = refs
+ self.ref_names = ref_names
+ self.selected = self.ref_names
+ self.fitResultDict = {}
+ self.fit_method = self.cb_xanes_fit_model.currentText()
+ self.alphaForLM = self.dsb_alphaForLM.value()
+
+ self.decon_ims, self.rfactor, self.coeffs_arr = xanes_fitting(
+ self.im_stack, self.e_list, self.refs, method=self.fit_method, alphaForLM=self.alphaForLM
+ )
+
+ (self.dim1, self.dim2, self.dim3) = self.im_stack.shape
+ self.cn = int(self.dim2 // 2)
+ self.sz = np.max([int(self.dim2 * 0.15), int(self.dim3 * 0.15)])
+ self.image_roi = pg.RectROI(
+ [int(self.dim3 // 2), int(self.dim2 // 2)],
+ [self.sz, self.sz],
+ pen="w",
+ maxBounds=QtCore.QRectF(0, 0, self.dim3, self.dim2),
+ )
+
+ self.image_roi.addTranslateHandle([0, 0], [2, 2])
+ self.image_roi.addRotateHandle([0, 1], [2, 2])
+
+ # self.image_roi = pg.PolyLineROI([[0, 0], [0, self.sz], [self.sz, self.sz], [self.sz, 0]],
+ # pos=(int(self.dim2 // 2), int(self.dim3 // 2)),
+ # maxBounds=QtCore.QRect(0, 0, self.dim3, self.dim2), closed=True)
+ # self.image_roi.addTranslateHandle([self.sz // 2, self.sz // 2], [2, 2])
+
+ self.stack_center = int(self.dim1 // 2)
+ self.stack_width = int(self.dim1 * 0.05)
+ # self.image_view.setCurrentIndex(self.stack_center)
+
+ self.image_view.addItem(self.image_roi)
+ self.xdata = self.e_list + self.sb_e_shift.value()
+
+ self.scrollBar_setup()
+ self.display_image_data()
+ self.display_references()
+ self.update_spectrum()
+
+ # connections
+ self.sb_e_shift.valueChanged.connect(self.update_spectrum)
+ self.pb_re_fit.clicked.connect(self.re_fit_xanes)
+ self.pb_edit_refs.clicked.connect(self.choose_refs)
+ self.image_roi.sigRegionChanged.connect(self.update_spectrum)
+ self.hsb_xanes_stk.valueChanged.connect(self.display_image_data)
+ self.hsb_chem_map.valueChanged.connect(self.display_image_data)
+ # self.pb_showMultiColor.clicked.connect(self.generateMultiColorView)
+ # self.pb_showCompSpec.clicked.connect(self.showComponentXANES)
+ self.pb_showCompSpec.clicked.connect(self.generateCompoisteImageSpectrumView)
+
+ # menu
+ self.actionSave_Chem_Map.triggered.connect(self.save_chem_map)
+ self.actionSave_R_factor_Image.triggered.connect(self.save_rfactor_img)
+ #self.actionSave_Live_Fit_Data.triggered.connect(self.pg_export_spec_fit)
+ self.actionSave_Live_Fit_Data.triggered.connect(self.export_live_data)
+ self.actionExport_Fit_Stats.triggered.connect(self.exportFitResults)
+ self.actionExport_Ref_Plot.triggered.connect(self.pg_export_references)
+
+ def scrollBar_setup(self):
+ self.hsb_xanes_stk.setValue(self.stack_center)
+ self.hsb_xanes_stk.setMaximum(self.dim1 - 1)
+ self.hsb_chem_map.setValue(0)
+ self.hsb_chem_map.setMaximum(self.decon_ims.shape[-1] - 1)
+
+ def display_image_data(self):
+
+ self.image_view.setImage(self.im_stack[self.hsb_xanes_stk.value()])
+ self.image_view.ui.menuBtn.hide()
+ self.image_view.ui.roiBtn.hide()
+ self.image_view.setPredefinedGradient("viridis")
+
+ self.image_view_maps.setImage(self.decon_ims.transpose(2, 0, 1)[self.hsb_chem_map.value()])
+ self.image_view_maps.setPredefinedGradient("bipolar")
+ self.image_view_maps.ui.menuBtn.hide()
+ self.image_view_maps.ui.roiBtn.hide()
+
+ def display_references(self):
+
+ self.inter_ref = interploate_E(self.refs, self.xdata)
+ self.plt_colors = ["c", "m", "y", "w"] * 10
+ self.spectrum_view_refs.addLegend()
+ for ii in range(self.inter_ref.shape[0]):
+ if len(self.selected) != 0:
+ self.spectrum_view_refs.plot(
+ self.xdata,
+ self.inter_ref[ii],
+ pen=pg.mkPen(self.plt_colors[ii], width=2),
+ name=self.selected[1:][ii],
+ )
+ else:
+ self.spectrum_view_refs.plot(
+ self.xdata,
+ self.inter_ref[ii],
+ pen=pg.mkPen(self.plt_colors[ii], width=2),
+ name="ref" + str(ii + 1),
+ )
+
+ def choose_refs(self):
+ "Interactively exclude some standards from the reference file"
+ self.ref_edit_window = RefChooser(
+ self.ref_names,
+ self.im_stack,
+ self.e_list,
+ self.refs,
+ self.sb_e_shift.value(),
+ self.cb_xanes_fit_model.currentText(),
+ )
+ self.ref_edit_window.show()
+ # self.rf_plot = pg.plot(title="RFactor Tracker")
+
+ # connections
+ self.ref_edit_window.choosenRefsSignal.connect(self.update_refs)
+ self.ref_edit_window.fitResultsSignal.connect(self.plotFitResults)
+
+ def update_refs(self, list_):
+ self.selected = list_ # list_ is the signal from ref chooser
+ self.update_spectrum()
+ self.re_fit_xanes()
+
+ def update_spectrum(self):
+
+ self.roi_img = self.image_roi.getArrayRegion(self.im_stack, self.image_view.imageItem, axes=(1, 2))
+ sizex, sizey = self.roi_img.shape[1], self.roi_img.shape[2]
+ posx, posy = self.image_roi.pos()
+ self.roi_info.setText(f"ROI_Pos: {int(posx)},{int(posy)} ROI_Size: {sizex},{sizey}")
+
+ self.xdata1 = self.e_list + self.sb_e_shift.value()
+ self.ydata1 = get_mean_spectra(self.roi_img)
+ self.fit_method = self.cb_xanes_fit_model.currentText()
+
+ if len(self.selected) != 0:
+
+ self.inter_ref = interploate_E(self.refs[self.selected], self.xdata1)
+ stats, coeffs = xanes_fitting_1D(
+ self.ydata1,
+ self.xdata1,
+ self.refs[self.selected],
+ method=self.fit_method,
+ alphaForLM=self.alphaForLM,
+ )
+
+ else:
+ self.inter_ref = interploate_E(self.refs, self.xdata1)
+ stats, coeffs = xanes_fitting_1D(
+ self.ydata1, self.xdata1, self.refs, method=self.fit_method, alphaForLM=self.alphaForLM
+ )
+
+ self.fit_ = np.dot(coeffs, self.inter_ref)
+ pen = pg.mkPen("g", width=1.5)
+ pen2 = pg.mkPen("r", width=1.5)
+ # pen3 = pg.mkPen("y", width=1.5)
+ self.spectrum_view.addLegend()
+ self.spectrum_view.setLabel("bottom", "Energy")
+ self.spectrum_view.setLabel("left", "Intensity", "A.U.")
+ self.spectrum_view.plot(self.xdata1, self.ydata1, pen=pen, name="Data", clear=True)
+ self.spectrum_view.plot(self.xdata1, self.fit_, name="Fit", pen=pen2)
+
+ for n, (coff, ref, plt_clr) in enumerate(zip(coeffs, self.inter_ref, self.plt_colors)):
+
+ if len(self.selected) != 0:
+
+ self.spectrum_view.plot(self.xdata1, np.dot(coff, ref), name=self.selected[1:][n], pen=plt_clr)
+ else:
+ self.spectrum_view.plot(self.xdata1, np.dot(coff, ref), name="ref" + str(n + 1), pen=plt_clr)
+ # set the rfactor value to the line edit slot
+ self.results = (
+ f"Coefficients: {coeffs} \n"
+ f"R-Factor: {stats['R_Factor']}, R-Square: {stats['R_Square']},\n "
+ f"Chi-Square: {stats['Chi_Square']}, "
+ f"Reduced Chi-Square: {stats['Reduced Chi_Square']}"
+ )
+
+ self.fit_results.setText(self.results)
+
+ def re_fit_xanes(self):
+ if len(self.selected) != 0:
+ self.decon_ims, self.rfactor, self.coeffs_arr = xanes_fitting(
+ self.im_stack,
+ self.e_list + self.sb_e_shift.value(),
+ self.refs[self.selected],
+ method=self.cb_xanes_fit_model.currentText(),
+ alphaForLM=self.alphaForLM,
+ )
+ else:
+ # if non athena file with no header is loaded no ref file cannot be edited
+ self.decon_ims, self.rfactor, self.coeffs_arr = xanes_fitting(
+ self.im_stack,
+ self.e_list + self.sb_e_shift.value(),
+ self.refs,
+ method=self.cb_xanes_fit_model.currentText(),
+ alphaForLM=self.alphaForLM,
+ )
+
+ # rfactor is a list of all spectra so take the mean
+ self.rfactor_mean = np.mean(self.rfactor)
+ self.image_view_maps.setImage(self.decon_ims.transpose(2, 0, 1))
+ self.scrollBar_setup()
+
+ def plotFitResults(self, decon_ims, rfactor_mean, coeff_array):
+ # upadte the chem maps and scrollbar params
+ self.image_view_maps.setImage(decon_ims.transpose(2, 0, 1))
+ # self.hsb_chem_map.setValue(0)
+ # self.hsb_chem_map.setMaximum(decon_ims.shape[-1]-1)
+
+ # set the rfactor value to the line edit slot
+ self.le_r_sq.setText(f"{rfactor_mean :.4f}")
+
+ def showComponentXANES(self):
+ compNum = self.hsb_chem_map.value()
+ currentComp = self.decon_ims.transpose(2, 0, 1)[compNum]
+ currentCompMask = currentComp > 0
+ yData = applyMaskGetMeanSpectrum(self.im_stack, currentCompMask)
+ xanes_comp_plot = pg.plot(
+ self.e_list + self.sb_e_shift.value(),
+ yData,
+ title=f"Component_{compNum}",
+ pen=pg.mkPen("y", width=2, style=QtCore.Qt.DotLine),
+ symbol="o",
+ )
+ xanes_comp_plot.setLabel("bottom", "Energy (keV)")
+ xanes_comp_plot.setLabel("left", "Intensity")
+
+ def plotDeconvSpectrum(self, clusterSigma=0):
+
+ try:
+ self.ref_plot.close()
+
+ except:
+ pass
+
+ self.ref_plot = plot(title="Deconvoluted XANES Spectra")
+ self.ref_plot.setLabel("bottom", "Energy")
+ self.ref_plot.setLabel("left", "Intensity")
+ self.ref_plot.addLegend()
+
+ for n, compImage in enumerate(self.decon_ims.transpose(2, 0, 1)):
+ mask = np.where(compImage > clusterSigma * np.std(compImage), compImage, 0)
+
+ self.ref_plot.plot(
+ self.xdata1,
+ get_mean_spectra(self.im_stack * mask),
+ pen=pg.mkPen(self.plt_colors[n], width=2),
+ name=f'Component_{n + 1}'
+ )
+
+ def generateCompoisteImageSpectrumView(self):
+ self.multichanneldict = {}
+
+ spectrumDF = getDeconvolutedXANESSpectrum(self.im_stack, self.decon_ims.transpose(2, 0, 1),
+ self.xdata1, clusterSigma=3)
+
+ for n, (colorName, image) in enumerate(zip(cmap_dict.keys(), self.decon_ims.transpose((2, 0, 1)))):
+ low, high = np.min(image), np.max(image)
+ self.multichanneldict[f'Image {n + 1}'] = {'ImageName': f'Image {n + 1}',
+ 'ImageDir': '.',
+ 'Image': image,
+ 'Color': colorName,
+ 'CmapLimits': (low, high),
+ 'Opacity': 1.0
+ }
+ self.muli_color_window = MultiXANESWindow(image_dict=self.multichanneldict, spec_df=spectrumDF)
+ self.muli_color_window.show()
+
+ def generateMultiColorView(self):
+ self.multichanneldict = {}
+
+ for n, (colorName, image) in enumerate(zip(cmap_dict.keys(), self.decon_ims.transpose((2, 0, 1)))):
+ low, high = np.min(image), np.max(image)
+ self.multichanneldict[f"Image {n + 1}"] = {
+ "ImageName": f"Image {n + 1}",
+ "ImageDir": ".",
+ "Image": image,
+ "Color": colorName,
+ "CmapLimits": (low, high),
+ "Opacity": 1.0,
+ }
+ self.muli_color_window = MultiChannelWindow(image_dict=self.multichanneldict)
+ self.muli_color_window.show()
+
+ def save_chem_map(self):
+ file_name = QFileDialog().getSaveFileName(self,
+ "save image",
+ os.path.join(self.user_wd,"chemical_map.tiff"),
+ "image data (*tiff)")
+ if file_name[0]:
+ tf.imsave(str(file_name[0]), np.float32(self.decon_ims.transpose(2, 0, 1)), imagej=True)
+ self.user_wd = os.path.dirname(file_name[0])
+ else:
+ logger.error("No file to save")
+ pass
+
+ def save_rfactor_img(self):
+ file_name = QFileDialog().getSaveFileName(self,
+ "save image",
+ os.path.join(self.user_wd,"r-factor_map.tiff"),
+ "image data (*tiff)")
+ if file_name[0]:
+ tf.imsave(str(file_name[0]), np.float32(self.rfactor), imagej=True)
+ self.user_wd = os.path.dirname(file_name[0])
+ else:
+ logger.error("No file to save")
+ pass
+
+ def save_spec_fit(self):
+ try:
+ to_save = np.column_stack([self.xdata1, self.ydata1, self.fit_])
+ file_name = QFileDialog().getSaveFileName(self,
+ "save spectrum",
+ os.path.join(self.user_wd,"spec_fit.txt"),
+ "spectrum and fit (*txt)")
+ if file_name[0]:
+ np.savetxt(str(file_name[0]) + ".txt", to_save)
+ self.user_wd = os.path.dirname(file_name[0])
+ else:
+ pass
+ except Exception:
+ logger.error("No file to save")
+ pass
+
+ def pg_export_spec_fit(self):
+
+ exporter = pg.exporters.CSVExporter(self.spectrum_view.plotItem)
+ exporter.parameters()["columnMode"] = "(x,y,y,y) for all plots"
+ file_name = QFileDialog().getSaveFileName(self,
+ "save spectrum",
+ os.path.join(self.user_wd,"spec_fit.txt"),
+ "spectrum and fit (*csv)")
+ if file_name[0]:
+ exporter.export(str(file_name[0]) + ".csv")
+ self.user_wd = os.path.dirname(file_name[0])
+ else:
+ pass
+
+ def pg_export_references(self):
+
+ exporter = pg.exporters.CSVExporter(self.spectrum_view_refs.plotItem)
+ exporter.parameters()["columnMode"] = "(x,y,y,y) for all plots"
+ file_name = QFileDialog().getSaveFileName(self,
+ "save references",
+ os.path.join(self.user_wd,"xanes_references.csv"),
+ "column data (*csv)"
+ )
+ if file_name[0]:
+ exporter.export(str(file_name[0]))
+ self.user_wd = os.path.dirname(file_name[0])
+ else:
+ pass
+
+ def exportFitResults(self):
+ file_name = QFileDialog().getSaveFileName(self,
+ "save txt",
+ os.path.join(self.user_wd,"xanes_1D_fit_results.txt"),
+ "txt data (*txt)")
+ if file_name[0]:
+ with open(file_name[0], "w") as file:
+ file.write(self.results)
+ self.user_wd = os.path.dirname(file_name[0])
+ else:
+ pass
+
+ def export_live_data(self):
+ file_name = QFileDialog().getSaveFileName(self,
+ "save all live data",
+ os.path.join(self.user_wd,"xanes_fit"),
+ "All Files (*)")
+ exporter_csv = pg.exporters.CSVExporter(self.spectrum_view.plotItem)
+ exporter_csv.parameters()["columnMode"] = "(x,y,y,y) for all plots"
+ exporter_png = pg.exporters.ImageExporter(self.spectrum_view.getViewBox())
+ exporter_img_png = pg.exporters.ImageExporter(self.image_view.getView())
+ if file_name[0]:
+ exporter_csv.export(str(file_name[0]+"_data.csv"))
+ exporter_png.export(str(file_name[0]+"_spec_image.png"))
+ exporter_img_png.export(str(file_name[0]+"_area_map.png"))
+ with open(file_name[0]+"_params.txt", "w") as file:
+ file.write(self.results)
+ self.user_wd = os.path.dirname(file_name[0])
+
+
+class RefChooser(QtWidgets.QMainWindow):
+ choosenRefsSignal: pyqtSignal = QtCore.pyqtSignal(list)
+ fitResultsSignal: pyqtSignal = QtCore.pyqtSignal(np.ndarray, float, np.ndarray)
+
+ def __init__(self, ref_names, im_stack, e_list, refs, e_shift, fit_model):
+ super(RefChooser, self).__init__()
+ uic.loadUi(os.path.join(ui_path, "uis/RefChooser.ui"), self)
+ self.user_wd = os.path.abspath("~")
+ self.centralwidget.setStyleSheet(open(os.path.join(ui_path, "css/defaultStyle.css")).read())
+ self.ref_names = ref_names
+ self.refs = refs
+ self.im_stack = im_stack
+ self.e_list = e_list
+ self.e_shift = e_shift
+ self.fit_model = fit_model
+
+ self.all_boxes = []
+ self.rFactorList = []
+
+ self.displayCombinations()
+
+ # selection become more apparent than default with red-ish color
+ self.tableWidget.setStyleSheet("background-color: white; selection-background-color: rgb(200,0,0);")
+
+ # add a line to the plot to walk through the table. Note that the table is not sorted
+ self.selectionLine = pg.InfiniteLine(
+ pos=1, angle=90, pen=pg.mkPen("m", width=2.5), movable=True, bounds=None, label="Move Me!"
+ )
+ self.stat_view.setLabel("bottom", "Fit ID")
+ self.stat_view.setLabel("left", "Reduced Chi^2")
+
+ for n, i in enumerate(self.ref_names):
+ self.cb_i = QtWidgets.QCheckBox(self.ref_box_frame)
+ if n == 0:
+ self.cb_i.setChecked(True)
+ self.cb_i.setEnabled(False)
+ self.cb_i.setObjectName(i)
+ self.cb_i.setText(i)
+ self.gridLayout_2.addWidget(self.cb_i, n, 0, 1, 1)
+ self.cb_i.toggled.connect(self.enableApply)
+ self.all_boxes.append(self.cb_i)
+
+ # connections
+ self.pb_apply.clicked.connect(self.clickedWhichAre)
+ self.pb_combo.clicked.connect(self.tryAllCombo)
+ self.actionExport_Results_csv.triggered.connect(self.exportFitResults)
+ self.selectionLine.sigPositionChanged.connect(self.updateFitWithLine)
+ self.tableWidget.itemSelectionChanged.connect(self.updateWithTableSelection)
+ # self.stat_view.scene().sigMouseClicked.connect(self.moveSelectionLine)
+ self.stat_view.mouseDoubleClickEvent = self.moveSelectionLine
+ self.sb_max_combo.valueChanged.connect(self.displayCombinations)
+ # self.pb_sort_with_r.clicked.connect(lambda: self.tableWidget.sortItems(3, QtCore.Qt.AscendingOrder))
+ self.pb_sort_with_r.clicked.connect(self.sortTable)
+ self.cb_sorter.currentTextChanged.connect(self.sortTable)
+
+ def clickedWhich(self):
+ button_name = self.sender()
+
+ def populateChecked(self):
+ self.onlyCheckedBoxes = []
+ for names in self.all_boxes:
+ if names.isChecked():
+ self.onlyCheckedBoxes.append(names.objectName())
+
+ QtCore.pyqtSlot()
+
+ def clickedWhichAre(self):
+ self.populateChecked()
+ self.choosenRefsSignal.emit(self.onlyCheckedBoxes)
+
+ def generateRefList(self, ref_list, maxCombo, minCombo=1):
+
+ """
+ Creates a list of reference combinations for xanes fitting
+
+ Paramaters;
+
+ ref_list (list): list of ref names from the header
+ maxCombo (int): maximum number of ref lists in combination
+ minCombo (int): min number of ref lists in combination
+
+ returns;
+
+ 1. int: length of total number of combinations
+ 2. list: all the combinations
+
+ """
+
+ if not maxCombo > len(ref_list):
+
+ iter_list = []
+ while minCombo < maxCombo + 1:
+ iter_list += list(combinations(ref_list, minCombo))
+ minCombo += 1
+ return len(iter_list), iter_list
+
+ else:
+ raise ValueError(" Maximum numbinations cannot be larger than number of list items")
+
+ def displayCombinations(self):
+ niter, self.iter_list = self.generateRefList(self.ref_names[1:], self.sb_max_combo.value())
+ self.label_nComb.setText(str(niter) + " Combinations")
+
+ @QtCore.pyqtSlot()
+ def tryAllCombo(self):
+ # empty list to to keep track and plot of reduced chi2 of all the fits
+ self.rfactor_list = []
+
+ # create dataframe for the table
+ self.df = pd.DataFrame(
+ columns=["Fit Number", "References", "Coefficients", "R-Factor", "R^2", "chi^2", "red-chi^2", "Score"]
+ )
+
+ # df columns is the header for the table widget
+ self.tableWidget.setHorizontalHeaderLabels(self.df.columns)
+ # self.iter_list = list(combinations(self.ref_names[1:],self.sb_max_combo.value()))
+
+ niter, self.iter_list = self.generateRefList(self.ref_names[1:], self.sb_max_combo.value())
+ tot_combo = len(self.iter_list)
+ for n, refs in enumerate(self.iter_list):
+ self.statusbar.showMessage(f"{n + 1}/{tot_combo}")
+ selectedRefs = list((str(self.ref_names[0]),) + refs)
+ self.fit_combo_progress.setValue((n + 1) * 100 / tot_combo)
+ self.stat, self.coeffs_arr = xanes_fitting_Binned(
+ self.im_stack, self.e_list + self.e_shift, self.refs[selectedRefs], method=self.fit_model
+ )
+
+ self.rfactor_list.append(self.stat["Reduced Chi_Square"])
+ self.stat_view.plot(
+ x=np.arange(n + 1),
+ y=self.rfactor_list,
+ clear=True,
+ title="Reduced Chi^2",
+ pen=pg.mkPen("y", width=2, style=QtCore.Qt.DotLine),
+ symbol="o",
+ )
+
+ # arbitary number to rank the best fit
+ fit_score = (self.stat["R_Square"] + np.sum(self.coeffs_arr)) / (
+ self.stat["R_Factor"] + self.stat["Reduced Chi_Square"]
+ )
+
+ resultsDict = {
+ "Fit Number": n,
+ "References": str(selectedRefs[1:]),
+ "Coefficients": str(np.around(self.coeffs_arr, 4)),
+ "Sum of Coefficients": str(np.around(np.sum(self.coeffs_arr), 4)),
+ "R-Factor": self.stat["R_Factor"],
+ "R^2": self.stat["R_Square"],
+ "chi^2": self.stat["Chi_Square"],
+ "red-chi^2": self.stat["Reduced Chi_Square"],
+ "Score": np.around(fit_score, 4),
+ }
+
+ self.df = pd.concat([self.df, pd.DataFrame([resultsDict])], ignore_index=True)
+
+ self.dataFrametoQTable(self.df)
+ QtTest.QTest.qWait(0.1) # hepls with real time plotting
+
+ self.stat_view.addItem(self.selectionLine)
+
+ def dataFrametoQTable(self, df_: pd.DataFrame):
+ nRows = len(df_.index)
+ nColumns = len(df_.columns)
+ self.tableWidget.setRowCount(nRows)
+ self.tableWidget.setColumnCount(nColumns)
+ self.tableWidget.setHorizontalHeaderLabels(df_.columns)
+
+ for i in range(nRows):
+ for j in range(nColumns):
+ cell = QtWidgets.QTableWidgetItem(str(df_.values[i][j]))
+ self.tableWidget.setItem(i, j, cell)
+
+ # set the property of the table view. Size policy to make the contents justified
+ self.tableWidget.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.AdjustToContents)
+ self.tableWidget.resizeColumnsToContents()
+
+ def exportFitResults(self):
+ file_name = QFileDialog().getSaveFileName(self, "save csv", "xanes_fit_results_log.csv", "txt data (*csv)")
+ if file_name[0]:
+ with open(str(file_name[0]), "w") as fp:
+ self.df.to_csv(fp)
+ else:
+ pass
+
+ def selectTableAndCheckBox(self, x):
+ nSelection = int(round(x))
+ self.tableWidget.selectRow(nSelection)
+ fit_num = int(self.tableWidget.item(nSelection, 0).text())
+ refs_selected = self.iter_list[fit_num]
+
+ # reset all the checkboxes to uncheck state, except the energy
+ for checkstate in self.findChildren(QtWidgets.QCheckBox):
+ if checkstate.isEnabled():
+ checkstate.setChecked(False)
+
+ for cb_names in refs_selected:
+ checkbox = self.findChild(QtWidgets.QCheckBox, name=cb_names)
+ checkbox.setChecked(True)
+
+ def updateFitWithLine(self):
+ pos_x, pos_y = self.selectionLine.pos()
+ x = self.df.index[self.df[str("Fit Number")] == np.round(pos_x)][0]
+ self.selectTableAndCheckBox(x)
+
+ def updateWithTableSelection(self):
+ x = self.tableWidget.currentRow()
+ self.selectTableAndCheckBox(x)
+
+ def moveSelectionLine(self, event):
+ if event.button() == QtCore.Qt.LeftButton:
+ Pos = self.stat_view.plotItem.vb.mapSceneToView(event.pos())
+ self.selectionLine.setPos(Pos.x())
+
+ def sortTable(self):
+ sorter_dict = {
+ "R-Factor": "R-Factor",
+ "R-Square": "R^2",
+ "Chi-Square": "chi^2",
+ "Reduced Chi-Square": "red-chi^2",
+ "Fit Number": "Fit Number",
+ }
+ sorter = sorter_dict[self.cb_sorter.currentText()]
+ self.df = self.df.sort_values(sorter, ignore_index=True)
+ self.dataFrametoQTable(self.df)
+
+ def enableApply(self):
+
+ """ """
+ self.populateChecked()
+ if len(self.onlyCheckedBoxes) > 1:
+ self.pb_apply.setEnabled(True)
+ else:
+ self.pb_apply.setEnabled(False)
+
+class ScatterPlot(QtWidgets.QMainWindow):
+ def __init__(self, img1, img2, nameTuple):
+ super(ScatterPlot, self).__init__()
+
+ uic.loadUi(os.path.join(ui_path, "uis/ScatterView.ui"), self)
+ self.user_wd = os.path.abspath("~")
+ self.centralwidget.setStyleSheet(open(os.path.join(ui_path, "css/defaultStyle.css")).read())
+ self.clearPgPlot()
+ self.w1 = self.scatterViewer.addPlot()
+ self.img1 = img1
+ self.img2 = img2
+ self.nameTuple = nameTuple
+ x, y = np.shape(self.img1)
+ self.s1 = pg.ScatterPlotItem(size=2, pen=pg.mkPen(None), brush=pg.mkBrush(255, 255, 0, 255))
+ # print(self.s1)
+
+ # create three polyline ROIs for masking
+ Xsize = self.img1.max() / 6
+ Ysize = self.img2.max() / 6
+
+ self.scatter_mask = pg.PolyLineROI(
+ [[0, 0], [0, Ysize], [Xsize / 2, Ysize * 1.5], [Xsize, Ysize], [Xsize, 0]],
+ pos=None,
+ pen=pg.mkPen("r", width=2),
+ hoverPen=pg.mkPen("w", width=2),
+ closed=True,
+ removable=True,
+ )
+
+ self.scatter_mask2 = pg.PolyLineROI(
+ [
+ [Xsize * 1.2, 0],
+ [Xsize * 1.2, Ysize * 2],
+ [Xsize * 2, Ysize * 2],
+ [Xsize * 3, Ysize],
+ [Xsize * 2, 0],
+ ],
+ pos=None,
+ pen=pg.mkPen("g", width=2),
+ hoverPen=pg.mkPen("w", width=2),
+ closed=True,
+ removable=True,
+ )
+ self.scatter_mask3 = pg.PolyLineROI(
+ [
+ [Xsize * 2.5, 0],
+ [Xsize * 2.5, Ysize],
+ [Xsize * 4, Ysize],
+ [Xsize * 4, 0],
+ [Xsize * 3.7, Ysize * -0.5],
+ ],
+ pos=None,
+ pen=pg.mkPen("c", width=2),
+ hoverPen=pg.mkPen("w", width=2),
+ closed=True,
+ removable=True,
+ )
+
+ self.fitScatter = self.fitScatter2 = self.fitScatter3 = None
+
+ self.rois = {
+ "ROI 1": (self.scatter_mask, self.rb_roi1.isChecked(), self.fitScatter),
+ "ROI 2": (self.scatter_mask2, self.rb_roi2.isChecked(), self.fitScatter2),
+ "ROI 3": (self.scatter_mask3, self.rb_roi3.isChecked(), self.fitScatter3),
+ }
+
+ self.windowNames = {"ROI 1": self.fitScatter, "ROI 2": self.fitScatter2, "ROI 3": self.fitScatter3}
+
+ self.s1.setData(self.img1.flatten(), self.img2.flatten())
+ self.w1.setLabel("bottom", self.nameTuple[0], "counts")
+ self.label_img1.setText(self.nameTuple[0])
+ self.w1.setLabel("left", self.nameTuple[1], "counts")
+ self.label_img2.setText(self.nameTuple[1])
+ self.w1.addItem(self.s1)
+
+ self.image_view.setImage(self.img1)
+ self.image_view.ui.menuBtn.hide()
+ self.image_view.ui.roiBtn.hide()
+ self.image_view.setPredefinedGradient("thermal")
+
+ self.image_view2.setImage(self.img2)
+ self.image_view2.ui.menuBtn.hide()
+ self.image_view2.ui.roiBtn.hide()
+ self.image_view2.setPredefinedGradient("thermal")
+
+ # connections
+ self.actionSave_Plot.triggered.connect(self.pg_export_correlation)
+ self.actionSave_Images.triggered.connect(self.tiff_export_images)
+ # self.pb_define_mask.clicked.connect(lambda:self.createMask(self.scatter_mask))
+ self.pb_define_mask.clicked.connect(self.addMultipleROIs)
+ # self.pb_apply_mask.clicked.connect(lambda:self.getMaskRegion(self.scatter_mask))
+ self.pb_apply_mask.clicked.connect(self.applyMultipleROIs)
+ self.pb_clear_mask.clicked.connect(self.clearMultipleROIs)
+ self.pb_compositeScatter.clicked.connect(self.createCompositeScatter)
+ [rbs.clicked.connect(self.updateROIDict) for rbs in [self.rb_roi1, self.rb_roi2, self.rb_roi3]]
+
+ def pg_export_correlation(self):
+
+ exporter = pg.exporters.CSVExporter(self.w1)
+ exporter.parameters()["columnMode"] = "(x,y,y,y) for all plots"
+ file_name = QFileDialog().getSaveFileName(self,
+ "save correlation",
+ os.path.join(self.user_wd,"correlation.csv"),
+ "spectrum and fit (*csv)")
+ if file_name[0]:
+ exporter.export(str(file_name[0]) + ".csv")
+ self.statusbar.showMessage(f"Data saved to {str(file_name[0])}")
+ self.user_wd = os.path.dirname(file_name[0])
+ else:
+ pass
+
+ def tiff_export_images(self):
+ file_name = QFileDialog().getSaveFileName(self,
+ "save images",
+ os.path.join(self.user_wd,"image.txt"),
+ "spectrum and fit (*tiff)")
+ if file_name[0]:
+ tf.imsave(str(file_name[0]) + ".tiff", np.dstack([self.img1, self.img2]).T)
+ self.statusbar.showMessage(f"Images saved to {str(file_name[0])}")
+ self.user_wd = os.path.dirname(file_name[0])
+ else:
+ pass
+
+ def createMask(self, ROIName):
+
+ try:
+ self.w1.removeItem(ROIName)
+ except Exception:
+ pass
+ self.w1.addItem(ROIName)
+
+ def clearMask(self, ROIName):
+ self.w1.removeItem(ROIName)
+
+ def clearPgPlot(self):
+ try:
+ self.masked_img.close()
+ except Exception:
+ pass
+
+ def getMaskRegion(self, ROIName, generateSeperateWindows=True):
+
+ """filter scatterplot points using polylineROI region"""
+
+ # Ref : https://stackoverflow.com/questions/57719303/how-to-map-mouse-position-on-a-scatterplot
+
+ # get the roi region:QPaintPathObject
+ roiShape = self.rois[ROIName][0].mapToItem(self.s1, self.rois[ROIName][0].shape())
+
+ # get data in the scatter plot
+ scatterData = np.array(self.s1.getData())
+
+ # generate a binary mask for points inside or outside the roishape
+ selected = [roiShape.contains(QtCore.QPointF(pt[0], pt[1])) for pt in scatterData.T]
+
+ # reshape the mask to image dimensions
+ self.mask2D = np.reshape(selected, (self.img1.shape))
+
+ # get masked image1
+ self.maskedImage = self.mask2D * self.img1
+
+ # get rid of the (0,0) values in the masked array
+ self.xData, self.yData = np.compress(selected, scatterData[0]), np.compress(selected, scatterData[1])
+
+ # linear regeression of the filtered X,Y data
+ result = linregress(self.xData, self.yData)
+
+ # Pearson's correlation of the filtered X,Y data
+ pr, pp = stats.pearsonr(self.xData, self.yData)
+
+ # apply the solved equation to xData to generate the fit line
+ self.yyData = result.intercept + result.slope * self.xData
+
+ # Prepare strings for fit results and stats
+ self.fitLineEqn = (
+ f" y = x*{result.slope :.3e} + {result.intercept :.3e},"
+ f"\n R^2 = {result.rvalue**2 :.3f}, r = {pr :.3f}"
+ )
+ FitStats1 = f" Slope Error = {result.stderr :.3e}, Intercept Error = {result.intercept_stderr :.3e}\n"
+ FitStats2 = f" Pearson’s correlation coefficient = {pr :.3f}"
+ refs = "\n\n ***References****\n\n scipy.stats.linregress, scipy.stats.pearsonr "
+ fitStats = (
+ f"\n ***{ROIName} Fit Results***\n\n" + " Equation: " + self.fitLineEqn + FitStats1 + FitStats2 + refs
+ )
+
+ # generate new window to plot the results
+
+ if generateSeperateWindows:
+ self.windowNames[ROIName] = MaskedScatterPlotFit(
+ [self.xData, self.yData],
+ [self.xData, self.yyData],
+ self.mask2D,
+ self.maskedImage,
+ fitStats,
+ self.fitLineEqn,
+ self.nameTuple,
+ )
+ self.windowNames[ROIName].show()
+
+ """
+ from scipy.linalg import lstsq
+ M = xData[:, np.newaxis]**[0, 1] #use >1 for polynomial fits
+ p, res, rnk, s = lstsq(M, yData)
+ yyData = p[0] + p[1]*xData
+ """
+
+ def updateROIDict(self):
+ self.rois = {
+ "ROI 1": (self.scatter_mask, self.rb_roi1.isChecked()),
+ "ROI 2": (self.scatter_mask2, self.rb_roi2.isChecked()),
+ "ROI 3": (self.scatter_mask3, self.rb_roi3.isChecked()),
+ }
+
+ def applyMultipleROIs(self):
+ with pg.BusyCursor():
+ self.updateROIDict()
+ for key in self.rois.keys():
+ if self.rois[key][1]:
+ self.getMaskRegion(key)
+ else:
+ pass
+
+ def addMultipleROIs(self):
+ self.updateROIDict()
+ for key in self.rois.keys():
+ if self.rois[key][1]:
+ self.createMask(self.rois[key][0])
+ else:
+ self.clearMask(self.rois[key][0])
+
+ def clearMultipleROIs(self):
+ self.updateROIDict()
+ for key in self.rois.keys():
+ if not self.rois[key][1]:
+ self.clearMask(self.rois[key][0])
+ else:
+ pass
+
+ def createCompositeScatter(self):
+
+ points = []
+ fitLine = []
+ masks = []
+ roiFitEqn = {}
+
+ self.updateROIDict()
+ for n, key in enumerate(self.rois.keys()):
+ if self.rois[key][1]:
+ self.getMaskRegion(key, generateSeperateWindows=False)
+ points.append(np.column_stack([self.xData, self.yData]))
+ fitLine.append(np.column_stack([self.xData, self.yyData]))
+ masks.append(self.mask2D)
+ roiFitEqn[key] = self.fitLineEqn
+ else:
+ pass
+
+ self.compositeScatterWindow = CompositeScatterPlot(
+ points,
+ fitLine,
+ np.array(masks),
+ roiFitEqn,
+ self.nameTuple
+ )
+ self.compositeScatterWindow.show()
+
+ def _createCompositeScatter(self):
+ self.scatterColors = ["w", "c", "y", "k", "m"]
+ points = []
+ fitLine = []
+
+ self.updateROIDict()
+ for n, key in enumerate(self.rois.keys()):
+ if self.rois[key][1]:
+ self.getMaskRegion(key, generateSeperateWindows=False)
+
+ for x, y, yy in zip(self.xData, self.yData, self.yyData):
+
+ points.append(
+ {
+ "pos": (x, y),
+ "data": "id",
+ "size": 3,
+ "pen": pg.mkPen(None),
+ "brush": self.scatterColors[n],
+ }
+ )
+ fitLine.extend(np.column_stack((self.xData, self.yyData)))
+ else:
+ pass
+
+ logger.info(f" fitline shape: {np.shape(fitLine)}")
+ self.compositeScatterWindow = CompositeScatterPlot(points, np.array(fitLine))
+ self.compositeScatterWindow.show()
+
+ def getROIParams(self):
+ print(np.array(self.scatter_mask.getSceneHandlePositions()))
+
+
+class MaskedScatterPlotFit(QtWidgets.QMainWindow):
+ def __init__(self, scatterData, fitData, mask, maskedImage, fitString, fitEquation, nameTuple):
+ super(MaskedScatterPlotFit, self).__init__()
+
+ uic.loadUi(os.path.join(ui_path, "uis/maskedScatterPlotFit.ui"), self)
+ self.user_wd = os.path.abspath("~")
+ self.centralwidget.setStyleSheet(open(os.path.join(ui_path, "css/defaultStyle.css")).read())
+ self.scatterData = scatterData
+ self.fitData = fitData
+ self.mask = mask
+ self.maskedImage = maskedImage
+ self.fitString = fitString
+ self.fitEquation = fitEquation
+ self.nameTuple = nameTuple
+
+ # set the graphicslayoutwidget in the ui as canvas
+ self.canvas = self.scatterViewer.addPlot()
+ self.canvas.addLegend()
+ self.canvas.setLabel("bottom", self.nameTuple[0], "counts")
+ self.canvas.setLabel("left", self.nameTuple[1], "counts")
+ self.gb_maskedImage1.setTitle(f" Masked {self.nameTuple[0]}")
+
+ # generate a scatter plot item
+ self.scattered = pg.ScatterPlotItem(size=3.5, pen=pg.mkPen(None), brush=pg.mkBrush(5, 214, 255, 200))
+
+ # set scatter plot data
+ self.scattered.setData(scatterData[0], scatterData[1], name="Data")
+
+ # set z value negative to show scatter data behind the fit line
+ self.scattered.setZValue(-10)
+
+ # add scatter plot to the canvas
+ self.canvas.addItem(self.scattered)
+
+ # generate plotitem for fit line
+ self.fitLinePlot = pg.PlotDataItem(pen=pg.mkPen(pg.mkColor(220, 20, 60), width=3.3))
+
+ # set line plot data
+ self.fitLinePlot.setData(fitData[0], fitData[1], name="Linear Fit")
+
+ # add line plot to the canvas
+ self.canvas.addItem(self.fitLinePlot)
+
+ # display Mask
+ self.imageView_mask.setImage(self.mask)
+ self.imageView_mask.ui.menuBtn.hide()
+ self.imageView_mask.ui.roiBtn.hide()
+ self.imageView_mask.setPredefinedGradient("plasma")
+
+ # display masked Image
+ self.imageView_maskedImage.setImage(self.maskedImage)
+ self.imageView_maskedImage.ui.menuBtn.hide()
+ self.imageView_maskedImage.ui.roiBtn.hide()
+ self.imageView_maskedImage.setPredefinedGradient("viridis")
+
+ # display Fit stats
+ self.text_fit_results.setPlainText(fitString)
+ self.canvas.setTitle(self.fitEquation, color="r")
+
+ # connections
+ self.pb_copy_results.clicked.connect(self.copyFitResults)
+ self.pb_save_results.clicked.connect(self.saveFitResults)
+ self.actionSave_Plot.triggered.connect(self.pg_export_correlation)
+ self.actionSaveMask.triggered.connect(self.saveMask)
+ self.actionSaveMaskedImage.triggered.connect(self.saveImage)
+
+ def saveFitResults(self):
+ S__File = QFileDialog.getSaveFileName(self, "save txt", "correlationPlotFit.txt", "txt data (*txt)")
+
+ Text = self.text_fit_results.toPlainText()
+ if S__File[0]:
+ with open(S__File[0], "w") as file:
+ file.write(Text)
+
+ def copyFitResults(self):
+ self.text_fit_results.selectAll()
+ self.text_fit_results.copy()
+ self.statusbar.showMessage("text copied to clipboard")
+
+ def pg_export_correlation(self):
+
+ exporter = pg.exporters.CSVExporter(self.canvas)
+ exporter.parameters()["columnMode"] = "(x,y,y,y) for all plots"
+ file_name = QFileDialog().getSaveFileName(
+ self, "save correlation", "scatterData.csv", "spectrum and fit (*csv)"
+ )
+ if file_name[0]:
+ exporter.export(str(file_name[0]))
+ self.statusbar.showMessage(f"Data saved to {str(file_name[0])}")
+ else:
+ pass
+
+ def saveImage(self):
+
+ file_name = QFileDialog().getSaveFileName(self, "Save image data", "image.tiff", "image file(*tiff *tif )")
+ if file_name[0]:
+ tf.imsave(str(file_name[0]), self.maskedImage)
+ self.statusbar.showMessage(f"Data saved to {str(file_name[0])}")
+ else:
+ self.statusbar.showMessage("Saving cancelled")
+ pass
+
+ def saveMask(self):
+
+ file_name = QFileDialog().getSaveFileName(self, "Save image data", "mask.tiff", "image file(*tiff *tif )")
+ if file_name[0]:
+ tf.imsave(str(file_name[0]), self.mask)
+ self.statusbar.showMessage(f"Data saved to {str(file_name[0])}")
+ else:
+ self.statusbar.showMessage("Saving cancelled")
+ pass
+
+class ComponentScatterPlot(QtWidgets.QMainWindow):
+ def __init__(self, decomp_stack, specs):
+ super(ComponentScatterPlot, self).__init__()
+
+ uic.loadUi(os.path.join(ui_path, "uis/ComponentScatterPlot.ui"), self)
+ self.user_wd = os.path.abspath("~")
+ self.centralwidget.setStyleSheet(open(os.path.join(ui_path, "css/defaultStyle.css")).read())
+ self.w1 = self.scatterViewer.addPlot()
+ self.decomp_stack = decomp_stack
+ self.specs = specs
+ (self.dim1, self.dim3, self.dim2) = self.decomp_stack.shape
+ # fill the combonbox depending in the number of components for scatter plot
+ for n, combs in enumerate(combinations(np.arange(self.dim1), 2)):
+ self.cb_scatter_comp.addItem(str(combs))
+ self.cb_scatter_comp.setItemData(n, combs)
+
+ self.s1 = pg.ScatterPlotItem(size=3, pen=pg.mkPen(None), brush=pg.mkBrush(255, 255, 0, 120))
+
+ self.setImageAndScatterPlot()
+ # connections
+ self.actionSave_Plot.triggered.connect(self.pg_export_correlation)
+ self.actionSave_Images.triggered.connect(self.tiff_export_images)
+ self.pb_updateComponents.clicked.connect(self.setImageAndScatterPlot)
+ self.pb_define_mask.clicked.connect(self.createMask)
+ self.pb_apply_mask.clicked.connect(self.getMaskRegion)
+ self.pb_reset_mask.clicked.connect(self.resetMask)
+ self.pb_addALine.clicked.connect(lambda: self.createMask(Line=True))
+
+ def setImageAndScatterPlot(self):
+
+ try:
+ self.s1.clear()
+ except Exception:
+ pass
+
+ comp_tuple = self.cb_scatter_comp.currentData()
+ self.img1, self.img2 = self.decomp_stack[comp_tuple[0]], self.decomp_stack[comp_tuple[-1]]
+ self.image_view.setImage(self.decomp_stack[comp_tuple[0]])
+ self.image_view.ui.menuBtn.hide()
+ self.image_view.ui.roiBtn.hide()
+ self.image_view.setPredefinedGradient("bipolar")
+
+ self.image_view2.setImage(self.decomp_stack[comp_tuple[-1]])
+ self.image_view2.ui.menuBtn.hide()
+ self.image_view2.ui.roiBtn.hide()
+ self.image_view2.setPredefinedGradient("bipolar")
+
+ points = []
+ for i, j in zip(self.img1.flatten(), self.img2.flatten()):
+
+ points.append(
+ {
+ "pos": (i, j),
+ "data": "id",
+ "size": 5,
+ "pen": pg.mkPen(None),
+ "brush": pg.mkBrush(255, 255, 0, 160),
+ }
+ )
+
+ self.s1.addPoints(points)
+ self.w1.addItem(self.s1)
+ # self.s1.setData(self.specs[:, comp_tuple[0]], self.specs[:, comp_tuple[-1]])
+ self.w1.setLabel("bottom", f"PC{comp_tuple[0]+1}")
+ self.w1.setLabel("left", f"PC{comp_tuple[-1]+1}")
+ self.label_im1.setText(f"PC{comp_tuple[0]+1}")
+ self.label_im2.setText(f"PC{comp_tuple[-1]+1}")
+
+ def createMask(self, Line=False):
+
+ self.size = self.img1.max() / 10
+ self.pos = int(self.img1.mean())
+
+ if Line:
+ self.lineROI = pg.LineSegmentROI(
+ [0, 1],
+ pos=(self.pos, self.pos),
+ pen=pg.mkPen("r", width=4),
+ hoverPen=pg.mkPen("g", width=4),
+ removable=True,
+ )
+ self.w1.addItem(self.lineROI)
+
+ else:
+
+ self.scatter_mask = pg.PolyLineROI(
+ [[0, 0], [0, self.size], [self.size, self.size], [self.size, 0]],
+ pos=(self.pos, self.pos),
+ pen=pg.mkPen("r", width=4),
+ hoverPen=pg.mkPen("g", width=4),
+ closed=True,
+ removable=True,
+ )
+
+ self.w1.addItem(self.scatter_mask)
+
+ def resetMask(self):
+ self.clearMask()
+ self.createMask()
+
+ def clearMask(self):
+ try:
+ self.w1.removeItem(self.scatter_mask)
+ except AttributeError:
+ pass
+
+ def clearPgPlot(self):
+ try:
+ self.masked_img.close()
+ except Exception:
+ pass
+
+ def getMaskRegion(self):
+
+ # Ref : https://stackoverflow.com/questions/57719303/how-to-map-mouse-position-on-a-scatterplot
+
+ roiShape = self.scatter_mask.mapToItem(self.s1, self.scatter_mask.shape())
+ self._points = list()
+ logger.info("Building Scatter Plot Window; Please wait..")
+ for i in range(len(self.img1.flatten())):
+ self._points.append(QtCore.QPointF(self.img1.flatten()[i], self.img2.flatten()[i]))
+
+ selected = [roiShape.contains(pt) for pt in self._points]
+ img_selected = np.reshape(selected, (self.img1.shape))
+
+ self.masked_img = singleStackViewer(img_selected * self.img1, gradient="bipolar")
+ self.masked_img.show()
+
+ def pg_export_correlation(self):
+
+ exporter = pg.exporters.CSVExporter(self.w1)
+ exporter.parameters()["columnMode"] = "(x,y,y,y) for all plots"
+ file_name = QFileDialog().getSaveFileName(self, "save correlation", "", "spectrum and fit (*csv)")
+ if file_name[0]:
+ exporter.export(str(file_name[0]) + ".csv")
+ self.statusbar.showMessage(f"Data saved to {str(file_name[0])}")
+ else:
+ pass
+
+ def tiff_export_images(self):
+ file_name = QFileDialog().getSaveFileName(self, "save images", "", "spectrum and fit (*tiff)")
+ if file_name[0]:
+ tf.imsave(str(file_name[0]) + ".tiff", np.dstack([self.img1, self.img2]).T)
+ self.statusbar.showMessage(f"Images saved to {str(file_name[0])}")
+ else:
+ pass
+
+class LoadingScreen(QtWidgets.QSplashScreen):
+ def __init__(self):
+ super(LoadingScreen, self).__init__()
+ uic.loadUi(os.path.join(ui_path, "uis/animationWindow.ui"), self)
+ self.setWindowOpacity(0.65)
+ self.movie = QMovie("uis/animation.gif")
+ self.label.setMovie(self.movie)
+
+ def mousePressEvent(self, event):
+ # disable default "click-to-dismiss" behaviour
+ pass
+
+ def startAnimation(self):
+ self.movie.start()
+ self.show()
+
+ def stopAnimation(self):
+ self.movie.stop()
+ self.hide()
+
+class CompositeScatterPlot(QtWidgets.QMainWindow):
+ def __init__(self, scatterPoints, fitLine, maskImages, fitEquations, nameTuple):
+ super(CompositeScatterPlot, self).__init__()
+
+ uic.loadUi(os.path.join(ui_path, "uis/multipleScatterFit.ui"), self)
+ self.user_wd = os.path.abspath("~")
+ self.centralwidget.setStyleSheet(open(os.path.join(ui_path, "css/defaultStyle.css")).read())
+
+ self.scatterPoints = scatterPoints
+ # print(f"{np.shape(self.scatterPoints) = }")
+ self.fitLine = fitLine
+ #print(f"{np.shape(self.fitLine) = }")
+ self.scatterColors = ["r", (0, 115, 0), (4, 186, 186), "c", "w", "k"]
+ self.fitColors = ["b", "r", "m", "k", "b"]
+ self.roiNames = list(fitEquations.keys())
+ self.fitEqns = list(fitEquations.values())
+ # print(f"{np.shape(self.roiNames) = }")
+ # print(f"{np.shape(self.fitEqns) = }")
+ self.nameTuple = nameTuple
+ self.maskImages = maskImages
+
+ # self.scatterViewer.setBackground('w')
+ # set the graphicslayoutwidget in the ui as canvas
+ self.canvas = self.scatterViewer.addPlot()
+ self.canvas.addLegend()
+ self.canvas.setLabel("bottom", self.nameTuple[0], "counts")
+ self.canvas.setLabel("left", self.nameTuple[1], "counts")
+
+ # connections
+ self.actionExport.triggered.connect(self.exportData)
+ self.actionSave_as_PNG.triggered.connect(self.exportAsPNG)
+ self.actionGenerate_MultiColor_Mask.triggered.connect(self.generateMultiColorView)
+ self.actionWhite.triggered.connect(lambda: self.scatterViewer.setBackground("w"))
+ self.actionBlack.triggered.connect(lambda: self.scatterViewer.setBackground("k"))
+
+ with pg.BusyCursor():
+
+ for arr, fitline, clr, fitClr, rname, feqn in zip(
+ self.scatterPoints, self.fitLine, self.scatterColors, self.fitColors, self.roiNames, self.fitEqns
+ ):
+
+ sctrPoints = []
+ for pt in arr:
+ sctrPoints.append(
+ {"pos": (pt[0], pt[1]), "data": "id", "size": 3, "pen": pg.mkPen(None), "brush": clr}
+ )
+
+ # generate a scatter plot item
+ self.scattered = pg.ScatterPlotItem(size=4.5, pen=clr, brush=pg.mkBrush(5, 214, 255, 200))
+ # set scatter plot data
+ self.scattered.addPoints(sctrPoints, name=rname)
+
+ # set z value negative to show scatter data behind the fit line
+ self.scattered.setZValue(-10)
+
+ # add scatter plot to the canvas
+ self.canvas.addItem(self.scattered)
+
+ # generate plotitem for fit line
+ self.fitLinePlot = pg.PlotDataItem(pen=pg.mkPen(fitClr, width=4.5))
+
+ # set line plot data
+ self.fitLinePlot.setData(fitline, name=feqn)
+
+ # add line plot to the canvas
+ self.canvas.addItem(self.fitLinePlot)
+
+ def generateMultiColorView(self):
+ self.multichanneldict = {}
+
+ for n, (colorName, image, rname) in enumerate(zip(cmap_dict.keys(), self.maskImages, self.roiNames)):
+ low, high = np.min(image), np.max(image)
+ self.multichanneldict[rname] = {
+ "ImageName": rname,
+ "ImageDir": ".",
+ "Image": image,
+ "Color": colorName,
+ "CmapLimits": (low, high),
+ "Opacity": 1.0,
+ }
+
+ # print( self.multichanneldict)
+ self.muli_color_window = MultiChannelWindow(image_dict=self.multichanneldict)
+ self.muli_color_window.show()
+
+ def exportData(self):
+
+ exporter = pg.exporters.CSVExporter(self.canvas)
+ # exporter.parameters()['columnMode'] = '(x,y,y,y) for all plots'
+ file_name = QFileDialog().getSaveFileName(self,
+ "Save CSV Data",
+ os.path.join(self.user_wd,"scatter.csv"),
+ "image file (*csv)")
+ if file_name[0]:
+ exporter.export(str(file_name[0]))
+ self.statusbar.showMessage(f"Data saved to {str(file_name[0])}")
+ self.user_wd = os.path.dirname(file_name[0])
+ else:
+ pass
+
+ def exportAsPNG(self):
+ file_name = QFileDialog().getSaveFileName(self,
+ "Save Image",
+ os.path.join(self.user_wd,"image.png"),
+ "PNG(*.png);; TIFF(*.tiff);; JPG(*.jpg)"
+ )
+ exporter = pg.exporters.ImageExporter(self.canvas)
+
+ if file_name[0]:
+ exporter.export(str(file_name[0]))
+ self.statusbar.showMessage(f"Image saved to {str(file_name[0])}")
+ self.user_wd = os.path.dirname(file_name[0])
+ else:
+ pass
+
+class MaskSpecViewer(QtWidgets.QMainWindow):
+ def __init__(self, xanes_stack=None, xrf_map=None, energy=[]):
+ super(MaskSpecViewer, self).__init__()
+ uic.loadUi(os.path.join(ui_path, "uis/MaskedView.ui"), self)
+ self.user_wd = os.path.abspath("~")
+
+ self.xanes_stack = xanes_stack
+ self.xrf_map = xrf_map
+ self.energy = energy
+ self.xrf_map = self.xanes_stack[-1]
+ self.view_data()
+
+ # connections
+ self.sldr_xrf_low.valueChanged.connect(self.create_mask)
+ self.sldr_xrf_high.valueChanged.connect(self.create_mask)
+ self.pb_apply_mask.clicked.connect(self.apply_mask_to_xanes)
+ self.pb_export_mask.clicked.connect(self.export_mask)
+ self.pb_import_mask.clicked.connect(self.import_a_mask)
+ self.actionLoad_Energy_List.triggered.connect(self.load_energy)
+ self.actionLoad_XANES_Stack.triggered.connect(self.load_xanes_stack)
+ self.actionLoad_XRF_Map.triggered.connect(self.load_xrf_map)
+
+ def view_data(self):
+
+ self.xanes_view.setImage(self.xanes_stack)
+ self.xanes_view.ui.menuBtn.hide()
+ self.xanes_view.ui.roiBtn.hide()
+ (self.dim1, self.dim3, self.dim2) = self.xanes_stack.shape
+ self.xanes_view.setPredefinedGradient("viridis")
+ self.xanes_view.setCurrentIndex(self.dim1 // 2)
+ self.statusbar.showMessage("One image from the XANES stack is used as mask")
+ self.xrf_view.setImage(self.xrf_map)
+ self.xrf_view.ui.menuBtn.hide()
+ self.xrf_view.ui.roiBtn.hide()
+ self.xrf_view.setPredefinedGradient("viridis")
+
+ self.mask_view.ui.menuBtn.hide()
+ self.mask_view.ui.roiBtn.hide()
+
+ def create_mask(self):
+ self.threshold_low = np.around(self.sldr_xrf_low.value() * 0.01, 3)
+ self.threshold_high = np.around(self.sldr_xrf_high.value() * 0.01, 3)
+ self.sldr_xrf_low.setMaximum(self.sldr_xrf_high.value() + 1)
+ self.sldr_xrf_high.setMinimum(self.sldr_xrf_low.value() + 1)
+ self.norm_xrf_map = remove_nan_inf(self.xrf_map) / remove_nan_inf(self.xrf_map.max())
+ self.norm_xrf_map[self.norm_xrf_map < self.threshold_low] = 0
+ self.norm_xrf_map[self.norm_xrf_map > self.threshold_high] = 0
+ self.xrf_view.setImage(self.norm_xrf_map)
+ self.le_sldr_vals.setText(str(self.threshold_low) + " to " + str(self.threshold_high))
+ self.statusbar.showMessage("New Threshold Applied")
+ self.xrf_mask = np.where(self.norm_xrf_map > 0, self.norm_xrf_map, 0)
+ self.xrf_mask[self.xrf_mask > 0] = 1
+ self.mask_view.setImage(self.xrf_mask)
+
+ def load_xanes_stack(self):
+ """loading a new xanes stack"""
+ filename = QFileDialog().getOpenFileName(self, "Select image data", "", "image file(*tiff *tif )")
+ self.file_name = str(filename[0])
+ self.xanes_stack = tf.imread(self.file_name).transpose(0, 2, 1)
+ self.view_data()
+
+ def load_energy(self):
+ """To load energy list that will be used for plotting the spectra.
+ number of stack should match length of energy list"""
+
+ file_name = QFileDialog().getOpenFileName(self, "Open energy list", "", "text file (*.txt)")
+
+ try:
+ self.energy = np.loadtxt(str(file_name[0]))
+ logger.info("Energy file loaded")
+ assert len(self.energy) == self.dim1
+ self.view_data()
+
+ except OSError:
+ logger.error("No File selected")
+ pass
+
+ def load_xrf_map(self):
+ """To xrf map for masking. If 3D mean will be taken"""
+
+ filename = QFileDialog().getOpenFileName(self, "Select image data", "", "image file(*tiff *tif )")
+ self.xrf_file_name = str(filename[0])
+ self.xrf_map = tf.imread(self.xrf_file_name)
+ if self.xrf_map.ndim == 3:
+ self.xrf_map = self.xrf_map.mean(0).T
+
+ else:
+ self.xrf_map = self.xrf_map.T
+
+ assert (
+ self.dim3,
+ self.dim2,
+ ) == self.xrf_map.shape, f"Unexpected image dimensions: {self.xrf_map.shape} vs {(self.dim2,self.dim3)}"
+
+ self.view_data()
+ self.create_mask()
+
+ def apply_mask_to_xanes(self):
+
+ """Generates a mask with 0 and 1 from the choosen threshold and multply with the xanes stack.
+ A spectrum will be generated from the new masked stack"""
+
+ self.masked_xanes = self.xanes_stack * self.xrf_mask
+ self.xanes_view.setImage(self.masked_xanes)
+ self.xanes_view.setCurrentIndex(self.dim1 // 2)
+ self.statusbar.showMessage("Mask Applied to XANES")
+ self.mask_spec = get_mean_spectra(self.masked_xanes)
+
+ if len(self.energy) != 0:
+ self.xdata = self.energy
+ else:
+ self.xdata = np.arange(0, self.dim1)
+ self.statusbar.showMessage("No Energy List Available; Integer values are used for plotting")
+
+ self.spectrum_view.plot(self.xdata, self.mask_spec, clear=True)
+
+ def import_a_mask(self):
+ filename = QFileDialog().getOpenFileName(self, "Select image data", "", "image file(*tiff *tif )")
+ xrf_file_name = str(filename[0])
+ self.xrf_mask = tf.imread(xrf_file_name).T
+ self.statusbar.showMessage("A New Mask Imported")
+ self.mask_view.setImage(self.xrf_mask)
+ self.apply_mask_to_xanes()
+
+ def export_mask(self):
+ try:
+ file_name = QFileDialog().getSaveFileName(self, "Save image data", "", "image file(*tiff *tif )")
+ tf.imsave(str(file_name[0]) + ".tiff", self.xrf_mask.T)
+ logger.info(f"Updated Image Saved: {str(file_name[0])}")
+ self.statusbar.showMessage("Mask Exported")
+ except Exception:
+ logger.error("No file to save")
+ pass
+
+class StackInfo(QtWidgets.QMainWindow):
+ def __init__(self, text_to_write: str = " "):
+ super(StackInfo, self).__init__()
+ uic.loadUi(os.path.join(ui_path, "uis/log.ui"), self)
+ self.user_wd = os.path.abspath("~")
+
+ self.text_to_write = text_to_write
+ self.pte_run_cmd.setPlainText(self.text_to_write)
+
+ # connections
+ self.pb_save_cmd.clicked.connect(self.save_file)
+ self.pb_clear_cmd.clicked.connect(self.clear_text)
+
+ def save_file(self):
+ S__File = QFileDialog.getSaveFileName(None, "SaveFile", "/", "txt Files (*.txt)")
+
+ Text = self.pte_run_cmd.toPlainText()
+ if S__File[0]:
+ with open(S__File[0], "w") as file:
+ file.write(Text)
+
+ def clear_text(self):
+ self.pte_run_cmd.clear()
+
+class MultiChannelWindow(QtWidgets.QMainWindow):
+ def __init__(self, image_dict=None):
+ super(MultiChannelWindow, self).__init__()
+ if image_dict is None:
+ image_dict = {}
+ uic.loadUi(os.path.join(ui_path, "uis/mutlichannel.ui"), self)
+ self.user_wd = os.path.abspath("~")
+
+ self.canvas = self.img_view.addPlot(title="")
+ self.canvas.getViewBox().invertY(True)
+ self.canvas.setAspectLocked(True)
+ self.cb_choose_color.addItems([i for i in cmap_dict.keys()])
+ #self.canvas.set
+
+ self.image_dict = image_dict
+ self.buildFromDictionary()
+
+ # connections
+ self.actionLoad.triggered.connect(self.createMuliColorAndList)
+ self.actionLoad_Stack.triggered.connect(self.createMuliColorAndList)
+ self.actionSave_Stack_tiff.triggered.connect(self.saveTiffData)
+ self.cb_choose_color.currentTextChanged.connect(self.updateImageDictionary)
+ self.pb_update_low_high.clicked.connect(self.updateImageDictionary)
+ self.listWidget.itemClicked.connect(self.editImageProperties)
+ self.listWidget.itemDoubleClicked.connect(self.showOneImageOnly)
+ self.pb_show_selected.clicked.connect(self.showOneImageOnly)
+ self.pb_show_all.clicked.connect(self.showAllItems)
+ self.actionLoad_State_File.triggered.connect(self.importState)
+ self.actionSave_State.triggered.connect(self.exportState)
+ self.actionSave_View.triggered.connect(self.saveImage)
+
+ def buildFromDictionary(self):
+ if self.image_dict is not None:
+ self.createMultiColorView(self.image_dict)
+ self.displayImageNames(self.image_dict)
+ else:
+ pass
+
+ def generateImageDictionary(self):
+ """Creates a dictionary contains image path, color scheme chosen, throshold limits etc.
+ when user edits the parameters dictionary will be updated and unwrapped for display later.
+ This dictionary is saved as json file while saving the state. Two image loading options are possible.
+ User can either select multiple 2D array images or one 3D array (stack)"""
+
+ clickedAction = self.sender()
+
+ if clickedAction.text() == "Load Images":
+ # multiple images are selected
+ self.loadMultipleImageFiles()
+
+ elif clickedAction.text() == "Load Stack":
+ # an image stack is selected
+ self.loadAsStack()
+
+ def loadMultipleImageFiles(self):
+
+ filter = "TIFF (*.tiff);;TIF (*.tif)"
+ QtWidgets.QFileDialog().setFileMode(QtWidgets.QFileDialog.ExistingFiles)
+ # choose mutliple tiff files
+ names = QtWidgets.QFileDialog().getOpenFileNames(self, "Open files", " ", filter)
+ if names[0]:
+ self.image_dict = {}
+ # select the file directory. Image files are expected to be in the same folder
+ self.imageDir = os.path.dirname(names[0][0])
+
+ # create the dictionary
+ for colorName, image in zip(cmap_dict.keys(), names[0]):
+ # squeeze to allow with pseudo 3D axis from some tomo recon (eg. 1, 100,100 array)
+ im_array = np.squeeze(tf.imread(image))
+ # set values for thresholding as image min and max
+ low, high = np.min(im_array), np.max(im_array)
+ # name of the tiff file is chosen as key for the dictionary,
+ # inner keys are properties set for that image
+ im_name = os.path.basename(image)
+ # construct the dictionary
+ self.image_dict[f"{os.path.basename(image)}"] = {
+ "ImageName": im_name,
+ "ImageDir": self.imageDir,
+ "Image": im_array,
+ "Color": colorName,
+ "CmapLimits": (low, high),
+ "Opacity": 1.0,
+ }
+ else:
+ pass
+
+ def loadAsStack(self):
+ """construct the dictionary with image +number as the key.
+ All other steps are similar to the loadMultipleImageFiles function"""
+
+ filter = "TIFF (*.tiff);;TIF (*.tif)"
+ file_name = QtWidgets.QFileDialog().getOpenFileName(
+ self, "Open a Stack", "", "TIFF(*tiff *tif);;all_files (*)", filter
+ )
+ if file_name[0]:
+ self.imageDir = os.path.dirname(file_name[0])
+ self.image_dict = {}
+ im_stack = np.squeeze(tf.imread(file_name[0]))
+ # asset the file is a stack
+ assert im_stack.ndim == 3, "Not a stack"
+ # construct the dictionary
+ for n, (colorName, image) in enumerate(zip(cmap_dict.keys(), im_stack)):
+ low, high = np.min(image), np.max(image)
+ self.image_dict[f"Image {n+1}"] = {
+ "ImageName": f"Image {n+1}",
+ "ImageDir": self.imageDir,
+ "Image": image,
+ "Color": colorName,
+ "CmapLimits": (low, high),
+ "Opacity": 1.0,
+ }
+
+ def loadAnImage(self, image, colormap, cmap_limits, opacity=1):
+ """load single image and colorbar to the widget. This function will be looped for
+ multiple images later
+ """
+ # get pg image item
+ img = pg.ImageItem()
+ # add image to the graphicsview widget
+ self.canvas.addItem(img)
+ # set the color map
+ cmap = pg.ColorMap(pos=np.linspace(0, 1, len(colormap)), color=colormap)
+ # image = np.squeeze(tf.imread(image_path))
+ # set image to the image item with cmap
+ img.setImage(np.array(image), lut=cmap.getLookupTable(), opacity=opacity)
+
+ # set colorbar for thresholding
+ bar = pg.ColorBarItem(values=cmap_limits, cmap=cmap, limits=(0, None), orientation="vertical")
+ bar.setImageItem(img)
+ # set composition mode to plus for overlaying
+ img.setCompositionMode(QtGui.QPainter.CompositionMode_Plus)
+
+ def createMultiColorView(self, image_dictionary):
+ """Function creates multi color image view by taking image
+ data and parameters from the dictionary"""
+
+ # clear the plots and list in case of re-loading
+ self.canvas.clear()
+ self.listWidget.clear()
+
+ # display individual images in for loop
+ for path_and_color in image_dictionary.values():
+ self.loadAnImage(
+ path_and_color["Image"],
+ cmap_dict[path_and_color["Color"]],
+ path_and_color["CmapLimits"],
+ path_and_color["Opacity"],
+ )
+
+ def showOneImageOnly(self):
+ editItem = self.listWidget.currentItem()
+ editRow = self.listWidget.currentRow()
+ for i in range(self.listWidget.count()):
+ if self.listWidget.item(i) == editItem:
+ editItemName = self.listWidget.item(i).text().split(",")[0]
+ self.image_dict[editItemName]["Opacity"] = 1
+
+ elif self.listWidget.item(i) != editItem:
+ editItemName = self.listWidget.item(i).text().split(",")[0]
+ self.image_dict[editItemName]["Opacity"] = 0
+
+ self.createMultiColorView(self.image_dict)
+ self.displayImageNames(self.image_dict)
+ self.listWidget.setCurrentRow(editRow)
+
+ def showAllItems(self):
+
+ editItem = self.listWidget.currentItem()
+ editRow = self.listWidget.currentRow()
+ for i in range(self.listWidget.count()):
+ editItemName = self.listWidget.item(i).text().split(",")[0]
+ self.image_dict[editItemName]["Opacity"] = 1
+
+ self.createMultiColorView(self.image_dict)
+ self.displayImageNames(self.image_dict)
+ self.listWidget.setCurrentRow(editRow)
+
+ def displayImageNames(self, image_dictionary):
+ """Populate the list widget table with image name and color used to plot,
+ using image dictionary input"""
+
+ for im_name, vals in image_dictionary.items():
+ self.listWidget.addItem(f"{im_name},{vals['Color']}")
+ self.listWidget.setCurrentRow(0)
+
+ def createMuliColorAndList(self):
+ """Finally Load Images and poplulate the list widget from the dictionary"""
+ with pg.BusyCursor(): # gives the circle showing gui is doing something
+ self.generateImageDictionary()
+ if self.image_dict:
+ self.createMultiColorView(self.image_dict)
+ self.displayImageNames(self.image_dict)
+
+ else:
+ pass
+
+ def sliderSetUp(self, im_array):
+ """Setting the slider min and max from image values"""
+
+ low = (np.min(im_array) / np.max(im_array)) * 100
+ self.sldr_low.setMaximum(100)
+ self.sldr_low.setMinimum(low)
+ self.sldr_high.setMaximum(100)
+ self.sldr_high.setMinimum(low)
+
+ def editImageProperties(self, item):
+ """function to control the assigned properties such as color,
+ threshold limits, opacity etc of a single image selected using the list widget item"""
+
+ editItem = item.text()
+ # get the dictionary key from item text
+ editItemName = editItem.split(",")[0]
+ editItemColor = editItem.split(",")[1]
+ im_array = self.image_dict[editItemName]["Image"]
+ self.sliderSetUp(im_array)
+ setValLow = (self.image_dict[editItemName]["CmapLimits"][0] * 100) / np.max(im_array)
+ setValHigh = (self.image_dict[editItemName]["CmapLimits"][1] * 100) / np.max(im_array)
+ setOpacity = self.image_dict[editItemName]["Opacity"] * 100
+ self.sldr_low.setValue(int(setValLow))
+ self.sldr_high.setValue(int(setValHigh))
+ self.sldr_opacity.setValue(int(setOpacity))
+ self.low_high_vals.setText(f"low:{self.sldr_low.value()}," f"high:{self.sldr_high.value()}")
+ self.cb_choose_color.setCurrentText(editItemColor)
+
+ def updateImageDictionary(self):
+ newColor = self.cb_choose_color.currentText()
+ editItem = self.listWidget.currentItem().text()
+ editRow = self.listWidget.currentRow()
+ editItemName = editItem.split(",")[0]
+ self.imageDir = self.image_dict[editItemName]["ImageDir"]
+ im_array = self.image_dict[editItemName]["Image"]
+ self.sliderSetUp(im_array)
+ cmap_limits = (
+ self.sldr_low.value() * np.max(im_array) / 100,
+ self.sldr_high.value() * np.max(im_array) / 100,
+ )
+ self.low_high_vals.setText(f"low:{cmap_limits[0]:.3f},high:{cmap_limits[1]:.3f}")
+ opacity = self.sldr_opacity.value() / 100
+ self.opacity_val.setText(str(opacity))
+ self.image_dict[editItemName] = {
+ "ImageName": editItemName,
+ "ImageDir": self.imageDir,
+ "Image": im_array,
+ "Color": newColor,
+ "CmapLimits": cmap_limits,
+ "Opacity": opacity,
+ }
+
+ self.createMultiColorView(self.image_dict)
+ self.displayImageNames(self.image_dict)
+ self.listWidget.setCurrentRow(editRow)
+
+ def exportState(self):
+
+ file_name = QtWidgets.QFileDialog().getSaveFileName(
+ self, "Save Current State", "multicolor_params.json", "json file(*json)"
+ )
+ """
+ for val in self.image_dict.values():
+ val['CmapLimits'] = json.dumps(str(val['CmapLimits']))
+ """
+
+ if file_name[0]:
+
+ with open(f"{file_name[0]}", "w") as fp:
+ json.dump(self.image_dict, fp, indent=4, cls=jsonEncoder)
+
+ else:
+ pass
+
+ def importState(self):
+ file_name = QtWidgets.QFileDialog().getOpenFileName(
+ self, "Open a State File", "", "json file(*json);;all_files (*)"
+ )
+ if file_name[0]:
+ with open(file_name[0], "r") as fp:
+ self.image_dict = json.load(fp)
+
+ self.createMultiColorView(self.image_dict)
+ self.displayImageNames(self.image_dict)
+ else:
+ pass
+
+ def saveImage(self):
+ file_name = QtWidgets.QFileDialog().getSaveFileName(
+ self, "Save Image", "multicolor_image.png", "PNG(*.png);; TIFF(*.tiff);; JPG(*.jpg)"
+ )
+ exporter = pg.exporters.ImageExporter(self.canvas.getViewBox())
+ exporter.export(file_name[0])
+
+ def saveTiffData(self):
+ file_name = QtWidgets.QFileDialog().getSaveFileName(self, "Save Image", 'stack_image_data.tiff',
+ 'TIFF(*.tiff)')
+ saveStack = [image_property['Image'] for image_property in self.image_dict.values()]
+ print(np.shape(saveStack))
+
+ if file_name[0]:
+ tf.imsave(file_name[0], saveStack)
+ else:
+ return
+
+class MultiXANESWindow(MultiChannelWindow):
+
+ def __init__(self, image_dict=None, spec_df=None):
+ super().__init__(image_dict=None)
+
+ self.image_dict = image_dict
+ self.spec_df = spec_df
+
+ uic.loadUi(os.path.join(ui_path, 'uis/MultiImageSpectrumView.ui'), self)
+ self.user_wd = os.path.abspath("~")
+ # Copy from MultiChannelWindow Start here
+ self.canvas = self.img_view.addPlot(title="")
+ self.canvas.getViewBox().invertY(True)
+ #self.canvas.setZValue(-10)
+ self.canvas.setAspectLocked(True)
+ self.cb_choose_color.addItems([i for i in cmap_dict.keys()])
+ #self.canvas.getViewBox().setBackgroundColor(pg.mkColor(222,222,222))
+ #self.canvas.getViewBox().setOpacity(0.5)
+
+ self.image_dict = image_dict
+ self.buildFromDictionary()
+
+ self.actionLoad.triggered.connect(self.createMuliColorAndList)
+ self.actionLoad_Stack.triggered.connect(self.createMuliColorAndList)
+ self.cb_choose_color.currentTextChanged.connect(self.updateImageDictionary)
+ self.pb_update_low_high.clicked.connect(self.updateImageDictionary)
+ self.listWidget.itemClicked.connect(self.editImageProperties)
+ self.listWidget.itemDoubleClicked.connect(self.showOneImageOnly)
+ self.pb_show_selected.clicked.connect(self.showOneImageOnly)
+ self.pb_show_all.clicked.connect(self.showAllItems)
+ self.actionLoad_State_File.triggered.connect(self.importState)
+ self.actionSave_State.triggered.connect(self.exportState)
+ self.actionSave_View.triggered.connect(self.saveImage)
+ # Copy from MultiChannelWindow End here
+ self.actionSave_Spectrum_Data.triggered.connect(self.exportDisplayedSpectra)
+ self.listWidget_Spectrum.itemClicked.connect(self.plotNormSpectrum)
+ self.pb_apply_xanes_norm.clicked.connect(lambda: self.updateSpecData(plotNorm=True))
+ self.createMultiSpectrumLibrary()
+
+ [dsb.valueChanged.connect(lambda: self.updateSpecData()) for dsb in
+ [self.dsb_norm_Eo, self.dsb_norm_pre1, self.dsb_norm_pre2, self.dsb_norm_post1,
+ self.dsb_norm_post2, self.sb_norm_order]]
+
+ def createSpectrumPropertyDict(self, specName, xdata, ydata, e0, pre1, pre2, norm1, norm2, normOrder):
+ SingleSpecProperty = {'Name': specName,
+ 'Data': (xdata, ydata),
+ 'NormParams': [e0, pre1, pre2, norm1, norm2, normOrder]}
+
+ return SingleSpecProperty
+
+ def createMultiSpectrumLibrary(self):
+ self.spec_dict = {}
+ column_names = self.spec_df.columns
+ spec_array = self.spec_df.to_numpy()
+ energy = spec_array[:, 0]
+ for i in range(self.spec_df.shape[1]):
+ if i != 0:
+ specData = spec_array[:, i]
+ e0_init = energy[np.argmax(np.gradient(specData))]
+
+ pre1, pre2, post1, post2 = xanesNormalization(
+ energy,
+ specData,
+ e0=e0_init,
+ step=None,
+ nnorm=1,
+ nvict=0,
+ method = "guess"
+ )
+
+ self.spec_dict[column_names[i]] = self.createSpectrumPropertyDict(column_names[i], energy, specData,
+ e0_init, pre1, pre2, post1, post2, 1)
+ self.nomalizeSpectraAndPlot(self.spec_dict)
+ self.spectrumDictToListWidget()
+
+ def nomalizeSpectraAndPlot(self, spectrumParamDict):
+ # print(self.spec_dict)
+ try:
+ self.spectrum_view.clear()
+ except:
+ pass
+ self.spectrum_view.setLabel("bottom", "Energy")
+ self.spectrum_view.setLabel("left", "Intensity")
+ self.spectrum_view.addLegend()
+ plt_colors = ['r', 'g', (31, 81, 255), 'c', 'm', 'y', 'w']
+ for n, params in enumerate(spectrumParamDict.values()):
+ e0_ = params['NormParams'][0]
+ pre1_ = params['NormParams'][1]
+ pre2_ = params['NormParams'][2]
+ norm1_ = params['NormParams'][3]
+ norm2_ = params['NormParams'][4]
+ normOrder_ = params['NormParams'][5]
+
+ preLine, postLine, self.normData = xanesNormalization(
+ params['Data'][0],
+ params['Data'][1],
+ e0=e0_,
+ step=None,
+ nnorm=normOrder_,
+ nvict=0,
+ pre1=pre1_,
+ pre2=pre2_,
+ norm1=norm1_,
+ norm2=norm2_
+ )
+
+ # 'NormParams': (e0, pre1, pre2, norm1, norm2, normOrder)}
+ self.spectrum_view.plot(params['Data'][0], self.normData,
+ pen=pg.mkPen(plt_colors[n], width=2),
+ name=f"Norm._{params['Name']}")
+
+ def loadAndPlotSpectrumData(self):
+ filter = 'txt (*.tiff);;csv (*.csv)'
+ file_name = QtWidgets.QFileDialog().getOpenFileName(self, "Open a spectrum file", '',
+ 'txt (*.tiff);;csv (*.csv);;all_files (*)', filter)
+
+ if file_name[0]:
+ self.spec_df = pd.read_csv(file_name[0], index_col=None)
+ # print(self.spec_df.head())
+ # print(self.spec_df.shape[1])
+ self.createMultiSpectrumLibrary()
+ else:
+ return
+
+ def spectrumDictToListWidget(self):
+ for params in self.spec_dict.values():
+ # Creates a QListWidgetItem
+ specItem = QtWidgets.QListWidgetItem()
+
+ # Setting QListWidgetItem Text
+ specItem.setText(params['Name'])
+
+ # Setting your QListWidgetItem Data
+ specItem.setData(QtCore.Qt.UserRole, params)
+
+ # Add the new rule to the QListWidget
+ self.listWidget_Spectrum.addItem(specItem)
+
+ def plotNormSpectrum(self, item):
+ self.selectedItem = item
+ self.editItemName = self.selectedItem.text()
+ self.editItemData = self.selectedItem.data(QtCore.Qt.UserRole)
+
+ e0_ = self.editItemData['NormParams'][0]
+ pre1_ = self.editItemData['NormParams'][1]
+ pre2_ = self.editItemData['NormParams'][2]
+ norm1_ = self.editItemData['NormParams'][3]
+ norm2_ = self.editItemData['NormParams'][4]
+ normOrder_ = self.editItemData['NormParams'][5]
+
+ self.dsb_norm_Eo.setValue(e0_) # loop later
+ self.dsb_norm_pre1.setValue(pre1_)
+ self.dsb_norm_pre2.setValue(pre2_)
+ self.dsb_norm_post1.setValue(norm1_)
+ self.dsb_norm_post2.setValue(norm2_)
+ self.sb_norm_order.setValue(normOrder_)
+
+ preLine, postLine, normSpec = xanesNormalization(
+ self.editItemData['Data'][0],
+ self.editItemData['Data'][1],
+ e0=e0_,
+ step=None,
+ nnorm=normOrder_,
+ nvict=0,
+ pre1=pre1_,
+ pre2=pre2_,
+ norm1=norm1_,
+ norm2=norm2_
+ )
+
+ self.spectrum_view.clear()
+ self.spectrum_view.plot(self.editItemData['Data'][0], self.editItemData['Data'][1],
+ title=f"Normalization Plot_{self.editItemData['Name']}",
+ pen=pg.mkPen('y', width=2), name=self.editItemData['Name'])
+ self.spectrum_view.plot(self.editItemData['Data'][0], preLine, pen=pg.mkPen('c', width=2), name='Pre')
+ self.spectrum_view.plot(self.editItemData['Data'][0], postLine, pen=pg.mkPen('m', width=2), name='Norm')
+
+ # def updateNormParamaters(self):
+
+ def updateSpecData(self, plotNorm=False):
+
+ # loop later
+ self.editItemData['NormParams'][0] = self.dsb_norm_Eo.value()
+ self.editItemData['NormParams'][1] = self.dsb_norm_pre1.value()
+ self.editItemData['NormParams'][2] = self.dsb_norm_pre2.value()
+ self.editItemData['NormParams'][3] = self.dsb_norm_post1.value()
+ self.editItemData['NormParams'][4] = self.dsb_norm_post2.value()
+ self.editItemData['NormParams'][5] = self.sb_norm_order.value()
+
+ self.spec_dict[self.editItemName] = self.editItemData
+ self.selectedItem.setData(QtCore.Qt.UserRole, self.editItemData)
+ if plotNorm:
+ self.nomalizeSpectraAndPlot(self.spec_dict)
+ else:
+ self.plotNormSpectrum(self.selectedItem)
+
+ def exportDisplayedSpectra(self):
+ exporter = pg.exporters.CSVExporter(self.spectrum_view.plotItem)
+ exporter.parameters()['columnMode'] = '(x,y,y,y) for all plots'
+ file_name = QFileDialog().getSaveFileName(self, "save spectra", 'xanes.csv', 'spectra (*csv)')
+ if file_name[0]:
+ exporter.export(str(file_name[0]))
+ else:
+ self.statusbar_main.showMessage('Saving cancelled')
+ pass
+
+
+def start_xmidas():
+ def formatter(prog):
+ # Set maximum width such that printed help mostly fits in the RTD theme code block (documentation).
+ return argparse.RawDescriptionHelpFormatter(prog, max_help_position=20, width=90)
+ '''
+ parser = argparse.ArgumentParser(
+ description=f"XMidas: v{__version__}",
+ formatter_class=formatter,
+ )
+ parser.parse_args()
+ '''
+ logger.setLevel(logging.INFO)
+ formatter = logging.Formatter(fmt="%(asctime)s : %(levelname)s : %(message)s")
+ stream_handler = logging.StreamHandler()
+ stream_handler.setFormatter(formatter)
+ stream_handler.setLevel(logging.INFO)
+ if logger.hasHandlers():
+ logger.handlers.clear()
+ logger.addHandler(stream_handler)
+
+ if version.parse(PYQT_VERSION_STR) >= version.parse("5.14"):
+ QApplication.setAttribute(QtCore.Qt.HighDpiScaleFactorRoundingPolicy.PassThrough)
+
+ app = QtWidgets.QApplication(sys.argv)
+ # app.setAttribute(QtCore.Qt.AA_Use96Dpi)
+ window = midasWindow()
+ window.show()
+ sys.exit(app.exec_())
+
+
+if __name__ == "__main__":
+ start_xmidas()
diff --git a/xmidas/uis/ClusterView.ui b/xmidas/uis/ClusterView.ui
index 6f5fa2e..0fea754 100644
--- a/xmidas/uis/ClusterView.ui
+++ b/xmidas/uis/ClusterView.ui
@@ -1,266 +1,266 @@
-
-
- MainWindow
-
-
-
- 0
- 0
- 979
- 815
-
-
-
-
- 0
- 0
-
-
-
- MainWindow
-
-
- background-color: rgb(240, 240, 240);
-font: 10pt "Segoe UI";
-
-
-
- QPushButton {
-background-color: rgb(175, 236, 255);
-color: rgb(255, 5,0);
-}
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- Composite Map
-
-
- Qt::AlignCenter
-
-
-
- -
-
-
- Opan as RGBCMY Image
-
-
-
- -
-
-
-
-
- -
-
-
-
-
-
-
-
-
- Nth Cluster
-
-
- Qt::AlignCenter
-
-
-
- -
-
-
- -
-
-
-
-
-
-
- 0
- 0
-
-
-
- 0
-
-
- 20
-
-
- 1
-
-
- 1
-
-
- Qt::Horizontal
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- font: 12pt "Segoe UI";
-
-
- 1/3
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
- 100
-
-
- 100
-
-
-
-
-
-
-
-
- font: 75 12pt "MS Shell Dlg 2";
-
-
- Cluster Spectrum
-
-
- Qt::AlignCenter
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
-
-
- Show all
-
-
-
-
-
- -
-
-
- QAbstractScrollArea::AdjustToContents
-
-
-
-
-
-
-
-
-
-
-
-
-
- Save All Clusters
-
-
-
-
- Save Current Cluster
-
-
-
-
- Save Composite Map as Masks
-
-
-
-
- Save All Cluster Spectra
-
-
-
-
- Save Current Spectrum
-
-
-
-
- Save Results as a Folder
-
-
-
-
-
- PlotWidget
- QGraphicsView
-
-
-
- ImageView
- QGraphicsView
-
-
-
-
-
-
+
+
+ MainWindow
+
+
+
+ 0
+ 0
+ 979
+ 815
+
+
+
+
+ 0
+ 0
+
+
+
+ MainWindow
+
+
+ background-color: rgb(240, 240, 240);
+font: 10pt "Segoe UI";
+
+
+
+ QPushButton {
+background-color: rgb(175, 236, 255);
+color: rgb(255, 5,0);
+}
+
+
+ -
+
+
-
+
+
-
+
+
+
+
+
+ Composite Map
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+ Opan as RGBCMY Image
+
+
+
+ -
+
+
+
+
+ -
+
+
-
+
+
+
+
+
+ Nth Cluster
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+ -
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+ 0
+
+
+ 20
+
+
+ 1
+
+
+ 1
+
+
+ Qt::Horizontal
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ font: 12pt "Segoe UI";
+
+
+ 1/3
+
+
+
+
+
+
+
+
+
+ -
+
+
-
+
+
+ 100
+
+
+ 100
+
+
-
+
+
-
+
+
+ font: 75 12pt "MS Shell Dlg 2";
+
+
+ Cluster Spectrum
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+
+
+ Show all
+
+
+
+
+
+ -
+
+
+ QAbstractScrollArea::AdjustToContents
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Save All Clusters
+
+
+
+
+ Save Current Cluster
+
+
+
+
+ Save Composite Map as Masks
+
+
+
+
+ Save All Cluster Spectra
+
+
+
+
+ Save Current Spectrum
+
+
+
+
+ Save Results as a Folder
+
+
+
+
+
+ PlotWidget
+ QGraphicsView
+
+
+
+ ImageView
+ QGraphicsView
+
+
+
+
+
+
diff --git a/xmidas/uis/ComponentScatterPlot.ui b/xmidas/uis/ComponentScatterPlot.ui
index 2e4519b..ee95575 100644
--- a/xmidas/uis/ComponentScatterPlot.ui
+++ b/xmidas/uis/ComponentScatterPlot.ui
@@ -1,195 +1,195 @@
-
-
- ScatterPlot
-
-
-
- 0
- 0
- 1034
- 859
-
-
-
- Correlation Plot
-
-
- font: 12pt "MS Shell Dlg 2";
-
-
-
- -
-
-
- 10
-
-
- 10
-
-
- 10
-
-
- 10
-
-
-
-
-
- Image
-
-
- Qt::AlignCenter
-
-
-
- -
-
-
-
-
- -
-
-
- 10
-
-
- 10
-
-
- 10
-
-
- 10
-
-
-
-
-
- Image
-
-
- Qt::AlignCenter
-
-
-
- -
-
-
-
-
- -
-
-
- -
-
-
- Qt::LeftToRight
-
-
- QFrame::StyledPanel
-
-
- QFrame::Raised
-
-
-
-
-
-
- Apply
-
-
-
- -
-
-
- Scatter View of
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- Add A Line
-
-
-
- -
-
-
- Create A Mask
-
-
-
- -
-
-
- Reset Mask
-
-
-
- -
-
-
- Apply Mask
-
-
-
-
-
-
-
-
-
-
-
- Save Plot
-
-
-
-
- Save Images
-
-
-
-
-
- ImageView
- QGraphicsView
-
-
-
- GraphicsLayoutWidget
- QGraphicsView
-
-
-
-
-
-
+
+
+ ScatterPlot
+
+
+
+ 0
+ 0
+ 1034
+ 859
+
+
+
+ Correlation Plot
+
+
+ font: 12pt "MS Shell Dlg 2";
+
+
+
+ -
+
+
+ 10
+
+
+ 10
+
+
+ 10
+
+
+ 10
+
+
-
+
+
+ Image
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+
+
+ -
+
+
+ 10
+
+
+ 10
+
+
+ 10
+
+
+ 10
+
+
-
+
+
+ Image
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+
+
+ -
+
+
+ -
+
+
+ Qt::LeftToRight
+
+
+ QFrame::StyledPanel
+
+
+ QFrame::Raised
+
+
+
-
+
+
+ Apply
+
+
+
+ -
+
+
+ Scatter View of
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+ -
+
+
+
+
+
+ -
+
+
-
+
+
+ Add A Line
+
+
+
+ -
+
+
+ Create A Mask
+
+
+
+ -
+
+
+ Reset Mask
+
+
+
+ -
+
+
+ Apply Mask
+
+
+
+
+
+
+
+
+
+
+
+ Save Plot
+
+
+
+
+ Save Images
+
+
+
+
+
+ ImageView
+ QGraphicsView
+
+
+
+ GraphicsLayoutWidget
+ QGraphicsView
+
+
+
+
+
+
diff --git a/xmidas/uis/ComponentView.ui b/xmidas/uis/ComponentView.ui
index df74ea3..c7aca47 100644
--- a/xmidas/uis/ComponentView.ui
+++ b/xmidas/uis/ComponentView.ui
@@ -1,296 +1,303 @@
-
-
- MainWindow
-
-
-
- 0
- 0
- 920
- 858
-
-
-
- MainWindow
-
-
- background-color: rgb(240, 240, 240);
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Components
-
-
- Qt::AlignCenter
-
-
-
- -
-
-
-
-
- -
-
-
-
-
-
-
- 0
- 0
-
-
-
- QSlider::groove:horizontal {
-border: 1px solid #bbb;
-background: white;
-height: 10px;
-border-radius: 4px;
-}
-
-QSlider::sub-page:horizontal {
-background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
- stop: 0 #66e, stop: 1 #bbf);
-background: qlineargradient(x1: 0, y1: 0.2, x2: 1, y2: 1,
- stop: 0 #bbf, stop: 1 #55f);
-border: 1px solid #777;
-height: 10px;
-border-radius: 4px;
-}
-
-QSlider::add-page:horizontal {
-background: #fff;
-border: 1px solid #777;
-height: 10px;
-border-radius: 4px;
-}
-
-QSlider::handle:horizontal {
-background: qlineargradient(x1:0, y1:0, x2:1, y2:1,
- stop:0 #eee, stop:1 #ccc);
-border: 1px solid #777;
-width: 13px;
-margin-top: -2px;
-margin-bottom: -2px;
-border-radius: 4px;
-}
-
-QSlider::handle:horizontal:hover {
-background: qlineargradient(x1:0, y1:0, x2:1, y2:1,
- stop:0 #fff, stop:1 #ddd);
-border: 1px solid #444;
-border-radius: 2px;
-}
-
-QSlider::sub-page:horizontal:disabled {
-background: #bbb;
-border-color: #999;
-}
-
-QSlider::add-page:horizontal:disabled {
-background: #eee;
-border-color: #999;
-}
-
-QSlider::handle:horizontal:disabled {
-background: #eee;
-border: 1px solid #aaa;
-border-radius: 4px;
-}
-
-QPushButton {
-background-color: rgb(175, 236, 255);
-color: rgb(255, 0, 127);
-}
-
-
- 20
-
-
- 1
-
-
- 1
-
-
- Qt::Horizontal
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- font: 12pt "Segoe UI";
-
-
- 1/3
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
- Component Masks
-
-
- Qt::AlignCenter
-
-
-
- -
-
-
- -
-
-
-
-
-
- Show All Spectra
-
-
-
- -
-
-
- Opan as RGBCMY Image
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
- Masked Spectrum
-
-
- Qt::AlignCenter
-
-
-
- -
-
-
- -
-
-
- -
-
-
-
-
-
- Component Spectrum
-
-
- Qt::AlignCenter
-
-
-
-
-
-
-
- -
-
-
- QFrame::StyledPanel
-
-
- QFrame::Raised
-
-
-
-
-
-
-
-
-
- Open ScatterPlot
-
-
-
-
-
-
-
-
-
-
-
-
- Save
-
-
-
-
-
- PlotWidget
- QGraphicsView
-
-
-
- ImageView
- QGraphicsView
-
-
-
-
-
-
+
+
+ MainWindow
+
+
+
+ 0
+ 0
+ 920
+ 858
+
+
+
+ MainWindow
+
+
+ background-color: rgb(240, 240, 240);
+
+
+
+
+
+
+ -
+
+
-
+
+
-
+
+
-
+
+
-
+
+
+
+
+
+ Components
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+
+
+ -
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+ QSlider::groove:horizontal {
+border: 1px solid #bbb;
+background: white;
+height: 10px;
+border-radius: 4px;
+}
+
+QSlider::sub-page:horizontal {
+background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
+ stop: 0 #66e, stop: 1 #bbf);
+background: qlineargradient(x1: 0, y1: 0.2, x2: 1, y2: 1,
+ stop: 0 #bbf, stop: 1 #55f);
+border: 1px solid #777;
+height: 10px;
+border-radius: 4px;
+}
+
+QSlider::add-page:horizontal {
+background: #fff;
+border: 1px solid #777;
+height: 10px;
+border-radius: 4px;
+}
+
+QSlider::handle:horizontal {
+background: qlineargradient(x1:0, y1:0, x2:1, y2:1,
+ stop:0 #eee, stop:1 #ccc);
+border: 1px solid #777;
+width: 13px;
+margin-top: -2px;
+margin-bottom: -2px;
+border-radius: 4px;
+}
+
+QSlider::handle:horizontal:hover {
+background: qlineargradient(x1:0, y1:0, x2:1, y2:1,
+ stop:0 #fff, stop:1 #ddd);
+border: 1px solid #444;
+border-radius: 2px;
+}
+
+QSlider::sub-page:horizontal:disabled {
+background: #bbb;
+border-color: #999;
+}
+
+QSlider::add-page:horizontal:disabled {
+background: #eee;
+border-color: #999;
+}
+
+QSlider::handle:horizontal:disabled {
+background: #eee;
+border: 1px solid #aaa;
+border-radius: 4px;
+}
+
+QPushButton {
+background-color: rgb(175, 236, 255);
+color: rgb(255, 0, 127);
+}
+
+
+ 20
+
+
+ 1
+
+
+ 1
+
+
+ Qt::Horizontal
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ font: 12pt "Segoe UI";
+
+
+ 1/3
+
+
+
+
+
+
+
+ -
+
+
-
+
+
+
+
+
+ Component Masks
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+ -
+
+
+
+
+
+ Show All Spectra
+
+
+
+ -
+
+
+ Open as RGBCMY Image
+
+
+
+
+
+
+
+ -
+
+
-
+
+
+
+
+
+ Masked Spectrum
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+
+
+
+ Component Spectrum
+
+
+ Qt::AlignCenter
+
+
+
+
+
+
+
+ -
+
+
+ QFrame::StyledPanel
+
+
+ QFrame::Raised
+
+
+
-
+
+
+
+
+
+ Open ScatterPlot
+
+
+
+ -
+
+
+ Open XANES Norm. View
+
+
+
+
+
+
+
+
+
+
+
+
+ Save
+
+
+
+
+
+ PlotWidget
+ QGraphicsView
+
+
+
+ ImageView
+ QGraphicsView
+
+
+
+
+
+
diff --git a/xmidas/uis/Log.ui b/xmidas/uis/Log.ui
index 92ca4ec..6ff023b 100644
--- a/xmidas/uis/Log.ui
+++ b/xmidas/uis/Log.ui
@@ -1,68 +1,68 @@
-
-
- MainWindow
-
-
-
- 0
- 0
- 624
- 759
-
-
-
- Log
-
-
-
- -
-
-
- font: 10pt "Segoe UI";
-
-
- QAbstractScrollArea::AdjustToContentsOnFirstShow
-
-
- QPlainTextEdit::NoWrap
-
-
- start typing here..
-
-
-
- -
-
-
-
-
-
- Save
-
-
-
- -
-
-
- Clear
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+ MainWindow
+
+
+
+ 0
+ 0
+ 624
+ 759
+
+
+
+ Log
+
+
+
+ -
+
+
+ font: 10pt "Segoe UI";
+
+
+ QAbstractScrollArea::AdjustToContentsOnFirstShow
+
+
+ QPlainTextEdit::NoWrap
+
+
+ start typing here..
+
+
+
+ -
+
+
-
+
+
+ Save
+
+
+
+ -
+
+
+ Clear
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/xmidas/uis/MaskedView.ui b/xmidas/uis/MaskedView.ui
index a8c40db..7a08678 100644
--- a/xmidas/uis/MaskedView.ui
+++ b/xmidas/uis/MaskedView.ui
@@ -1,352 +1,352 @@
-
-
- MainWindow
-
-
-
- 0
- 0
- 930
- 779
-
-
-
- MaskedXANES
-
-
-
-
-
-
- -
-
-
-
-
-
- color: rgb(255, 0, 0);
-font: 12pt "MS Shell Dlg 2";
-
-
- XANES Stack
-
-
- Qt::AlignCenter
-
-
-
- -
-
-
-
-
- -
-
-
-
-
-
- font: 12pt "MS Shell Dlg 2";
-color: rgb(255, 0, 0);
-
-
- Mask
-
-
- Qt::AlignCenter
-
-
-
- -
-
-
-
-
- -
-
-
- 0
-
-
-
-
-
- A Tiff Mask with same dimensions
-
-
- background-color: rgb(170, 255, 255);
-font: 10pt "MS Shell Dlg 2";
-
-
- Import Mask
-
-
-
- -
-
-
- Save Mask tiff
-
-
- background-color: rgb(170, 255, 255);
-font: 10pt "MS Shell Dlg 2";
-
-
- Export Mask
-
-
-
- -
-
-
- Apply the mask to XANES
-
-
- background-color: rgb(170, 255, 255);
-font: 10pt "MS Shell Dlg 2";
-
-
- Apply
-
-
-
-
-
- -
-
-
-
-
-
- font: 75 12pt "MS Shell Dlg 2";
-color: rgb(255, 0, 0);
-
-
- Mean Spectrum
-
-
- Qt::AlignCenter
-
-
-
- -
-
-
-
-
- -
-
-
-
-
-
-
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
- -
-
-
- font: 12pt "MS Shell Dlg 2";
-color: rgb(255, 0, 0);
-
-
- XRF Map
-
-
- Qt::AlignCenter
-
-
-
- -
-
-
- font: 10pt "MS Shell Dlg 2";
-color: rgb(255, 0, 0);
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
- Qt::NoFocus
-
-
- 100
-
-
- 5
-
-
- 5
-
-
- 0
-
-
- 0
-
-
- true
-
-
- Qt::Vertical
-
-
- QSlider::TicksAbove
-
-
- 5
-
-
-
-
-
- -
-
-
-
-
-
- Qt::NoFocus
-
-
- 100
-
-
- 5
-
-
- 5
-
-
- 100
-
-
- 100
-
-
- true
-
-
- Qt::Vertical
-
-
- false
-
-
- false
-
-
- QSlider::TicksBelow
-
-
- 5
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Save XANES Stack
-
-
-
-
- Save XRF Map
-
-
-
-
- Save Spectrum
-
-
-
-
- Load Energy List
-
-
-
-
- Load XRF Map
-
-
-
-
- Load XANES Stack
-
-
-
-
-
- ImageView
- QGraphicsView
-
-
-
- PlotWidget
- QGraphicsView
-
-
-
-
-
-
+
+
+ MainWindow
+
+
+
+ 0
+ 0
+ 930
+ 779
+
+
+
+ MaskedXANES
+
+
+
+
+
+
+ -
+
+
-
+
+
+ color: rgb(255, 0, 0);
+font: 12pt "MS Shell Dlg 2";
+
+
+ XANES Stack
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+
+
+ -
+
+
-
+
+
+ font: 12pt "MS Shell Dlg 2";
+color: rgb(255, 0, 0);
+
+
+ Mask
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+
+
+ -
+
+
+ 0
+
+
-
+
+
+ A Tiff Mask with same dimensions
+
+
+ background-color: rgb(170, 255, 255);
+font: 10pt "MS Shell Dlg 2";
+
+
+ Import Mask
+
+
+
+ -
+
+
+ Save Mask tiff
+
+
+ background-color: rgb(170, 255, 255);
+font: 10pt "MS Shell Dlg 2";
+
+
+ Export Mask
+
+
+
+ -
+
+
+ Apply the mask to XANES
+
+
+ background-color: rgb(170, 255, 255);
+font: 10pt "MS Shell Dlg 2";
+
+
+ Apply
+
+
+
+
+
+ -
+
+
-
+
+
+ font: 75 12pt "MS Shell Dlg 2";
+color: rgb(255, 0, 0);
+
+
+ Mean Spectrum
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+
+
+ -
+
+
-
+
+
-
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+ font: 12pt "MS Shell Dlg 2";
+color: rgb(255, 0, 0);
+
+
+ XRF Map
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+ font: 10pt "MS Shell Dlg 2";
+color: rgb(255, 0, 0);
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+ -
+
+
-
+
+
+ -
+
+
-
+
+
-
+
+
+ Qt::NoFocus
+
+
+ 100
+
+
+ 5
+
+
+ 5
+
+
+ 0
+
+
+ 0
+
+
+ true
+
+
+ Qt::Vertical
+
+
+ QSlider::TicksAbove
+
+
+ 5
+
+
+
+
+
+ -
+
+
-
+
+
+ Qt::NoFocus
+
+
+ 100
+
+
+ 5
+
+
+ 5
+
+
+ 100
+
+
+ 100
+
+
+ true
+
+
+ Qt::Vertical
+
+
+ false
+
+
+ false
+
+
+ QSlider::TicksBelow
+
+
+ 5
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Save XANES Stack
+
+
+
+
+ Save XRF Map
+
+
+
+
+ Save Spectrum
+
+
+
+
+ Load Energy List
+
+
+
+
+ Load XRF Map
+
+
+
+
+ Load XANES Stack
+
+
+
+
+
+ ImageView
+ QGraphicsView
+
+
+
+ PlotWidget
+ QGraphicsView
+
+
+
+
+
+
diff --git a/xmidas/uis/MultiImageSpectrumView.ui b/xmidas/uis/MultiImageSpectrumView.ui
new file mode 100644
index 0000000..a418c19
--- /dev/null
+++ b/xmidas/uis/MultiImageSpectrumView.ui
@@ -0,0 +1,734 @@
+
+
+ MainWindow
+
+
+
+ 0
+ 0
+ 1182
+ 821
+
+
+
+ Chemical Map Spectrum View
+
+
+ font: 12pt "Segoe UI"
+
+
+
+ QPushButton {
+border: 1px solid #555;
+border-radius: 5px;
+background: qradialgradient(cx: 0.3, cy: -0.1,
+fx: 0.7, fy: 0.1,
+radius: 1, stop: 0 #fff, stop: 1 #888);
+background-color: rgb(170, 255, 255);
+}
+
+QPushButton:hover{
+ background-color: rgb(255, 255, 0);
+ }
+
+QPushButton:pressed{
+ background-color: rgb(0,255, 0);
+ }
+
+font: 12pt "Segoe UI";
+
+
+ -
+
+
+ QFrame::StyledPanel
+
+
+ QFrame::Raised
+
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+
+ -
+
+
+ Edit
+
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+ 0
+
+
+
+
+ 0
+ 0
+ 212
+ 85
+
+
+
+ Thresholding
+
+
+
-
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+ 0,100
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
-
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+ Qt::NoFocus
+
+
+ click update after making changes
+
+
+ 100
+
+
+ 5
+
+
+ 5
+
+
+ 100
+
+
+ 100
+
+
+ true
+
+
+ Qt::Horizontal
+
+
+ false
+
+
+ false
+
+
+ QSlider::NoTicks
+
+
+ 5
+
+
+
+
+
+ -
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+ Qt::NoFocus
+
+
+ click update after making changes
+
+
+ 100
+
+
+ 5
+
+
+ 5
+
+
+ 0
+
+
+ 0
+
+
+ true
+
+
+ Qt::Horizontal
+
+
+ QSlider::NoTicks
+
+
+ 5
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0
+ 0
+ 212
+ 85
+
+
+
+ Opacity
+
+
+ -
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+ 1
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+ click update after making changes
+
+
+ 100
+
+
+ 10
+
+
+ 100
+
+
+ Qt::Horizontal
+
+
+
+
+
+
+
+
+
+ -
+
+
+ execute above changes to the selected item
+
+
+ Update
+
+
+
+ -
+
+
-
+
+
+ Show Selected
+
+
+
+ -
+
+
+ Show All
+
+
+
+ -
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+ change properties of the selected item
+
+
+ font: 8pt "Segoe UI";
+
+
+ QAbstractScrollArea::AdjustToContents
+
+
+
+ -
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+ Change Selected To
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+ -
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ -
+
+
+ QFrame::StyledPanel
+
+
+ QFrame::Raised
+
+
+
-
+
+
+ -
+
+
+ XANES Normalization Parameters
+
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+ eV
+
+
+ -500.000000000000000
+
+
+ 500.000000000000000
+
+
+ -10.000000000000000
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ eV
+
+
+ 0.000000000000000
+
+
+ 1000.000000000000000
+
+
+ 25.000000000000000
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ 1
+
+
+ 5
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Post-edge
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ to
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Norm. Order
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ eV
+
+
+ 2
+
+
+ -500.000000000000000
+
+
+ 500.000000000000000
+
+
+ 1.000000000000000
+
+
+ -50.000000000000000
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ eV
+
+
+ 0.000000000000000
+
+
+ 1500.000000000000000
+
+
+ 75.000000000000000
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Pre-edge
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ to
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Eo
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ eV
+
+
+ 1000.000000000000000
+
+
+ 20000.000000000000000
+
+
+ 7125.000000000000000
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Plot Normalized Spectra
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
+
+
+
+
+ Load Images
+
+
+ Select and load multiple tiff images to create a multi color view
+
+
+
+
+ Load 2
+
+
+
+
+ Load 3
+
+
+
+
+ Load 4
+
+
+
+
+ Load 5
+
+
+
+
+ Load 6
+
+
+
+
+ Export Image
+
+
+ Export the image view as a sinle image file
+
+
+
+
+ Save State File
+
+
+ Save the current state of the view. Images and properties are saved
+
+
+
+
+ Load State File
+
+
+ Load a state (json file) saved previously.
+
+
+
+
+ Load Stack
+
+
+ Load images as a stack of tiff
+
+
+
+
+ Save Displayed Spectra(.CSV)
+
+
+
+
+
+ PlotWidget
+ QGraphicsView
+
+
+
+ GraphicsLayoutWidget
+ QGraphicsView
+
+
+
+
+
+
diff --git a/xmidas/uis/RefChooser.ui b/xmidas/uis/RefChooser.ui
index eea416f..26f9474 100644
--- a/xmidas/uis/RefChooser.ui
+++ b/xmidas/uis/RefChooser.ui
@@ -1,247 +1,252 @@
-
-
- MainWindow
-
-
-
- 0
- 0
- 986
- 985
-
-
-
- ArrowCursor
-
-
- Select References
-
-
- font: 10pt "MS Shell Dlg 2";
-
-
-
- QCheckBox:checked {
-color: rgb(255, 75, 52);
- background-color: rgb(255, 248, 149);
-}
-
-QPushButton {
-background-color: rgb(175, 236, 255);
-color: rgb(255, 5,0);
-}
-
-QPushButton:disabled {
-background-color: rgb(255, 227, 213);
-color: rgb(255, 255, 255);
-}
-
-
-
-
-
-
- 25
-
-
- 25
-
-
- 25
-
-
- 25
-
- -
-
-
-
- 0
- 0
-
-
-
- QFrame::StyledPanel
-
-
- QFrame::Raised
-
-
-
-
- -
-
-
- Drag the line or double click on a point to select the parameters
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- QFrame::StyledPanel
-
-
- QFrame::Raised
-
-
-
-
-
-
-
-
-
-
-
-
- Max. No. of Refs
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
- 1
-
-
- 10
-
-
- 2
-
-
-
-
-
-
-
- -
-
-
- Try All Cobinations
-
-
-
- -
-
-
- false
-
-
- Fit With Selected
-
-
-
-
-
-
- -
-
-
- color: rgb(255, 75, 52);
-font: 10pt "MS Shell Dlg 2";
-
-
- N Combinations
-
-
- Qt::AlignCenter
-
-
-
- -
-
-
- selection-color: rgb(0, 170, 127);
-
-
- 1
-
-
-
- -
-
-
-
-
-
- Sort by
-
-
-
- -
-
-
-
-
- Fit Number
-
-
- -
-
- Reduced Chi-Square
-
-
- -
-
- R-Factor
-
-
- -
-
- R-Square
-
-
- -
-
- Chi-Square
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
- Export Results (.csv)
-
-
-
-
-
- PlotWidget
- QGraphicsView
-
-
-
-
-
-
+
+
+ MainWindow
+
+
+
+ 0
+ 0
+ 986
+ 985
+
+
+
+ ArrowCursor
+
+
+ Select References
+
+
+ font: 10pt "MS Shell Dlg 2";
+
+
+
+ QCheckBox:checked {
+color: rgb(255, 75, 52);
+ background-color: rgb(255, 248, 149);
+}
+
+QPushButton {
+background-color: rgb(175, 236, 255);
+color: rgb(255, 5,0);
+}
+
+QPushButton:disabled {
+background-color: rgb(255, 227, 213);
+color: rgb(255, 255, 255);
+}
+
+
+
+
+
+
+ 25
+
+
+ 25
+
+
+ 25
+
+
+ 25
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ QFrame::StyledPanel
+
+
+ QFrame::Raised
+
+
+
+
+ -
+
+
+ Drag the line or double click on a point to select the parameters
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ QFrame::StyledPanel
+
+
+ QFrame::Raised
+
+
+
-
+
+
-
+
+
-
+
+
+ Max. No. of Refs
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+ -
+
+
+ 1
+
+
+ 10
+
+
+ 2
+
+
+
+
+
+
+
+ -
+
+
+ Try All Cobinations
+
+
+
+ -
+
+
+ false
+
+
+ Fit With Selected
+
+
+
+
+
+
+ -
+
+
+ color: rgb(255, 75, 52);
+font: 10pt "MS Shell Dlg 2";
+
+
+ N Combinations
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+ selection-color: rgb(0, 170, 127);
+
+
+ 1
+
+
+
+ -
+
+
-
+
+
+ Sort by
+
+
+
+ -
+
+
-
+
+ Reduced Chi-Square
+
+
+ -
+
+ Score
+
+
+ -
+
+ Fit Number
+
+
+ -
+
+ R-Factor
+
+
+ -
+
+ R-Square
+
+
+ -
+
+ Chi-Square
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
+
+ Export Results (.csv)
+
+
+
+
+
+ PlotWidget
+ QGraphicsView
+
+
+
+
+
+
diff --git a/xmidas/uis/SVGs/Arrow Down.svg b/xmidas/uis/SVGs/Arrow Down.svg
deleted file mode 100644
index cce1eec..0000000
--- a/xmidas/uis/SVGs/Arrow Down.svg
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
diff --git a/xmidas/uis/SVGs/Arrow Left.svg b/xmidas/uis/SVGs/Arrow Left.svg
deleted file mode 100644
index 93a3cd4..0000000
--- a/xmidas/uis/SVGs/Arrow Left.svg
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
diff --git a/xmidas/uis/SVGs/Arrow Right.svg b/xmidas/uis/SVGs/Arrow Right.svg
deleted file mode 100644
index fb1f0e1..0000000
--- a/xmidas/uis/SVGs/Arrow Right.svg
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
diff --git a/xmidas/uis/SVGs/Arrow Up.svg b/xmidas/uis/SVGs/Arrow Up.svg
deleted file mode 100644
index 40dbd57..0000000
--- a/xmidas/uis/SVGs/Arrow Up.svg
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
diff --git a/xmidas/uis/SVGs/Basket.svg b/xmidas/uis/SVGs/Basket.svg
deleted file mode 100644
index e33eea3..0000000
--- a/xmidas/uis/SVGs/Basket.svg
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
diff --git a/xmidas/uis/SVGs/Book.svg b/xmidas/uis/SVGs/Book.svg
deleted file mode 100644
index 27d79f2..0000000
--- a/xmidas/uis/SVGs/Book.svg
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
diff --git a/xmidas/uis/SVGs/Calendar.svg b/xmidas/uis/SVGs/Calendar.svg
deleted file mode 100644
index 8e6ee76..0000000
--- a/xmidas/uis/SVGs/Calendar.svg
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
diff --git a/xmidas/uis/SVGs/Camera.svg b/xmidas/uis/SVGs/Camera.svg
deleted file mode 100644
index 80b9e35..0000000
--- a/xmidas/uis/SVGs/Camera.svg
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
diff --git a/xmidas/uis/SVGs/Case.svg b/xmidas/uis/SVGs/Case.svg
deleted file mode 100644
index 173d397..0000000
--- a/xmidas/uis/SVGs/Case.svg
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
diff --git a/xmidas/uis/SVGs/Change View.svg b/xmidas/uis/SVGs/Change View.svg
deleted file mode 100644
index 9332cfc..0000000
--- a/xmidas/uis/SVGs/Change View.svg
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
diff --git a/xmidas/uis/SVGs/Check V2.svg b/xmidas/uis/SVGs/Check V2.svg
deleted file mode 100644
index c8a5e40..0000000
--- a/xmidas/uis/SVGs/Check V2.svg
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
diff --git a/xmidas/uis/SVGs/Check.svg b/xmidas/uis/SVGs/Check.svg
deleted file mode 100644
index dadeaed..0000000
--- a/xmidas/uis/SVGs/Check.svg
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
diff --git a/xmidas/uis/SVGs/Chervon Right Circle.svg b/xmidas/uis/SVGs/Chervon Right Circle.svg
deleted file mode 100644
index 1492a0b..0000000
--- a/xmidas/uis/SVGs/Chervon Right Circle.svg
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
-
-
diff --git a/xmidas/uis/SVGs/Chevron Down Circle.svg b/xmidas/uis/SVGs/Chevron Down Circle.svg
deleted file mode 100644
index c7ce17b..0000000
--- a/xmidas/uis/SVGs/Chevron Down Circle.svg
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
-
-
diff --git a/xmidas/uis/SVGs/Chevron Down.svg b/xmidas/uis/SVGs/Chevron Down.svg
deleted file mode 100644
index 56a3576..0000000
--- a/xmidas/uis/SVGs/Chevron Down.svg
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
diff --git a/xmidas/uis/SVGs/Chevron Left Circle.svg b/xmidas/uis/SVGs/Chevron Left Circle.svg
deleted file mode 100644
index a0e84b0..0000000
--- a/xmidas/uis/SVGs/Chevron Left Circle.svg
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
-
-
diff --git a/xmidas/uis/SVGs/Chevron Left.svg b/xmidas/uis/SVGs/Chevron Left.svg
deleted file mode 100644
index f296cd7..0000000
--- a/xmidas/uis/SVGs/Chevron Left.svg
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
diff --git a/xmidas/uis/SVGs/Chevron Right.svg b/xmidas/uis/SVGs/Chevron Right.svg
deleted file mode 100644
index f468a3f..0000000
--- a/xmidas/uis/SVGs/Chevron Right.svg
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
diff --git a/xmidas/uis/SVGs/Chevron Up Circle.svg b/xmidas/uis/SVGs/Chevron Up Circle.svg
deleted file mode 100644
index 3ebfe80..0000000
--- a/xmidas/uis/SVGs/Chevron Up Circle.svg
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
-
-
diff --git a/xmidas/uis/SVGs/Chevron Up.svg b/xmidas/uis/SVGs/Chevron Up.svg
deleted file mode 100644
index fc00cf6..0000000
--- a/xmidas/uis/SVGs/Chevron Up.svg
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
diff --git a/xmidas/uis/SVGs/Clock.svg b/xmidas/uis/SVGs/Clock.svg
deleted file mode 100644
index 2bc6f3f..0000000
--- a/xmidas/uis/SVGs/Clock.svg
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
diff --git a/xmidas/uis/SVGs/Close.svg b/xmidas/uis/SVGs/Close.svg
deleted file mode 100644
index 5e22958..0000000
--- a/xmidas/uis/SVGs/Close.svg
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
diff --git a/xmidas/uis/SVGs/Cog.svg b/xmidas/uis/SVGs/Cog.svg
deleted file mode 100644
index 9a39f32..0000000
--- a/xmidas/uis/SVGs/Cog.svg
+++ /dev/null
@@ -1,40 +0,0 @@
-
-
-
-
diff --git a/xmidas/uis/SVGs/Cross Circle.svg b/xmidas/uis/SVGs/Cross Circle.svg
deleted file mode 100644
index b4d5ebb..0000000
--- a/xmidas/uis/SVGs/Cross Circle.svg
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
diff --git a/xmidas/uis/SVGs/Download.svg b/xmidas/uis/SVGs/Download.svg
deleted file mode 100644
index deeac83..0000000
--- a/xmidas/uis/SVGs/Download.svg
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
diff --git a/xmidas/uis/SVGs/Edit V2.svg b/xmidas/uis/SVGs/Edit V2.svg
deleted file mode 100644
index 49c8796..0000000
--- a/xmidas/uis/SVGs/Edit V2.svg
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
diff --git a/xmidas/uis/SVGs/Edit.svg b/xmidas/uis/SVGs/Edit.svg
deleted file mode 100644
index 7494aef..0000000
--- a/xmidas/uis/SVGs/Edit.svg
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
diff --git a/xmidas/uis/SVGs/File.svg b/xmidas/uis/SVGs/File.svg
deleted file mode 100644
index 9dadb9b..0000000
--- a/xmidas/uis/SVGs/File.svg
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
-
-
diff --git a/xmidas/uis/SVGs/Grid.svg b/xmidas/uis/SVGs/Grid.svg
deleted file mode 100644
index b9792e5..0000000
--- a/xmidas/uis/SVGs/Grid.svg
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
-
-
diff --git a/xmidas/uis/SVGs/Heart.svg b/xmidas/uis/SVGs/Heart.svg
deleted file mode 100644
index 5f71778..0000000
--- a/xmidas/uis/SVGs/Heart.svg
+++ /dev/null
@@ -1,18 +0,0 @@
-
-
-
-
diff --git a/xmidas/uis/SVGs/Image.svg b/xmidas/uis/SVGs/Image.svg
deleted file mode 100644
index 8399140..0000000
--- a/xmidas/uis/SVGs/Image.svg
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
diff --git a/xmidas/uis/SVGs/Link.svg b/xmidas/uis/SVGs/Link.svg
deleted file mode 100644
index fba631d..0000000
--- a/xmidas/uis/SVGs/Link.svg
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
diff --git a/xmidas/uis/SVGs/Location Cursor.svg b/xmidas/uis/SVGs/Location Cursor.svg
deleted file mode 100644
index 65858b3..0000000
--- a/xmidas/uis/SVGs/Location Cursor.svg
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
diff --git a/xmidas/uis/SVGs/Location.svg b/xmidas/uis/SVGs/Location.svg
deleted file mode 100644
index 7626878..0000000
--- a/xmidas/uis/SVGs/Location.svg
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
diff --git a/xmidas/uis/SVGs/Logout.svg b/xmidas/uis/SVGs/Logout.svg
deleted file mode 100644
index 04d2dde..0000000
--- a/xmidas/uis/SVGs/Logout.svg
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
-
-
diff --git a/xmidas/uis/SVGs/Mail.svg b/xmidas/uis/SVGs/Mail.svg
deleted file mode 100644
index c64f596..0000000
--- a/xmidas/uis/SVGs/Mail.svg
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
diff --git a/xmidas/uis/SVGs/Menu.svg b/xmidas/uis/SVGs/Menu.svg
deleted file mode 100644
index af3578c..0000000
--- a/xmidas/uis/SVGs/Menu.svg
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
-
-
diff --git a/xmidas/uis/SVGs/Message.svg b/xmidas/uis/SVGs/Message.svg
deleted file mode 100644
index 0dc9f24..0000000
--- a/xmidas/uis/SVGs/Message.svg
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
diff --git a/xmidas/uis/SVGs/Microphone.svg b/xmidas/uis/SVGs/Microphone.svg
deleted file mode 100644
index d3bdff4..0000000
--- a/xmidas/uis/SVGs/Microphone.svg
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
diff --git a/xmidas/uis/SVGs/More.svg b/xmidas/uis/SVGs/More.svg
deleted file mode 100644
index ad2af87..0000000
--- a/xmidas/uis/SVGs/More.svg
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
diff --git a/xmidas/uis/SVGs/Plus Circle.svg b/xmidas/uis/SVGs/Plus Circle.svg
deleted file mode 100644
index be293d9..0000000
--- a/xmidas/uis/SVGs/Plus Circle.svg
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
diff --git a/xmidas/uis/SVGs/Plus.svg b/xmidas/uis/SVGs/Plus.svg
deleted file mode 100644
index 9a2a645..0000000
--- a/xmidas/uis/SVGs/Plus.svg
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
diff --git a/xmidas/uis/SVGs/Power Button.svg b/xmidas/uis/SVGs/Power Button.svg
deleted file mode 100644
index 2541ea6..0000000
--- a/xmidas/uis/SVGs/Power Button.svg
+++ /dev/null
@@ -1,32 +0,0 @@
-
-
-
-
diff --git a/xmidas/uis/SVGs/Printer.svg b/xmidas/uis/SVGs/Printer.svg
deleted file mode 100644
index 5ac0097..0000000
--- a/xmidas/uis/SVGs/Printer.svg
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
diff --git a/xmidas/uis/SVGs/Settings.svg b/xmidas/uis/SVGs/Settings.svg
deleted file mode 100644
index 28474d0..0000000
--- a/xmidas/uis/SVGs/Settings.svg
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
diff --git a/xmidas/uis/SVGs/Share.svg b/xmidas/uis/SVGs/Share.svg
deleted file mode 100644
index 3fe3197..0000000
--- a/xmidas/uis/SVGs/Share.svg
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
diff --git a/xmidas/uis/SVGs/Shutter.svg b/xmidas/uis/SVGs/Shutter.svg
deleted file mode 100644
index 92d99e7..0000000
--- a/xmidas/uis/SVGs/Shutter.svg
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
diff --git a/xmidas/uis/SVGs/Star.svg b/xmidas/uis/SVGs/Star.svg
deleted file mode 100644
index facd65d..0000000
--- a/xmidas/uis/SVGs/Star.svg
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
-
diff --git a/xmidas/uis/SVGs/Trash.svg b/xmidas/uis/SVGs/Trash.svg
deleted file mode 100644
index ec862c9..0000000
--- a/xmidas/uis/SVGs/Trash.svg
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
diff --git a/xmidas/uis/SVGs/Trophy.svg b/xmidas/uis/SVGs/Trophy.svg
deleted file mode 100644
index 050c08d..0000000
--- a/xmidas/uis/SVGs/Trophy.svg
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
diff --git a/xmidas/uis/SVGs/User.svg b/xmidas/uis/SVGs/User.svg
deleted file mode 100644
index 71bb60b..0000000
--- a/xmidas/uis/SVGs/User.svg
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
diff --git a/xmidas/uis/SVGs/Video.svg b/xmidas/uis/SVGs/Video.svg
deleted file mode 100644
index 6d8869f..0000000
--- a/xmidas/uis/SVGs/Video.svg
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
diff --git a/xmidas/uis/Scatter3D.ui b/xmidas/uis/Scatter3D.ui
index ca2ab8d..cefddb8 100644
--- a/xmidas/uis/Scatter3D.ui
+++ b/xmidas/uis/Scatter3D.ui
@@ -1,130 +1,130 @@
-
-
- MainWindow
-
-
-
- 0
- 0
- 658
- 628
-
-
-
- MainWindow
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- 0
- 0
-
-
-
-
-
-
-
-
-
-
-
-
-
- Export
-
-
-
-
- Save as PNG
-
-
-
-
- Generate MultiColor Mask
-
-
-
-
- Black
-
-
-
-
- Charcol
-
-
-
-
- White
-
-
-
-
- Open Images
-
-
-
-
- Open a Stack
-
-
-
-
- Export Image
-
-
-
-
-
- GLViewWidget
- QGraphicsView
-
-
-
-
-
-
+
+
+ MainWindow
+
+
+
+ 0
+ 0
+ 658
+ 628
+
+
+
+ MainWindow
+
+
+
+ -
+
+
+
+
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Export
+
+
+
+
+ Save as PNG
+
+
+
+
+ Generate MultiColor Mask
+
+
+
+
+ Black
+
+
+
+
+ Charcol
+
+
+
+
+ White
+
+
+
+
+ Open Images
+
+
+
+
+ Open a Stack
+
+
+
+
+ Export Image
+
+
+
+
+
+ GLViewWidget
+ QGraphicsView
+
+
+
+
+
+
diff --git a/xmidas/uis/Scatter3D_plotly.ui b/xmidas/uis/Scatter3D_plotly.ui
index 1318496..df22d6d 100644
--- a/xmidas/uis/Scatter3D_plotly.ui
+++ b/xmidas/uis/Scatter3D_plotly.ui
@@ -1,120 +1,120 @@
-
-
- MainWindow
-
-
-
- 0
- 0
- 856
- 628
-
-
-
- MainWindow
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- 0
- 0
-
-
-
-
-
-
-
-
-
-
-
-
-
- toolBar
-
-
- TopToolBarArea
-
-
- false
-
-
-
-
-
-
-
- Export
-
-
-
-
- Save as PNG
-
-
-
-
- Generate MultiColor Mask
-
-
-
-
- Black
-
-
-
-
- Grey
-
-
-
-
- White
-
-
-
-
-
- QWebEngineView
- QGraphicsView
-
-
-
-
-
-
+
+
+ MainWindow
+
+
+
+ 0
+ 0
+ 856
+ 628
+
+
+
+ MainWindow
+
+
+
+ -
+
+
+
+
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+
+
+
+
+
+
+
+
+
+
+ toolBar
+
+
+ TopToolBarArea
+
+
+ false
+
+
+
+
+
+
+
+ Export
+
+
+
+
+ Save as PNG
+
+
+
+
+ Generate MultiColor Mask
+
+
+
+
+ Black
+
+
+
+
+ Grey
+
+
+
+
+ White
+
+
+
+
+
+ QWebEngineView
+ QGraphicsView
+
+
+
+
+
+
diff --git a/xmidas/uis/ScatterView.ui b/xmidas/uis/ScatterView.ui
index f5394d3..4f0831e 100644
--- a/xmidas/uis/ScatterView.ui
+++ b/xmidas/uis/ScatterView.ui
@@ -1,249 +1,249 @@
-
-
- CorrelationPlot
-
-
-
- 0
- 0
- 1034
- 859
-
-
-
- Correlation Plot
-
-
- font:10pt "Segoe UI";
-
-
-
- QRadioButton::indicator {
- border: 3px solid rgb(150, 150,150);
- width: 15px;
- height: 15px;
- border-radius: 10px;
- background: rgb(255, 255, 255);
-}
-QRadioButton::indicator:hover {
- border: 3px solid rgb(58, 66, 81);
-}
-QRadioButton::indicator:checked {
- background: 3px solid rgb(225, 75, 225);
- border: 3px solid rgb(255, 252, 255);
-}
-
-
- -
-
-
- ROI Mask
-
-
-
-
-
-
-
-
-
- color: rgb(255, 0, 0);
-background-color: rgb(20, 20, 20);
-font: 87 10pt "Segoe UI Black";
-
-
-
- ROI 1
-
-
- true
-
-
- false
-
-
-
- -
-
-
- color: rgb(0, 255, 0);
-background-color: rgb(20, 20, 20);
-font: 87 10pt "Segoe UI Black";
-
-
- ROI 2
-
-
- false
-
-
-
- -
-
-
- color: rgb(0, 255, 255);
-background-color: rgb(20, 20, 20);
-font: 87 10pt "Segoe UI Black";
-
-
- ROI 3
-
-
- false
-
-
-
-
-
- -
-
-
- Create Composite Scatter Plot
-
-
-
- -
-
-
- Apply ROI Mask(s)
-
-
-
- -
-
-
- Clear Unchecked
-
-
-
- -
-
-
- Add Checked ROI(s)
-
-
-
-
-
-
- -
-
-
- 10
-
-
- 10
-
-
- 10
-
-
- 10
-
-
-
-
-
- Image 1 (Blue Shade)
-
-
- Qt::AlignCenter
-
-
-
- -
-
-
-
-
- -
-
-
- 10
-
-
- 10
-
-
- 10
-
-
- 10
-
-
-
-
-
- Image 2 (Green Shade)
-
-
- Qt::AlignCenter
-
-
-
- -
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- Save Plot
-
-
-
-
- Save Images
-
-
-
-
- Swap Axes
-
-
-
-
-
- GraphicsLayoutWidget
- QGraphicsView
-
-
-
- ImageView
- QGraphicsView
-
-
-
-
-
-
+
+
+ CorrelationPlot
+
+
+
+ 0
+ 0
+ 1034
+ 859
+
+
+
+ Correlation Plot
+
+
+ font:10pt "Segoe UI";
+
+
+
+ QRadioButton::indicator {
+ border: 3px solid rgb(150, 150,150);
+ width: 15px;
+ height: 15px;
+ border-radius: 10px;
+ background: rgb(255, 255, 255);
+}
+QRadioButton::indicator:hover {
+ border: 3px solid rgb(58, 66, 81);
+}
+QRadioButton::indicator:checked {
+ background: 3px solid rgb(225, 75, 225);
+ border: 3px solid rgb(255, 252, 255);
+}
+
+
+ -
+
+
+ ROI Mask
+
+
+
-
+
+
-
+
+
+ color: rgb(255, 0, 0);
+background-color: rgb(20, 20, 20);
+font: 87 10pt "Segoe UI Black";
+
+
+
+ ROI 1
+
+
+ true
+
+
+ false
+
+
+
+ -
+
+
+ color: rgb(0, 255, 0);
+background-color: rgb(20, 20, 20);
+font: 87 10pt "Segoe UI Black";
+
+
+ ROI 2
+
+
+ false
+
+
+
+ -
+
+
+ color: rgb(0, 255, 255);
+background-color: rgb(20, 20, 20);
+font: 87 10pt "Segoe UI Black";
+
+
+ ROI 3
+
+
+ false
+
+
+
+
+
+ -
+
+
+ Create Composite Scatter Plot
+
+
+
+ -
+
+
+ Apply ROI Mask(s)
+
+
+
+ -
+
+
+ Clear Unchecked
+
+
+
+ -
+
+
+ Add Checked ROI(s)
+
+
+
+
+
+
+ -
+
+
+ 10
+
+
+ 10
+
+
+ 10
+
+
+ 10
+
+
-
+
+
+ Image 1 (Blue Shade)
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+
+
+ -
+
+
+ 10
+
+
+ 10
+
+
+ 10
+
+
+ 10
+
+
-
+
+
+ Image 2 (Green Shade)
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+
+
+
+
+
+
+
+ Save Plot
+
+
+
+
+ Save Images
+
+
+
+
+ Swap Axes
+
+
+
+
+
+ GraphicsLayoutWidget
+ QGraphicsView
+
+
+
+ ImageView
+ QGraphicsView
+
+
+
+
+
+
diff --git a/xmidas/uis/StackViewer.ui b/xmidas/uis/StackViewer.ui
index 62f2665..1d58ea9 100644
--- a/xmidas/uis/StackViewer.ui
+++ b/xmidas/uis/StackViewer.ui
@@ -1,335 +1,335 @@
-
-
- MainWindow
-
-
-
- 0
- 0
- 931
- 815
-
-
-
- MainWindow
-
-
-
-
-
- 11
- 30
- 701
- 326
-
-
-
-
- 0
- 0
-
-
-
-
-
-
- 10
- 390
- 891
- 371
-
-
-
-
-
-
- 720
- 80
- 181
- 171
-
-
-
-
- 0
- 0
-
-
-
- Image ROI
-
-
-
- 11
-
-
- 11
-
- -
-
-
-
-
-
-
-
-
-
-
-
- Y End
-
-
-
- -
-
-
- true
-
-
-
-
-
- -
-
-
-
-
-
- X Start
-
-
-
- -
-
-
- true
-
-
-
-
-
- -
-
-
-
-
-
- Y Start
-
-
-
- -
-
-
- true
-
-
-
-
-
- -
-
-
-
-
-
- X End
-
-
-
- -
-
-
- true
-
-
-
-
-
-
-
- -
-
-
-
-
-
- font: 75 10pt "MS Shell Dlg 2";
-
-
- Size
-
-
-
- -
-
-
- true
-
-
-
-
-
-
-
-
-
-
-
-
- 720
- 250
- 181
- 139
-
-
-
-
- 0
- 0
-
-
-
- Spectrum ROI
-
-
- -
-
-
- Sync
-
-
-
- -
-
-
-
-
-
- Start
-
-
-
- -
-
-
- 10000
-
-
- 2
-
-
-
-
-
- -
-
-
-
-
-
- End
-
-
-
- -
-
-
- 1
-
-
- 10000
-
-
- 2
-
-
- 10
-
-
-
-
-
- -
-
-
-
-
-
- font: 75 10pt "MS Shell Dlg 2";
-
-
- Size
-
-
-
- -
-
-
- true
-
-
-
-
-
-
-
-
-
-
- 730
- 10
- 171
- 70
-
-
-
- -
-
-
- false
-
-
- background-color: rgb(170, 255, 255);
-font: 75 12pt "MS Shell Dlg 2";
-
-
- Play
-
-
-
- -
-
-
- Log View
-
-
-
- -
-
-
- Reset
-
-
-
-
-
-
-
-
-
-
-
- ImageView
- QGraphicsView
-
-
-
- PlotWidget
- QGraphicsView
-
-
-
-
-
-
+
+
+ MainWindow
+
+
+
+ 0
+ 0
+ 931
+ 815
+
+
+
+ MainWindow
+
+
+
+
+
+ 11
+ 30
+ 701
+ 326
+
+
+
+
+ 0
+ 0
+
+
+
+
+
+
+ 10
+ 390
+ 891
+ 371
+
+
+
+
+
+
+ 720
+ 80
+ 181
+ 171
+
+
+
+
+ 0
+ 0
+
+
+
+ Image ROI
+
+
+
+ 11
+
+
+ 11
+
+ -
+
+
-
+
+
-
+
+
-
+
+
+ Y End
+
+
+
+ -
+
+
+ true
+
+
+
+
+
+ -
+
+
-
+
+
+ X Start
+
+
+
+ -
+
+
+ true
+
+
+
+
+
+ -
+
+
-
+
+
+ Y Start
+
+
+
+ -
+
+
+ true
+
+
+
+
+
+ -
+
+
-
+
+
+ X End
+
+
+
+ -
+
+
+ true
+
+
+
+
+
+
+
+ -
+
+
-
+
+
+ font: 75 10pt "MS Shell Dlg 2";
+
+
+ Size
+
+
+
+ -
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+ 720
+ 250
+ 181
+ 139
+
+
+
+
+ 0
+ 0
+
+
+
+ Spectrum ROI
+
+
+ -
+
+
+ Sync
+
+
+
+ -
+
+
-
+
+
+ Start
+
+
+
+ -
+
+
+ 10000
+
+
+ 2
+
+
+
+
+
+ -
+
+
-
+
+
+ End
+
+
+
+ -
+
+
+ 1
+
+
+ 10000
+
+
+ 2
+
+
+ 10
+
+
+
+
+
+ -
+
+
-
+
+
+ font: 75 10pt "MS Shell Dlg 2";
+
+
+ Size
+
+
+
+ -
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+ 730
+ 10
+ 171
+ 70
+
+
+
+ -
+
+
+ false
+
+
+ background-color: rgb(170, 255, 255);
+font: 75 12pt "MS Shell Dlg 2";
+
+
+ Play
+
+
+
+ -
+
+
+ Log View
+
+
+
+ -
+
+
+ Reset
+
+
+
+
+
+
+
+
+
+
+
+ ImageView
+ QGraphicsView
+
+
+
+ PlotWidget
+ QGraphicsView
+
+
+
+
+
+
diff --git a/xmidas/uis/XANESViewer.ui b/xmidas/uis/XANESViewer.ui
index 1209c09..aad2c61 100644
--- a/xmidas/uis/XANESViewer.ui
+++ b/xmidas/uis/XANESViewer.ui
@@ -1,431 +1,413 @@
-
-
- mainWindow
-
-
-
- 0
- 0
- 1089
- 854
-
-
-
- XANES View
-
-
- font: 10pt "Verdana";
-
-
-
-
-
- QPushButton {
-background-color: rgb(175, 236, 255);
-color: rgb(255, 5,0);
-}
-
-
- -
-
-
-
-
-
- QFrame::StyledPanel
-
-
- QFrame::Raised
-
-
-
-
-
-
-
-
-
-
- 0
- 0
-
-
-
- Fit 2D
-
-
-
- -
-
-
-
-
-
-
-
-
- E_shift
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
- -10.000000000000000
-
-
- 10.000000000000000
-
-
- 0.500000000000000
-
-
-
- -
-
-
- Alpha:
-
-
-
- -
-
-
- 10.000000000000000
-
-
- 0.250000000000000
-
-
- 0.100000000000000
-
-
-
-
-
- -
-
-
-
-
-
- Fitting Model
-
-
-
- -
-
-
-
-
- NNLS
-
-
- -
-
- LASSO
-
-
- -
-
- RIDGE
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- font: 8pt "MS Shell Dlg 2";
-color: rgb(0, 85, 255);
-
-
- Results Text
-
-
- Qt::AlignCenter
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- 0
- 0
-
-
-
- ROI Position
-
-
- Qt::AlignCenter
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Qt::Horizontal
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
-
-
- -
-
-
-
-
-
-
- 0
- 0
-
-
-
-
-
-
-
-
-
-
-
-
-
- Qt::Horizontal
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Opan as RGBCMY Image
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
-
-
- XANES Maps
-
-
- Qt::AlignCenter
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Show Component Spectrum
-
-
-
-
-
- -
-
-
-
-
-
- Live ROI Fit
-
-
- Qt::AlignCenter
-
-
-
- -
-
-
-
-
- -
-
-
-
-
-
-
- 0
- 0
-
-
-
- Choose References
-
-
-
- -
-
-
-
-
-
- References
-
-
- Qt::AlignCenter
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- Export Fit Stats
-
-
-
-
- Export Ref. Plot
-
-
-
-
- Save Chem Map
-
-
-
-
- Save R-factor Image
-
-
-
-
- false
-
-
- Export References
-
-
-
-
- Export Fit Stats
-
-
-
-
- Save Live Fit Data
-
-
-
-
-
- PlotWidget
- QGraphicsView
-
-
-
- ImageView
- QGraphicsView
-
-
-
-
-
-
+
+
+ mainWindow
+
+
+
+ 0
+ 0
+ 983
+ 811
+
+
+
+ XANES Fit View
+
+
+ font: 10pt "Segoe UI";
+
+
+
+
+ QPushButton {
+background-color: rgb(175, 236, 255);
+color: rgb(255, 5,0);
+}
+
+
+
+ 22
+
+
+ 22
+
+
+ 22
+
+
+ 22
+
+ -
+
+
-
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+ ROI Position
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Qt::Horizontal
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+
+
+ -
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+
+
+
+ XANES Maps
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Qt::Horizontal
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Open Composite Chem Map Viewer
+
+
+
+
+
+ -
+
+
-
+
+
+ Live ROI Fit
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+
+
+ -
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+ Choose References
+
+
+
+ -
+
+
+
+
+
+ References
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+
+
+
+
+ -
+
+
-
+
+
-
+
+
-
+
+
+ E_shift
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+ -
+
+
+ -10.000000000000000
+
+
+ 10.000000000000000
+
+
+ 0.500000000000000
+
+
+
+ -
+
+
+ Alpha:
+
+
+
+ -
+
+
+ 10.000000000000000
+
+
+ 0.250000000000000
+
+
+ 0.100000000000000
+
+
+
+
+
+ -
+
+
-
+
+
+ Fitting Model
+
+
+
+ -
+
+
-
+
+ NNLS
+
+
+ -
+
+ LASSO
+
+
+ -
+
+ RIDGE
+
+
+
+
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Fit 2D
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ font: 8pt "MS Shell Dlg 2";
+color: rgb(0, 85, 255);
+
+
+ Results Text
+
+
+ Qt::AlignCenter
+
+
+
+
+
+
+
+
+
+
+
+ Export Fit Stats
+
+
+
+
+ Export Ref. Plot
+
+
+
+
+ Save Chem Map
+
+
+
+
+ Save R-factor Image
+
+
+
+
+ false
+
+
+ Export References
+
+
+
+
+ Export Fit Stats
+
+
+
+
+ Save Live Fit Data
+
+
+
+
+
+ PlotWidget
+ QGraphicsView
+
+
+
+ ImageView
+ QGraphicsView
+
+
+
+
+
+
diff --git a/xmidas/uis/__init__.py b/xmidas/uis/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/xmidas/uis/align_test.ui b/xmidas/uis/align_test.ui
index da5604d..a5ab854 100644
--- a/xmidas/uis/align_test.ui
+++ b/xmidas/uis/align_test.ui
@@ -1,71 +1,71 @@
-
-
- MainWindow
-
-
-
- 0
- 0
- 280
- 271
-
-
-
- MainWindow
-
-
-
-
-
- 100
- 50
- 93
- 28
-
-
-
- Load
-
-
-
-
-
- 100
- 100
- 93
- 28
-
-
-
- Align
-
-
-
-
-
- 100
- 160
- 93
- 28
-
-
-
- Save
-
-
-
-
-
-
-
-
-
+
+
+ MainWindow
+
+
+
+ 0
+ 0
+ 280
+ 271
+
+
+
+ MainWindow
+
+
+
+
+
+ 100
+ 50
+ 93
+ 28
+
+
+
+ Load
+
+
+
+
+
+ 100
+ 100
+ 93
+ 28
+
+
+
+ Align
+
+
+
+
+
+ 100
+ 160
+ 93
+ 28
+
+
+
+ Save
+
+
+
+
+
+
+
+
+
diff --git a/xmidas/uis/animation2.gif b/xmidas/uis/animation2.gif
deleted file mode 100644
index b5261ca..0000000
Binary files a/xmidas/uis/animation2.gif and /dev/null differ
diff --git a/xmidas/uis/animationWindow.ui b/xmidas/uis/animationWindow.ui
index b90a5e0..21e0c3a 100644
--- a/xmidas/uis/animationWindow.ui
+++ b/xmidas/uis/animationWindow.ui
@@ -1,68 +1,68 @@
-
-
- Wait
-
-
-
- 0
- 0
- 200
- 200
-
-
-
- Wait...
-
-
- Qt::LeftToRight
-
-
-
-background-color: rgba(0, 0, 90, 125);
-
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
- -
-
-
-
- 0
- 0
-
-
-
- Qt::NoContextMenu
-
-
-
-
-
-
-
-
- false
-
-
- Qt::AlignCenter
-
-
-
-
-
-
-
-
+
+
+ Wait
+
+
+
+ 0
+ 0
+ 200
+ 200
+
+
+
+ Wait...
+
+
+ Qt::LeftToRight
+
+
+
+background-color: rgba(0, 0, 90, 125);
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Qt::NoContextMenu
+
+
+
+
+
+
+
+
+ false
+
+
+ Qt::AlignCenter
+
+
+
+
+
+
+
+
diff --git a/xmidas/uis/mainwindow_admin.ui b/xmidas/uis/mainwindow_admin.ui
deleted file mode 100644
index a7d17b9..0000000
--- a/xmidas/uis/mainwindow_admin.ui
+++ /dev/null
@@ -1,2814 +0,0 @@
-
-
- Ajith
- MainWindow
-
-
- true
-
-
-
- 0
- 0
- 1364
- 1060
-
-
-
-
- 0
- 0
-
-
-
- NSLS-II MIDAS
-
-
-
- ../pancake.ico../pancake.ico
-
-
- font: 12pt "Segoe UI";
-
-
-
-
- true
-
-
-
- 0
- 0
-
-
-
- font: 10pt "Segoe UI";
-
-
-QPushButton {
-background-color: rgb(175, 236, 255);
-color: rgb(255, 5,0);
-}
-
-QSlider::groove:horizontal {
-border: 1px solid #bbb;
-background: white;
-height: 10px;
-border-radius: 4px;
-}
-
-QSlider::sub-page:horizontal {
-background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
- stop: 0 #66e, stop: 1 #bbf);
-background: qlineargradient(x1: 0, y1: 0.2, x2: 1, y2: 1,
- stop: 0 #bbf, stop: 1 #55f);
-border: 1px solid #777;
-height: 10px;
-border-radius: 4px;
-}
-
-QSlider::add-page:horizontal {
-background: #fff;
-border: 1px solid #777;
-height: 10px;
-border-radius: 4px;
-}
-
-QSlider::handle:horizontal {
-background: qlineargradient(x1:0, y1:0, x2:1, y2:1,
- stop:0 #eee, stop:1 #ccc);
-border: 1px solid #777;
-width: 13px;
-margin-top: -2px;
-margin-bottom: -2px;
-border-radius: 4px;
-}
-
-QSlider::handle:horizontal:hover {
-background: qlineargradient(x1:0, y1:0, x2:1, y2:1,
- stop:0 #fff, stop:1 #ddd);
-border: 1px solid #444;
-border-radius: 2px;
-}
-
-QSlider::sub-page:horizontal:disabled {
-background: #bbb;
-border-color: #999;
-}
-
-QSlider::add-page:horizontal:disabled {
-background: #eee;
-border-color: #999;
-}
-
-QSlider::handle:horizontal:disabled {
-background: #eee;
-border: 1px solid #aaa;
-border-radius: 4px;
-}
-
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- QFrame::StyledPanel
-
-
- QFrame::Sunken
-
-
-
-
-
-
-
- 0
- 0
-
-
-
-
-
-
- 0
-
-
-
-
- 0
- 0
- 411
- 355
-
-
-
- Adjust Image Dimensions
-
-
-
-
-
-
-
- 0
- 0
-
-
-
-
-
-
- QFrame::StyledPanel
-
-
- QFrame::Raised
-
-
-
-
-
-
- QLayout::SetMinimumSize
-
-
-
-
-
-
- 0
- 0
-
-
-
- 0
-
-
- 500
-
-
- 0
-
-
- 10
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- 1
-
-
- 5000
-
-
- 1200
-
-
- 10
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- false
-
-
- px
-
-
- 1
-
-
- 10000
-
-
- 100
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- false
-
-
- px
-
-
- 1
-
-
- 10000
-
-
- 100
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- false
-
-
- px
-
-
- 0
-
-
- 10000
-
-
- 0
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Y Dimension
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- false
-
-
- px
-
-
- 0
-
-
- 10000
-
-
- 0
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- X Dimension
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Stack Range
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- to
-
-
- Qt::AlignCenter
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- to
-
-
- Qt::AlignCenter
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- to
-
-
- Qt::AlignCenter
-
-
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Adjust the dimensions of the image
-
-
-
-
-
- Update
-
-
-
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- QFrame::StyledPanel
-
-
- QFrame::Raised
-
-
-
-
-
-
-
-
-
-
- 0
- 0
-
-
-
- Removes one column/row from all four edges
-
-
- Remove Edges
-
-
-
- -
-
-
-
-
-
- true
-
-
-
- 0
- 0
-
-
-
- rebin
-
-
-
- -
-
-
- true
-
-
-
- 0
- 0
-
-
-
- Upscale
-
-
-
- -
-
-
-
-
-
- Ratio
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
- true
-
-
-
- 0
- 0
-
-
-
- font: 10pt "MS Shell Dlg 2";
-
-
- 2
-
-
- 16
-
-
- 2
-
-
- 2
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 0
- 0
- 334
- 423
-
-
-
- Image Processing
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
- 0
- 0
-
-
-
- Covert image dat to log values.
-
-
-
-
-
- Log
-
-
- false
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Intensity Normalization with the last Frame.
-
-
- Normalize
-
-
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Reverse the arrays. 012 will be 210
-
-
- Qt::LeftToRight
-
-
- Transpose
-
-
-
-
-
- -
-
-
- QFrame::StyledPanel
-
-
- QFrame::Raised
-
-
-
-
-
-
-
-
-
- Remove Outliers (NSigma)
-
-
-
- -
-
-
- false
-
-
-
-
-
- 200
-
-
- 3
-
-
- Qt::Horizontal
-
-
-
- -
-
-
- 1
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
-
-
-
-
-
- -
-
-
- QFrame::StyledPanel
-
-
- QFrame::Raised
-
-
-
-
-
-
-
-
-
-
-
-
- Thresholding
-
-
-
-
-
- -
-
-
-
-
-
- false
-
-
- 100
-
-
- 5
-
-
- 5
-
-
- 5
-
-
- Qt::Horizontal
-
-
-
- -
-
-
- 5
-
-
-
-
-
-
-
-
-
-
- -
-
-
- QFrame::StyledPanel
-
-
- QFrame::Raised
-
-
-
-
-
-
- uses savgol_filter to smooth data
-
-
- Smoothen
-
-
-
- -
-
-
-
-
-
- false
-
-
- 3
-
-
- 12
-
-
- 2
-
-
- 2
-
-
- 3
-
-
- Qt::Horizontal
-
-
- QSlider::TicksBelow
-
-
- 2
-
-
-
- -
-
-
- Window size
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 0
- 0
- 420
- 344
-
-
-
- Alignment
-
-
- -
-
-
-
-
-
-
-
-
-
- Transformations:
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
-
-
- TRANSLATION
-
-
- -
-
- RIGID_BODY
-
-
- -
-
- SCALED_ROTATION
-
-
- -
-
- AFFINE
-
-
- -
-
- BILINEAR
-
-
-
-
-
-
- -
-
-
-
-
-
- Reference:
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
-
-
- previous
-
-
- -
-
- mean
-
-
- -
-
- first
-
-
-
-
-
-
- -
-
-
-
-
-
-
- 0
- 0
-
-
-
- Iterative Mode
-
-
-
- -
-
-
-
-
-
- Max Iter.
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- 2
-
-
- 24
-
-
-
-
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Align
-
-
-
- -
-
-
-
-
-
-
- 0
- 0
-
-
-
- Load Reference Stack
-
-
-
- -
-
-
- No Ref. Available
-
-
- true
-
-
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Save Transformation File
-
-
-
- -
-
-
- Use
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Load Transformation File
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
-
-
- Reset Image
-
-
-
- -
-
-
- true
-
-
- 2
-
-
-
-
- 0
- 0
- 411
- 318
-
-
-
- Component Analysis
-
-
-
-
-
-
-
-
-
-
- 0
- 0
-
-
-
-
-
-
- Calculate Components
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
-
-
- PCA Scree Plot
-
-
-
- -
-
-
-
-
-
- Method
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
-
- PCA
-
-
- -
-
- NMF
-
-
- -
-
- FastICA
-
-
- -
-
- IncrementalPCA
-
-
- -
-
- TruncatedSVD
-
-
- -
-
- FactorAnalysis
-
-
- -
-
- DictionaryLearning
-
-
-
-
-
-
- -
-
-
-
-
-
- Number of Components
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
- 1
-
-
- 4
-
-
-
-
-
-
-
-
-
-
-
-
- 0
- 0
- 411
- 318
-
-
-
- Cluster Analysis
-
-
- -
-
-
-
-
-
-
- 0
- 0
-
-
-
-
-
-
- Calculate Clusters
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
-
-
- KMeans Variance Plot
-
-
-
- -
-
-
- Method
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
-
- KMeans
-
-
- -
-
- MiniBatchKMeans
-
-
- -
-
- MeanShift
-
-
- -
-
- Spectral Clustering
-
-
- -
-
- Correlation-Kmeans
-
-
- -
-
- Affinity Propagation
-
-
-
-
- -
-
-
- Number of Clusters
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
- 1
-
-
- 4
-
-
-
-
-
-
-
-
-
-
- 0
- 0
- 411
- 318
-
-
-
- XANES Fitting
-
-
- -
-
-
-
- 11
-
-
- 11
-
-
-
-
-
-
-
-
-
- 0
- 0
-
-
-
-
-
-
- Load Energy List
-
-
-
- -
-
-
- keV
-
-
-
-
-
- -
-
-
-
-
-
-
- 0
- 0
-
-
-
-
-
-
- Load Ref. Spec.
-
-
-
- -
-
-
-
-
-
- Plot
-
-
-
-
-
- -
-
-
- true
-
-
-
- 0
- 0
-
-
-
-
-
-
- Fit
-
-
-
-
-
-
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 40
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- font:12pt "Segoe UI";
-
-
-
-
-
-
- QLayout::SetMaximumSize
-
-
-
-
-
-
- 0
- 0
-
-
-
-
-
-
- Save Image (.tiff)
-
-
-
- -
-
-
- 0
-
-
-
- Live
-
-
-
-
-
-
-
- 0
- 0
-
-
-
- Send to Collector
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
-
-
- Save
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
-
-
-
-
- Normalized
-
-
- -
-
-
- Save
-
-
-
- -
-
-
- Clear
-
-
-
- -
-
-
- Norm. to Collector
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
-
-
-
-
- Collector
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
- -
-
-
- Clear
-
-
-
- -
-
-
- Save
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
-
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Stack Info
-
-
-
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- QFrame::StyledPanel
-
-
- QFrame::Sunken
-
-
-
- QLayout::SetDefaultConstraint
-
-
- 11
-
-
- 11
-
-
-
-
-
-
- 0
- 0
-
-
-
- ROI Shape
-
-
-
-
-
-
-
- 0
- 0
-
-
-
- Rectangle
-
-
- true
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Ellipse
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Polygon
-
-
- false
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Circle
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Line
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Show ROI Stack
-
-
-
-
-
-
- -
-
-
- font: 9pt "Segoe UI";
-
-
- ROI Positions
-
-
-
-
-
-
- Spectrum ROI
-
-
-
-
-
-
- color: rgb(255, 0,0);
-
-
- roi_size
-
-
-
- -
-
-
- Range (eV):
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
-
-
-
- Size (eV):
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
- color: rgb(255, 0,0);
-
-
- roix, roiy
-
-
-
-
-
-
- -
-
-
- Image ROI
-
-
-
-
-
-
- Position:
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
- color: rgb(255, 0,0);
-
-
- roix, roiy
-
-
-
- -
-
-
-
-
-
- Size(pixels):
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
- color: rgb(255, 0, 0);
-
-
- roi_size
-
-
-
-
-
-
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- 2
-
-
-
-
- 0
- 0
- 361
- 193
-
-
-
- Image Calculations
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Add ROI_2
-
-
-
- -
-
-
- Calculation:
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
-
- Subtract
-
-
- -
-
- Divide
-
-
- -
-
- Add
-
-
- -
-
- Compare
-
-
-
-
-
-
-
-
-
-
-
-
- 0
- 0
- 361
- 193
-
-
-
- Spectrum Calculations
-
-
- -
-
-
-
-
-
-
-
-
-
-
- 0
- 0
-
-
-
- Add ROI 2
-
-
- true
-
-
- false
-
-
-
- -
-
-
-
-
-
-
- 0
- 0
-
-
-
- Calculation
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
-
- Divide
-
-
- -
-
- Subtract
-
-
- -
-
- Add
-
-
- -
-
- Correlation Plot
-
-
-
-
-
-
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 40
-
-
-
-
-
-
-
-
-
-
-
-
- 0
- 0
- 433
- 308
-
-
-
- XANES Normalization
-
-
- -
-
-
-
- 0
- 0
-
-
-
- to
-
-
- Qt::AlignCenter
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- 1
-
-
- 5
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Eo
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- eV
-
-
- 1000.000000000000000
-
-
- 20000.000000000000000
-
-
- 7125.000000000000000
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- calculate the energy point with maximum derivative
-
-
- Auto Eo
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- eV
-
-
- 2
-
-
- -500.000000000000000
-
-
- 500.000000000000000
-
-
- 1.000000000000000
-
-
- -50.000000000000000
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Pre-edge
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- eV
-
-
- -500.000000000000000
-
-
- 500.000000000000000
-
-
- -10.000000000000000
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Post-edge
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- to
-
-
- Qt::AlignCenter
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Norm. Order
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- eV
-
-
- 0.000000000000000
-
-
- 1000.000000000000000
-
-
- 25.000000000000000
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- <html><head/><body><p> For mbak algorithm only, must be in <span style=" font-weight:600; font-style:italic;">element<space>edge</span> format</p></body></html>
-
-
- Fe K
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Element:
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- eV
-
-
- 0.000000000000000
-
-
- 1500.000000000000000
-
-
- 75.000000000000000
-
-
-
- -
-
-
- Initial Guess
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Apply to Spectrum
-
-
-
- -
-
-
- Apply to Stack
-
-
-
-
-
-
-
- -
-
-
- -
-
-
- Available Stacks
-
-
-
-
-
-
-
-
-
-
-
-
- Open PDF
-
-
-
-
- Open in GitHub (most updated)
-
-
-
-
- true
-
-
- Open Image Data
-
-
- Support all tiff and specific h5 files
-
-
- Ctrl+O
-
-
-
-
- Close
-
-
-
-
- Exit
-
-
- Ctrl+Q
-
-
-
-
- false
-
-
- Export Tiff Stack
-
-
- Save the displayed/Modified stack as a tiff file
-
-
- Ctrl+S
-
-
-
-
- Open PyXRF
-
-
-
-
- Open Image J
-
-
-
-
- Open TomViz
-
-
-
-
- Open Mantis
-
-
-
-
- Open Athena
-
-
-
-
- DataBroker
-
-
-
-
- Open HXN DB
-
-
-
-
- false
-
-
- Load Energy
-
-
- Load list of energies for XANES stack. Supports only .txt fromat
-
-
- Ctrl+E
-
-
-
-
- Create a Virtual Stack
-
-
- Create a stack from multiple tiff images of same shape
-
-
- Ctrl+M
-
-
-
-
- true
-
-
- Open Mask Generator
-
-
- A new window will be opened to creat threshold based masks
-
-
-
-
- Create elist from log file
-
-
-
-
- false
-
-
- Save Energy List
-
-
-
-
- true
-
-
- MultiColorView
-
-
- A new window will be opened to align images in a stack
-
-
-
-
- White
-
-
-
-
- true
-
-
- true
-
-
- Black
-
-
-
-
- Red
-
-
-
-
- Yellow
-
-
-
-
- Blue
-
-
-
-
- false
-
-
- false
-
-
- Dark Mode
-
-
-
-
- Black
-
-
-
-
- false
-
-
- false
-
-
- Default
-
-
-
-
- Vivid
-
-
-
-
- Save Sum Image
-
-
-
-
- Subtract ROI as Background
-
-
-
-
- Export Norm. Params
-
-
-
-
- 2
-
-
-
-
- 4
-
-
-
-
- 6
-
-
-
-
- 10
-
-
-
-
- 2
-
-
-
-
- 3
-
-
-
-
- 4
-
-
-
-
- 5
-
-
-
-
- 6
-
-
-
-
- 8
-
-
-
-
- 10
-
-
-
-
- 2
-
-
-
-
- Import Norm. Params
-
-
-
-
- 1
-
-
-
-
- Save Sum Spectrum
-
-
-
-
- Save Mean Spectrum
-
-
-
-
- Save Current Image as Mask
-
-
-
-
-
- PlotWidget
- QGraphicsView
-
-
-
- ImageView
- QGraphicsView
-
-
-
-
-
-
diff --git a/xmidas/uis/maskedScatterPlotFit.ui b/xmidas/uis/maskedScatterPlotFit.ui
index e8bd894..8ad2145 100644
--- a/xmidas/uis/maskedScatterPlotFit.ui
+++ b/xmidas/uis/maskedScatterPlotFit.ui
@@ -1,187 +1,187 @@
-
-
- CorrelationPlot
-
-
-
- 0
- 0
- 967
- 816
-
-
-
- Correlation Plot
-
-
- font: 12pt "MS Shell Dlg 2";
-
-
-
-
- 10
-
-
- 25
-
-
- 10
-
-
- 10
-
- -
-
-
- Scatter Plot
-
-
-
-
-
-
-
- 0
- 0
-
-
-
-
-
-
-
- -
-
-
- Mask
-
-
-
-
-
-
-
- 0
- 0
-
-
-
-
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Fit Results
-
-
-
-
-
-
- Copy
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- font: 11pt "Consolas";
-
-
- true
-
-
-
- -
-
-
- Export
-
-
-
-
-
-
- -
-
-
- Masked Image1
-
-
-
-
-
-
-
- 0
- 0
-
-
-
-
-
-
-
-
-
-
-
-
-
- Scatter Plot+Fit
-
-
-
-
- Mask
-
-
-
-
- Masked Image
-
-
-
-
-
- ImageView
- QGraphicsView
-
-
-
- GraphicsLayoutWidget
- QGraphicsView
-
-
-
-
-
-
+
+
+ CorrelationPlot
+
+
+
+ 0
+ 0
+ 967
+ 816
+
+
+
+ Correlation Plot
+
+
+ font: 12pt "MS Shell Dlg 2";
+
+
+
+
+ 10
+
+
+ 25
+
+
+ 10
+
+
+ 10
+
+ -
+
+
+ Scatter Plot
+
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+
+
+
+
+ -
+
+
+ Mask
+
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Fit Results
+
+
+
-
+
+
+ Copy
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ font: 11pt "Consolas";
+
+
+ true
+
+
+
+ -
+
+
+ Export
+
+
+
+
+
+
+ -
+
+
+ Masked Image1
+
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Scatter Plot+Fit
+
+
+
+
+ Mask
+
+
+
+
+ Masked Image
+
+
+
+
+
+ ImageView
+ QGraphicsView
+
+
+
+ GraphicsLayoutWidget
+ QGraphicsView
+
+
+
+
+
+
diff --git a/xmidas/uis/midas.py b/xmidas/uis/midas.py
deleted file mode 100644
index 4b0ea40..0000000
--- a/xmidas/uis/midas.py
+++ /dev/null
@@ -1,1048 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# Form implementation generated from reading ui file 'mainwindow_admin.ui'
-#
-# Created by: PyQt5 UI code generator 5.14.1
-#
-# WARNING! All changes made in this file will be lost!
-
-
-from PyQt5 import QtCore, QtGui, QtWidgets
-
-
-class Ui_MainWindow(object):
- def setupUi(self, MainWindow):
- MainWindow.setObjectName("MainWindow")
- MainWindow.setEnabled(True)
- MainWindow.resize(1246, 936)
- sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred)
- sizePolicy.setHorizontalStretch(0)
- sizePolicy.setVerticalStretch(0)
- sizePolicy.setHeightForWidth(MainWindow.sizePolicy().hasHeightForWidth())
- MainWindow.setSizePolicy(sizePolicy)
- MainWindow.setStyleSheet("font: 10pt \"Segoe UI\";\n"
-"\n"
-"\n"
-"QSlider::groove:horizontal {\n"
-"border: 1px solid #bbb;\n"
-"background: white;\n"
-"height: 10px;\n"
-"border-radius: 4px;\n"
-"}\n"
-"\n"
-"QSlider::sub-page:horizontal {\n"
-"background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,\n"
-" stop: 0 #66e, stop: 1 #bbf);\n"
-"background: qlineargradient(x1: 0, y1: 0.2, x2: 1, y2: 1,\n"
-" stop: 0 #bbf, stop: 1 #55f);\n"
-"border: 1px solid #777;\n"
-"height: 10px;\n"
-"border-radius: 4px;\n"
-"}\n"
-"\n"
-"QSlider::add-page:horizontal {\n"
-"background: #fff;\n"
-"border: 1px solid #777;\n"
-"height: 10px;\n"
-"border-radius: 4px;\n"
-"}\n"
-"\n"
-"QSlider::handle:horizontal {\n"
-"background: qlineargradient(x1:0, y1:0, x2:1, y2:1,\n"
-" stop:0 #eee, stop:1 #ccc);\n"
-"border: 1px solid #777;\n"
-"width: 13px;\n"
-"margin-top: -2px;\n"
-"margin-bottom: -2px;\n"
-"border-radius: 4px;\n"
-"}\n"
-"\n"
-"QSlider::handle:horizontal:hover {\n"
-"background: qlineargradient(x1:0, y1:0, x2:1, y2:1,\n"
-" stop:0 #fff, stop:1 #ddd);\n"
-"border: 1px solid #444;\n"
-"border-radius: 4px;\n"
-"}\n"
-"\n"
-"QSlider::sub-page:horizontal:disabled {\n"
-"background: #bbb;\n"
-"border-color: #999;\n"
-"}\n"
-"\n"
-"QSlider::add-page:horizontal:disabled {\n"
-"background: #eee;\n"
-"border-color: #999;\n"
-"}\n"
-"\n"
-"QSlider::handle:horizontal:disabled {\n"
-"background: #eee;\n"
-"border: 1px solid #aaa;\n"
-"border-radius: 4px;\n"
-"}")
- self.centralwidget = QtWidgets.QWidget(MainWindow)
- self.centralwidget.setEnabled(False)
- sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.MinimumExpanding)
- sizePolicy.setHorizontalStretch(0)
- sizePolicy.setVerticalStretch(0)
- sizePolicy.setHeightForWidth(self.centralwidget.sizePolicy().hasHeightForWidth())
- self.centralwidget.setSizePolicy(sizePolicy)
- self.centralwidget.setStyleSheet("QSlider::groove:horizontal {\n"
-"border: 1px solid #bbb;\n"
-"background: white;\n"
-"height: 10px;\n"
-"border-radius: 4px;\n"
-"}\n"
-"\n"
-"QSlider::sub-page:horizontal {\n"
-"background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,\n"
-" stop: 0 #66e, stop: 1 #bbf);\n"
-"background: qlineargradient(x1: 0, y1: 0.2, x2: 1, y2: 1,\n"
-" stop: 0 #bbf, stop: 1 #55f);\n"
-"border: 1px solid #777;\n"
-"height: 10px;\n"
-"border-radius: 4px;\n"
-"}\n"
-"\n"
-"QSlider::add-page:horizontal {\n"
-"background: #fff;\n"
-"border: 1px solid #777;\n"
-"height: 10px;\n"
-"border-radius: 4px;\n"
-"}\n"
-"\n"
-"QSlider::handle:horizontal {\n"
-"background: qlineargradient(x1:0, y1:0, x2:1, y2:1,\n"
-" stop:0 #eee, stop:1 #ccc);\n"
-"border: 1px solid #777;\n"
-"width: 13px;\n"
-"margin-top: -2px;\n"
-"margin-bottom: -2px;\n"
-"border-radius: 4px;\n"
-"}\n"
-"\n"
-"QSlider::handle:horizontal:hover {\n"
-"background: qlineargradient(x1:0, y1:0, x2:1, y2:1,\n"
-" stop:0 #fff, stop:1 #ddd);\n"
-"border: 1px solid #444;\n"
-"border-radius: 4px;\n"
-"}\n"
-"\n"
-"QSlider::sub-page:horizontal:disabled {\n"
-"background: #bbb;\n"
-"border-color: #999;\n"
-"}\n"
-"\n"
-"QSlider::add-page:horizontal:disabled {\n"
-"background: #eee;\n"
-"border-color: #999;\n"
-"}\n"
-"\n"
-"QSlider::handle:horizontal:disabled {\n"
-"background: #eee;\n"
-"border: 1px solid #aaa;\n"
-"border-radius: 4px;\n"
-"}")
- self.centralwidget.setObjectName("centralwidget")
- self.gridLayout_16 = QtWidgets.QGridLayout(self.centralwidget)
- self.gridLayout_16.setObjectName("gridLayout_16")
- self.scrollArea = QtWidgets.QScrollArea(self.centralwidget)
- sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Expanding)
- sizePolicy.setHorizontalStretch(0)
- sizePolicy.setVerticalStretch(0)
- sizePolicy.setHeightForWidth(self.scrollArea.sizePolicy().hasHeightForWidth())
- self.scrollArea.setSizePolicy(sizePolicy)
- self.scrollArea.setStyleSheet("font:12pt \"Segoe UI\";")
- self.scrollArea.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.AdjustIgnored)
- self.scrollArea.setWidgetResizable(True)
- self.scrollArea.setAlignment(QtCore.Qt.AlignCenter)
- self.scrollArea.setObjectName("scrollArea")
- self.scrollAreaWidgetContents = QtWidgets.QWidget()
- self.scrollAreaWidgetContents.setGeometry(QtCore.QRect(0, 0, 321, 855))
- self.scrollAreaWidgetContents.setObjectName("scrollAreaWidgetContents")
- self.gridLayout_9 = QtWidgets.QGridLayout(self.scrollAreaWidgetContents)
- self.gridLayout_9.setObjectName("gridLayout_9")
- self.gridLayout_13 = QtWidgets.QGridLayout()
- self.gridLayout_13.setObjectName("gridLayout_13")
- self.pb_reset_img = QtWidgets.QPushButton(self.scrollAreaWidgetContents)
- self.pb_reset_img.setStyleSheet("background-color: rgb(175, 236, 255);\n"
-"color: rgb(255, 0, 127);\n"
-"")
- self.pb_reset_img.setObjectName("pb_reset_img")
- self.gridLayout_13.addWidget(self.pb_reset_img, 0, 0, 1, 1)
- self.gridLayout_9.addLayout(self.gridLayout_13, 1, 0, 1, 1)
- self.toolBox = QtWidgets.QToolBox(self.scrollAreaWidgetContents)
- sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred)
- sizePolicy.setHorizontalStretch(0)
- sizePolicy.setVerticalStretch(0)
- sizePolicy.setHeightForWidth(self.toolBox.sizePolicy().hasHeightForWidth())
- self.toolBox.setSizePolicy(sizePolicy)
- self.toolBox.setStyleSheet("font: 10pt \"Segoe UI\";")
- self.toolBox.setObjectName("toolBox")
- self.page = QtWidgets.QWidget()
- self.page.setGeometry(QtCore.QRect(0, 0, 368, 331))
- self.page.setObjectName("page")
- self.gridLayout_31 = QtWidgets.QGridLayout(self.page)
- self.gridLayout_31.setObjectName("gridLayout_31")
- self.frame_7 = QtWidgets.QFrame(self.page)
- self.frame_7.setFrameShape(QtWidgets.QFrame.StyledPanel)
- self.frame_7.setFrameShadow(QtWidgets.QFrame.Raised)
- self.frame_7.setObjectName("frame_7")
- self.gridLayout_30 = QtWidgets.QGridLayout(self.frame_7)
- self.gridLayout_30.setObjectName("gridLayout_30")
- self.gridLayout_17 = QtWidgets.QGridLayout()
- self.gridLayout_17.setSizeConstraint(QtWidgets.QLayout.SetMinimumSize)
- self.gridLayout_17.setObjectName("gridLayout_17")
- self.sb_zrange1 = QtWidgets.QSpinBox(self.frame_7)
- self.sb_zrange1.setMinimum(0)
- self.sb_zrange1.setMaximum(500)
- self.sb_zrange1.setProperty("value", 0)
- self.sb_zrange1.setDisplayIntegerBase(10)
- self.sb_zrange1.setObjectName("sb_zrange1")
- self.gridLayout_17.addWidget(self.sb_zrange1, 0, 1, 1, 1)
- self.label_5 = QtWidgets.QLabel(self.frame_7)
- self.label_5.setAlignment(QtCore.Qt.AlignCenter)
- self.label_5.setObjectName("label_5")
- self.gridLayout_17.addWidget(self.label_5, 1, 2, 1, 1)
- self.label_9 = QtWidgets.QLabel(self.frame_7)
- self.label_9.setAlignment(QtCore.Qt.AlignCenter)
- self.label_9.setObjectName("label_9")
- self.gridLayout_17.addWidget(self.label_9, 2, 2, 1, 1)
- self.sb_yrange2 = QtWidgets.QSpinBox(self.frame_7)
- self.sb_yrange2.setReadOnly(False)
- self.sb_yrange2.setMinimum(1)
- self.sb_yrange2.setMaximum(10000)
- self.sb_yrange2.setProperty("value", 100)
- self.sb_yrange2.setObjectName("sb_yrange2")
- self.gridLayout_17.addWidget(self.sb_yrange2, 2, 3, 1, 1)
- self.sb_zrange2 = QtWidgets.QSpinBox(self.frame_7)
- self.sb_zrange2.setMinimum(1)
- self.sb_zrange2.setMaximum(5000)
- self.sb_zrange2.setProperty("value", 1200)
- self.sb_zrange2.setDisplayIntegerBase(10)
- self.sb_zrange2.setObjectName("sb_zrange2")
- self.gridLayout_17.addWidget(self.sb_zrange2, 0, 3, 1, 1)
- self.sb_xrange1 = QtWidgets.QSpinBox(self.frame_7)
- self.sb_xrange1.setReadOnly(False)
- self.sb_xrange1.setMinimum(0)
- self.sb_xrange1.setMaximum(10000)
- self.sb_xrange1.setProperty("value", 0)
- self.sb_xrange1.setObjectName("sb_xrange1")
- self.gridLayout_17.addWidget(self.sb_xrange1, 1, 1, 1, 1)
- self.sb_xrange2 = QtWidgets.QSpinBox(self.frame_7)
- self.sb_xrange2.setReadOnly(False)
- self.sb_xrange2.setMinimum(1)
- self.sb_xrange2.setMaximum(10000)
- self.sb_xrange2.setProperty("value", 100)
- self.sb_xrange2.setObjectName("sb_xrange2")
- self.gridLayout_17.addWidget(self.sb_xrange2, 1, 3, 1, 1)
- self.label_22 = QtWidgets.QLabel(self.frame_7)
- self.label_22.setAlignment(QtCore.Qt.AlignCenter)
- self.label_22.setObjectName("label_22")
- self.gridLayout_17.addWidget(self.label_22, 0, 2, 1, 1)
- self.label_19 = QtWidgets.QLabel(self.frame_7)
- self.label_19.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
- self.label_19.setObjectName("label_19")
- self.gridLayout_17.addWidget(self.label_19, 1, 0, 1, 1)
- self.sb_yrange1 = QtWidgets.QSpinBox(self.frame_7)
- self.sb_yrange1.setReadOnly(False)
- self.sb_yrange1.setMinimum(0)
- self.sb_yrange1.setMaximum(10000)
- self.sb_yrange1.setProperty("value", 0)
- self.sb_yrange1.setObjectName("sb_yrange1")
- self.gridLayout_17.addWidget(self.sb_yrange1, 2, 1, 1, 1)
- self.label_15 = QtWidgets.QLabel(self.frame_7)
- self.label_15.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
- self.label_15.setObjectName("label_15")
- self.gridLayout_17.addWidget(self.label_15, 2, 0, 1, 1)
- self.label_20 = QtWidgets.QLabel(self.frame_7)
- self.label_20.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
- self.label_20.setObjectName("label_20")
- self.gridLayout_17.addWidget(self.label_20, 0, 0, 1, 1)
- self.gridLayout_30.addLayout(self.gridLayout_17, 0, 0, 1, 1)
- self.pb_crop = QtWidgets.QPushButton(self.frame_7)
- sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
- sizePolicy.setHorizontalStretch(0)
- sizePolicy.setVerticalStretch(0)
- sizePolicy.setHeightForWidth(self.pb_crop.sizePolicy().hasHeightForWidth())
- self.pb_crop.setSizePolicy(sizePolicy)
- self.pb_crop.setStyleSheet("background-color: rgb(175, 236, 255);\n"
-"color: rgb(255, 0, 127);\n"
-"")
- self.pb_crop.setObjectName("pb_crop")
- self.gridLayout_30.addWidget(self.pb_crop, 1, 0, 1, 1)
- self.gridLayout_31.addWidget(self.frame_7, 1, 0, 1, 1)
- self.frame_6 = QtWidgets.QFrame(self.page)
- self.frame_6.setFrameShape(QtWidgets.QFrame.StyledPanel)
- self.frame_6.setFrameShadow(QtWidgets.QFrame.Raised)
- self.frame_6.setObjectName("frame_6")
- self.gridLayout_7 = QtWidgets.QGridLayout(self.frame_6)
- self.gridLayout_7.setObjectName("gridLayout_7")
- self.horizontalLayout_9 = QtWidgets.QHBoxLayout()
- self.horizontalLayout_9.setObjectName("horizontalLayout_9")
- self.cb_rebin = QtWidgets.QCheckBox(self.frame_6)
- self.cb_rebin.setEnabled(False)
- sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Preferred)
- sizePolicy.setHorizontalStretch(0)
- sizePolicy.setVerticalStretch(0)
- sizePolicy.setHeightForWidth(self.cb_rebin.sizePolicy().hasHeightForWidth())
- self.cb_rebin.setSizePolicy(sizePolicy)
- self.cb_rebin.setObjectName("cb_rebin")
- self.horizontalLayout_9.addWidget(self.cb_rebin)
- self.horizontalLayout_10 = QtWidgets.QHBoxLayout()
- self.horizontalLayout_10.setObjectName("horizontalLayout_10")
- self.cb_upscale = QtWidgets.QCheckBox(self.frame_6)
- self.cb_upscale.setEnabled(False)
- sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Preferred)
- sizePolicy.setHorizontalStretch(0)
- sizePolicy.setVerticalStretch(0)
- sizePolicy.setHeightForWidth(self.cb_upscale.sizePolicy().hasHeightForWidth())
- self.cb_upscale.setSizePolicy(sizePolicy)
- self.cb_upscale.setObjectName("cb_upscale")
- self.horizontalLayout_10.addWidget(self.cb_upscale)
- self.horizontalLayout_9.addLayout(self.horizontalLayout_10)
- self.sb_scaling_factor = QtWidgets.QSpinBox(self.frame_6)
- self.sb_scaling_factor.setEnabled(False)
- sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
- sizePolicy.setHorizontalStretch(0)
- sizePolicy.setVerticalStretch(0)
- sizePolicy.setHeightForWidth(self.sb_scaling_factor.sizePolicy().hasHeightForWidth())
- self.sb_scaling_factor.setSizePolicy(sizePolicy)
- self.sb_scaling_factor.setStyleSheet("font: 10pt \"MS Shell Dlg 2\";")
- self.sb_scaling_factor.setMinimum(2)
- self.sb_scaling_factor.setMaximum(16)
- self.sb_scaling_factor.setSingleStep(2)
- self.sb_scaling_factor.setProperty("value", 2)
- self.sb_scaling_factor.setObjectName("sb_scaling_factor")
- self.horizontalLayout_9.addWidget(self.sb_scaling_factor)
- self.gridLayout_7.addLayout(self.horizontalLayout_9, 2, 0, 1, 1)
- self.cb_remove_edges = QtWidgets.QCheckBox(self.frame_6)
- sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Preferred)
- sizePolicy.setHorizontalStretch(0)
- sizePolicy.setVerticalStretch(0)
- sizePolicy.setHeightForWidth(self.cb_remove_edges.sizePolicy().hasHeightForWidth())
- self.cb_remove_edges.setSizePolicy(sizePolicy)
- self.cb_remove_edges.setObjectName("cb_remove_edges")
- self.gridLayout_7.addWidget(self.cb_remove_edges, 0, 0, 1, 1)
- self.gridLayout_31.addWidget(self.frame_6, 2, 0, 1, 1)
- spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
- self.gridLayout_31.addItem(spacerItem, 0, 0, 1, 1)
- spacerItem1 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
- self.gridLayout_31.addItem(spacerItem1, 3, 0, 1, 1)
- self.toolBox.addItem(self.page, "")
- self.page_2 = QtWidgets.QWidget()
- self.page_2.setGeometry(QtCore.QRect(0, 0, 299, 462))
- self.page_2.setObjectName("page_2")
- self.gridLayout_8 = QtWidgets.QGridLayout(self.page_2)
- self.gridLayout_8.setObjectName("gridLayout_8")
- self.groupBox = QtWidgets.QGroupBox(self.page_2)
- self.groupBox.setTitle("")
- self.groupBox.setObjectName("groupBox")
- self.gridLayout_28 = QtWidgets.QGridLayout(self.groupBox)
- self.gridLayout_28.setObjectName("gridLayout_28")
- self.frame = QtWidgets.QFrame(self.groupBox)
- self.frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
- self.frame.setFrameShadow(QtWidgets.QFrame.Raised)
- self.frame.setObjectName("frame")
- self.gridLayout_27 = QtWidgets.QGridLayout(self.frame)
- self.gridLayout_27.setObjectName("gridLayout_27")
- self.groupBox_9 = QtWidgets.QGroupBox(self.frame)
- self.groupBox_9.setObjectName("groupBox_9")
- self.gridLayout_24 = QtWidgets.QGridLayout(self.groupBox_9)
- self.gridLayout_24.setObjectName("gridLayout_24")
- self.verticalLayout_3 = QtWidgets.QVBoxLayout()
- self.verticalLayout_3.setObjectName("verticalLayout_3")
- self.horizontalLayout_7 = QtWidgets.QHBoxLayout()
- self.horizontalLayout_7.setObjectName("horizontalLayout_7")
- self.cb_log = QtWidgets.QCheckBox(self.groupBox_9)
- self.cb_log.setStyleSheet("")
- self.cb_log.setChecked(False)
- self.cb_log.setObjectName("cb_log")
- self.horizontalLayout_7.addWidget(self.cb_log)
- self.cb_norm = QtWidgets.QCheckBox(self.groupBox_9)
- self.cb_norm.setObjectName("cb_norm")
- self.horizontalLayout_7.addWidget(self.cb_norm)
- self.verticalLayout_3.addLayout(self.horizontalLayout_7)
- self.cb_transpose = QtWidgets.QCheckBox(self.groupBox_9)
- self.cb_transpose.setLayoutDirection(QtCore.Qt.LeftToRight)
- self.cb_transpose.setObjectName("cb_transpose")
- self.verticalLayout_3.addWidget(self.cb_transpose)
- self.gridLayout_24.addLayout(self.verticalLayout_3, 0, 0, 1, 1)
- self.gridLayout_27.addWidget(self.groupBox_9, 0, 0, 1, 1)
- self.gridLayout_28.addWidget(self.frame, 0, 0, 1, 1)
- self.frame_4 = QtWidgets.QFrame(self.groupBox)
- self.frame_4.setFrameShape(QtWidgets.QFrame.StyledPanel)
- self.frame_4.setFrameShadow(QtWidgets.QFrame.Raised)
- self.frame_4.setObjectName("frame_4")
- self.gridLayout_25 = QtWidgets.QGridLayout(self.frame_4)
- self.gridLayout_25.setObjectName("gridLayout_25")
- self.gridLayout_21 = QtWidgets.QGridLayout()
- self.gridLayout_21.setObjectName("gridLayout_21")
- self.cb_remove_outliers = QtWidgets.QCheckBox(self.frame_4)
- self.cb_remove_outliers.setObjectName("cb_remove_outliers")
- self.gridLayout_21.addWidget(self.cb_remove_outliers, 0, 0, 1, 1)
- self.horizontalLayout = QtWidgets.QHBoxLayout()
- self.horizontalLayout.setObjectName("horizontalLayout")
- self.hs_nsigma = QtWidgets.QSlider(self.frame_4)
- self.hs_nsigma.setEnabled(False)
- self.hs_nsigma.setStyleSheet("border-color: rgb(0, 85, 255);")
- self.hs_nsigma.setMaximum(200)
- self.hs_nsigma.setProperty("value", 3)
- self.hs_nsigma.setOrientation(QtCore.Qt.Horizontal)
- self.hs_nsigma.setObjectName("hs_nsigma")
- self.horizontalLayout.addWidget(self.hs_nsigma)
- self.label_nsigma = QtWidgets.QLabel(self.frame_4)
- self.label_nsigma.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
- self.label_nsigma.setObjectName("label_nsigma")
- self.horizontalLayout.addWidget(self.label_nsigma)
- self.gridLayout_21.addLayout(self.horizontalLayout, 1, 0, 1, 1)
- self.gridLayout_25.addLayout(self.gridLayout_21, 0, 0, 1, 1)
- self.gridLayout_28.addWidget(self.frame_4, 1, 0, 1, 1)
- self.frame_3 = QtWidgets.QFrame(self.groupBox)
- self.frame_3.setFrameShape(QtWidgets.QFrame.StyledPanel)
- self.frame_3.setFrameShadow(QtWidgets.QFrame.Raised)
- self.frame_3.setObjectName("frame_3")
- self.gridLayout_26 = QtWidgets.QGridLayout(self.frame_3)
- self.gridLayout_26.setObjectName("gridLayout_26")
- self.gridLayout_5 = QtWidgets.QGridLayout()
- self.gridLayout_5.setObjectName("gridLayout_5")
- self.horizontalLayout_3 = QtWidgets.QHBoxLayout()
- self.horizontalLayout_3.setObjectName("horizontalLayout_3")
- self.cb_remove_bg = QtWidgets.QCheckBox(self.frame_3)
- self.cb_remove_bg.setObjectName("cb_remove_bg")
- self.horizontalLayout_3.addWidget(self.cb_remove_bg)
- self.gridLayout_5.addLayout(self.horizontalLayout_3, 0, 0, 1, 1)
- self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
- self.horizontalLayout_2.setObjectName("horizontalLayout_2")
- self.hs_bg_threshold = QtWidgets.QSlider(self.frame_3)
- self.hs_bg_threshold.setEnabled(False)
- self.hs_bg_threshold.setMaximum(100)
- self.hs_bg_threshold.setSingleStep(5)
- self.hs_bg_threshold.setPageStep(5)
- self.hs_bg_threshold.setProperty("value", 5)
- self.hs_bg_threshold.setOrientation(QtCore.Qt.Horizontal)
- self.hs_bg_threshold.setObjectName("hs_bg_threshold")
- self.horizontalLayout_2.addWidget(self.hs_bg_threshold)
- self.label_bg_threshold = QtWidgets.QLabel(self.frame_3)
- self.label_bg_threshold.setObjectName("label_bg_threshold")
- self.horizontalLayout_2.addWidget(self.label_bg_threshold)
- self.gridLayout_5.addLayout(self.horizontalLayout_2, 1, 0, 1, 1)
- self.gridLayout_26.addLayout(self.gridLayout_5, 0, 0, 1, 1)
- self.gridLayout_28.addWidget(self.frame_3, 2, 0, 1, 1)
- self.frame_2 = QtWidgets.QFrame(self.groupBox)
- self.frame_2.setFrameShape(QtWidgets.QFrame.StyledPanel)
- self.frame_2.setFrameShadow(QtWidgets.QFrame.Raised)
- self.frame_2.setObjectName("frame_2")
- self.gridLayout_3 = QtWidgets.QGridLayout(self.frame_2)
- self.gridLayout_3.setObjectName("gridLayout_3")
- self.cb_smooth = QtWidgets.QCheckBox(self.frame_2)
- self.cb_smooth.setObjectName("cb_smooth")
- self.gridLayout_3.addWidget(self.cb_smooth, 0, 0, 1, 1)
- self.horizontalLayout_4 = QtWidgets.QHBoxLayout()
- self.horizontalLayout_4.setObjectName("horizontalLayout_4")
- self.hs_smooth_size = QtWidgets.QSlider(self.frame_2)
- self.hs_smooth_size.setEnabled(False)
- self.hs_smooth_size.setMinimum(3)
- self.hs_smooth_size.setMaximum(12)
- self.hs_smooth_size.setSingleStep(2)
- self.hs_smooth_size.setPageStep(2)
- self.hs_smooth_size.setProperty("value", 3)
- self.hs_smooth_size.setOrientation(QtCore.Qt.Horizontal)
- self.hs_smooth_size.setTickPosition(QtWidgets.QSlider.TicksBelow)
- self.hs_smooth_size.setTickInterval(2)
- self.hs_smooth_size.setObjectName("hs_smooth_size")
- self.horizontalLayout_4.addWidget(self.hs_smooth_size)
- self.smooth_winow_size = QtWidgets.QLabel(self.frame_2)
- self.smooth_winow_size.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
- self.smooth_winow_size.setObjectName("smooth_winow_size")
- self.horizontalLayout_4.addWidget(self.smooth_winow_size)
- self.gridLayout_3.addLayout(self.horizontalLayout_4, 1, 0, 1, 1)
- self.gridLayout_28.addWidget(self.frame_2, 3, 0, 1, 1)
- self.gridLayout_8.addWidget(self.groupBox, 0, 0, 1, 1)
- self.toolBox.addItem(self.page_2, "")
- self.gridLayout_9.addWidget(self.toolBox, 0, 0, 1, 1)
- spacerItem2 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed)
- self.gridLayout_9.addItem(spacerItem2, 2, 0, 1, 1)
- self.toolBox_2 = QtWidgets.QToolBox(self.scrollAreaWidgetContents)
- self.toolBox_2.setObjectName("toolBox_2")
- self.page_5 = QtWidgets.QWidget()
- self.page_5.setGeometry(QtCore.QRect(0, 0, 298, 189))
- self.page_5.setObjectName("page_5")
- self.gridLayout_15 = QtWidgets.QGridLayout(self.page_5)
- self.gridLayout_15.setObjectName("gridLayout_15")
- self.gridLayout = QtWidgets.QGridLayout()
- self.gridLayout.setObjectName("gridLayout")
- self.pb_calc_components = QtWidgets.QPushButton(self.page_5)
- sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed)
- sizePolicy.setHorizontalStretch(0)
- sizePolicy.setVerticalStretch(0)
- sizePolicy.setHeightForWidth(self.pb_calc_components.sizePolicy().hasHeightForWidth())
- self.pb_calc_components.setSizePolicy(sizePolicy)
- self.pb_calc_components.setStyleSheet("background-color: rgb(175, 236, 255);\n"
-"color: rgb(255, 0, 127);\n"
-"")
- self.pb_calc_components.setObjectName("pb_calc_components")
- self.gridLayout.addWidget(self.pb_calc_components, 0, 0, 1, 1)
- self.pb_pca_scree = QtWidgets.QPushButton(self.page_5)
- sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
- sizePolicy.setHorizontalStretch(0)
- sizePolicy.setVerticalStretch(0)
- sizePolicy.setHeightForWidth(self.pb_pca_scree.sizePolicy().hasHeightForWidth())
- self.pb_pca_scree.setSizePolicy(sizePolicy)
- self.pb_pca_scree.setStyleSheet("background-color: rgb(175, 236, 255);\n"
-"color: rgb(255, 0, 127);\n"
-"")
- self.pb_pca_scree.setObjectName("pb_pca_scree")
- self.gridLayout.addWidget(self.pb_pca_scree, 1, 0, 1, 1)
- self.horizontalLayout_5 = QtWidgets.QHBoxLayout()
- self.horizontalLayout_5.setObjectName("horizontalLayout_5")
- self.label_11 = QtWidgets.QLabel(self.page_5)
- self.label_11.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
- self.label_11.setObjectName("label_11")
- self.horizontalLayout_5.addWidget(self.label_11)
- self.cb_comp_method = QtWidgets.QComboBox(self.page_5)
- sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
- sizePolicy.setHorizontalStretch(0)
- sizePolicy.setVerticalStretch(0)
- sizePolicy.setHeightForWidth(self.cb_comp_method.sizePolicy().hasHeightForWidth())
- self.cb_comp_method.setSizePolicy(sizePolicy)
- self.cb_comp_method.setObjectName("cb_comp_method")
- self.cb_comp_method.addItem("")
- self.cb_comp_method.addItem("")
- self.cb_comp_method.addItem("")
- self.cb_comp_method.addItem("")
- self.cb_comp_method.addItem("")
- self.cb_comp_method.addItem("")
- self.cb_comp_method.addItem("")
- self.horizontalLayout_5.addWidget(self.cb_comp_method)
- self.gridLayout.addLayout(self.horizontalLayout_5, 2, 0, 1, 1)
- self.horizontalLayout_6 = QtWidgets.QHBoxLayout()
- self.horizontalLayout_6.setObjectName("horizontalLayout_6")
- self.label = QtWidgets.QLabel(self.page_5)
- self.label.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
- self.label.setObjectName("label")
- self.horizontalLayout_6.addWidget(self.label)
- self.sb_ncomp = QtWidgets.QSpinBox(self.page_5)
- self.sb_ncomp.setMinimum(1)
- self.sb_ncomp.setProperty("value", 4)
- self.sb_ncomp.setObjectName("sb_ncomp")
- self.horizontalLayout_6.addWidget(self.sb_ncomp)
- self.gridLayout.addLayout(self.horizontalLayout_6, 3, 0, 1, 1)
- self.gridLayout_15.addLayout(self.gridLayout, 0, 0, 1, 1)
- self.toolBox_2.addItem(self.page_5, "")
- self.page_6 = QtWidgets.QWidget()
- self.page_6.setGeometry(QtCore.QRect(0, 0, 308, 185))
- self.page_6.setObjectName("page_6")
- self.gridLayout_18 = QtWidgets.QGridLayout(self.page_6)
- self.gridLayout_18.setObjectName("gridLayout_18")
- self.gridLayout_4 = QtWidgets.QGridLayout()
- self.gridLayout_4.setObjectName("gridLayout_4")
- self.pb_calc_cluster = QtWidgets.QPushButton(self.page_6)
- sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed)
- sizePolicy.setHorizontalStretch(0)
- sizePolicy.setVerticalStretch(0)
- sizePolicy.setHeightForWidth(self.pb_calc_cluster.sizePolicy().hasHeightForWidth())
- self.pb_calc_cluster.setSizePolicy(sizePolicy)
- self.pb_calc_cluster.setStyleSheet("background-color: rgb(175, 236, 255);\n"
-"color: rgb(255, 0, 127);\n"
-"")
- self.pb_calc_cluster.setObjectName("pb_calc_cluster")
- self.gridLayout_4.addWidget(self.pb_calc_cluster, 0, 0, 1, 3)
- self.pb_kmeans_elbow = QtWidgets.QPushButton(self.page_6)
- sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed)
- sizePolicy.setHorizontalStretch(0)
- sizePolicy.setVerticalStretch(0)
- sizePolicy.setHeightForWidth(self.pb_kmeans_elbow.sizePolicy().hasHeightForWidth())
- self.pb_kmeans_elbow.setSizePolicy(sizePolicy)
- self.pb_kmeans_elbow.setStyleSheet("background-color: rgb(175, 236, 255);\n"
-"color: rgb(255, 0, 127);\n"
-"")
- self.pb_kmeans_elbow.setObjectName("pb_kmeans_elbow")
- self.gridLayout_4.addWidget(self.pb_kmeans_elbow, 1, 0, 1, 3)
- self.label_10 = QtWidgets.QLabel(self.page_6)
- self.label_10.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
- self.label_10.setObjectName("label_10")
- self.gridLayout_4.addWidget(self.label_10, 2, 0, 1, 1)
- self.cb_clust_method = QtWidgets.QComboBox(self.page_6)
- sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
- sizePolicy.setHorizontalStretch(0)
- sizePolicy.setVerticalStretch(0)
- sizePolicy.setHeightForWidth(self.cb_clust_method.sizePolicy().hasHeightForWidth())
- self.cb_clust_method.setSizePolicy(sizePolicy)
- self.cb_clust_method.setObjectName("cb_clust_method")
- self.cb_clust_method.addItem("")
- self.cb_clust_method.addItem("")
- self.cb_clust_method.addItem("")
- self.cb_clust_method.addItem("")
- self.cb_clust_method.addItem("")
- self.cb_clust_method.addItem("")
- self.gridLayout_4.addWidget(self.cb_clust_method, 2, 1, 1, 2)
- self.label_2 = QtWidgets.QLabel(self.page_6)
- self.label_2.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
- self.label_2.setObjectName("label_2")
- self.gridLayout_4.addWidget(self.label_2, 3, 0, 1, 2)
- self.sb_ncluster = QtWidgets.QSpinBox(self.page_6)
- self.sb_ncluster.setMinimum(1)
- self.sb_ncluster.setProperty("value", 4)
- self.sb_ncluster.setObjectName("sb_ncluster")
- self.gridLayout_4.addWidget(self.sb_ncluster, 3, 2, 1, 1)
- self.gridLayout_18.addLayout(self.gridLayout_4, 0, 0, 1, 1)
- self.toolBox_2.addItem(self.page_6, "")
- self.page_7 = QtWidgets.QWidget()
- self.page_7.setGeometry(QtCore.QRect(0, 0, 299, 156))
- self.page_7.setObjectName("page_7")
- self.gridLayout_20 = QtWidgets.QGridLayout(self.page_7)
- self.gridLayout_20.setObjectName("gridLayout_20")
- self.gridLayout_2 = QtWidgets.QGridLayout()
- self.gridLayout_2.setObjectName("gridLayout_2")
- self.pb_elist_xanes = QtWidgets.QPushButton(self.page_7)
- sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred)
- sizePolicy.setHorizontalStretch(0)
- sizePolicy.setVerticalStretch(0)
- sizePolicy.setHeightForWidth(self.pb_elist_xanes.sizePolicy().hasHeightForWidth())
- self.pb_elist_xanes.setSizePolicy(sizePolicy)
- self.pb_elist_xanes.setStyleSheet("background-color: rgb(175, 236, 255);\n"
-"color: rgb(255, 0, 127);\n"
-"")
- self.pb_elist_xanes.setObjectName("pb_elist_xanes")
- self.gridLayout_2.addWidget(self.pb_elist_xanes, 0, 0, 1, 2)
- self.cb_kev_flag = QtWidgets.QCheckBox(self.page_7)
- self.cb_kev_flag.setObjectName("cb_kev_flag")
- self.gridLayout_2.addWidget(self.cb_kev_flag, 0, 2, 1, 1)
- self.pb_ref_xanes = QtWidgets.QPushButton(self.page_7)
- sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred)
- sizePolicy.setHorizontalStretch(0)
- sizePolicy.setVerticalStretch(0)
- sizePolicy.setHeightForWidth(self.pb_ref_xanes.sizePolicy().hasHeightForWidth())
- self.pb_ref_xanes.setSizePolicy(sizePolicy)
- self.pb_ref_xanes.setStyleSheet("background-color: rgb(175, 236, 255);\n"
-"color: rgb(255, 0, 127);\n"
-"")
- self.pb_ref_xanes.setObjectName("pb_ref_xanes")
- self.gridLayout_2.addWidget(self.pb_ref_xanes, 1, 0, 1, 2)
- self.pb_plot_refs = QtWidgets.QPushButton(self.page_7)
- self.pb_plot_refs.setStyleSheet("background-color: rgb(175, 236, 255);\n"
-"color: rgb(255, 0, 127);")
- self.pb_plot_refs.setObjectName("pb_plot_refs")
- self.gridLayout_2.addWidget(self.pb_plot_refs, 1, 2, 1, 1)
- self.cb_xanes_fitting_method = QtWidgets.QComboBox(self.page_7)
- self.cb_xanes_fitting_method.setObjectName("cb_xanes_fitting_method")
- self.cb_xanes_fitting_method.addItem("")
- self.gridLayout_2.addWidget(self.cb_xanes_fitting_method, 2, 0, 1, 1)
- self.pb_xanes_fit = QtWidgets.QPushButton(self.page_7)
- self.pb_xanes_fit.setEnabled(False)
- sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Minimum)
- sizePolicy.setHorizontalStretch(0)
- sizePolicy.setVerticalStretch(0)
- sizePolicy.setHeightForWidth(self.pb_xanes_fit.sizePolicy().hasHeightForWidth())
- self.pb_xanes_fit.setSizePolicy(sizePolicy)
- self.pb_xanes_fit.setStyleSheet("background-color: rgb(175, 236, 255);\n"
-"color: rgb(255, 0, 127);\n"
-"")
- self.pb_xanes_fit.setObjectName("pb_xanes_fit")
- self.gridLayout_2.addWidget(self.pb_xanes_fit, 2, 1, 1, 2)
- self.gridLayout_20.addLayout(self.gridLayout_2, 0, 0, 1, 1)
- spacerItem3 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
- self.gridLayout_20.addItem(spacerItem3, 1, 0, 1, 1)
- self.toolBox_2.addItem(self.page_7, "")
- self.gridLayout_9.addWidget(self.toolBox_2, 3, 0, 1, 1)
- self.scrollArea.setWidget(self.scrollAreaWidgetContents)
- self.gridLayout_16.addWidget(self.scrollArea, 0, 0, 1, 1)
- self.groupBox_6 = QtWidgets.QGroupBox(self.centralwidget)
- sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Preferred)
- sizePolicy.setHorizontalStretch(0)
- sizePolicy.setVerticalStretch(0)
- sizePolicy.setHeightForWidth(self.groupBox_6.sizePolicy().hasHeightForWidth())
- self.groupBox_6.setSizePolicy(sizePolicy)
- self.groupBox_6.setStyleSheet("font:12pt \"Segoe UI\";")
- self.groupBox_6.setTitle("")
- self.groupBox_6.setObjectName("groupBox_6")
- self.gridLayout_29 = QtWidgets.QGridLayout(self.groupBox_6)
- self.gridLayout_29.setObjectName("gridLayout_29")
- self.frame_5 = QtWidgets.QFrame(self.groupBox_6)
- self.frame_5.setFrameShape(QtWidgets.QFrame.StyledPanel)
- self.frame_5.setFrameShadow(QtWidgets.QFrame.Raised)
- self.frame_5.setObjectName("frame_5")
- self.gridLayout_23 = QtWidgets.QGridLayout(self.frame_5)
- self.gridLayout_23.setObjectName("gridLayout_23")
- self.groupBox_8 = QtWidgets.QGroupBox(self.frame_5)
- self.groupBox_8.setStyleSheet("font: 9pt \"Segoe UI\";")
- self.groupBox_8.setObjectName("groupBox_8")
- self.gridLayout_19 = QtWidgets.QGridLayout(self.groupBox_8)
- self.gridLayout_19.setObjectName("gridLayout_19")
- self.groupBox_5 = QtWidgets.QGroupBox(self.groupBox_8)
- self.groupBox_5.setObjectName("groupBox_5")
- self.gridLayout_11 = QtWidgets.QGridLayout(self.groupBox_5)
- self.gridLayout_11.setObjectName("gridLayout_11")
- self.le_spec_roi_size = QtWidgets.QLabel(self.groupBox_5)
- self.le_spec_roi_size.setStyleSheet("color: rgb(255, 0,0);")
- self.le_spec_roi_size.setObjectName("le_spec_roi_size")
- self.gridLayout_11.addWidget(self.le_spec_roi_size, 1, 1, 1, 1)
- self.label_8 = QtWidgets.QLabel(self.groupBox_5)
- self.label_8.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
- self.label_8.setObjectName("label_8")
- self.gridLayout_11.addWidget(self.label_8, 0, 0, 1, 1)
- self.label_29 = QtWidgets.QLabel(self.groupBox_5)
- self.label_29.setStyleSheet("")
- self.label_29.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
- self.label_29.setObjectName("label_29")
- self.gridLayout_11.addWidget(self.label_29, 1, 0, 1, 1)
- self.le_spec_roi = QtWidgets.QLabel(self.groupBox_5)
- self.le_spec_roi.setStyleSheet("color: rgb(255, 0,0);")
- self.le_spec_roi.setObjectName("le_spec_roi")
- self.gridLayout_11.addWidget(self.le_spec_roi, 0, 1, 1, 1)
- self.gridLayout_19.addWidget(self.groupBox_5, 0, 1, 1, 1)
- self.groupBox_4 = QtWidgets.QGroupBox(self.groupBox_8)
- self.groupBox_4.setObjectName("groupBox_4")
- self.gridLayout_12 = QtWidgets.QGridLayout(self.groupBox_4)
- self.gridLayout_12.setObjectName("gridLayout_12")
- self.label_4 = QtWidgets.QLabel(self.groupBox_4)
- self.label_4.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
- self.label_4.setObjectName("label_4")
- self.gridLayout_12.addWidget(self.label_4, 0, 0, 1, 1)
- self.le_roi = QtWidgets.QLabel(self.groupBox_4)
- self.le_roi.setStyleSheet("color: rgb(255, 0,0);")
- self.le_roi.setObjectName("le_roi")
- self.gridLayout_12.addWidget(self.le_roi, 0, 1, 1, 1)
- self.label_28 = QtWidgets.QLabel(self.groupBox_4)
- self.label_28.setStyleSheet("")
- self.label_28.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
- self.label_28.setObjectName("label_28")
- self.gridLayout_12.addWidget(self.label_28, 1, 0, 1, 1)
- self.le_roi_size = QtWidgets.QLabel(self.groupBox_4)
- self.le_roi_size.setStyleSheet("color: rgb(255, 0, 0);")
- self.le_roi_size.setObjectName("le_roi_size")
- self.gridLayout_12.addWidget(self.le_roi_size, 1, 1, 1, 1)
- self.gridLayout_19.addWidget(self.groupBox_4, 0, 0, 1, 1)
- self.gridLayout_23.addWidget(self.groupBox_8, 0, 0, 1, 1)
- self.groupBox_3 = QtWidgets.QGroupBox(self.frame_5)
- self.groupBox_3.setObjectName("groupBox_3")
- self.gridLayout_6 = QtWidgets.QGridLayout(self.groupBox_3)
- self.gridLayout_6.setObjectName("gridLayout_6")
- self.rb_math_roi_img = QtWidgets.QRadioButton(self.groupBox_3)
- self.rb_math_roi_img.setLayoutDirection(QtCore.Qt.LeftToRight)
- self.rb_math_roi_img.setObjectName("rb_math_roi_img")
- self.gridLayout_6.addWidget(self.rb_math_roi_img, 0, 0, 1, 1)
- self.pb_reset_roi_2 = QtWidgets.QPushButton(self.groupBox_3)
- self.pb_reset_roi_2.setStyleSheet("background-color: rgb(175, 236, 255);")
- self.pb_reset_roi_2.setObjectName("pb_reset_roi_2")
- self.gridLayout_6.addWidget(self.pb_reset_roi_2, 0, 1, 1, 1)
- self.label_14 = QtWidgets.QLabel(self.groupBox_3)
- self.label_14.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
- self.label_14.setObjectName("label_14")
- self.gridLayout_6.addWidget(self.label_14, 1, 0, 1, 1)
- self.cb_img_roi_action = QtWidgets.QComboBox(self.groupBox_3)
- sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred)
- sizePolicy.setHorizontalStretch(0)
- sizePolicy.setVerticalStretch(0)
- sizePolicy.setHeightForWidth(self.cb_img_roi_action.sizePolicy().hasHeightForWidth())
- self.cb_img_roi_action.setSizePolicy(sizePolicy)
- self.cb_img_roi_action.setObjectName("cb_img_roi_action")
- self.cb_img_roi_action.addItem("")
- self.cb_img_roi_action.addItem("")
- self.cb_img_roi_action.addItem("")
- self.cb_img_roi_action.addItem("")
- self.gridLayout_6.addWidget(self.cb_img_roi_action, 1, 1, 1, 1)
- self.gridLayout_23.addWidget(self.groupBox_3, 3, 0, 1, 1)
- self.groupBox_7 = QtWidgets.QGroupBox(self.frame_5)
- self.groupBox_7.setObjectName("groupBox_7")
- self.gridLayout_14 = QtWidgets.QGridLayout(self.groupBox_7)
- self.gridLayout_14.setObjectName("gridLayout_14")
- self.rb_math_roi = QtWidgets.QRadioButton(self.groupBox_7)
- sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
- sizePolicy.setHorizontalStretch(0)
- sizePolicy.setVerticalStretch(0)
- sizePolicy.setHeightForWidth(self.rb_math_roi.sizePolicy().hasHeightForWidth())
- self.rb_math_roi.setSizePolicy(sizePolicy)
- self.rb_math_roi.setCheckable(True)
- self.rb_math_roi.setChecked(False)
- self.rb_math_roi.setObjectName("rb_math_roi")
- self.gridLayout_14.addWidget(self.rb_math_roi, 0, 0, 1, 2)
- self.label_13 = QtWidgets.QLabel(self.groupBox_7)
- self.label_13.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
- self.label_13.setObjectName("label_13")
- self.gridLayout_14.addWidget(self.label_13, 1, 0, 1, 1)
- self.cb_roi_operation = QtWidgets.QComboBox(self.groupBox_7)
- sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred)
- sizePolicy.setHorizontalStretch(0)
- sizePolicy.setVerticalStretch(0)
- sizePolicy.setHeightForWidth(self.cb_roi_operation.sizePolicy().hasHeightForWidth())
- self.cb_roi_operation.setSizePolicy(sizePolicy)
- self.cb_roi_operation.setObjectName("cb_roi_operation")
- self.cb_roi_operation.addItem("")
- self.cb_roi_operation.addItem("")
- self.cb_roi_operation.addItem("")
- self.cb_roi_operation.addItem("")
- self.gridLayout_14.addWidget(self.cb_roi_operation, 1, 1, 1, 1)
- self.gridLayout_23.addWidget(self.groupBox_7, 10, 0, 1, 1)
- self.pb_save_disp_img = QtWidgets.QPushButton(self.frame_5)
- self.pb_save_disp_img.setStyleSheet("background-color: rgb(175, 236, 255);\n"
-"color: rgb(255, 0, 127);")
- self.pb_save_disp_img.setObjectName("pb_save_disp_img")
- self.gridLayout_23.addWidget(self.pb_save_disp_img, 13, 0, 1, 1)
- spacerItem4 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
- self.gridLayout_23.addItem(spacerItem4, 4, 0, 1, 1)
- self.pb_save_disp_spec = QtWidgets.QPushButton(self.frame_5)
- self.pb_save_disp_spec.setStyleSheet("background-color: rgb(175, 236, 255);\n"
-"color: rgb(255, 0, 127);")
- self.pb_save_disp_spec.setObjectName("pb_save_disp_spec")
- self.gridLayout_23.addWidget(self.pb_save_disp_spec, 14, 0, 1, 1)
- spacerItem5 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
- self.gridLayout_23.addItem(spacerItem5, 12, 0, 1, 1)
- self.groupBox_2 = QtWidgets.QGroupBox(self.frame_5)
- self.groupBox_2.setObjectName("groupBox_2")
- self.gridLayout_22 = QtWidgets.QGridLayout(self.groupBox_2)
- self.gridLayout_22.setObjectName("gridLayout_22")
- self.verticalLayout = QtWidgets.QVBoxLayout()
- self.verticalLayout.setObjectName("verticalLayout")
- self.rb_poly_roi = QtWidgets.QRadioButton(self.groupBox_2)
- self.rb_poly_roi.setChecked(True)
- self.rb_poly_roi.setObjectName("rb_poly_roi")
- self.verticalLayout.addWidget(self.rb_poly_roi)
- self.rb_rect_roi = QtWidgets.QRadioButton(self.groupBox_2)
- self.rb_rect_roi.setObjectName("rb_rect_roi")
- self.verticalLayout.addWidget(self.rb_rect_roi)
- self.gridLayout_22.addLayout(self.verticalLayout, 0, 0, 1, 2)
- self.verticalLayout_2 = QtWidgets.QVBoxLayout()
- self.verticalLayout_2.setObjectName("verticalLayout_2")
- self.rb_elli_roi = QtWidgets.QRadioButton(self.groupBox_2)
- self.rb_elli_roi.setObjectName("rb_elli_roi")
- self.verticalLayout_2.addWidget(self.rb_elli_roi)
- self.rb_circle_roi = QtWidgets.QRadioButton(self.groupBox_2)
- self.rb_circle_roi.setObjectName("rb_circle_roi")
- self.verticalLayout_2.addWidget(self.rb_circle_roi)
- self.gridLayout_22.addLayout(self.verticalLayout_2, 0, 2, 1, 1)
- self.rb_line_roi = QtWidgets.QRadioButton(self.groupBox_2)
- self.rb_line_roi.setObjectName("rb_line_roi")
- self.gridLayout_22.addWidget(self.rb_line_roi, 1, 0, 1, 1)
- self.gridLayout_23.addWidget(self.groupBox_2, 1, 0, 1, 1)
- spacerItem6 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
- self.gridLayout_23.addItem(spacerItem6, 2, 0, 1, 1)
- self.gridLayout_29.addWidget(self.frame_5, 0, 2, 2, 1)
- self.image_view = ImageView(self.groupBox_6)
- sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
- sizePolicy.setHorizontalStretch(0)
- sizePolicy.setVerticalStretch(0)
- sizePolicy.setHeightForWidth(self.image_view.sizePolicy().hasHeightForWidth())
- self.image_view.setSizePolicy(sizePolicy)
- self.image_view.setObjectName("image_view")
- self.gridLayout_29.addWidget(self.image_view, 0, 1, 1, 1)
- self.spectrum_view = PlotWidget(self.groupBox_6)
- self.spectrum_view.setObjectName("spectrum_view")
- self.gridLayout_29.addWidget(self.spectrum_view, 1, 1, 1, 1)
- self.gridLayout_16.addWidget(self.groupBox_6, 0, 1, 1, 1)
- MainWindow.setCentralWidget(self.centralwidget)
- self.menubar = QtWidgets.QMenuBar(MainWindow)
- self.menubar.setGeometry(QtCore.QRect(0, 0, 1246, 29))
- self.menubar.setObjectName("menubar")
- self.menuManual = QtWidgets.QMenu(self.menubar)
- self.menuManual.setObjectName("menuManual")
- self.menuFile = QtWidgets.QMenu(self.menubar)
- self.menuFile.setObjectName("menuFile")
- self.menuMask = QtWidgets.QMenu(self.menubar)
- self.menuMask.setObjectName("menuMask")
- MainWindow.setMenuBar(self.menubar)
- self.statusbar_main = QtWidgets.QStatusBar(MainWindow)
- self.statusbar_main.setObjectName("statusbar_main")
- MainWindow.setStatusBar(self.statusbar_main)
- self.actionOpen_PDF = QtWidgets.QAction(MainWindow)
- self.actionOpen_PDF.setObjectName("actionOpen_PDF")
- self.actionOpen_in_GitHub = QtWidgets.QAction(MainWindow)
- self.actionOpen_in_GitHub.setObjectName("actionOpen_in_GitHub")
- self.actionOpen_Image_Data = QtWidgets.QAction(MainWindow)
- self.actionOpen_Image_Data.setEnabled(True)
- self.actionOpen_Image_Data.setObjectName("actionOpen_Image_Data")
- self.actionClose = QtWidgets.QAction(MainWindow)
- self.actionClose.setObjectName("actionClose")
- self.actionExit = QtWidgets.QAction(MainWindow)
- self.actionExit.setObjectName("actionExit")
- self.actionSave_as = QtWidgets.QAction(MainWindow)
- self.actionSave_as.setObjectName("actionSave_as")
- self.actionOpen_PyXRF = QtWidgets.QAction(MainWindow)
- self.actionOpen_PyXRF.setObjectName("actionOpen_PyXRF")
- self.actionOpen_Image_J = QtWidgets.QAction(MainWindow)
- self.actionOpen_Image_J.setObjectName("actionOpen_Image_J")
- self.actionOpen_TomViz = QtWidgets.QAction(MainWindow)
- self.actionOpen_TomViz.setObjectName("actionOpen_TomViz")
- self.actionOpen_Mantis = QtWidgets.QAction(MainWindow)
- self.actionOpen_Mantis.setObjectName("actionOpen_Mantis")
- self.actionOpen_Athena = QtWidgets.QAction(MainWindow)
- self.actionOpen_Athena.setObjectName("actionOpen_Athena")
- self.actionDataBroker = QtWidgets.QAction(MainWindow)
- self.actionDataBroker.setObjectName("actionDataBroker")
- self.actionOpen_HXN_DB = QtWidgets.QAction(MainWindow)
- self.actionOpen_HXN_DB.setObjectName("actionOpen_HXN_DB")
- self.actionLoad_Energy = QtWidgets.QAction(MainWindow)
- self.actionLoad_Energy.setObjectName("actionLoad_Energy")
- self.actionOpen_Multiple_Files = QtWidgets.QAction(MainWindow)
- self.actionOpen_Multiple_Files.setObjectName("actionOpen_Multiple_Files")
- self.actionOpen_Mask_Gen = QtWidgets.QAction(MainWindow)
- self.actionOpen_Mask_Gen.setObjectName("actionOpen_Mask_Gen")
- self.actionCreate_elist_from_log = QtWidgets.QAction(MainWindow)
- self.actionCreate_elist_from_log.setObjectName("actionCreate_elist_from_log")
- self.actionSave_Energy_List = QtWidgets.QAction(MainWindow)
- self.actionSave_Energy_List.setObjectName("actionSave_Energy_List")
- self.actionAlign_Stack = QtWidgets.QAction(MainWindow)
- self.actionAlign_Stack.setObjectName("actionAlign_Stack")
- self.menuManual.addSeparator()
- self.menuManual.addAction(self.actionOpen_in_GitHub)
- self.menuFile.addAction(self.actionOpen_Image_Data)
- self.menuFile.addAction(self.actionOpen_Multiple_Files)
- self.menuFile.addAction(self.actionLoad_Energy)
- self.menuFile.addAction(self.actionSave_Energy_List)
- self.menuFile.addAction(self.actionSave_as)
- self.menuFile.addAction(self.actionExit)
- self.menuMask.addAction(self.actionOpen_Mask_Gen)
- self.menuMask.addAction(self.actionAlign_Stack)
- self.menubar.addAction(self.menuFile.menuAction())
- self.menubar.addAction(self.menuMask.menuAction())
- self.menubar.addAction(self.menuManual.menuAction())
-
- self.retranslateUi(MainWindow)
- self.toolBox.setCurrentIndex(1)
- self.toolBox_2.setCurrentIndex(2)
- QtCore.QMetaObject.connectSlotsByName(MainWindow)
-
- def retranslateUi(self, MainWindow):
- _translate = QtCore.QCoreApplication.translate
- MainWindow.setWindowTitle(_translate("MainWindow", "NSLS-II MIDAS"))
- self.pb_reset_img.setText(_translate("MainWindow", "Reset Image"))
- self.label_5.setText(_translate("MainWindow", "to"))
- self.label_9.setText(_translate("MainWindow", "to"))
- self.sb_yrange2.setSuffix(_translate("MainWindow", " px"))
- self.sb_xrange1.setSuffix(_translate("MainWindow", " px"))
- self.sb_xrange2.setSuffix(_translate("MainWindow", " px"))
- self.label_22.setText(_translate("MainWindow", "to"))
- self.label_19.setText(_translate("MainWindow", "X Dimension"))
- self.sb_yrange1.setSuffix(_translate("MainWindow", " px"))
- self.label_15.setText(_translate("MainWindow", "Y Dimension"))
- self.label_20.setText(_translate("MainWindow", "Stack Range "))
- self.pb_crop.setToolTip(_translate("MainWindow", "Adjust the dimensions of the image"))
- self.pb_crop.setText(_translate("MainWindow", "Update"))
- self.cb_rebin.setText(_translate("MainWindow", "rebin"))
- self.cb_upscale.setText(_translate("MainWindow", "Upscale"))
- self.cb_remove_edges.setToolTip(_translate("MainWindow", "Removes one column/row from all four edges"))
- self.cb_remove_edges.setText(_translate("MainWindow", "Remove Edges"))
- self.toolBox.setItemText(self.toolBox.indexOf(self.page), _translate("MainWindow", "Adjust Image Dimensions"))
- self.groupBox_9.setTitle(_translate("MainWindow", "Transform"))
- self.cb_log.setToolTip(_translate("MainWindow", "Covert image dat to log values."))
- self.cb_log.setText(_translate("MainWindow", "Log "))
- self.cb_norm.setToolTip(_translate("MainWindow", "Intensity Normalization with the last Frame."))
- self.cb_norm.setText(_translate("MainWindow", "Normalize"))
- self.cb_transpose.setToolTip(_translate("MainWindow", "Reverse the arrays. 012 will be 210"))
- self.cb_transpose.setText(_translate("MainWindow", "Transpose"))
- self.cb_remove_outliers.setText(_translate("MainWindow", "Remove Outliers (NSigma)"))
- self.label_nsigma.setText(_translate("MainWindow", "1"))
- self.cb_remove_bg.setText(_translate("MainWindow", "Thresholding"))
- self.label_bg_threshold.setText(_translate("MainWindow", "5"))
- self.cb_smooth.setToolTip(_translate("MainWindow", "uses savgol_filter to smooth data"))
- self.cb_smooth.setText(_translate("MainWindow", "Smoothen"))
- self.smooth_winow_size.setText(_translate("MainWindow", "Window size"))
- self.toolBox.setItemText(self.toolBox.indexOf(self.page_2), _translate("MainWindow", "Image Processing"))
- self.pb_calc_components.setText(_translate("MainWindow", "Calculate Components"))
- self.pb_pca_scree.setText(_translate("MainWindow", "PCA Scree Plot"))
- self.label_11.setText(_translate("MainWindow", "Method"))
- self.cb_comp_method.setItemText(0, _translate("MainWindow", "PCA"))
- self.cb_comp_method.setItemText(1, _translate("MainWindow", "NMF"))
- self.cb_comp_method.setItemText(2, _translate("MainWindow", "FastICA"))
- self.cb_comp_method.setItemText(3, _translate("MainWindow", "IncrementalPCA"))
- self.cb_comp_method.setItemText(4, _translate("MainWindow", "TruncatedSVD"))
- self.cb_comp_method.setItemText(5, _translate("MainWindow", "FactorAnalysis"))
- self.cb_comp_method.setItemText(6, _translate("MainWindow", "DictionaryLearning"))
- self.label.setText(_translate("MainWindow", "Number of Components"))
- self.toolBox_2.setItemText(self.toolBox_2.indexOf(self.page_5), _translate("MainWindow", "Component Analysis"))
- self.pb_calc_cluster.setText(_translate("MainWindow", "Calculate Clusters"))
- self.pb_kmeans_elbow.setText(_translate("MainWindow", "KMeans Variance Plot"))
- self.label_10.setText(_translate("MainWindow", "Method"))
- self.cb_clust_method.setItemText(0, _translate("MainWindow", "KMeans"))
- self.cb_clust_method.setItemText(1, _translate("MainWindow", "MiniBatchKMeans"))
- self.cb_clust_method.setItemText(2, _translate("MainWindow", "MeanShift"))
- self.cb_clust_method.setItemText(3, _translate("MainWindow", "Spectral Clustering"))
- self.cb_clust_method.setItemText(4, _translate("MainWindow", "Correlation-Kmeans"))
- self.cb_clust_method.setItemText(5, _translate("MainWindow", "Affinity Propagation"))
- self.label_2.setText(_translate("MainWindow", "Number of Clusters"))
- self.toolBox_2.setItemText(self.toolBox_2.indexOf(self.page_6), _translate("MainWindow", "Cluster Analysis"))
- self.pb_elist_xanes.setText(_translate("MainWindow", "Load Energy List"))
- self.cb_kev_flag.setText(_translate("MainWindow", "keV"))
- self.pb_ref_xanes.setText(_translate("MainWindow", "Load Ref. Spec."))
- self.pb_plot_refs.setText(_translate("MainWindow", "Plot"))
- self.cb_xanes_fitting_method.setItemText(0, _translate("MainWindow", "NNLS"))
- self.pb_xanes_fit.setText(_translate("MainWindow", " Fit"))
- self.toolBox_2.setItemText(self.toolBox_2.indexOf(self.page_7), _translate("MainWindow", "XANES Fitting"))
- self.groupBox_8.setTitle(_translate("MainWindow", "ROI Positions"))
- self.groupBox_5.setTitle(_translate("MainWindow", "Spectrum ROI"))
- self.le_spec_roi_size.setText(_translate("MainWindow", "roi_size"))
- self.label_8.setText(_translate("MainWindow", "Range (eV):"))
- self.label_29.setText(_translate("MainWindow", "Size (eV):"))
- self.le_spec_roi.setText(_translate("MainWindow", "roix, roiy"))
- self.groupBox_4.setTitle(_translate("MainWindow", "Image ROI"))
- self.label_4.setText(_translate("MainWindow", "Position:"))
- self.le_roi.setText(_translate("MainWindow", "roix, roiy"))
- self.label_28.setText(_translate("MainWindow", "Size(pixels):"))
- self.le_roi_size.setText(_translate("MainWindow", "roi_size"))
- self.groupBox_3.setTitle(_translate("MainWindow", "Image Calculations"))
- self.rb_math_roi_img.setText(_translate("MainWindow", "Add Math ROI"))
- self.pb_reset_roi_2.setText(_translate("MainWindow", "Reset"))
- self.label_14.setText(_translate("MainWindow", "Action:"))
- self.cb_img_roi_action.setItemText(0, _translate("MainWindow", "Subtract"))
- self.cb_img_roi_action.setItemText(1, _translate("MainWindow", "Divide"))
- self.cb_img_roi_action.setItemText(2, _translate("MainWindow", "Add"))
- self.cb_img_roi_action.setItemText(3, _translate("MainWindow", "Compare"))
- self.groupBox_7.setTitle(_translate("MainWindow", "Spectrum Calculations"))
- self.rb_math_roi.setText(_translate("MainWindow", "Add Math ROI"))
- self.label_13.setText(_translate("MainWindow", "Action:"))
- self.cb_roi_operation.setItemText(0, _translate("MainWindow", "Divide"))
- self.cb_roi_operation.setItemText(1, _translate("MainWindow", "Subtract"))
- self.cb_roi_operation.setItemText(2, _translate("MainWindow", "Add"))
- self.cb_roi_operation.setItemText(3, _translate("MainWindow", "Correlation Plot"))
- self.pb_save_disp_img.setText(_translate("MainWindow", "Save Current Image (.tiff)"))
- self.pb_save_disp_spec.setText(_translate("MainWindow", "Save Current Spectrum (.txt)"))
- self.groupBox_2.setTitle(_translate("MainWindow", "ROI Shape"))
- self.rb_poly_roi.setText(_translate("MainWindow", "Polygon (default)"))
- self.rb_rect_roi.setText(_translate("MainWindow", "Rectangle"))
- self.rb_elli_roi.setText(_translate("MainWindow", "Ellipse"))
- self.rb_circle_roi.setText(_translate("MainWindow", "Circle"))
- self.rb_line_roi.setText(_translate("MainWindow", "Line"))
- self.menuManual.setTitle(_translate("MainWindow", "Help"))
- self.menuFile.setTitle(_translate("MainWindow", "File"))
- self.menuMask.setTitle(_translate("MainWindow", "Tools"))
- self.actionOpen_PDF.setText(_translate("MainWindow", "Open PDF"))
- self.actionOpen_in_GitHub.setText(_translate("MainWindow", "Open in GitHub (most updated)"))
- self.actionOpen_Image_Data.setText(_translate("MainWindow", "Open Image Data"))
- self.actionOpen_Image_Data.setToolTip(_translate("MainWindow", "Support all tiff and specific h5 files"))
- self.actionOpen_Image_Data.setShortcut(_translate("MainWindow", "Ctrl+O"))
- self.actionClose.setText(_translate("MainWindow", "Close"))
- self.actionExit.setText(_translate("MainWindow", "Exit"))
- self.actionExit.setShortcut(_translate("MainWindow", "Ctrl+Q"))
- self.actionSave_as.setText(_translate("MainWindow", "Export Tiff Stack"))
- self.actionSave_as.setToolTip(_translate("MainWindow", "Save the displayed/Modified stack as a tiff file"))
- self.actionSave_as.setShortcut(_translate("MainWindow", "Ctrl+S"))
- self.actionOpen_PyXRF.setText(_translate("MainWindow", "Open PyXRF"))
- self.actionOpen_Image_J.setText(_translate("MainWindow", "Open Image J"))
- self.actionOpen_TomViz.setText(_translate("MainWindow", "Open TomViz"))
- self.actionOpen_Mantis.setText(_translate("MainWindow", "Open Mantis"))
- self.actionOpen_Athena.setText(_translate("MainWindow", "Open Athena"))
- self.actionDataBroker.setText(_translate("MainWindow", "DataBroker"))
- self.actionOpen_HXN_DB.setText(_translate("MainWindow", "Open HXN DB"))
- self.actionLoad_Energy.setText(_translate("MainWindow", "Load Energy"))
- self.actionLoad_Energy.setToolTip(_translate("MainWindow", "Load list of energies for XANES stack. Supports only .txt fromat"))
- self.actionLoad_Energy.setShortcut(_translate("MainWindow", "Ctrl+E"))
- self.actionOpen_Multiple_Files.setText(_translate("MainWindow", "Open Multiple Files"))
- self.actionOpen_Multiple_Files.setToolTip(_translate("MainWindow", "Create a stack from multiple tiff images of same shape"))
- self.actionOpen_Multiple_Files.setShortcut(_translate("MainWindow", "Ctrl+M"))
- self.actionOpen_Mask_Gen.setText(_translate("MainWindow", "Open Mask Generator"))
- self.actionOpen_Mask_Gen.setToolTip(_translate("MainWindow", "A new window will be opened to creat threshold based masks"))
- self.actionCreate_elist_from_log.setText(_translate("MainWindow", "Create elist from log file"))
- self.actionSave_Energy_List.setText(_translate("MainWindow", "Save Energy List"))
- self.actionAlign_Stack.setText(_translate("MainWindow", "Align Stack"))
- self.actionAlign_Stack.setToolTip(_translate("MainWindow", "A new window will be opened to align images in a stack"))
-from pyqtgraph import ImageView, PlotWidget
-
-
-if __name__ == "__main__":
- import sys
- app = QtWidgets.QApplication(sys.argv)
- MainWindow = QtWidgets.QMainWindow()
- ui = Ui_MainWindow()
- ui.setupUi(MainWindow)
- MainWindow.show()
- sys.exit(app.exec_())
diff --git a/xmidas/uis/midasMainwindow.ui b/xmidas/uis/midasMainwindow.ui
index eb98ef8..dcd166c 100644
--- a/xmidas/uis/midasMainwindow.ui
+++ b/xmidas/uis/midasMainwindow.ui
@@ -1,2938 +1,3034 @@
-
-
- Ajith
- MainWindow
-
-
- true
-
-
-
- 0
- 0
- 1232
- 931
-
-
-
-
- 0
- 0
-
-
-
- NSLS-II MIDAS
-
-
-
- pancake.icopancake.ico
-
-
- font: 10pt "Segoe UI";
-
-
-
-
- true
-
-
-
- 0
- 0
-
-
-
- QWidget {
-font: 10pt "Segoe UI";
-}
-
-QPushButton {
-background-color: rgb(175, 236, 255);
-color: rgb(255, 5,0);
-font: 10pt "Segoe UI";
-}
-
-QLabel {
-font: 10pt "Segoe UI";
-}
-
-QSlider::groove:horizontal {
-border: 1px solid #bbb;
-background: white;
-height: 10px;
-border-radius: 4px;
-}
-
-QSlider::sub-page:horizontal {
-background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
- stop: 0 #66e, stop: 1 #bbf);
-background: qlineargradient(x1: 0, y1: 0.2, x2: 1, y2: 1,
- stop: 0 #bbf, stop: 1 #55f);
-border: 1px solid #777;
-height: 10px;
-border-radius: 4px;
-}
-
-QSlider::add-page:horizontal {
-background: #fff;
-border: 1px solid #777;
-height: 10px;
-border-radius: 4px;
-}
-
-QSlider::handle:horizontal {
-background: qlineargradient(x1:0, y1:0, x2:1, y2:1,
- stop:0 #eee, stop:1 #ccc);
-border: 1px solid #777;
-width: 13px;
-margin-top: -2px;
-margin-bottom: -2px;
-border-radius: 4px;
-}
-
-QSlider::handle:horizontal:hover {
-background: qlineargradient(x1:0, y1:0, x2:1, y2:1,
- stop:0 #fff, stop:1 #ddd);
-border: 1px solid #444;
-border-radius: 2px;
-}
-
-QSlider::sub-page:horizontal:disabled {
-background: #bbb;
-border-color: #999;
-}
-
-QSlider::add-page:horizontal:disabled {
-background: #eee;
-border-color: #999;
-}
-
-QSlider::handle:horizontal:disabled {
-background: #eee;
-border: 1px solid #aaa;
-border-radius: 4px;
-}
-
-
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- QFrame::StyledPanel
-
-
- QFrame::Sunken
-
-
-
-
-
-
-
- 0
- 0
-
-
-
-
-
-
- 2
-
-
-
-
- 0
- 0
- 368
- 325
-
-
-
- Adjust Image Dimensions
-
-
-
-
-
-
-
- 0
- 0
-
-
-
-
-
-
- QFrame::StyledPanel
-
-
- QFrame::Raised
-
-
-
-
-
-
- QLayout::SetMinimumSize
-
-
-
-
-
-
- 0
- 0
-
-
-
- 0
-
-
- 500
-
-
- 0
-
-
- 10
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- 1
-
-
- 5000
-
-
- 1200
-
-
- 10
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- false
-
-
- px
-
-
- 1
-
-
- 10000
-
-
- 100
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- false
-
-
- px
-
-
- 1
-
-
- 10000
-
-
- 100
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- false
-
-
- px
-
-
- 0
-
-
- 10000
-
-
- 0
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Y Dimension
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- false
-
-
- px
-
-
- 0
-
-
- 10000
-
-
- 0
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- X Dimension
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Stack Range
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- to
-
-
- Qt::AlignCenter
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- to
-
-
- Qt::AlignCenter
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- to
-
-
- Qt::AlignCenter
-
-
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Adjust the dimensions of the image
-
-
-
-
-
- Update
-
-
-
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- QFrame::StyledPanel
-
-
- QFrame::Raised
-
-
-
-
-
-
-
-
-
-
- 0
- 0
-
-
-
- Removes one column/row from all four edges
-
-
- Remove Edges
-
-
-
- -
-
-
-
-
-
- true
-
-
-
- 0
- 0
-
-
-
- rebin
-
-
-
- -
-
-
- true
-
-
-
- 0
- 0
-
-
-
- Upscale
-
-
-
- -
-
-
-
-
-
- Ratio
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
- true
-
-
-
- 0
- 0
-
-
-
- font: 10pt "MS Shell Dlg 2";
-
-
- 2
-
-
- 16
-
-
- 2
-
-
- 2
-
-
-
-
-
-
-
-
-
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 40
-
-
-
-
-
-
-
-
-
-
-
-
- 0
- 0
- 300
- 392
-
-
-
- Image Processing
-
-
- -
-
-
-
-
-
-
- reverses the image axes (ZXY) to (YXZ)
-
-
- Transpose
-
-
-
- -
-
-
- swaps 2nd and 3rd axes (ZXY) to (ZYX)
-
-
- Swap XY Axes
-
-
-
- -
-
-
-
-
-
-
-
-
-
- 0
- 0
-
-
-
- Covert image dat to log values.
-
-
-
-
-
- Log
-
-
- false
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Intensity Normalization with the last Frame.
-
-
- Normalize to Max
-
-
-
-
-
-
-
- -
-
-
- QFrame::StyledPanel
-
-
- QFrame::Raised
-
-
-
-
-
-
-
-
-
- Remove Outliers (NSigma)
-
-
-
- -
-
-
- false
-
-
-
-
-
- 200
-
-
- 3
-
-
- Qt::Horizontal
-
-
-
- -
-
-
- 1
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
-
-
-
-
-
- -
-
-
- QFrame::StyledPanel
-
-
- QFrame::Raised
-
-
-
-
-
-
-
-
-
-
-
-
- Thresholding
-
-
-
-
-
- -
-
-
-
-
-
- false
-
-
- 100
-
-
- 5
-
-
- 5
-
-
- 5
-
-
- Qt::Horizontal
-
-
-
- -
-
-
- 5
-
-
-
-
-
-
-
-
-
-
- -
-
-
- QFrame::StyledPanel
-
-
- QFrame::Raised
-
-
-
-
-
-
- uses savgol_filter to smooth data
-
-
- Smoothen
-
-
-
- -
-
-
-
-
-
- false
-
-
- 3
-
-
- 12
-
-
- 2
-
-
- 2
-
-
- 3
-
-
- Qt::Horizontal
-
-
- QSlider::TicksBelow
-
-
- 2
-
-
-
- -
-
-
- Window size
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 0
- 0
- 379
- 309
-
-
-
- Alignment
-
-
- -
-
-
-
-
-
-
-
-
-
- Transformations:
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
-
-
- TRANSLATION
-
-
- -
-
- RIGID_BODY
-
-
- -
-
- SCALED_ROTATION
-
-
- -
-
- AFFINE
-
-
- -
-
- BILINEAR
-
-
-
-
-
-
- -
-
-
-
-
-
- Reference:
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
-
-
- previous
-
-
- -
-
- mean
-
-
- -
-
- first
-
-
-
-
-
-
- -
-
-
-
-
-
-
- 0
- 0
-
-
-
- Iterative Mode
-
-
-
- -
-
-
-
-
-
- Max Iter.
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- 2
-
-
- 24
-
-
-
-
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Align
-
-
-
- -
-
-
-
-
-
-
- 0
- 0
-
-
-
- Load Reference Stack
-
-
-
- -
-
-
- No Ref. Available
-
-
- true
-
-
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Save Transformation File
-
-
-
- -
-
-
- Use
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Load Transformation File
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
-
-
- Reset Image
-
-
-
- -
-
-
- true
-
-
- 2
-
-
-
-
- 0
- 0
- 379
- 321
-
-
-
- Component Analysis
-
-
-
-
-
-
-
-
-
-
- 0
- 0
-
-
-
-
-
-
- Calculate Components
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
-
-
- PCA Scree Plot
-
-
-
- -
-
-
-
-
-
- Method
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
-
- PCA
-
-
- -
-
- NMF
-
-
- -
-
- FastICA
-
-
- -
-
- IncrementalPCA
-
-
- -
-
- TruncatedSVD
-
-
- -
-
- FactorAnalysis
-
-
- -
-
- DictionaryLearning
-
-
-
-
-
-
- -
-
-
-
-
-
- Number of Components
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
- 1
-
-
- 4
-
-
-
-
-
-
-
-
-
-
-
-
- 0
- 0
- 379
- 321
-
-
-
- Cluster Analysis
-
-
- -
-
-
-
-
-
-
- 0
- 0
-
-
-
-
-
-
- Calculate Clusters
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
-
-
- KMeans Variance Plot
-
-
-
- -
-
-
- Method
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
-
- KMeans
-
-
- -
-
- MiniBatchKMeans
-
-
- -
-
- MeanShift
-
-
- -
-
- Spectral Clustering
-
-
- -
-
- Correlation-Kmeans
-
-
- -
-
- Affinity Propagation
-
-
-
-
- -
-
-
- Number of Clusters
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
- 1
-
-
- 4
-
-
-
-
-
-
-
-
-
-
- 0
- 0
- 379
- 205
-
-
-
- XANES Fitting
-
-
- -
-
-
-
- 11
-
-
- 11
-
-
-
-
-
-
-
-
-
- 0
- 0
-
-
-
-
-
-
- Load Energy List
-
-
-
- -
-
-
- keV
-
-
-
-
-
- -
-
-
-
-
-
-
- 0
- 0
-
-
-
-
-
-
- Load Ref. Spec.
-
-
-
- -
-
-
-
-
-
- Plot
-
-
-
-
-
- -
-
-
- true
-
-
-
- 0
- 0
-
-
-
-
-
-
- Fit
-
-
-
-
-
-
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 40
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
-
-
-
-
-
-
- QLayout::SetMaximumSize
-
-
-
-
-
- 0
-
-
-
- Live
-
-
-
-
-
-
-
- 0
- 0
-
-
-
- Send to Plot Collection
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
-
-
- Save
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
-
-
-
-
- Normalized
-
-
- -
-
-
- Save
-
-
-
- -
-
-
- Clear
-
-
-
- -
-
-
- Norm. to Collector
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
-
-
-
-
- Collection
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
- -
-
-
- Clear
-
-
-
- -
-
-
- Save
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
-
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- QFrame::StyledPanel
-
-
- QFrame::Sunken
-
-
-
- QLayout::SetDefaultConstraint
-
-
- 11
-
-
- 11
-
-
-
-
-
-
- 0
- 0
-
-
-
- ROI Shape
-
-
-
-
-
-
-
- 0
- 0
-
-
-
- Rectangle
-
-
- true
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Ellipse
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Polygon
-
-
- false
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Circle
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Line
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Zoom to ROI
-
-
-
-
-
-
- -
-
-
- font: 9pt "Segoe UI";
-
-
- ROI Positions
-
-
-
-
-
-
- Spectrum ROI
-
-
-
-
-
-
- Range (eV):
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
- color: rgb(255, 0,0);
-
-
- roi_size
-
-
-
- -
-
-
- color: rgb(255, 0,0);
-
-
- roix, roiy
-
-
-
- -
-
-
-
-
-
- Size (eV):
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
-
-
-
- -
-
-
- Image ROI
-
-
-
-
-
-
- color: rgb(255, 0,0);
-
-
- roix, roiy
-
-
-
- -
-
-
- Position:
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
-
-
-
- Size(pixels):
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
- color: rgb(255, 0, 0);
-
-
- roi_size
-
-
-
-
-
-
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- 1
-
-
-
-
- 0
- 0
- 361
- 193
-
-
-
- Image Calculations
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Add ROI_2
-
-
-
- -
-
-
- Calculation:
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
-
- Subtract
-
-
- -
-
- Divide
-
-
- -
-
- Add
-
-
- -
-
- Compare
-
-
-
-
- -
-
-
- Apply
-
-
-
-
-
-
-
-
-
-
-
- 0
- 0
- 361
- 231
-
-
-
- Spectrum Calculations
-
-
- -
-
-
-
-
-
-
-
-
-
-
- 0
- 0
-
-
-
- Add ROI 2
-
-
- true
-
-
- false
-
-
- false
-
-
-
- -
-
-
-
-
-
-
- 0
- 0
-
-
-
- Calculation
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
-
- Divide
-
-
- -
-
- Subtract
-
-
- -
-
- Add
-
-
- -
-
- Correlation Plot
-
-
-
-
-
-
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 40
-
-
-
-
- -
-
-
- Apply
-
-
-
- -
-
-
- Use ROI for Correlations
-
-
-
-
-
-
-
-
-
-
-
- 0
- 0
- 386
- 273
-
-
-
- XANES Normalization
-
-
- -
-
-
-
- 0
- 0
-
-
-
- to
-
-
- Qt::AlignCenter
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- 1
-
-
- 5
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Eo
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- eV
-
-
- 1000.000000000000000
-
-
- 20000.000000000000000
-
-
- 7125.000000000000000
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- calculate the energy point with maximum derivative
-
-
- Auto Eo
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- eV
-
-
- 2
-
-
- -500.000000000000000
-
-
- 500.000000000000000
-
-
- 1.000000000000000
-
-
- -50.000000000000000
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Pre-edge
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- eV
-
-
- -500.000000000000000
-
-
- 500.000000000000000
-
-
- -10.000000000000000
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Post-edge
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- to
-
-
- Qt::AlignCenter
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Norm. Order
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- eV
-
-
- 0.000000000000000
-
-
- 1000.000000000000000
-
-
- 25.000000000000000
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- <html><head/><body><p> For mbak algorithm only, must be in <span style=" font-weight:600; font-style:italic;">element<space>edge</span> format</p></body></html>
-
-
- Fe K
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Element:
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- eV
-
-
- 0.000000000000000
-
-
- 1500.000000000000000
-
-
- 75.000000000000000
-
-
-
- -
-
-
- Initial Guess
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Apply to Spectrum
-
-
-
- -
-
-
- Apply to Stack
-
-
-
-
-
-
-
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 40
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 0
- 0
-
-
-
- toolBar
-
-
- TopToolBarArea
-
-
- false
-
-
-
-
-
-
-
- Open PDF
-
-
-
-
- Open in GitHub (most updated)
-
-
-
-
- true
-
-
- Open Image Data
-
-
- Support all tiff and specific h5 files
-
-
- Ctrl+O
-
-
-
-
- Close
-
-
-
-
- Exit
-
-
- Ctrl+Q
-
-
-
-
- false
-
-
- Export Tiff Stack
-
-
- Save the displayed/Modified stack as a tiff file
-
-
- Ctrl+S
-
-
-
-
- Open PyXRF
-
-
-
-
- Open Image J
-
-
-
-
- Open TomViz
-
-
-
-
- Open Mantis
-
-
-
-
- Open Athena
-
-
-
-
- DataBroker
-
-
-
-
- Open HXN DB
-
-
-
-
- false
-
-
- Load Energy
-
-
- Load list of energies for XANES stack. Supports only .txt fromat
-
-
- Ctrl+E
-
-
-
-
- Create a Virtual Stack
-
-
- Create a stack from multiple tiff images of same shape
-
-
- Ctrl+M
-
-
-
-
- true
-
-
- Open Mask Generator
-
-
- A new window will be opened to creat threshold based masks
-
-
-
-
- Create elist from log file
-
-
-
-
- false
-
-
- Export Energy List
-
-
-
-
- true
-
-
- MultiColorView
-
-
- A new window will be opened to align images in a stack
-
-
-
-
- White
-
-
-
-
- true
-
-
- true
-
-
- Black
-
-
-
-
- Red
-
-
-
-
- Yellow
-
-
-
-
- Blue
-
-
-
-
- false
-
-
- false
-
-
- Dark Mode
-
-
-
-
- Black
-
-
-
-
- false
-
-
- false
-
-
- Default
-
-
-
-
- Vivid
-
-
-
-
- Export Sum Image (3D to 2D)
-
-
-
-
- Subtract ROI as Background
-
-
-
-
- Export Norm. Params
-
-
-
-
- 2
-
-
-
-
- 4
-
-
-
-
- 6
-
-
-
-
- 10
-
-
-
-
- 2
-
-
-
-
- 3
-
-
-
-
- 4
-
-
-
-
- 5
-
-
-
-
- 6
-
-
-
-
- 8
-
-
-
-
- 10
-
-
-
-
- 2
-
-
-
-
- Import Norm. Params
-
-
-
-
- 1
-
-
-
-
- Save Sum Spectrum
-
-
-
-
- Save Mean Spectrum
-
-
-
-
- Save Current Image as Mask
-
-
-
-
- Stack to RGBCMY Image
-
-
-
-
- Apply Current Crop to All images
-
-
- all images in the folder will be cropped in reference to current
-
-
-
-
-
-
-
-
-
-
- Save Current State
-
-
-
-
- Normalize with another Stack
-
-
-
-
- Stack Info
-
-
- Diaplays details of the stack
-
-
-
-
- Export Image
-
-
- Saves displayed 2D image frame
-
-
-
-
-
- ..
-
-
- Export Stack
-
-
- Save current stack as is
-
-
- false
-
-
-
-
- Export Mean Image (3D to 2D)
-
-
-
-
- Plot All Possible Image Correlations
-
-
-
-
-
- PlotWidget
- QGraphicsView
-
-
-
- ImageView
- QGraphicsView
-
-
-
-
-
-
+
+
+ Ajith
+ MainWindow
+
+
+ true
+
+
+
+ 0
+ 0
+ 1287
+ 842
+
+
+
+
+ 0
+ 0
+
+
+
+ NSLS-II MIDAS
+
+
+
+ pancake.icopancake.ico
+
+
+ font: 10pt "Segoe UI";
+
+
+
+
+ true
+
+
+
+ 0
+ 0
+
+
+
+ QWidget {
+font: 10pt "Segoe UI";
+}
+
+QPushButton {
+background-color: rgb(175, 236, 255);
+color: rgb(255, 5,0);
+font: 10pt "Segoe UI";
+}
+
+QLabel {
+font: 10pt "Segoe UI";
+}
+
+QSlider::groove:horizontal {
+border: 1px solid #bbb;
+background: white;
+height: 10px;
+border-radius: 4px;
+}
+
+QSlider::sub-page:horizontal {
+background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
+ stop: 0 #66e, stop: 1 #bbf);
+background: qlineargradient(x1: 0, y1: 0.2, x2: 1, y2: 1,
+ stop: 0 #bbf, stop: 1 #55f);
+border: 1px solid #777;
+height: 10px;
+border-radius: 4px;
+}
+
+QSlider::add-page:horizontal {
+background: #fff;
+border: 1px solid #777;
+height: 10px;
+border-radius: 4px;
+}
+
+QSlider::handle:horizontal {
+background: qlineargradient(x1:0, y1:0, x2:1, y2:1,
+ stop:0 #eee, stop:1 #ccc);
+border: 1px solid #777;
+width: 13px;
+margin-top: -2px;
+margin-bottom: -2px;
+border-radius: 4px;
+}
+
+QSlider::handle:horizontal:hover {
+background: qlineargradient(x1:0, y1:0, x2:1, y2:1,
+ stop:0 #fff, stop:1 #ddd);
+border: 1px solid #444;
+border-radius: 2px;
+}
+
+QSlider::sub-page:horizontal:disabled {
+background: #bbb;
+border-color: #999;
+}
+
+QSlider::add-page:horizontal:disabled {
+background: #eee;
+border-color: #999;
+}
+
+QSlider::handle:horizontal:disabled {
+background: #eee;
+border: 1px solid #aaa;
+border-radius: 4px;
+}
+
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ QFrame::StyledPanel
+
+
+ QFrame::Sunken
+
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+
+
+
+ 0
+
+
+
+
+ 0
+ 0
+ 302
+ 288
+
+
+
+ Adjust Image Dimensions
+
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+
+
+
+ QFrame::StyledPanel
+
+
+ QFrame::Raised
+
+
+
-
+
+
+ QLayout::SetMinimumSize
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+ 0
+
+
+ 500
+
+
+ 0
+
+
+ 10
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ 1
+
+
+ 5000
+
+
+ 1200
+
+
+ 10
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ false
+
+
+ px
+
+
+ 1
+
+
+ 10000
+
+
+ 100
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ false
+
+
+ px
+
+
+ 1
+
+
+ 10000
+
+
+ 100
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ false
+
+
+ px
+
+
+ 0
+
+
+ 10000
+
+
+ 0
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Y Dimension
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ false
+
+
+ px
+
+
+ 0
+
+
+ 10000
+
+
+ 0
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ X Dimension
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Stack Range
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ to
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ to
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ to
+
+
+ Qt::AlignCenter
+
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Adjust the dimensions of the image
+
+
+
+
+
+ Update
+
+
+
+ -
+
+
+ Apply crop to all tiffs in directory
+
+
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ QFrame::StyledPanel
+
+
+ QFrame::Raised
+
+
+
-
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+ Removes one column/row from all four edges
+
+
+ Remove Edges
+
+
+
+ -
+
+
-
+
+
+ true
+
+
+
+ 0
+ 0
+
+
+
+ rebin
+
+
+
+ -
+
+
+ true
+
+
+
+ 0
+ 0
+
+
+
+ Upscale
+
+
+
+ -
+
+
-
+
+
+ Ratio
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+ -
+
+
+ true
+
+
+
+ 0
+ 0
+
+
+
+ font: 10pt "MS Shell Dlg 2";
+
+
+ 2
+
+
+ 16
+
+
+ 2
+
+
+ 2
+
+
+
+
+
+
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+
+
+
+
+
+
+
+
+ 0
+ 0
+ 233
+ 365
+
+
+
+ Image Processing
+
+
+ -
+
+
+
-
+
+
+ reverses the image axes (ZXY) to (YXZ)
+
+
+ Transpose
+
+
+
+ -
+
+
+ swaps 2nd and 3rd axes (ZXY) to (ZYX)
+
+
+ Swap XY Axes
+
+
+
+ -
+
+
-
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+ Covert image dat to log values.
+
+
+
+
+
+ Log
+
+
+ false
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Intensity Normalization with the last Frame.
+
+
+ Normalize to Max
+
+
+
+
+
+
+
+ -
+
+
+ QFrame::StyledPanel
+
+
+ QFrame::Raised
+
+
+
-
+
+
-
+
+
+ Remove Outliers (NSigma)
+
+
+
+ -
+
+
+ false
+
+
+
+
+
+ 200
+
+
+ 3
+
+
+ Qt::Horizontal
+
+
+
+ -
+
+
+ 1
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+
+
+
+
+
+ -
+
+
+ QFrame::StyledPanel
+
+
+ QFrame::Raised
+
+
+
-
+
+
-
+
+
-
+
+
+ Thresholding
+
+
+
+
+
+ -
+
+
-
+
+
+ false
+
+
+ 100
+
+
+ 5
+
+
+ 5
+
+
+ 5
+
+
+ Qt::Horizontal
+
+
+
+ -
+
+
+ 5
+
+
+
+
+
+
+
+
+
+
+ -
+
+
+ QFrame::StyledPanel
+
+
+ QFrame::Raised
+
+
+
-
+
+
+ uses savgol_filter to smooth data
+
+
+ Smoothen
+
+
+
+ -
+
+
-
+
+
+ false
+
+
+ 3
+
+
+ 12
+
+
+ 2
+
+
+ 2
+
+
+ 3
+
+
+ Qt::Horizontal
+
+
+ QSlider::TicksBelow
+
+
+ 2
+
+
+
+ -
+
+
+ Window size
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0
+ 0
+ 286
+ 247
+
+
+
+ Alignment
+
+
+ -
+
+
+
-
+
+
-
+
+
+ Transformations:
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+ -
+
+
-
+
+ TRANSLATION
+
+
+ -
+
+ RIGID_BODY
+
+
+ -
+
+ SCALED_ROTATION
+
+
+ -
+
+ AFFINE
+
+
+ -
+
+ BILINEAR
+
+
+
+
+
+
+ -
+
+
-
+
+
+ Reference:
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+ -
+
+
-
+
+ previous
+
+
+ -
+
+ mean
+
+
+ -
+
+ first
+
+
+
+
+
+
+ -
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+ Iterative Mode
+
+
+
+ -
+
+
-
+
+
+ Max Iter.
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ 2
+
+
+ 24
+
+
+
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Align
+
+
+
+ -
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+ Load Reference Stack
+
+
+
+ -
+
+
+ No Ref. Available
+
+
+ true
+
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Save Transformation File
+
+
+
+ -
+
+
+ Use
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Load Transformation File
+
+
+
+
+
+
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+
+
+ Reset Image
+
+
+
+ -
+
+
+ true
+
+
+ 1
+
+
+
+
+ 0
+ 0
+ 302
+ 205
+
+
+
+ Component Analysis
+
+
+
-
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+
+
+
+ Calculate Components
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+
+
+ PCA Scree Plot
+
+
+
+ -
+
+
-
+
+
+ Method
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
-
+
+ PCA
+
+
+ -
+
+ NMF
+
+
+ -
+
+ FastICA
+
+
+ -
+
+ IncrementalPCA
+
+
+ -
+
+ TruncatedSVD
+
+
+ -
+
+ FactorAnalysis
+
+
+ -
+
+ DictionaryLearning
+
+
+
+
+
+
+ -
+
+
-
+
+
+ Number of Components
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+ -
+
+
+ 1
+
+
+ 4
+
+
+
+
+
+
+
+
+
+
+
+
+ 0
+ 0
+ 302
+ 205
+
+
+
+ Cluster Analysis
+
+
+ -
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+
+
+
+ Calculate Clusters
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+
+
+ KMeans Variance Plot
+
+
+
+ -
+
+
+ Method
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
-
+
+ KMeans
+
+
+ -
+
+ MiniBatchKMeans
+
+
+ -
+
+ MeanShift
+
+
+ -
+
+ Spectral Clustering
+
+
+ -
+
+ Correlation-Kmeans
+
+
+ -
+
+ Affinity Propagation
+
+
+
+
+ -
+
+
+ Number of Clusters
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+ -
+
+
+ 1
+
+
+ 4
+
+
+
+
+
+
+
+
+
+
+ 0
+ 0
+ 302
+ 205
+
+
+
+ XANES Fitting
+
+
+ -
+
+
+
+ 11
+
+
+ 11
+
+
-
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+
+
+
+ Load Energy List
+
+
+
+ -
+
+
+ keV
+
+
+
+
+
+ -
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+
+
+
+ Load Ref. Spec.
+
+
+
+ -
+
+
+
+
+
+ Plot
+
+
+
+
+
+ -
+
+
+ true
+
+
+
+ 0
+ 0
+
+
+
+
+
+
+ Fit
+
+
+
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+
+
+
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+
+
+
+
+
+
+ QLayout::SetMaximumSize
+
+
-
+
+
+ 0
+
+
+
+ Live
+
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+ Send to Plot Collection
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+
+
+ Save
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+
+
+
+
+ Normalized
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ -
+
+
+ Norm. to Collector
+
+
+
+ -
+
+
+ Save
+
+
+
+ -
+
+
+ Clear
+
+
+
+
+
+
+
+ Collection
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ -
+
+
+ Clear
+
+
+
+ -
+
+
+ Save
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ QFrame::StyledPanel
+
+
+ QFrame::Sunken
+
+
+
-
+
+
-
+
+
+ font: 9pt "Segoe UI";
+
+
+ ROI Positions
+
+
+
-
+
+
+ Spectrum ROI
+
+
+
-
+
+
+ Range (eV):
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+ -
+
+
+ color: rgb(255, 0,0);
+
+
+ roi_size
+
+
+
+ -
+
+
+ color: rgb(255, 0,0);
+
+
+ roix, roiy
+
+
+
+ -
+
+
+
+
+
+ Size (eV):
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+
+
+
+ -
+
+
+ Image ROI
+
+
+
-
+
+
+ Position:
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+ -
+
+
+ color: rgb(255, 0,0);
+
+
+ roix, roiy
+
+
+
+ -
+
+
+
+
+
+ Size(pixels):
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+ -
+
+
+ color: rgb(255, 0, 0);
+
+
+ roi_size
+
+
+
+
+
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ ROI Shape
+
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+ Ellipse
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Rectangle
+
+
+ true
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Polygon
+
+
+ false
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Circle
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Zoom to ROI
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Line
+
+
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Qt::LeftToRight
+
+
+ 2
+
+
+
+
+ 0
+ 0
+ 305
+ 384
+
+
+
+ Image Calculations
+
+
+
-
+
+
+
+
+
+
-
+
+
+
+
+
+ Add ROI_2
+
+
+
+ -
+
+
+ Calculation:
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
-
+
+ Subtract
+
+
+ -
+
+ Divide
+
+
+ -
+
+ Add
+
+
+ -
+
+ Compare
+
+
+
+
+ -
+
+
+ Apply
+
+
+
+
+
+
+
+
+
+
+
+ 0
+ 0
+ 323
+ 384
+
+
+
+ Spectrum Calculations
+
+
+ -
+
+
+
+
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+ Add ROI 2
+
+
+ true
+
+
+ false
+
+
+ false
+
+
+
+ -
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+ Calculation
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
-
+
+ Divide
+
+
+ -
+
+ Subtract
+
+
+ -
+
+ Add
+
+
+ -
+
+ Correlation Plot
+
+
+
+
+
+
+ -
+
+
+ Use ROI for Correlations
+
+
+
+ -
+
+
+ Apply
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+
+
+
+
+
+
+
+
+ 0
+ 0
+ 365
+ 384
+
+
+
+ XANES Normalization
+
+
+ -
+
+
+
+
+
+
-
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+ calculate the energy point with maximum derivative
+
+
+ Find Eo
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Initial Guess
+
+
+
+ -
+
+
-
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+ Element_Edge:
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Pre-edge
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Post-edge
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+
+
+ -
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+ <html><head/><body><p> For mbak algorithm only, must be in <span style=" font-weight:600; font-style:italic;">element<space>edge</span> format</p></body></html>
+
+
+ Fe_K
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ eV
+
+
+ 2
+
+
+ -500.000000000000000
+
+
+ 500.000000000000000
+
+
+ 1.000000000000000
+
+
+ -50.000000000000000
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ eV
+
+
+ 0.000000000000000
+
+
+ 1000.000000000000000
+
+
+ 25.000000000000000
+
+
+
+
+
+ -
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+ Eo:
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ to
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ to
+
+
+ Qt::AlignCenter
+
+
+
+
+
+ -
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+ eV
+
+
+ 1000.000000000000000
+
+
+ 20000.000000000000000
+
+
+ 7125.000000000000000
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ eV
+
+
+ -500.000000000000000
+
+
+ 500.000000000000000
+
+
+ -10.000000000000000
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ eV
+
+
+ 0.000000000000000
+
+
+ 1500.000000000000000
+
+
+ 75.000000000000000
+
+
+
+
+
+
+
+ -
+
+
-
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+ Norm. Order
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ 1
+
+
+ 5
+
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Use Flattened
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Apply to Spectrum
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Apply to Stack
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Ignore Post Edge (Stack Only)
+
+
+
+ -
+
+
+ MBAK Algorithm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0
+ 0
+
+
+
+ toolBar
+
+
+ TopToolBarArea
+
+
+ false
+
+
+
+
+
+
+
+ Open PDF
+
+
+
+
+ Open in GitHub (most updated)
+
+
+
+
+ true
+
+
+ Open Image Data
+
+
+ Support all tiff and specific h5 files
+
+
+ Ctrl+O
+
+
+
+
+ Close
+
+
+
+
+ Exit
+
+
+ Ctrl+Q
+
+
+
+
+ false
+
+
+ Export Tiff Stack
+
+
+ Save the displayed/Modified stack as a tiff file
+
+
+ Ctrl+S
+
+
+
+
+ Open PyXRF
+
+
+
+
+ Open Image J
+
+
+
+
+ Open TomViz
+
+
+
+
+ Open Mantis
+
+
+
+
+ Open Athena
+
+
+
+
+ DataBroker
+
+
+
+
+ Open HXN DB
+
+
+
+
+ false
+
+
+ Load Energy
+
+
+ Load list of energies for XANES stack. Supports only .txt fromat
+
+
+ Ctrl+E
+
+
+
+
+ Create a Virtual Stack
+
+
+ Create a stack from multiple tiff images of same shape
+
+
+ Ctrl+M
+
+
+
+
+ true
+
+
+ Open Mask Generator
+
+
+ A new window will be opened to creat threshold based masks
+
+
+
+
+ Create elist from log file
+
+
+
+
+ false
+
+
+ Export Energy List
+
+
+
+
+ true
+
+
+ MultiColorView
+
+
+ A new window will be opened to align images in a stack
+
+
+
+
+ White
+
+
+
+
+ true
+
+
+ true
+
+
+ Black
+
+
+
+
+ Red
+
+
+
+
+ Yellow
+
+
+
+
+ Blue
+
+
+
+
+ false
+
+
+ false
+
+
+ Dark Mode
+
+
+
+
+ Black
+
+
+
+
+ false
+
+
+ false
+
+
+ Default
+
+
+
+
+ Vivid
+
+
+
+
+ Export Sum Image (XYZ to sum(XY))
+
+
+
+
+ Subtract ROI as Background
+
+
+
+
+ Export Norm. Params
+
+
+
+
+ 2
+
+
+
+
+ 4
+
+
+
+
+ 6
+
+
+
+
+ 10
+
+
+
+
+ 2
+
+
+
+
+ 3
+
+
+
+
+ 4
+
+
+
+
+ 5
+
+
+
+
+ 6
+
+
+
+
+ 8
+
+
+
+
+ 10
+
+
+
+
+ 2
+
+
+
+
+ Import Norm. Params
+
+
+
+
+ 1
+
+
+
+
+ Save Sum Spectrum
+
+
+
+
+ Save Mean Spectrum
+
+
+
+
+ Save Current Image as Mask
+
+
+
+
+ Stack to RGBCMY Image
+
+
+
+
+ Apply Current Crop to All images
+
+
+ all images in the folder will be cropped in reference to current
+
+
+
+
+
+
+
+
+
+
+ Save Current State
+
+
+
+
+ Normalize with another Stack
+
+
+
+
+ Stack Info
+
+
+ Diaplays details of the stack
+
+
+
+
+ Export Image
+
+
+ Saves displayed 2D image frame
+
+
+
+
+
+ ..
+
+
+ Export Stack
+
+
+ Save current stack as is
+
+
+ false
+
+
+
+
+ Export Mean Image (XYZ to mean(XY))
+
+
+
+
+ Plot All Possible Image Correlations
+
+
+
+
+ Export Image as CSV (XYZ to Z,X*Y)
+
+
+
+
+
+ PlotWidget
+ QGraphicsView
+
+
+
+ ImageView
+ QGraphicsView
+
+
+
+
+
+
diff --git a/xmidas/uis/multipleScatterFit.ui b/xmidas/uis/multipleScatterFit.ui
index 7112364..64b9363 100644
--- a/xmidas/uis/multipleScatterFit.ui
+++ b/xmidas/uis/multipleScatterFit.ui
@@ -1,114 +1,114 @@
-
-
- MainWindow
-
-
-
- 0
- 0
- 856
- 628
-
-
-
- MainWindow
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- 0
- 0
-
-
-
-
-
-
-
-
-
-
-
-
-
- toolBar
-
-
- TopToolBarArea
-
-
- false
-
-
-
-
-
-
-
- Export
-
-
-
-
- Save as PNG
-
-
-
-
- Generate MultiColor Mask
-
-
-
-
- Black
-
-
-
-
- White
-
-
-
-
-
- GraphicsLayoutWidget
- QGraphicsView
-
-
-
-
-
-
+
+
+ MainWindow
+
+
+
+ 0
+ 0
+ 856
+ 628
+
+
+
+ MainWindow
+
+
+
+ -
+
+
+
+
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+
+
+
+
+
+
+
+
+
+
+ toolBar
+
+
+ TopToolBarArea
+
+
+ false
+
+
+
+
+
+
+
+ Export
+
+
+
+
+ Save as PNG
+
+
+
+
+ Generate MultiColor Mask
+
+
+
+
+ Black
+
+
+
+
+ White
+
+
+
+
+
+ GraphicsLayoutWidget
+ QGraphicsView
+
+
+
+
+
+
diff --git a/xmidas/uis/mutlichannel.ui b/xmidas/uis/mutlichannel.ui
index 133f006..7315290 100644
--- a/xmidas/uis/mutlichannel.ui
+++ b/xmidas/uis/mutlichannel.ui
@@ -1,458 +1,464 @@
-
-
- MainWindow
-
-
-
- 0
- 0
- 674
- 765
-
-
-
- MainWindow
-
-
- font: 12pt "Segoe UI"
-
-
-
- QPushButton {
-border: 1px solid #555;
-border-radius: 5px;
-background: qradialgradient(cx: 0.3, cy: -0.1,
-fx: 0.7, fy: 0.1,
-radius: 1, stop: 0 #fff, stop: 1 #888);
-background-color: rgb(170, 255, 255);
-}
-
-QPushButton:hover{
- background-color: rgb(255, 255, 0);
- }
-
-QPushButton:pressed{
- background-color: rgb(0,255, 0);
- }
-
-font: 12pt "Segoe UI";
-
-
-
- 25
-
-
- 25
-
-
- 25
-
-
- 25
-
- -
-
-
-
- 0
- 0
-
-
-
-
- -
-
-
- Edit
-
-
-
-
-
-
-
- 0
- 0
-
-
-
- 0
-
-
-
-
- 0
- 0
- 316
- 85
-
-
-
- Thresholding
-
-
-
-
-
-
-
-
-
-
- 0
- 0
-
-
-
- 0,100
-
-
- Qt::AlignCenter
-
-
-
- -
-
-
-
-
-
-
-
-
-
- 0
- 0
-
-
-
- Qt::NoFocus
-
-
- click update after making changes
-
-
- 100
-
-
- 5
-
-
- 5
-
-
- 100
-
-
- 100
-
-
- true
-
-
- Qt::Horizontal
-
-
- false
-
-
- false
-
-
- QSlider::NoTicks
-
-
- 5
-
-
-
-
-
- -
-
-
-
-
-
-
- 0
- 0
-
-
-
- Qt::NoFocus
-
-
- click update after making changes
-
-
- 100
-
-
- 5
-
-
- 5
-
-
- 0
-
-
- 0
-
-
- true
-
-
- Qt::Horizontal
-
-
- QSlider::NoTicks
-
-
- 5
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 0
- 0
- 316
- 85
-
-
-
- Opacity
-
-
- -
-
-
-
-
-
-
- 0
- 0
-
-
-
- 1
-
-
- Qt::AlignCenter
-
-
-
- -
-
-
- click update after making changes
-
-
- 100
-
-
- 10
-
-
- 100
-
-
- Qt::Horizontal
-
-
-
-
-
-
-
-
-
- -
-
-
- execute above changes to the selected item
-
-
- Update
-
-
-
- -
-
-
-
-
-
- Show Selected
-
-
-
- -
-
-
- Show All
-
-
-
- -
-
-
-
-
-
-
- 0
- 0
-
-
-
- change properties of the selected item
-
-
- font: 8pt "Segoe UI";
-
-
- QAbstractScrollArea::AdjustToContents
-
-
-
- -
-
-
-
-
-
-
- 0
- 0
-
-
-
- Change Selected To
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
- true
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Load Images
-
-
- Select and load multiple tiff images to create a multi color view
-
-
-
-
- Load 2
-
-
-
-
- Load 3
-
-
-
-
- Load 4
-
-
-
-
- Load 5
-
-
-
-
- Load 6
-
-
-
-
- Export Image
-
-
- Export the image view as a sinle image file
-
-
-
-
- Save State File
-
-
- Save the current state of the view. Images and properties are saved
-
-
-
-
- Load State File
-
-
- Load a state (json file) saved previously.
-
-
-
-
- Load Stack
-
-
- Load images as a stack of tiff
-
-
-
-
-
- GraphicsLayoutWidget
- QGraphicsView
-
-
-
-
-
-
+
+
+ MainWindow
+
+
+
+ 0
+ 0
+ 612
+ 765
+
+
+
+ MainWindow
+
+
+ font: 12pt "Segoe UI"
+
+
+
+ QPushButton {
+border: 1px solid #555;
+border-radius: 5px;
+background: qradialgradient(cx: 0.3, cy: -0.1,
+fx: 0.7, fy: 0.1,
+radius: 1, stop: 0 #fff, stop: 1 #888);
+background-color: rgb(170, 255, 255);
+}
+
+QPushButton:hover{
+ background-color: rgb(255, 255, 0);
+ }
+
+QPushButton:pressed{
+ background-color: rgb(0,255, 0);
+ }
+
+font: 12pt "Segoe UI";
+
+
+
+ 25
+
+
+ 25
+
+
+ 25
+
+
+ 25
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ -
+
+
+ Edit
+
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+ 0
+
+
+
+
+ 0
+ 0
+ 254
+ 85
+
+
+
+ Thresholding
+
+
+
-
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+ 0,100
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
-
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+ Qt::NoFocus
+
+
+ click update after making changes
+
+
+ 100
+
+
+ 5
+
+
+ 5
+
+
+ 100
+
+
+ 100
+
+
+ true
+
+
+ Qt::Horizontal
+
+
+ false
+
+
+ false
+
+
+ QSlider::NoTicks
+
+
+ 5
+
+
+
+
+
+ -
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+ Qt::NoFocus
+
+
+ click update after making changes
+
+
+ 100
+
+
+ 5
+
+
+ 5
+
+
+ 0
+
+
+ 0
+
+
+ true
+
+
+ Qt::Horizontal
+
+
+ QSlider::NoTicks
+
+
+ 5
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0
+ 0
+ 98
+ 81
+
+
+
+ Opacity
+
+
+ -
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+ 1
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+ click update after making changes
+
+
+ 100
+
+
+ 10
+
+
+ 100
+
+
+ Qt::Horizontal
+
+
+
+
+
+
+
+
+
+ -
+
+
+ execute above changes to the selected item
+
+
+ Update
+
+
+
+ -
+
+
-
+
+
+ Show Selected
+
+
+
+ -
+
+
+ Show All
+
+
+
+ -
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+ change properties of the selected item
+
+
+ font: 8pt "Segoe UI";
+
+
+ QAbstractScrollArea::AdjustToContents
+
+
+
+ -
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+ Change Selected To
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+ -
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Load Images
+
+
+ Select and load multiple tiff images to create a multi color view
+
+
+
+
+ Load 2
+
+
+
+
+ Load 3
+
+
+
+
+ Load 4
+
+
+
+
+ Load 5
+
+
+
+
+ Load 6
+
+
+
+
+ Export Image
+
+
+ Export the image view as a sinle image file
+
+
+
+
+ Save State File
+
+
+ Save the current state of the view. Images and properties are saved
+
+
+
+
+ Load State File
+
+
+ Load a state (json file) saved previously.
+
+
+
+
+ Load Stack
+
+
+ Load images as a stack of tiff
+
+
+
+
+ Save Stack (.tiff)
+
+
+
+
+
+ GraphicsLayoutWidget
+ QGraphicsView
+
+
+
+
+
+
diff --git a/xmidas/uis/singleStackView.ui b/xmidas/uis/singleStackView.ui
index d832b04..22ee549 100644
--- a/xmidas/uis/singleStackView.ui
+++ b/xmidas/uis/singleStackView.ui
@@ -1,151 +1,151 @@
-
-
- MainWindow
-
-
-
- 0
- 0
- 691
- 566
-
-
-
- MainWindow
-
-
- QSlider::groove:horizontal {
-border: 1px solid #bbb;
-background: white;
-height: 10px;
-border-radius: 4px;
-}
-
-QSlider::sub-page:horizontal {
-background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
- stop: 0 #66e, stop: 1 #bbf);
-background: qlineargradient(x1: 0, y1: 0.2, x2: 1, y2: 1,
- stop: 0 #bbf, stop: 1 #55f);
-border: 1px solid #777;
-height: 10px;
-border-radius: 4px;
-}
-
-QSlider::add-page:horizontal {
-background: #fff;
-border: 1px solid #777;
-height: 10px;
-border-radius: 4px;
-}
-
-QSlider::handle:horizontal {
-background: qlineargradient(x1:0, y1:0, x2:1, y2:1,
- stop:0 #eee, stop:1 #ccc);
-border: 1px solid #777;
-width: 13px;
-margin-top: -2px;
-margin-bottom: -2px;
-border-radius: 4px;
-}
-
-QSlider::handle:horizontal:hover {
-background: qlineargradient(x1:0, y1:0, x2:1, y2:1,
- stop:0 #fff, stop:1 #ddd);
-border: 1px solid #444;
-border-radius: 2px;
-}
-
-QSlider::sub-page:horizontal:disabled {
-background: #bbb;
-border-color: #999;
-}
-
-QSlider::add-page:horizontal:disabled {
-background: #eee;
-border-color: #999;
-}
-
-QSlider::handle:horizontal:disabled {
-background: #eee;
-border: 1px solid #aaa;
-border-radius: 4px;
-}
-
-QPushButton {
-background-color: rgb(175, 236, 255);
-color: rgb(255, 0, 127);
-}
-
-
-
- -
-
-
-
-
-
-
- 0
- 0
-
-
-
-
- -
-
-
-
-
-
- Qt::Horizontal
-
-
-
- -
-
-
- font: 12pt "MS Shell Dlg 2";
-
-
- 10
-
-
-
-
-
-
-
-
-
-
-
-
-
- Save
-
-
-
-
-
- ImageView
- QGraphicsView
-
-
-
-
-
-
+
+
+ MainWindow
+
+
+
+ 0
+ 0
+ 691
+ 566
+
+
+
+ MainWindow
+
+
+ QSlider::groove:horizontal {
+border: 1px solid #bbb;
+background: white;
+height: 10px;
+border-radius: 4px;
+}
+
+QSlider::sub-page:horizontal {
+background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
+ stop: 0 #66e, stop: 1 #bbf);
+background: qlineargradient(x1: 0, y1: 0.2, x2: 1, y2: 1,
+ stop: 0 #bbf, stop: 1 #55f);
+border: 1px solid #777;
+height: 10px;
+border-radius: 4px;
+}
+
+QSlider::add-page:horizontal {
+background: #fff;
+border: 1px solid #777;
+height: 10px;
+border-radius: 4px;
+}
+
+QSlider::handle:horizontal {
+background: qlineargradient(x1:0, y1:0, x2:1, y2:1,
+ stop:0 #eee, stop:1 #ccc);
+border: 1px solid #777;
+width: 13px;
+margin-top: -2px;
+margin-bottom: -2px;
+border-radius: 4px;
+}
+
+QSlider::handle:horizontal:hover {
+background: qlineargradient(x1:0, y1:0, x2:1, y2:1,
+ stop:0 #fff, stop:1 #ddd);
+border: 1px solid #444;
+border-radius: 2px;
+}
+
+QSlider::sub-page:horizontal:disabled {
+background: #bbb;
+border-color: #999;
+}
+
+QSlider::add-page:horizontal:disabled {
+background: #eee;
+border-color: #999;
+}
+
+QSlider::handle:horizontal:disabled {
+background: #eee;
+border: 1px solid #aaa;
+border-radius: 4px;
+}
+
+QPushButton {
+background-color: rgb(175, 236, 255);
+color: rgb(255, 0, 127);
+}
+
+
+
+ -
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+
+ -
+
+
-
+
+
+ Qt::Horizontal
+
+
+
+ -
+
+
+ font: 12pt "MS Shell Dlg 2";
+
+
+ 10
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Save
+
+
+
+
+
+ ImageView
+ QGraphicsView
+
+
+
+
+
+
diff --git a/xmidas/uis/xanesFitStat.ui b/xmidas/uis/xanesFitStat.ui
index 25685bf..258e475 100644
--- a/xmidas/uis/xanesFitStat.ui
+++ b/xmidas/uis/xanesFitStat.ui
@@ -1,47 +1,47 @@
-
-
- MainWindow
-
-
-
- 0
- 0
- 792
- 481
-
-
-
- MainWindow
-
-
-
- -
-
-
- -
-
-
-
-
-
-
-
-
-
- PlotWidget
- QGraphicsView
-
-
-
-
-
-
+
+
+ MainWindow
+
+
+
+ 0
+ 0
+ 792
+ 481
+
+
+
+ MainWindow
+
+
+
+ -
+
+
+ -
+
+
+
+
+
+
+
+
+
+ PlotWidget
+ QGraphicsView
+
+
+
+
+
+
diff --git a/xmidas/uis/xrf_xanes_gui_3ID.ui b/xmidas/uis/xrf_xanes_gui_3ID.ui
index 8755841..18a9043 100644
--- a/xmidas/uis/xrf_xanes_gui_3ID.ui
+++ b/xmidas/uis/xrf_xanes_gui_3ID.ui
@@ -1,756 +1,756 @@
-
-
- Ajith
- MainWindow
-
-
-
- 0
- 0
- 820
- 553
-
-
-
- HXN_Wizard
-
-
- font: 12pt "MS Shell Dlg 2";
-
-
-
- -
-
-
-
-
-
-
- 0
- 0
-
-
-
-
-
-
-
- 20
-
-
-
-
-
-
-
-
-
- 0
- 0
-
-
-
-
-
-
- C:\Matrix\Blue Pill\Morpheus.csv
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
-
-
- C:\Matrix\Blue Pill
-
-
-
- -
-
-
- 0
-
-
- 10
-
-
-
-
-
-
- 0
- 0
-
-
-
- Select Working Directory
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Select Paramater File
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Select XANES Reference File (xanes only)
-
-
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
-
-
- C:\Matrix\Blue Pill\TheChosenOne.json
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- background-color: rgb(255, 221, 98);
-
-
- Open PyXRF GUI
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
-
-
- -
-
-
- font: 12pt "MS Shell Dlg 2";
-
-
- 1
-
-
- false
-
-
-
- XRF
-
-
-
-
-
-
- XRF Batch Processing
-
-
- Qt::AlignCenter
-
-
-
-
-
-
- 150
-
-
- 150
-
-
-
-
-
- 92158
-
-
- 00000
-
-
-
- -
-
-
- 92102
-
-
- 00000
-
-
-
- -
-
-
- Last Scan ID:
-
-
-
- -
-
-
- Scalar Name:
-
-
-
- -
-
-
- First Scan ID:
-
-
-
- -
-
-
- sclr1_ch4
-
-
- Fe_K
-
-
-
- -
-
-
- background-color: rgb(85, 255, 127);
-
-
- Start Batch Processing
-
-
-
-
-
-
-
-
- -
-
-
- 150
-
-
- 150
-
-
-
-
-
- XRF Live Processing
-
-
- Qt::AlignCenter
-
-
-
-
-
-
-
-
-
- background-color: rgb(0, 170, 255);
-background-color: rgb(67, 246, 255);
-
-
- Initiate Live
-
-
-
- -
-
-
- background-color: rgb(255, 130, 67);
-font: 75 12pt "MS Shell Dlg 2";
-
-
-
- Start
-
-
-
- -
-
-
- Live Processing is not ready
-
-
- Qt::AlignCenter
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- XANES
-
-
- -
-
-
- 50
-
-
- 50
-
-
-
-
-
-
-
-
- First Scan ID:
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
- 92102
-
-
- 00000
-
-
-
- -
-
-
- XANES Element
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
- Fe_K
-
-
- Fe_K
-
-
-
- -
-
-
- Alignemnt Element
-
-
-
- -
-
-
- P_K
-
-
- Pt_L
-
-
-
-
-
- -
-
-
- 50
-
-
- 0
-
-
-
-
-
- Last Scan ID:
-
-
-
- -
-
-
- 92158
-
-
- 00000
-
-
-
- -
-
-
- Scalar Name
-
-
-
- -
-
-
- sclr1_ch4
-
-
- Fe_K
-
-
-
- -
-
-
- Save All Elem tiff Stacks
-
-
- true
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Subtract Pre-edge
-
-
-
-
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 49
- 20
-
-
-
-
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 48
-
-
-
-
- -
-
-
- 20
-
-
- 20
-
-
-
-
-
-
- 0
- 0
-
-
-
- Fitting method
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
-
- nnls
-
-
- -
-
- admm
-
-
-
-
- -
-
-
- false
-
-
-
- 0
- 0
-
-
-
- Lambda for ADMM:
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
- false
-
-
-
- 0
- 0
-
-
-
- Qt::StrongFocus
-
-
- 5
-
-
- Lambda for ADMM
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Energy Shift (eV)
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Qt::StrongFocus
-
-
- 0
-
-
- Lambda for ADMM
-
-
-
- -
-
-
- Work Flow
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
-
- load_and_process
-
-
- -
-
- process
-
-
- -
-
- build_xanes_map
-
-
-
-
- -
-
-
- font: 12pt "MS Shell Dlg 2";
-background-color: rgb(170, 255, 255);
-
-
- Go
-
-
-
- -
-
-
- background-color: rgb(255, 77, 46);
-color: rgb(0, 0, 0);
-font: 75 10pt "MS Shell Dlg 2";
-
-
- Close All Plots
-
-
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 49
- 20
-
-
-
-
-
-
-
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 52
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+ Ajith
+ MainWindow
+
+
+
+ 0
+ 0
+ 820
+ 553
+
+
+
+ HXN_Wizard
+
+
+ font: 12pt "MS Shell Dlg 2";
+
+
+
+ -
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+
+
+
+
+ 20
+
+
-
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+
+
+
+ C:\Matrix\Blue Pill\Morpheus.csv
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+
+
+ C:\Matrix\Blue Pill
+
+
+
+ -
+
+
+ 0
+
+
+ 10
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+ Select Working Directory
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Select Paramater File
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Select XANES Reference File (xanes only)
+
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+
+
+ C:\Matrix\Blue Pill\TheChosenOne.json
+
+
+
+
+
+
+
+
+ -
+
+
-
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ background-color: rgb(255, 221, 98);
+
+
+ Open PyXRF GUI
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+ -
+
+
+ font: 12pt "MS Shell Dlg 2";
+
+
+ 1
+
+
+ false
+
+
+
+ XRF
+
+
+
-
+
+
+ XRF Batch Processing
+
+
+ Qt::AlignCenter
+
+
+
-
+
+
+ 150
+
+
+ 150
+
+
-
+
+
+ 92158
+
+
+ 00000
+
+
+
+ -
+
+
+ 92102
+
+
+ 00000
+
+
+
+ -
+
+
+ Last Scan ID:
+
+
+
+ -
+
+
+ Scalar Name:
+
+
+
+ -
+
+
+ First Scan ID:
+
+
+
+ -
+
+
+ sclr1_ch4
+
+
+ Fe_K
+
+
+
+ -
+
+
+ background-color: rgb(85, 255, 127);
+
+
+ Start Batch Processing
+
+
+
+
+
+
+
+
+ -
+
+
+ 150
+
+
+ 150
+
+
-
+
+
+ XRF Live Processing
+
+
+ Qt::AlignCenter
+
+
+
-
+
+
-
+
+
+ background-color: rgb(0, 170, 255);
+background-color: rgb(67, 246, 255);
+
+
+ Initiate Live
+
+
+
+ -
+
+
+ background-color: rgb(255, 130, 67);
+font: 75 12pt "MS Shell Dlg 2";
+
+
+
+ Start
+
+
+
+ -
+
+
+ Live Processing is not ready
+
+
+ Qt::AlignCenter
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ XANES
+
+
+ -
+
+
+ 50
+
+
+ 50
+
+
-
+
+
-
+
+
+ First Scan ID:
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+ -
+
+
+ 92102
+
+
+ 00000
+
+
+
+ -
+
+
+ XANES Element
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+ -
+
+
+ Fe_K
+
+
+ Fe_K
+
+
+
+ -
+
+
+ Alignemnt Element
+
+
+
+ -
+
+
+ P_K
+
+
+ Pt_L
+
+
+
+
+
+ -
+
+
+ 50
+
+
+ 0
+
+
-
+
+
+ Last Scan ID:
+
+
+
+ -
+
+
+ 92158
+
+
+ 00000
+
+
+
+ -
+
+
+ Scalar Name
+
+
+
+ -
+
+
+ sclr1_ch4
+
+
+ Fe_K
+
+
+
+ -
+
+
+ Save All Elem tiff Stacks
+
+
+ true
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Subtract Pre-edge
+
+
+
+
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 49
+ 20
+
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 48
+
+
+
+
+ -
+
+
+ 20
+
+
+ 20
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+ Fitting method
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
-
+
+ nnls
+
+
+ -
+
+ admm
+
+
+
+
+ -
+
+
+ false
+
+
+
+ 0
+ 0
+
+
+
+ Lambda for ADMM:
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+ -
+
+
+ false
+
+
+
+ 0
+ 0
+
+
+
+ Qt::StrongFocus
+
+
+ 5
+
+
+ Lambda for ADMM
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Energy Shift (eV)
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Qt::StrongFocus
+
+
+ 0
+
+
+ Lambda for ADMM
+
+
+
+ -
+
+
+ Work Flow
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
-
+
+ load_and_process
+
+
+ -
+
+ process
+
+
+ -
+
+ build_xanes_map
+
+
+
+
+ -
+
+
+ font: 12pt "MS Shell Dlg 2";
+background-color: rgb(170, 255, 255);
+
+
+ Go
+
+
+
+ -
+
+
+ background-color: rgb(255, 77, 46);
+color: rgb(0, 0, 0);
+font: 75 10pt "MS Shell Dlg 2";
+
+
+ Close All Plots
+
+
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 49
+ 20
+
+
+
+
+
+
+
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 52
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/xmidas/utils.py b/xmidas/utils.py
new file mode 100644
index 0000000..31067ac
--- /dev/null
+++ b/xmidas/utils.py
@@ -0,0 +1,815 @@
+""" Helper Functions (make a class later)"""
+
+
+import h5py
+import logging
+import numpy as np
+import pandas as pd
+import os
+import scipy.optimize as opt
+import scipy.stats as stats
+
+import sklearn.decomposition as sd
+import sklearn.cluster as sc
+from scipy.signal import savgol_filter
+from skimage.transform import resize
+from skimage import filters
+from sklearn import linear_model
+from larch.xafs import pre_edge, preedge, mback
+from larch.io import read_ascii, read_athena
+from larch import Group
+import xraydb
+from pystackreg import StackReg
+
+logger = logging.getLogger()
+
+def get_xrf_data(h='h5file'):
+ """
+ get xrf stack from h5 data generated at NSLS-II beamlines
+
+ Arguments:
+ h5/hdf5 file
+
+ Returns:
+ norm_xrf_stack - xrf stack image normalized with Io
+ mono_e - excitation enegy used for xrf
+ beamline - identity of the beamline
+ Io_avg - an average Io value, used before taking log
+
+ """
+
+ f = h5py.File(h, "r")
+
+ if list(f.keys())[0] == "xrfmap":
+ logger.info("Data from HXN/TES/SRX")
+ beamline = f["xrfmap/scan_metadata"].attrs["scan_instrument_id"]
+
+ try:
+
+ beamline_scalar = {"HXN": 2, "SRX": 0, "TES": 0}
+
+ if beamline in beamline_scalar.keys():
+
+ Io = np.array(f["xrfmap/scalers/val"])[:, :, beamline_scalar[beamline]]
+ raw_xrf_stack = np.array(f["xrfmap/detsum/counts"])
+ norm_xrf_stack = raw_xrf_stack
+ Io_avg = int(remove_nan_inf(Io).mean())
+ else:
+ logger.error("Unknown Beamline Scalar")
+ except Exception:
+ logger.warning("Unknown Scalar: Raw Detector count in use")
+ norm_xrf_stack = np.array(f["xrfmap/detsum/counts"])
+
+ elif list(f.keys())[0] == "xrmmap":
+ logger.info("Data from XFM")
+ beamline = "XFM"
+ raw_xrf_stack = np.array(f["xrmmap/mcasum/counts"])
+ Io = np.array(f["xrmmap/scalars/I0"])
+ norm_xrf_stack = raw_xrf_stack
+ Io_avg = int(remove_nan_inf(Io).mean())
+
+ elif list(f.keys())[0] == "MAPS":
+ logger.info("MAPS file")
+ beamline = "APS"
+ raw_xrf_stack = np.array(f["MAPS/Spectra/mca_arr"])
+ Io = 1 #have to find the name of the scalar
+ norm_xrf_stack = raw_xrf_stack.transpose((1, 2, 0))
+ Io_avg = int(remove_nan_inf(Io).mean())
+
+ else:
+ logger.error("Unknown Data Format")
+
+ try:
+ mono_e = int(f["xrfmap/scan_metadata"].attrs["instrument_mono_incident_energy"] * 1000)
+ logger.info("Excitation energy was taken from the h5 data")
+
+ except Exception:
+ mono_e = 12000
+ logger.info(f"Unable to get Excitation energy from the h5 data; using default value {mono_e} KeV")
+
+ return remove_nan_inf(norm_xrf_stack.transpose((2, 0, 1))), mono_e + 1500, beamline, Io_avg
+
+
+def remove_nan_inf(im):
+ im = np.array(im, dtype=np.float32)
+ im[np.isnan(im)] = 0
+ im[np.isinf(im)] = 0
+ return im
+
+
+def rebin_image(im, bin_factor):
+ arrx, arry = np.shape(im)
+ if arrx / bin_factor != int or arrx / bin_factor != int:
+ logger.error("Invalid Binning")
+
+ else:
+ shape = (arrx / bin_factor, arry / bin_factor)
+ return im.reshape(shape).mean(-1).mean(1)
+
+
+def remove_hot_pixels(image_array, NSigma=5):
+ image_array = remove_nan_inf(image_array)
+ a, b, c = np.shape(image_array)
+ img_stack2 = np.zeros((a, b, c))
+ for i in range(a):
+ im = image_array[i, :, :]
+ im[abs(im) > np.std(im) * NSigma] = im.mean()
+ img_stack2[i, :, :] = im
+ return img_stack2
+
+
+def smoothen(image_array, w_size=5):
+ a, b, c = np.shape(image_array)
+ spec2D_Matrix = np.reshape(image_array, (a, (b * c)))
+ smooth2D_Matrix = savgol_filter(spec2D_Matrix, w_size, w_size - 2, axis=0)
+ return remove_nan_inf(np.reshape(smooth2D_Matrix, (a, b, c)))
+
+
+def resize_stack(image_array, upscaling=False, scaling_factor=2):
+ en, im1, im2 = np.shape(image_array)
+
+ if upscaling:
+ im1_ = im1 * scaling_factor
+ im2_ = im2 * scaling_factor
+ img_stack_resized = resize(image_array, (en, im1_, im2_))
+
+ else:
+ im1_ = int(im1 / scaling_factor)
+ im2_ = int(im2 / scaling_factor)
+ img_stack_resized = resize(image_array, (en, im1_, im2_))
+
+ return img_stack_resized
+
+
+def normalize(image_array, norm_point=-1):
+ norm_stack = image_array / image_array[norm_point]
+ return remove_nan_inf(norm_stack)
+
+
+def remove_edges(image_array):
+ # z, x, y = np.shape(image_array)
+ return image_array[:, 1:-1, 1:-1]
+
+
+def background_value(image_array):
+ img = image_array.mean(0)
+ img_h = img.mean(0)
+ img_v = img.mean(1)
+ h = np.gradient(img_h)
+ v = np.gradient(img_v)
+ bg = np.min([img_h[h == h.max()], img_v[v == v.max()]])
+ return bg
+
+
+def background_subtraction(img_stack, bg_percentage=10):
+ img_stack = remove_nan_inf(img_stack)
+ a, b, c = np.shape(img_stack)
+ ref_image = np.reshape(img_stack.mean(0), (b * c))
+ bg_ratio = int((b * c) * 0.01 * bg_percentage)
+ bg_ = np.max(sorted(ref_image)[0:bg_ratio])
+ bged_img_stack = img_stack - bg_[:, np.newaxis, np.newaxis]
+ return bged_img_stack
+
+
+def background_subtraction2(img_stack, bg_percentage=10):
+ img_stack = remove_nan_inf(img_stack)
+ a, b, c = np.shape(img_stack)
+ bg_ratio = int((b * c) * 0.01 * bg_percentage)
+ bged_img_stack = img_stack.copy()
+
+ for n, img in enumerate(img_stack):
+ bg_ = np.max(sorted(img.flatten())[0:bg_ratio])
+ print(bg_)
+ bged_img_stack[n] = img - bg_
+
+ return remove_nan_inf(bged_img_stack)
+
+
+def background1(img_stack):
+ img = img_stack.sum(0)
+ img_h = img.mean(0)
+ img_v = img.mean(1)
+ h = np.gradient(img_h)
+ v = np.gradient(img_v)
+ bg = np.min([img_h[h == h.max()], img_v[v == v.max()]])
+ return bg
+
+
+def get_sum_spectra(image_array):
+ spec = np.sum(image_array, axis=(1, 2))
+ return spec
+
+
+def get_mean_spectra(image_array):
+ spec = np.mean(image_array, axis=(1, 2))
+ return spec
+
+
+def flatten_(image_array):
+ z, x, y = np.shape(image_array)
+ flat_array = np.reshape(image_array, (x * y, z))
+ return flat_array
+
+
+def image_to_pandas(image_array):
+ a, b, c = np.shape(image_array)
+ im_array = np.reshape(image_array, ((b * c), a))
+ a, b = im_array.shape
+ df = pd.DataFrame(
+ data=im_array[:, :], columns=["e" + str(i) for i in range(b)], index=["s" + str(i) for i in range(a)]
+ )
+ return df
+
+
+def image_to_pandas2(image_array):
+ a, b, c = np.shape(image_array)
+ im_array = np.reshape(image_array, (a, (b * c)))
+ a, b = im_array.shape
+ df = pd.DataFrame(
+ data=im_array[:, :], index=["e" + str(i) for i in range(a)], columns=["s" + str(i) for i in range(b)]
+ )
+ return df
+
+
+def neg_log(image_array):
+ absorb = -1 * np.log(image_array)
+ return remove_nan_inf(absorb)
+
+
+def clean_stack(img_stack, auto_bg=False, bg_percentage=5):
+ a, b, c = np.shape(img_stack)
+
+ if auto_bg is True:
+ bg_ = background1(img_stack)
+
+ else:
+ sum_spec = (img_stack.sum(1)).sum(1)
+ ref_stk_num = np.where(sum_spec == sum_spec.max())[-1]
+
+ ref_image = np.reshape(img_stack[ref_stk_num], (b * c))
+ bg_ratio = int((b * c) * 0.01 * bg_percentage)
+ bg_ = np.max(sorted(ref_image)[0:bg_ratio])
+
+ bg = np.where(img_stack[ref_stk_num] > bg_, img_stack[ref_stk_num], 0)
+ bg2 = np.where(bg < bg_, bg, 1)
+
+ bged_img_stack = img_stack * bg2
+
+ return remove_nan_inf(bged_img_stack)
+
+
+def subtractBackground(im_stack, bg_region):
+ if bg_region.ndim == 3:
+ bg_region_ = np.mean(bg_region, axis=(1, 2))
+
+ elif bg_region.ndim == 2:
+ bg_region_ = np.mean(bg_region, axis=1)
+
+ else:
+ bg_region_ = bg_region
+
+ return im_stack - bg_region_[:, np.newaxis, np.newaxis]
+
+
+def classify(img_stack, correlation="Pearson"):
+ img_stack_ = img_stack
+ a, b, c = np.shape(img_stack_)
+ norm_img_stack = normalize(img_stack_)
+ f = np.reshape(norm_img_stack, (a, (b * c)))
+
+ max_x, max_y = np.where(norm_img_stack.sum(0) == (norm_img_stack.sum(0)).max())
+ ref = norm_img_stack[:, int(max_x), int(max_y)]
+ corr = np.zeros(len(f.T))
+ for s in range(len(f.T)):
+ if correlation == "Kendall":
+ r, p = stats.kendalltau(ref, f.T[s])
+ elif correlation == "Pearson":
+ r, p = stats.pearsonr(ref, f.T[s])
+
+ corr[s] = r
+
+ cluster_image = np.reshape(corr, (b, c))
+ return (cluster_image ** 3), img_stack_
+
+
+def correlation_kmeans(img_stack, n_clusters, correlation="Pearson"):
+ img, bg_image = classify(img_stack, correlation)
+ img[np.isnan(img)] = -99999
+ X = img.reshape((-1, 1))
+ k_means = sc.KMeans(n_clusters)
+ k_means.fit(X)
+
+ X_cluster = k_means.labels_
+ X_cluster = X_cluster.reshape(img.shape) + 1
+
+ return X_cluster
+
+
+def cluster_stack(
+ im_array, method="KMeans", n_clusters_=4, decomposed=False, decompose_method="PCA", decompose_comp=2
+):
+ a, b, c = im_array.shape
+
+ if method == "Correlation-Kmeans":
+
+ X_cluster = correlation_kmeans(im_array, n_clusters_, correlation="Pearson")
+
+ else:
+
+ methods = {
+ "MiniBatchKMeans": sc.MiniBatchKMeans,
+ "KMeans": sc.KMeans,
+ "MeanShift": sc.MeanShift,
+ "Spectral Clustering": sc.SpectralClustering,
+ "Affinity Propagation": sc.AffinityPropagation,
+ }
+
+ if decomposed:
+ im_array = denoise_with_decomposition(im_array, method_=decompose_method, n_components=decompose_comp)
+
+ flat_array = np.reshape(im_array, (a, (b * c)))
+ init_cluster = methods[method](n_clusters=n_clusters_)
+ init_cluster.fit(np.transpose(flat_array))
+ X_cluster = init_cluster.labels_.reshape(b, c) + 1
+
+ decon_spectra = np.zeros((a, n_clusters_))
+ decon_images = np.zeros((n_clusters_, b, c))
+
+ for i in range(n_clusters_):
+ mask_i = np.where(X_cluster == (i + 1), X_cluster, 0)
+ spec_i = get_sum_spectra(im_array * mask_i)
+ decon_spectra[:, i] = spec_i
+ decon_images[i] = im_array.sum(0) * mask_i
+
+ return decon_images, X_cluster, decon_spectra
+
+def kmeans_variance(im_array):
+ a, b, c = im_array.shape
+ flat_array = np.reshape(im_array, (a, (b * c)))
+ var = np.arange(24)
+ clust_n = np.arange(24) + 2
+
+ for clust in var:
+ init_cluster = sc.KMeans(n_clusters=int(clust + 2))
+ init_cluster.fit(np.transpose(flat_array))
+ var_ = init_cluster.inertia_
+ var[clust] = np.float64(var_)
+
+ return clust_n, var
+
+
+def pca_scree(im_stack):
+ new_image = im_stack.transpose(2, 1, 0)
+ x, y, z = np.shape(new_image)
+ img_ = np.reshape(new_image, (x * y, z))
+ # pca = sd.PCA(z)
+ # pca.fit(img_)
+ pca = sd.TruncatedSVD(z - 1)
+ pca.fit(img_)
+ var = pca.singular_values_
+ # var = pca.singular_values_
+ return var
+
+
+def decompose_stack(im_stack, decompose_method="PCA", n_components_=3):
+ new_image = im_stack.transpose(2, 1, 0)
+ new_image[new_image<0] = 0
+
+ x, y, z = np.shape(new_image)
+ img_ = np.reshape(new_image, (x * y, z))
+ methods_dict = {
+ "PCA": sd.PCA,
+ "IncrementalPCA": sd.IncrementalPCA,
+ "NMF": sd.NMF,
+ "FastICA": sd.FastICA,
+ "DictionaryLearning": sd.MiniBatchDictionaryLearning,
+ "FactorAnalysis": sd.FactorAnalysis,
+ "TruncatedSVD": sd.TruncatedSVD,
+ }
+
+ _mdl = methods_dict[decompose_method](n_components=n_components_)
+
+ ims = (_mdl.fit_transform(img_).reshape(x, y, n_components_)).transpose(2, 1, 0)
+ spcs = _mdl.components_.transpose()
+ decon_spetra = np.zeros((z, n_components_))
+ decom_map = np.zeros((ims.shape))
+
+ for i in range(n_components_):
+ f = ims.copy()[i]
+ f[f < 0] = 0
+ f = np.where(f > 3 * np.std(f), f, 0)
+ spec_i = ((new_image.T * f).sum(1)).sum(1)
+ decon_spetra[:, i] = spec_i
+
+ f[f > 0] = i + 1
+ decom_map[i] = f
+ decom_map = decom_map.sum(0)
+
+ return np.float32(ims), spcs, decon_spetra, decom_map
+
+
+def denoise_with_decomposition(img_stack, method_="PCA", n_components=4):
+ new_image = img_stack.transpose(2, 1, 0)
+ x, y, z = np.shape(new_image)
+ img_ = np.reshape(new_image, (x * y, z))
+
+ methods_dict = {
+ "PCA": sd.PCA,
+ "IncrementalPCA": sd.IncrementalPCA,
+ "NMF": sd.NMF,
+ "FastICA": sd.FastICA,
+ "DictionaryLearning": sd.DictionaryLearning,
+ "FactorAnalysis": sd.FactorAnalysis,
+ "TruncatedSVD": sd.TruncatedSVD,
+ }
+
+ decomposed = methods_dict[method_](n_components=n_components)
+
+ ims = (decomposed.fit_transform(img_).reshape(x, y, n_components)).transpose(2, 1, 0)
+ ims[ims < 0] = 0
+ ims[ims > 0] = 1
+ mask = ims.sum(0)
+ mask[mask > 1] = 1
+ # mask = uniform_filter(mask)
+ filtered = img_stack * mask
+ # plt.figure()
+ # plt.imshow(filtered.sum(0))
+ # plt.title('background removed')
+ # plt.show()
+ return remove_nan_inf(filtered)
+
+
+def interploate_E(refs, e):
+ n = np.shape(refs)[1]
+ refs = np.array(refs)
+ ref_e = refs[:, 0]
+ ref = refs[:, 1:n]
+ all_ref = []
+ for i in range(n - 1):
+ ref_i = np.interp(e, ref_e, ref[:, i])
+ all_ref.append(ref_i)
+ return np.array(all_ref)
+
+
+def getStats(spec, fit, num_refs=2):
+ stats = {}
+
+ r_factor = (np.sum(spec - fit) ** 2) / np.sum(spec ** 2)
+ stats["R_Factor"] = np.around(r_factor, 5)
+
+ y_mean = np.sum(spec) / len(spec)
+ SS_tot = np.sum((spec - y_mean) ** 2)
+ SS_res = np.sum((spec - fit) ** 2)
+ r_square = 1 - (SS_res / SS_tot)
+ stats["R_Square"] = np.around(r_square, 4)
+
+ # https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.chisquare.html
+ # https://en.wikipedia.org/wiki/Chi-squared_distribution
+ # https://ned.ipac.caltech.edu/level5/Leo/Stats2_4.html
+ chisq = np.sum(((spec - fit) ** 2) / np.var(spec))
+ # chisq = np.sum((spec - fit) ** 2)
+ stats["Chi_Square"] = np.around(chisq, 5)
+
+ red_chisq = chisq / (len(spec) - num_refs)
+ stats["Reduced Chi_Square"] = np.around(red_chisq, 5)
+
+ return stats
+
+
+def xanes_fitting_1D(spec, e_list, refs, method="NNLS", alphaForLM=0.01):
+ """Linear combination fit of image data with reference standards"""
+
+ int_refs = interploate_E(refs, e_list)
+
+ if method == "NNLS":
+ coeffs, r = opt.nnls(int_refs.T, spec)
+
+ elif method == "LASSO":
+ lasso = linear_model.Lasso(positive=True, alpha=alphaForLM) # lowering alpha helps with 1D fits
+ fit_results = lasso.fit(int_refs.T, spec)
+ coeffs = fit_results.coef_
+
+ elif method == "RIDGE":
+ ridge = linear_model.Ridge(alpha=alphaForLM)
+ fit_results = ridge.fit(int_refs.T, spec)
+ coeffs = fit_results.coef_
+
+ fit = coeffs @ int_refs
+ stats = getStats(spec, fit, num_refs=np.min(np.shape(int_refs.T)))
+
+ return stats, np.around(coeffs, 4)
+
+
+def xanes_fitting(im_stack, e_list, refs, method="NNLS", alphaForLM=0.1, binStack=False):
+ """Linear combination fit of image data with reference standards"""
+
+ if binStack:
+ im_stack = resize_stack(im_stack, scaling_factor=4)
+
+ en, im1, im2 = np.shape(im_stack)
+ im_array = im_stack.reshape(en, im1 * im2)
+ coeffs_arr = []
+ r_factor_arr = []
+ lasso = linear_model.Lasso(positive=True, alpha=alphaForLM)
+ for n, i in enumerate(range(im1 * im2)):
+ stats, coeffs = xanes_fitting_1D(im_array[:, i], e_list, refs, method=method, alphaForLM=alphaForLM)
+ coeffs_arr.append(coeffs)
+ r_factor_arr.append(stats["R_Factor"])
+
+ abundance_map = np.reshape(coeffs_arr, (im1, im2, -1))
+ r_factor_im = np.reshape(r_factor_arr, (im1, im2))
+
+ return abundance_map, r_factor_im, np.mean(coeffs_arr, axis=0)
+
+
+def xanes_fitting_Line(im_stack, e_list, refs, method="NNLS", alphaForLM=0.05):
+ """Linear combination fit of image data with reference standards"""
+ en, im1, im2 = np.shape(im_stack)
+ im_array = np.mean(im_stack, 2)
+ coeffs_arr = []
+ meanStats = {"R_Factor": 0, "R_Square": 0, "Chi_Square": 0, "Reduced Chi_Square": 0}
+
+ for i in range(im1):
+ stats, coeffs = xanes_fitting_1D(im_array[:, i], e_list, refs, method=method, alphaForLM=alphaForLM)
+ coeffs_arr.append(coeffs)
+ for key in stats.keys():
+ meanStats[key] += stats[key]
+
+ for key, vals in meanStats.items():
+ meanStats[key] = np.around((vals / im1), 5)
+
+ return meanStats, np.mean(coeffs_arr, axis=0)
+
+
+def xanes_fitting_Binned(im_stack, e_list, refs, method="NNLS", alphaForLM=0.05):
+ """Linear combination fit of image data with reference standards"""
+
+ im_stack = resize_stack(im_stack, scaling_factor=10)
+ # use a simple filter to find threshold value
+ val = filters.threshold_otsu(im_stack[-1])
+ en, im1, im2 = np.shape(im_stack)
+ im_array = im_stack.reshape(en, im1 * im2)
+ coeffs_arr = []
+ meanStats = {"R_Factor": 0, "R_Square": 0, "Chi_Square": 0, "Reduced Chi_Square": 0}
+
+ specs_fitted = 0
+ total_spec = im1 * im2
+ for i in range(total_spec):
+ spec = im_array[:, i]
+ # do not fit low intensity/background regions
+ if spec[-1] > val:
+ specs_fitted += 1
+ stats, coeffs = xanes_fitting_1D(spec / spec[-1], e_list, refs, method=method, alphaForLM=alphaForLM)
+ coeffs_arr.append(coeffs)
+ for key in stats.keys():
+ meanStats[key] += stats[key]
+ else:
+ pass
+
+ for key, vals in meanStats.items():
+ meanStats[key] = np.around((vals / specs_fitted), 6)
+ # print(f"{specs_fitted}/{total_spec}")
+ return meanStats, np.mean(coeffs_arr, axis=0)
+
+
+def create_df_from_nor(athenafile="fe_refs.nor"):
+ """create pandas dataframe from athena nor file, first column
+ is energy and headers are sample names"""
+
+ refs = np.loadtxt(athenafile)
+ n_refs = refs.shape[-1]
+ skip_raw_n = n_refs + 6
+
+ df = pd.read_table(
+ athenafile, delim_whitespace=True, skiprows=skip_raw_n, header=None, usecols=np.arange(0, n_refs)
+ )
+ df2 = pd.read_table(
+ athenafile, delim_whitespace=True, skiprows=skip_raw_n - 1, usecols=np.arange(0, n_refs + 1)
+ )
+ new_col = df2.columns.drop("#")
+ df.columns = new_col
+ return df, list(new_col)
+
+
+def create_df_from_nor_try2(athenafile="fe_refs.nor"):
+ """create pandas dataframe from athena nor file, first column
+ is energy and headers are sample names"""
+
+ refs = np.loadtxt(athenafile)
+ n_refs = refs.shape[-1]
+ df_refs = pd.DataFrame(refs)
+
+ df = pd.read_csv(athenafile, header=None)
+ new_col = list((str(df.iloc[n_refs + 5].values)).split(" ")[2::2])
+ df_refs.columns = new_col
+
+ return df_refs, list(new_col)
+
+
+def energy_from_logfile(logfile="maps_log_tiff.txt"):
+ df = pd.read_csv(logfile, header=None, delim_whitespace=True, skiprows=9)
+ return df[9][df[7] == "energy"].values.astype(float)
+
+
+def xanesNormalization(e, mu, e0=7125, step=None,
+ nnorm=2, nvict=0, pre1=None, pre2=-50,
+ norm1=100, norm2=None, method="pre_edge",
+ useFlattened=False, Elemline = "Fe_K"):
+
+ elem, line = Elemline.split('_')
+ elemZ = xraydb.atomic_number(elem)
+ dat = Group(name='larchgroup', col1=e, col2=mu)
+
+
+ if method == "guess":
+ result = preedge(e, mu, e0, step=step, nnorm=nnorm, nvict=nvict)
+
+ return result["pre1"], result["pre2"], result["norm1"], result["norm2"]
+
+ elif method == "mback":
+ mback(e,mu, group=dat, z=elemZ, edge=line, e0=e0,fit_erfc=False)
+ return dat.f2, dat.fpp
+
+ else:
+ pre_edge(e, mu,group=dat,e0=e0, step=step, nnorm=nnorm,nvict=nvict, pre1=pre1,
+ pre2=pre2, norm1=norm1,norm2=norm2, make_flat = True)
+
+ if useFlattened:
+ normSpec = dat.flat
+ else:
+ normSpec = dat.norm
+
+ return dat.pre_edge, dat.post_edge, normSpec
+
+
+def xanesNormStack(e_list, im_stack, e0=7125, step=None,
+ nnorm=2, nvict=0, pre1=None, pre2=-50,
+ norm1=100, norm2=None, useFlattened=False, ignorePostEdgeNorm=False):
+ en, im1, im2 = np.shape(im_stack)
+ im_array = im_stack.reshape(en, im1 * im2)
+ normedStackArray = np.zeros_like(im_array)
+ dat = Group(name='larchgroup', col1=e_list, col2=get_mean_spectra(im_stack))
+
+
+ for i in range(im1 * im2):
+ pre_edge(e_list, im_array[:, i], e0=e0, group=dat, step=step, nnorm=nnorm,
+ nvict=nvict, pre1=pre1, pre2=pre2, norm1=norm1, norm2=norm2,make_flat = True)
+
+ if useFlattened:
+ normSpec = dat.flat
+ else:
+ normSpec = dat.norm
+
+ if ignorePostEdgeNorm:
+ normedStackArray[:, i] = normSpec * dat.post_edge
+ else:
+ normedStackArray[:, i] = normSpec
+
+ return remove_nan_inf(np.reshape(normedStackArray, (en, im1, im2)))
+
+def getDeconvolutedXANESSpectrum(xanesStack, chemMapStack, energy, clusterSigma=1):
+ compXanesSpetraAll = pd.DataFrame()
+ compXanesSpetraAll['Energy'] = energy
+
+ for n, compImage in enumerate(chemMapStack):
+ mask = np.where(compImage > clusterSigma * np.std(compImage), compImage, 0)
+ compXanesSpetraAll[f'Component_{n + 1}'] = get_mean_spectra(xanesStack * mask)
+ return compXanesSpetraAll
+
+
+def align_stack(
+ stack_img, ref_image_void=True, ref_stack=None, transformation=StackReg.TRANSLATION, reference="previous"
+):
+
+ """Image registration flow using pystack reg"""
+
+ # all the options are in one function
+
+ sr = StackReg(transformation)
+
+ if ref_image_void:
+ tmats_ = sr.register_stack(stack_img, reference=reference)
+
+ else:
+ tmats_ = sr.register_stack(ref_stack, reference=reference)
+ out_ref = sr.transform_stack(ref_stack)
+
+ out_stk = sr.transform_stack(stack_img, tmats=tmats_)
+ return np.float32(out_stk), tmats_
+
+
+def align_simple(stack_img, transformation=StackReg.TRANSLATION, reference="previous"):
+
+ sr = StackReg(transformation)
+ tmats_ = sr.register_stack(stack_img, reference="previous")
+ for i in range(10):
+ out_stk = sr.transform_stack(stack_img, tmats=tmats_)
+ return np.float32(out_stk)
+
+
+def align_with_tmat(stack_img, tmat_file, transformation=StackReg.TRANSLATION):
+
+ sr = StackReg(transformation)
+ out_stk = sr.transform_stack(stack_img, tmats=tmat_file)
+ return np.float32(out_stk)
+
+
+def align_stack_iter(
+ stack,
+ ref_stack_void=True,
+ ref_stack=None,
+ transformation=StackReg.TRANSLATION,
+ method=("previous", "first"),
+ max_iter=2,
+):
+ if ref_stack_void:
+ ref_stack = stack
+
+ for i in range(max_iter):
+ sr = StackReg(transformation)
+ for ii in range(len(method)):
+ print(ii, method[ii])
+ tmats = sr.register_stack(ref_stack, reference=method[ii])
+ ref_stack = sr.transform_stack(ref_stack)
+ stack = sr.transform_stack(stack, tmats=tmats)
+
+ return np.float32(stack)
+
+
+def applyMaskGetMeanSpectrum(im_stack, mask):
+ """A 2d mask to multiply with the 3d xanes stack and returns mean spectrum"""
+
+ masked_stack = im_stack * mask
+ return get_mean_spectra(masked_stack)
+
+
+def modifyStack(
+ raw_stack,
+ normalizeStack=False,
+ normToPoint=-1,
+ applySmooth=False,
+ smoothWindowSize=3,
+ applyThreshold=False,
+ thresholdValue=0,
+ removeOutliers=False,
+ nSigmaOutlier=3,
+ applyTranspose=False,
+ transposeVals=(0, 1, 2),
+ applyCrop=False,
+ cropVals=(0, 1, 2),
+ removeEdges=False,
+ resizeStack=False,
+ upScaling=False,
+ binFactor=2,
+):
+
+ """A giant function to modify the stack with many possible operations.
+ all the changes can be saved to a jason file as a config file. Enabling and
+ distabling the sliders is a problem"""
+
+ """
+ normStack = normalize(raw_stack, norm_point=normToPoint)
+ smoothStack = smoothen(raw_stack, w_size= smoothWindowSize)
+ thresholdStack = clean_stack(raw_stack, auto_bg=False, bg_percentage = thresholdValue)
+ outlierStack = remove_hot_pixels(raw_stack, NSigma=nSigmaOutlier)
+ transposeStack = np.transpose(raw_stack, transposeVals)
+ croppedStack = raw_stack[cropVals]
+ edgeStack = remove_edges(raw_stack)
+ binnedStack = resize_stack(raw_stack,upscaling=upScaling,scaling_factor=binFactor)
+
+ """
+
+ if removeOutliers:
+ modStack = remove_hot_pixels(raw_stack, NSigma=nSigmaOutlier)
+
+ else:
+ modStack = raw_stack
+
+ if applyThreshold:
+ modStack = clean_stack(modStack, auto_bg=False, bg_percentage=thresholdValue)
+
+ else:
+ pass
+
+ if applySmooth:
+ modStack = smoothen(modStack, w_size=smoothWindowSize)
+
+ else:
+ pass
+
+ if applyTranspose:
+ modStack = np.transpose(modStack, transposeVals)
+
+ else:
+ pass
+
+ if applyCrop:
+ modStack = modStack[cropVals]
+
+ else:
+ pass
+
+ if normalizeStack:
+ modStack = normalize(raw_stack, norm_point=normToPoint)
+ else:
+ pass