-
Notifications
You must be signed in to change notification settings - Fork 1
Arpes gui #35
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Arpes gui #35
Changes from all commits
2348e34
7a33a6a
d175e85
38cc77c
edecfcf
263c72b
82bac6e
c690b4a
e993b0e
c8d6497
ab5c98a
e32c1f5
35a867c
f66ca06
4eef8dd
2bc5265
b936f05
381f9ca
f5db38b
c688ac1
f29c452
9a5f4cd
8dea3c8
ece7604
c87fc1b
495a09d
9c8b12b
c9b8079
2f8da32
37a577d
e6995de
60a85a3
15c8af7
14306e8
08120d6
72a07a5
eee3402
f955c1c
5818cb7
7227446
3e31a22
4c28ff3
40b509a
9607b6b
d483815
e26036c
22a458b
ed8027b
a47bb54
9d7c1e2
4e35ccf
0430aff
5df5e41
2a7e0c3
917bd76
572a4df
70d4d9f
96d888b
936dee1
762f71f
8ff652e
7f76735
7aadfd6
3258102
a019a5e
1629809
18cfc9a
8c6c7f8
657b3ad
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| ARPES | ||
| cmap | ||
| codemirror | ||
| ipython | ||
| kernelspec | ||
| matplotlib | ||
| mpes | ||
| nbconvert | ||
| nbformat | ||
| numpy | ||
| nxarray | ||
| pygments | ||
| pyplot | ||
| venv |
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,114 @@ | ||
| import sys | ||
| from PyQt5.QtWidgets import QApplication, QMainWindow, QVBoxLayout, QWidget, QAction, QFileDialog, QSlider, QGridLayout,QHBoxLayout, QSizePolicy,QLabel, QGridLayout, QPushButton, QFileDialog | ||
| from PyQt5.QtCore import Qt | ||
| from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas | ||
| import matplotlib.pyplot as plt | ||
| import numpy as np | ||
| import h5py | ||
| from mpes_tools.Gui_3d import Gui_3d | ||
| import xarray as xr | ||
| from mpes_tools.hdf5 import load_h5 | ||
| from mpes_tools.show_4d_window import show_4d_window | ||
| import os | ||
| from PyQt5.QtGui import QPixmap | ||
| import nxarray | ||
|
|
||
| class ARPES_Analyser(QMainWindow): | ||
| def __init__(self): | ||
| super().__init__() | ||
|
|
||
| self.setWindowTitle("ARPES_Analyser") | ||
| self.setGeometry(100, 100, 400, 300) | ||
|
|
||
| # Central widget and main layout | ||
| central_widget = QWidget() | ||
| self.setCentralWidget(central_widget) | ||
| layout = QGridLayout() | ||
| central_widget.setLayout(layout) | ||
| N=256 | ||
|
|
||
| # Get the directory of the current script | ||
| base_path = os.path.dirname(os.path.abspath(__file__)) | ||
|
|
||
| # Build full path to image files in the same folder | ||
| image1_path = os.path.join(base_path, "METIS.png") | ||
| image2_path = os.path.join(base_path, "Phoibos.png") | ||
|
|
||
| # --- First Button + Image --- | ||
| vbox1 = QVBoxLayout() | ||
| label_img1 = QLabel() | ||
| pixmap1 = QPixmap(image1_path) # 🔁 Replace with your image path | ||
| label_img1.setPixmap(pixmap1.scaled(N, N, Qt.KeepAspectRatio, Qt.SmoothTransformation)) | ||
| label_img1.setAlignment(Qt.AlignCenter) | ||
|
|
||
| self.btn_open_h5 = QPushButton("Open File H5") | ||
| self.btn_open_h5.clicked.connect(self.open_file_dialoge) | ||
|
|
||
| vbox1.addWidget(label_img1) | ||
| vbox1.addWidget(self.btn_open_h5) | ||
|
|
||
| # --- Second Button + Image --- | ||
| vbox2 = QVBoxLayout() | ||
| label_img2 = QLabel() | ||
| pixmap2 = QPixmap(image2_path) # 🔁 Replace with your image path | ||
| label_img2.setPixmap(pixmap2.scaled(N, N, Qt.KeepAspectRatio, Qt.SmoothTransformation)) | ||
| label_img2.setAlignment(Qt.AlignCenter) | ||
|
|
||
| self.btn_open_phoibos = QPushButton("Open File Phoibos") | ||
| self.btn_open_phoibos.clicked.connect(self.open_file_phoibos) | ||
|
|
||
| vbox2.addWidget(label_img2) | ||
| vbox2.addWidget(self.btn_open_phoibos) | ||
|
|
||
| # Add the vbox layouts to the main grid layout | ||
| layout.addLayout(vbox1, 0, 0) | ||
| layout.addLayout(vbox2, 0, 1) | ||
|
|
||
| self.graph_windows = [] | ||
| self.ce = None | ||
|
|
||
| self.show() | ||
|
|
||
|
|
||
|
|
||
| def open_file_phoibos(self): | ||
| # ... existing code ... | ||
| file_path, _ = QFileDialog.getOpenFileName(self, "Open File", "", "Data Files (*.npz *.nxs)") | ||
| if file_path: | ||
| if file_path.endswith('.npz'): | ||
| loaded_data = np.load(file_path) | ||
| V1 = xr.DataArray(loaded_data['data_array'], | ||
| dims=['Angle', 'Ekin','delay'], | ||
| coords={'Angle': loaded_data['Angle'], | ||
| 'Ekin': loaded_data['Ekin'], | ||
| 'delay': loaded_data['delay']}) | ||
| elif file_path.endswith('.nxs'): | ||
| V1=nxarray.load(file_path) | ||
| V1=V1.rename({'angular0':'Angle','energy':'Ekin','delay':'delay'}) | ||
| V1=V1[list(V1.data_vars)[0]] | ||
|
|
||
| axis=[V1['Angle'],V1['Ekin']-21.7,V1['delay']] | ||
| V1 = V1.assign_coords(Ekin=V1.coords['Ekin'] -21.7) | ||
| graph_window= Gui_3d(V1) | ||
| graph_window.show() | ||
| self.graph_windows.append(graph_window) | ||
|
|
||
| def open_file_dialoge(self): | ||
| # Open file dialog to select a .h5 file | ||
| file_path, _ = QFileDialog.getOpenFileName(self, "Open hdf5", "", "h5 Files (*.h5)") | ||
| print(file_path) | ||
| if file_path: | ||
| data_array = load_h5(file_path) | ||
| graph_4d = show_4d_window(data_array) | ||
| graph_4d.show() | ||
| self.graph_windows.append(graph_4d) | ||
| # self.load_data(data_array) | ||
|
|
||
|
|
||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| app = QApplication(sys.argv) | ||
| window = ARPES_Analyser() | ||
| window.show() | ||
| sys.exit(app.exec_()) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,7 +1,10 @@ | ||
| """mpes-tools module easy access APIs.""" | ||
| import importlib.metadata | ||
|
|
||
| from mpes_tools.show_4d_window import MainWindow | ||
| from mpes_tools.fit_panel import fit_panel | ||
| from mpes_tools.Gui_3d import Gui_3d | ||
| from mpes_tools.Main import ARPES_Analyser | ||
| from mpes_tools.show_4d_window import show_4d_window | ||
|
|
||
| __version__ = importlib.metadata.version("mpes-tools") | ||
| __all__ = ["MainWindow"] | ||
| __all__ = ["show_4d_window", "Gui_3d", "fit_panel", "ARPES_Analyser"] |
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,80 @@ | ||
| from PyQt5.QtWidgets import QApplication, QMainWindow, QVBoxLayout, QWidget, QLabel,QHBoxLayout,QGridLayout | ||
| from superqt import QRangeSlider | ||
| from PyQt5.QtCore import Qt | ||
| import numpy as np | ||
| import matplotlib.pyplot as plt | ||
| from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas | ||
| import sys | ||
|
|
||
| class colorscale_slider(QWidget): | ||
| def __init__(self, layout, imshow_artist,canvas, limits=None): | ||
| super().__init__() | ||
| self.case=False | ||
| self.im = imshow_artist | ||
| self.canvas = canvas | ||
| self.colorbar = None # Optional: set this externally if you want to update a colorbar | ||
| if limits is None: | ||
| self.data = imshow_artist.get_array().data | ||
| self.vmin, self.vmax = float(np.min(self.data)), float(np.max(self.data)) | ||
| else: | ||
| self.vmin,self.vmax= limits | ||
| if self.vmin==self.vmax: | ||
| self.vmax += 0.1 | ||
| if self.vmax<10: | ||
| self.cmin, self.cmax = 10, 1e9 | ||
| self.case=True | ||
| else: | ||
| self.cmin, self.cmax=self.vmin,self.vmax | ||
| # Slider Widget | ||
| slider_widget = QWidget() | ||
| slider_layout = QVBoxLayout(slider_widget) | ||
|
|
||
| self.slider = QRangeSlider(Qt.Vertical) | ||
| self.slider.setFixedWidth(15) | ||
| self.slider.setMinimum(int(1 * self.cmin)) | ||
| self.slider.setMaximum(int(1.5* self.cmax)) | ||
| self.slider.setValue([float(self.vmin),float(self.vmax)]) | ||
| if self.case : | ||
| self.slider.setValue([self.new_values(self.vmin), self.new_values(self.vmax)]) | ||
|
Comment on lines
+37
to
+38
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't understand this. Please explain, and give meaningful variable names |
||
| self.slider.valueChanged.connect(lambda value: self.update_clim(value)) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why this lambda function, can't you use the function directly? |
||
|
|
||
| # self.vmin_label = QLabel(f"{self.vmin:.2e}") | ||
| # self.vmax_label = QLabel(f"{self.vmax:.2e}") | ||
| self.vmin_label = QLabel("") | ||
| self.vmax_label = QLabel("") | ||
| slider_layout.addWidget(self.vmax_label) | ||
| slider_layout.addWidget(self.slider) | ||
| slider_layout.addWidget(self.vmin_label) | ||
|
|
||
| # New horizontal layout: slider left, canvas right | ||
| h_container = QWidget() | ||
| h_layout = QHBoxLayout(h_container) | ||
| h_layout.addWidget(slider_widget) | ||
| h_layout.addWidget(self.canvas) | ||
| h_layout.addWidget(self.canvas, stretch=1) | ||
| if isinstance(layout, QGridLayout): | ||
| layout.addWidget(h_container,0,0) | ||
| else: | ||
| layout.insertWidget(0, h_container) | ||
|
|
||
|
|
||
| def new_values(self, x): | ||
| a = (self.cmax - self.cmin) / (self.vmax - self.vmin) | ||
| b = self.vmax * self.cmin - self.vmin * self.cmax | ||
| return int(a * x + b) | ||
|
|
||
| def inverse(self, x): | ||
| a = (self.cmax - self.cmin) / (self.vmax - self.vmin) | ||
| b = self.vmax * self.cmin - self.vmin * self.cmax | ||
| return (x - b) / a | ||
|
|
||
| def update_clim(self, value): | ||
| vmin, vmax = value | ||
| if self.case: | ||
| vmin, vmax = self.inverse(value[0]), self.inverse(value[1]) | ||
| self.im.set_clim(vmin, vmax) | ||
| # self.vmin_label.setText(f" {vmin:.2e}") | ||
| # self.vmax_label.setText(f"{vmax:.2e}") | ||
| if self.colorbar: | ||
| self.colorbar.update_normal(self.im) | ||
| self.canvas.draw_idle() | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| class Cursor_handler: | ||
| def __init__(self,fig,ax, artist, changes=None,parent=None): | ||
| self.artist=artist | ||
| self.active_cursor=None | ||
| self.changes=changes | ||
| self.parent = parent | ||
| self.ax=ax | ||
| self.fig=fig | ||
| self.fig.canvas.mpl_connect('pick_event', self.on_pick) | ||
| self.fig.canvas.mpl_connect('motion_notify_event', self.on_motion) | ||
| self.fig.canvas.mpl_connect('button_release_event', self.on_release) | ||
| def on_pick(self,event): # function to pick up the cursors or the dots | ||
| if event.artist == self.artist and self.parent.active_handler is None: | ||
| self.active_cursor = self.artist | ||
| self.parent.active_handler = self | ||
| def on_motion(self,event): # function to move the cursors or the dots | ||
| if self.active_cursor is not None and event.inaxes == self.ax: | ||
| if self.active_cursor == self.artist: | ||
| if self.artist.get_xdata()[0]==self.artist.get_xdata()[1]: | ||
| self.artist.set_xdata([event.xdata, event.xdata]) | ||
| self.changes() | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How does this work, if changes=None? |
||
| else : | ||
| self.artist.set_ydata([event.ydata, event.ydata]) | ||
| self.changes() | ||
| def on_release(self,event): | ||
| self.active_cursor = None | ||
| self.parent.active_handler = None | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| class Dot_handler: | ||
| def __init__(self,fig,ax, artist, changes=None): | ||
| self.artist=artist | ||
| self.active_cursor=None | ||
| self.changes=changes | ||
| self.ax=ax | ||
| self.fig=fig | ||
| self.fig.canvas.mpl_connect('pick_event', self.on_pick) | ||
| self.fig.canvas.mpl_connect('motion_notify_event', self.on_motion) | ||
| self.fig.canvas.mpl_connect('button_release_event', self.on_release) | ||
|
Comment on lines
+8
to
+10
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If you connect these handlers in each instance, this means you will have a lot of handlers connected to each event happening on the canvas. I am wondering if this might slow things down, compared to only one global handler per event type. |
||
| def on_pick(self,event): # function to pick up the cursors or the dots | ||
| if event.artist == self.artist: | ||
| self.active_cursor = self.artist | ||
| def on_motion(self,event): # function to move the cursors or the dots | ||
| if self.active_cursor is not None and event.inaxes == self.ax: | ||
| if self.active_cursor == self.artist: | ||
| self.artist.center= (event.xdata, event.ydata) | ||
| self.changes() | ||
| def on_release(self,event): | ||
| self.active_cursor = None | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this here? I don't understand this.