diff --git a/Cleopatra/ExWindow.py b/Cleopatra/ExWindow.py index fa849b3..632266c 100644 --- a/Cleopatra/ExWindow.py +++ b/Cleopatra/ExWindow.py @@ -19,7 +19,8 @@ class ExWindow(QWidget): super().__init__() self.setWindowTitle("Ex Plot") - self.setGeometry(100, 100, 400, 800) + # self.setGeometry(100, 100, 400, 800) + self.resize(400, 800) self.ASym = "" self.maxEx = 0 diff --git a/Cleopatra/FitExData.py b/Cleopatra/FitExData.py index b6bdee3..439610e 100644 --- a/Cleopatra/FitExData.py +++ b/Cleopatra/FitExData.py @@ -2,11 +2,35 @@ import numpy as np from scipy.optimize import curve_fit + +from PyQt6.QtWidgets import ( + QVBoxLayout, QWidget +) + import matplotlib.pyplot as plt +from matplotlib.backends.backend_qtagg import NavigationToolbar2QT as NavigationToolbar +from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas from ExtractXsecPy import read_DWBA -class Fitting: +class FitPlotWidget(QWidget): + def __init__(self, figure): + super().__init__() + + self.setWindowTitle("Fit Plot") + self.resize(800, 600) + + self.canvas = FigureCanvas(figure) + self.toolbar = NavigationToolbar(self.canvas, self) + + layout = QVBoxLayout(self) + layout.addWidget(self.toolbar) + layout.addWidget(self.canvas) + + self.setLayout(layout) + + +class Fitting(): def __init__(self): self.ExList = [] @@ -37,7 +61,7 @@ class Fitting: continue # Check for excitation energy lines - if line.startswith("#======================"): + if line.startswith("#="): # If there's an existing data block, save it if current_data: self.expData.append(np.array(current_data, dtype=float)) @@ -77,12 +101,12 @@ class Fitting: def FitData(self): - # Set initial offset values - x_offset, y_offset = 2000, 100 - - figure = [] + figure_list = [] for expDataID in range(len(self.expData)): + + print("============================================") + # Get the number of fit options and cross-sections nFit = len(self.fitOption[expDataID]) nXsec = len(self.data) @@ -97,6 +121,8 @@ class Fitting: fitTheory_lower = [] fitTheory_upper = [] + chi_squared = [] + for k in range(nFit): # Get the cross-section IDs for the current fit option and strip extra spaces xsecIDStr = self.fitOption[expDataID][k].strip() @@ -129,7 +155,14 @@ class Fitting: bounds=(lower_bounds, upper_bounds)) perr = np.sqrt(np.diag(pcov)) # Standard deviation of the parameters - print(f"Fitted scale for fit {k+1}: {popt} +/- {perr}") + + # Get the fitted model values + y_fit = fit_func(x_exp, *popt) + residuals = y_exp - y_fit + chi_squared.append(np.sum((residuals / y_err) ** 2)) + + print(f"Fitted scale for fit {k}: {', '.join([f'{x:.3f}' for x in popt])} +/- {', '.join([f'{x:.3f}' for x in perr])} | Chi^2 : {chi_squared[-1]:.4f}") + # print(f"Fitted scale for fit {k}: {popt} +/- {perr} | Chi^2 : {chi_squared[-1]:.4f}") # Append the theoretical fit for this fit option fitTheory.append(np.zeros_like(self.dataX)) @@ -146,14 +179,14 @@ class Fitting: fitTheory_lower[k] += (popt[p] - perr[p]) * np.interp(self.dataX, self.dataX, self.data[id]) fig = plt.figure() - figure.append(fig) + figure_list.append(fig) # Plot results - plt.errorbar(x_exp, y_exp, xerr=x_err, yerr=y_err, fmt='o', label='Experimental Data', color='blue') + plt.errorbar(x_exp, y_exp, xerr=x_err, yerr=y_err, fmt='x', label='Experimental Data', color='black', markersize = 15, elinewidth=2) # Plot all fit theories for i, fit in enumerate(fitTheory): - plt.plot(self.dataX, fit, label=f'Xsec:{self.fitOption[expDataID][i]} Fit') + plt.plot(self.dataX, fit, label=f'Chi2:{chi_squared[i]:.3f} | Xsec:{self.fitOption[expDataID][i]} Fit') plt.fill_between(self.dataX, fitTheory_lower[i], fitTheory_upper[i], alpha=0.2) # Customize plot @@ -168,11 +201,6 @@ class Fitting: plt.text(0.05, 0.05, f'Fit for Exp Data : {self.ExList[expDataID]} MeV', transform=plt.gca().transAxes, fontsize=12, verticalalignment='bottom', horizontalalignment='left', color='black') - manager = plt.get_current_fig_manager() - # manager.window.wm_geometry(f"+{x_offset}+{y_offset}") - manager.set_window_title(f"Exp Data : {self.ExList[expDataID]} MeV") - - x_offset += 100 - y_offset += 100 - plt.show() \ No newline at end of file + + return figure_list \ No newline at end of file diff --git a/Cleopatra/MatPlotLibWindow.py b/Cleopatra/MatPlotLibWindow.py index 3e5662d..8eb1376 100644 --- a/Cleopatra/MatPlotLibWindow.py +++ b/Cleopatra/MatPlotLibWindow.py @@ -18,7 +18,7 @@ class MatPlotLibWindow(QWidget): super().__init__() self.setWindowTitle("DWBA Plot") - self.setGeometry(100, 100, 800, 600) + self.resize(800, 600) self.x = [] self.data = [] diff --git a/PyGUIQt6/PtolemyGUIPy.py b/PyGUIQt6/PtolemyGUIPy.py index f31851c..db327a7 100755 --- a/PyGUIQt6/PtolemyGUIPy.py +++ b/PyGUIQt6/PtolemyGUIPy.py @@ -17,7 +17,7 @@ from CustomTextEdit import CustomTextEdit from ExtractXsecPy import extract_xsec from ExWindow import ExWindow from MatPlotLibWindow import MatPlotLibWindow -from FitExData import Fitting +from FitExData import Fitting, FitPlotWidget ################################################## MainWindow class MyWindow(QMainWindow): @@ -25,7 +25,7 @@ class MyWindow(QMainWindow): super().__init__() self.setWindowTitle("Ptolemy GUI") - self.setGeometry(100, 100, 1000, 800) + self.resize(1000, 800) self.setMinimumSize(1000, 800) self.lastDWBARecord = "lastDWBA.txt" @@ -36,6 +36,7 @@ class MyWindow(QMainWindow): self.plot_window = MatPlotLibWindow() self.Ex_window = ExWindow() self.fitting = Fitting() + self.fitCanvas = [] # Set up Group Box for DWBA Control self.gbDWBA = QGroupBox("DWBA") @@ -192,6 +193,7 @@ class MyWindow(QMainWindow): self.LoadFileToTextBox(self.DWBAFileName, True) + self.bnSaveFile.setEnabled(True) self.bnSaveExpDataFile.setEnabled(False) # Set up the layout @@ -249,6 +251,7 @@ class MyWindow(QMainWindow): self.LoadFileToTextBox(self.DWBAFileName) self.SaveLastOpenDWBASource() self.bnSaveExpDataFile.setEnabled(False) + self.bnSaveFile.setEnabled(True) def OpenExpDataFile(self): file_path, _ = QFileDialog.getOpenFileName(self, "Open File", "", "Text File (*.txt)") @@ -257,13 +260,19 @@ class MyWindow(QMainWindow): self.leExpDataFileName.setText(self.ExpDataFileName) self.LoadFileToTextBox(self.ExpDataFileName) self.bnSaveExpDataFile.setEnabled(True) + self.bnSaveFile.setEnabled(False) self.SaveLastOpenDWBASource() def LoadExpDataToTextBox(self): self.LoadFileToTextBox(self.ExpDataFileName) + self.leFileName.setText(self.DWBAFileName) self.bnSaveExpDataFile.setEnabled(True) + self.bnSaveFile.setEnabled(False) + + def LoadFileToTextBox(self, fileName, moveToButton = False): + self.bnSaveExpDataFile.setEnabled(False) + self.bnSaveFile.setEnabled(True) - def LoadFileToTextBox(self, fileName, moveToButton = False): # print(fileName) try: with open(fileName, 'r') as file: @@ -281,19 +290,19 @@ class MyWindow(QMainWindow): self.text_edit.setText(f"Failed to load file:\n{e}") self.leStatus.setText(f"Failed to load file:\n{e}") - self.bnSaveExpDataFile.setEnabled(False) - def SaveFile(self): - file_path = self.leFileName.text() - with open(file_path, 'w') as file: - file.write(self.text_edit.toPlainText()) - self.leStatus.setText(f"File saved to: {file_path}") + if self.bnSaveFile.isEnabled() : + file_path = self.leFileName.text() + with open(file_path, 'w') as file: + file.write(self.text_edit.toPlainText()) + self.leStatus.setText(f"File saved to: {file_path}") def SaveExpDataFile(self): - file_path = self.leExpDataFileName.text() - with open(file_path, 'w') as file: - file.write(self.text_edit.toPlainText()) - self.leStatus.setText(f"File saved to: {file_path}") + if self.bnSaveExpDataFile.isEnabled() : + file_path = self.leExpDataFileName.text() + with open(file_path, 'w') as file: + file.write(self.text_edit.toPlainText()) + self.leStatus.setText(f"File saved to: {file_path}") def DeleteinOutXsecFiles(self): if os.path.exists(self.DWBAFileName + ".in"): @@ -365,9 +374,17 @@ class MyWindow(QMainWindow): self.Ex_window.show() def fitData(self): + self.SaveExpDataFile() + + self.fitCanvas = [] self.fitting.read_expData(self.ExpDataFileName) self.fitting.read_data(self.DWBAFileName + ".Xsec.txt") - self.fitting.FitData() + figures = self.fitting.FitData() + + if figures: + for p, fig in enumerate(figures): + self.fitCanvas.append(FitPlotWidget(fig)) + self.fitCanvas[-1].show() def closeEvent(self, event): if self.plot_window: @@ -375,6 +392,9 @@ class MyWindow(QMainWindow): if self.Ex_window: self.Ex_window.close() # Close the PlotWindow when MainWindow closes self.Ex_window.__del__() + if self.fitCanvas : + for x in self.fitCanvas: + x.close() print("============== Bye Bye ========== ") event.accept() # Accept the event to proceed with closing the main window