"""PhysPlot main application module.
This module implements the complete PhysPlot desktop GUI application:
table-based data entry/import, column transformations, plotting with
matplotlib, and optional curve fitting.
Input data structure:
The main table stores numeric data in a QTableWidget. Row 0 contains
column-role combo boxes; rows 1..N contain numeric data. Plot generation
reads that table into ``OutPut_Table`` as a two-dimensional NumPy array.
File loaders return the same rectangular 2D array structure.
Return type:
GUI classes do not return data directly. Plot windows render matplotlib
figures, transformation functions write values back into table columns,
and loaders/configuration helpers update global GUI state used by the
active plot.
Optional main/runtime behavior:
This module can be imported by ``physplot.runner`` or run directly. When
run directly it delegates to ``physplot.runner.run_app()``.
Original metadata:
- File name: PhysPlot.py
- Authors: Muhammad Shiraz Ahmad and Sabieh Anwar
- Date created: 8/20/2019
- Date last modified: 5/15/2026
- Script Version: 2.0.0
- Python Version: 3.7.3
"""
import webbrowser
import ast
import importlib.util
import sys
from pathlib import Path
import numpy as np
from PyQt5 import QtCore, QtWidgets, QtGui
from PyQt5.QtCore import *
from PyQt5.QtWidgets import QDialog, QVBoxLayout, QWidget, QMessageBox, QFileDialog, QTableWidgetItem
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolbar
from matplotlib.figure import Figure
from scipy.optimize import curve_fit
plt_LableData = np.zeros((0, 4))
CURVE_FIT_ROWS = []
ACTIVE_CURVE_FIT_DEFINITIONS = []
FILELOADER_DIR = Path(__file__).resolve().parent.parent / "fileloader"
FUNCTIONS_DIR = Path(__file__).resolve().parent.parent / "functions"
CURVEFITTING_DIR = Path(__file__).resolve().parent.parent / "curvefitting"
APP_LOGO_PATH = Path(__file__).resolve().parent / "inc" / "PhysPlotWide1.png"
APP_ICON_PATH = Path(__file__).resolve().parent / "inc" / "PhysPlot.png"
try:
from .constants import (
AXIS_ROLE_OPTIONS,
COLORS,
GRID_COLOR_OPTIONS,
GRID_STYLE_OPTIONS,
LINESTYLES,
LINE_COLOR_OPTIONS,
LINE_STYLE_OPTIONS,
MARKERS,
MARKER_COLOR_OPTIONS,
MARKER_STYLE_OPTIONS,
PLOT_LABEL_DEFAULTS,
SCALE_X_OPTIONS,
CURVE_FIT_LABEL_MODES,
)
from .utils import fit_label, table_item_float
except ImportError:
from constants import (
AXIS_ROLE_OPTIONS,
COLORS,
GRID_COLOR_OPTIONS,
GRID_STYLE_OPTIONS,
LINESTYLES,
LINE_COLOR_OPTIONS,
LINE_STYLE_OPTIONS,
MARKERS,
MARKER_COLOR_OPTIONS,
MARKER_STYLE_OPTIONS,
PLOT_LABEL_DEFAULTS,
SCALE_X_OPTIONS,
CURVE_FIT_LABEL_MODES,
)
from utils import fit_label, table_item_float
def _set_combo_items(combo, values):
"""_set_combo_items(combo, values) -> object
Set combo items.
Parameters:
See function signature.
Returns:
object: Result described by the method name and GUI side effects.
"""
combo.clear()
combo.addItems(list(values))
def _role_index(role_name):
"""_role_index(role_name) -> object
Role index.
Parameters:
See function signature.
Returns:
object: Result described by the method name and GUI side effects.
"""
try:
return AXIS_ROLE_OPTIONS.index(role_name)
except ValueError:
return 0
def _loader_display_name(loader_path):
"""_loader_display_name(loader_path) -> object
Loader display name.
Parameters:
See function signature.
Returns:
object: Result described by the method name and GUI side effects.
"""
try:
module_ast = ast.parse(loader_path.read_text(encoding="utf-8", errors="ignore"))
for node in module_ast.body:
if (
isinstance(node, ast.Assign)
and any(isinstance(target, ast.Name) and target.id == "title" for target in node.targets)
and isinstance(node.value, ast.Constant)
and isinstance(node.value.value, str)
):
return node.value.value
except Exception:
pass
return loader_path.stem.replace("_", " ").title()
def _discover_loader_files():
"""_discover_loader_files() -> object
Discover loader files.
Parameters:
None
Returns:
object: Result described by the method name and GUI side effects.
"""
if not FILELOADER_DIR.exists():
return []
return sorted(
[path for path in FILELOADER_DIR.glob("*.py") if path.name != "__init__.py"],
key=lambda path: (path.stem != "default_loader", path.stem),
)
def _load_loader_module(loader_path):
"""_load_loader_module(loader_path) -> object
Load loader module.
Parameters:
See function signature.
Returns:
object: Result described by the method name and GUI side effects.
"""
module_name = f"fileloader.{loader_path.stem}"
spec = importlib.util.spec_from_file_location(module_name, loader_path)
if spec is None or spec.loader is None:
raise ImportError(f"Could not load file loader from {loader_path}")
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
if not isinstance(getattr(module, "title", None), str) or not module.title.strip():
raise AttributeError(f"{loader_path.name} must define a non-empty title string")
if not hasattr(module, "load_data"):
raise AttributeError(f"{loader_path.name} must define load_data(file_path)")
return module
def _discover_function_files():
"""_discover_function_files() -> object
Discover function files.
Parameters:
None
Returns:
object: Result described by the method name and GUI side effects.
"""
if not FUNCTIONS_DIR.exists():
return []
return sorted(
[path for path in FUNCTIONS_DIR.glob("*.py") if path.name != "__init__.py"],
key=lambda path: path.stem,
)
def _load_function_module(function_path):
"""_load_function_module(function_path) -> object
Load function module.
Parameters:
See function signature.
Returns:
object: Result described by the method name and GUI side effects.
"""
module_name = f"functions.{function_path.stem}"
spec = importlib.util.spec_from_file_location(module_name, function_path)
if spec is None or spec.loader is None:
raise ImportError(f"Could not load function from {function_path}")
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
if not hasattr(module, "transform"):
raise AttributeError(f"{function_path.name} must define transform(values)")
return module
def _discover_curve_fit_files():
"""_discover_curve_fit_files() -> object
Discover curve fit files.
Parameters:
None
Returns:
object: Result described by the method name and GUI side effects.
"""
if not CURVEFITTING_DIR.exists():
return []
return sorted(
[path for path in CURVEFITTING_DIR.glob("*.py") if path.name != "__init__.py"],
key=lambda path: path.stem,
)
def _load_curve_fit_module(curve_fit_path):
"""_load_curve_fit_module(curve_fit_path) -> object
Load curve fit module.
Parameters:
See function signature.
Returns:
object: Result described by the method name and GUI side effects.
"""
module_name = f"curvefitting.{curve_fit_path.stem}"
spec = importlib.util.spec_from_file_location(module_name, curve_fit_path)
if spec is None or spec.loader is None:
raise ImportError(f"Could not load curve fitting function from {curve_fit_path}")
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
for attribute in ("DISPLAY_NAME", "DEFAULT_LABEL", "KIND"):
if not hasattr(module, attribute):
raise AttributeError(f"{curve_fit_path.name} must define {attribute}")
if module.KIND == "poly" and not hasattr(module, "DEGREE"):
raise AttributeError(f"{curve_fit_path.name} must define DEGREE")
if module.KIND == "callable" and not hasattr(module, "function"):
raise AttributeError(f"{curve_fit_path.name} must define function(x, ...)")
if module.KIND not in {"poly", "callable"}:
raise ValueError(f"{curve_fit_path.name} KIND must be 'poly' or 'callable'")
return module
def _curve_fit_definition(curve_fit_path, index):
"""_curve_fit_definition(curve_fit_path, index) -> object
Curve fit definition.
Parameters:
See function signature.
Returns:
object: Result described by the method name and GUI side effects.
"""
module = _load_curve_fit_module(curve_fit_path)
definition = {
"display_name": module.DISPLAY_NAME,
"default_label": module.DEFAULT_LABEL,
"kind": module.KIND,
"label_modes": getattr(module, "LABEL_MODES", ["Off", "Equation", "Custom"]),
"check_box_name": f"checkBox__crvft_{index}",
"off_radio_name": "radioButton_off_crvft_1" if index == 1 else f"radioButton__off_crvft_{index}",
"equation_radio_name": f"radioButton_Equation_crvft_{index}",
"path": curve_fit_path,
}
if module.KIND == "poly":
definition["degree"] = module.DEGREE
else:
definition["function"] = module.function
definition["initial_guess"] = getattr(module, "INITIAL_GUESS", None)
return definition
def _load_curve_fit_definitions():
"""_load_curve_fit_definitions() -> object
Load curve fit definitions.
Parameters:
None
Returns:
object: Result described by the method name and GUI side effects.
"""
return [
_curve_fit_definition(path, index)
for index, path in enumerate(_discover_curve_fit_files(), start=1)
]
CURVE_FIT_DEFINITIONS = _load_curve_fit_definitions()
[docs]class Ui_ConfigWindow(object):
"""Plot configuration window for styling and curve-fit display options."""
[docs] def setupUiConfigWindow(self, ConfigWindow):
"""setupUiConfigWindow(self, ConfigWindow) -> None
Configure generated Qt user-interface widgets and signals.
Parameters:
See function signature.
Returns:
None: Result described by the method name and GUI side effects.
"""
ConfigWindow.setObjectName("ConfigWindow")
ConfigWindow.resize(440, 555)
ConfigWindow.setMinimumSize(QtCore.QSize(413, 550))
self.centralwidget = QtWidgets.QWidget(ConfigWindow)
self.centralwidget.setObjectName("centralwidget")
self.gridLayout_2 = QtWidgets.QGridLayout(self.centralwidget)
self.gridLayout_2.setObjectName("gridLayout_2")
self.gridLayout = QtWidgets.QGridLayout()
self.gridLayout.setObjectName("gridLayout")
self.horizontalLayout_12 = QtWidgets.QHBoxLayout()
self.horizontalLayout_12.setObjectName("horizontalLayout_12")
spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.horizontalLayout_12.addItem(spacerItem)
self.pushButton = QtWidgets.QPushButton(self.centralwidget)
self.pushButton.setObjectName("pushButton")
self.horizontalLayout_12.addWidget(self.pushButton)
spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.horizontalLayout_12.addItem(spacerItem1)
self.gridLayout.addLayout(self.horizontalLayout_12, 1, 0, 1, 1)
self.tabWidget1 = QtWidgets.QTabWidget(self.centralwidget)
font = QtGui.QFont()
font.setPointSize(11)
self.tabWidget1.setFont(font)
self.tabWidget1.setObjectName("tabWidget1")
self.tab_1 = QtWidgets.QWidget()
self.tab_1.setObjectName("tab_1")
self.gridLayout_3 = QtWidgets.QGridLayout(self.tab_1)
self.gridLayout_3.setObjectName("gridLayout_3")
self.scrollArea = QtWidgets.QScrollArea(self.tab_1)
self.scrollArea.setWidgetResizable(True)
self.scrollArea.setObjectName("scrollArea")
self.scrollAreaWidgetContents = QtWidgets.QWidget()
self.scrollAreaWidgetContents.setGeometry(QtCore.QRect(0, 0, 377, 562))
self.scrollAreaWidgetContents.setObjectName("scrollAreaWidgetContents")
self.gridLayout_4 = QtWidgets.QGridLayout(self.scrollAreaWidgetContents)
self.gridLayout_4.setObjectName("gridLayout_4")
self.groupBox = QtWidgets.QGroupBox(self.scrollAreaWidgetContents)
self.groupBox.setObjectName("groupBox")
self.gridLayout_6 = QtWidgets.QGridLayout(self.groupBox)
self.gridLayout_6.setObjectName("gridLayout_6")
self.verticalLayout_2 = QtWidgets.QVBoxLayout()
self.verticalLayout_2.setObjectName("verticalLayout_2")
self.label_Grid_Style = QtWidgets.QLabel(self.groupBox)
self.label_Grid_Style.setObjectName("label_Grid_Style")
self.verticalLayout_2.addWidget(self.label_Grid_Style)
self.label_Grid_Width = QtWidgets.QLabel(self.groupBox)
self.label_Grid_Width.setObjectName("label_Grid_Width")
self.verticalLayout_2.addWidget(self.label_Grid_Width)
self.label_Grid_Color = QtWidgets.QLabel(self.groupBox)
self.label_Grid_Color.setObjectName("label_Grid_Color")
self.verticalLayout_2.addWidget(self.label_Grid_Color)
self.gridLayout_6.addLayout(self.verticalLayout_2, 0, 0, 1, 1)
self.verticalLayout = QtWidgets.QVBoxLayout()
self.verticalLayout.setObjectName("verticalLayout")
self.comboBox_Grid_Style = QtWidgets.QComboBox(self.groupBox)
self.comboBox_Grid_Style.setObjectName("comboBox_Grid_Style")
self.comboBox_Grid_Style.addItem("")
self.comboBox_Grid_Style.addItem("")
self.comboBox_Grid_Style.addItem("")
self.comboBox_Grid_Style.addItem("")
self.comboBox_Grid_Style.addItem("")
validator = QtGui.QDoubleValidator()
self.verticalLayout.addWidget(self.comboBox_Grid_Style)
self.lineEdit_Grid_Width = QtWidgets.QLineEdit(self.groupBox)
self.lineEdit_Grid_Width.setValidator(validator)
self.lineEdit_Grid_Width.setInputMethodHints(QtCore.Qt.ImhDigitsOnly | QtCore.Qt.ImhFormattedNumbersOnly)
self.lineEdit_Grid_Width.setObjectName("lineEdit_Grid_Width")
self.verticalLayout.addWidget(self.lineEdit_Grid_Width)
self.comboBox_Grid_Color = QtWidgets.QComboBox(self.groupBox)
self.comboBox_Grid_Color.setObjectName("comboBox_Grid_Color")
self.comboBox_Grid_Color.addItem("")
self.comboBox_Grid_Color.addItem("")
self.comboBox_Grid_Color.addItem("")
self.comboBox_Grid_Color.addItem("")
self.comboBox_Grid_Color.addItem("")
self.comboBox_Grid_Color.addItem("")
self.comboBox_Grid_Color.addItem("")
self.verticalLayout.addWidget(self.comboBox_Grid_Color)
self.gridLayout_6.addLayout(self.verticalLayout, 0, 1, 1, 1)
self.gridLayout_4.addWidget(self.groupBox, 0, 0, 1, 1)
self.groupBox_2 = QtWidgets.QGroupBox(self.scrollAreaWidgetContents)
self.groupBox_2.setObjectName("groupBox_2")
self.gridLayout_7 = QtWidgets.QGridLayout(self.groupBox_2)
self.gridLayout_7.setObjectName("gridLayout_7")
self.verticalLayout_4 = QtWidgets.QVBoxLayout()
self.verticalLayout_4.setObjectName("verticalLayout_4")
self.label_Marker_Style = QtWidgets.QLabel(self.groupBox_2)
self.label_Marker_Style.setObjectName("label_Marker_Style")
self.verticalLayout_4.addWidget(self.label_Marker_Style)
self.label_Marker_Size = QtWidgets.QLabel(self.groupBox_2)
self.label_Marker_Size.setObjectName("label_Marker_Size")
self.verticalLayout_4.addWidget(self.label_Marker_Size)
self.label_Marker_Color = QtWidgets.QLabel(self.groupBox_2)
self.label_Marker_Color.setObjectName("label_Marker_Color")
self.verticalLayout_4.addWidget(self.label_Marker_Color)
self.gridLayout_7.addLayout(self.verticalLayout_4, 0, 0, 1, 1)
self.verticalLayout_3 = QtWidgets.QVBoxLayout()
self.verticalLayout_3.setObjectName("verticalLayout_3")
self.comboBox_Marker_Style = QtWidgets.QComboBox(self.groupBox_2)
self.comboBox_Marker_Style.setObjectName("comboBox_Marker_Style")
self.comboBox_Marker_Style.addItem("")
self.comboBox_Marker_Style.addItem("")
self.comboBox_Marker_Style.addItem("")
self.comboBox_Marker_Style.addItem("")
self.comboBox_Marker_Style.addItem("")
self.comboBox_Marker_Style.addItem("")
self.comboBox_Marker_Style.addItem("")
self.comboBox_Marker_Style.addItem("")
self.comboBox_Marker_Style.addItem("")
self.comboBox_Marker_Style.addItem("")
self.comboBox_Marker_Style.addItem("")
self.comboBox_Marker_Style.addItem("")
self.comboBox_Marker_Style.addItem("")
self.comboBox_Marker_Style.addItem("")
self.comboBox_Marker_Style.addItem("")
self.comboBox_Marker_Style.addItem("")
self.comboBox_Marker_Style.addItem("")
self.comboBox_Marker_Style.addItem("")
self.comboBox_Marker_Style.addItem("")
self.comboBox_Marker_Style.addItem("")
self.comboBox_Marker_Style.addItem("")
self.comboBox_Marker_Style.addItem("")
self.comboBox_Marker_Style.addItem("")
self.comboBox_Marker_Style.addItem("")
self.verticalLayout_3.addWidget(self.comboBox_Marker_Style)
self.lineEdit_Marker_Size = QtWidgets.QLineEdit(self.groupBox_2)
self.lineEdit_Marker_Size.setValidator(validator)
self.lineEdit_Marker_Size.setInputMethodHints(QtCore.Qt.ImhDigitsOnly | QtCore.Qt.ImhFormattedNumbersOnly)
self.lineEdit_Marker_Size.setObjectName("lineEdit_Marker_Size")
self.verticalLayout_3.addWidget(self.lineEdit_Marker_Size)
self.comboBox_Marker_Color = QtWidgets.QComboBox(self.groupBox_2)
self.comboBox_Marker_Color.setObjectName("comboBox_Marker_Color")
self.comboBox_Marker_Color.addItem("")
self.comboBox_Marker_Color.addItem("")
self.comboBox_Marker_Color.addItem("")
self.comboBox_Marker_Color.addItem("")
self.comboBox_Marker_Color.addItem("")
self.comboBox_Marker_Color.addItem("")
self.comboBox_Marker_Color.addItem("")
self.comboBox_Marker_Color.addItem("")
self.verticalLayout_3.addWidget(self.comboBox_Marker_Color)
self.gridLayout_7.addLayout(self.verticalLayout_3, 0, 1, 1, 1)
self.gridLayout_4.addWidget(self.groupBox_2, 1, 0, 1, 1)
self.groupBox_3 = QtWidgets.QGroupBox(self.scrollAreaWidgetContents)
self.groupBox_3.setObjectName("groupBox_3")
self.gridLayout_8 = QtWidgets.QGridLayout(self.groupBox_3)
self.gridLayout_8.setObjectName("gridLayout_8")
self.verticalLayout_5 = QtWidgets.QVBoxLayout()
self.verticalLayout_5.setObjectName("verticalLayout_5")
self.label_Line_Style = QtWidgets.QLabel(self.groupBox_3)
self.label_Line_Style.setObjectName("label_Line_Style")
self.verticalLayout_5.addWidget(self.label_Line_Style)
self.label_Line_Width = QtWidgets.QLabel(self.groupBox_3)
self.label_Line_Width.setObjectName("label_Line_Width")
self.verticalLayout_5.addWidget(self.label_Line_Width)
self.label_Line_Color = QtWidgets.QLabel(self.groupBox_3)
self.label_Line_Color.setObjectName("label_Line_Color")
self.verticalLayout_5.addWidget(self.label_Line_Color)
self.gridLayout_8.addLayout(self.verticalLayout_5, 0, 0, 1, 1)
self.verticalLayout_6 = QtWidgets.QVBoxLayout()
self.verticalLayout_6.setObjectName("verticalLayout_6")
self.comboBox_Line_Style = QtWidgets.QComboBox(self.groupBox_3)
self.comboBox_Line_Style.setObjectName("comboBox_Line_Style")
self.comboBox_Line_Style.addItem("")
self.comboBox_Line_Style.addItem("")
self.comboBox_Line_Style.addItem("")
self.comboBox_Line_Style.addItem("")
self.comboBox_Line_Style.addItem("")
self.verticalLayout_6.addWidget(self.comboBox_Line_Style)
self.lineEdit_Line_Width = QtWidgets.QLineEdit(self.groupBox_3)
self.lineEdit_Line_Width.setValidator(validator)
self.lineEdit_Line_Width.setInputMethodHints(QtCore.Qt.ImhDigitsOnly | QtCore.Qt.ImhFormattedNumbersOnly)
self.lineEdit_Line_Width.setObjectName("lineEdit_Line_Width")
self.verticalLayout_6.addWidget(self.lineEdit_Line_Width)
self.comboBox_Line_Color = QtWidgets.QComboBox(self.groupBox_3)
self.comboBox_Line_Color.setObjectName("comboBox_Line_Color")
self.comboBox_Line_Color.addItem("")
self.comboBox_Line_Color.addItem("")
self.comboBox_Line_Color.addItem("")
self.comboBox_Line_Color.addItem("")
self.comboBox_Line_Color.addItem("")
self.comboBox_Line_Color.addItem("")
self.comboBox_Line_Color.addItem("")
self.comboBox_Line_Color.addItem("")
self.verticalLayout_6.addWidget(self.comboBox_Line_Color)
self.gridLayout_8.addLayout(self.verticalLayout_6, 0, 1, 1, 1)
self.gridLayout_4.addWidget(self.groupBox_3, 2, 0, 1, 1)
self.groupBox_6 = QtWidgets.QGroupBox(self.scrollAreaWidgetContents)
self.groupBox_6.setObjectName("groupBox_6")
self.gridLayout_9 = QtWidgets.QGridLayout(self.groupBox_6)
self.gridLayout_9.setObjectName("gridLayout_9")
self.verticalLayout_9 = QtWidgets.QVBoxLayout()
self.verticalLayout_9.setObjectName("verticalLayout_9")
self.label_title = QtWidgets.QLabel(self.groupBox_6)
self.label_title.setObjectName("label_title")
self.verticalLayout_9.addWidget(self.label_title)
self.label_xLable = QtWidgets.QLabel(self.groupBox_6)
self.label_xLable.setObjectName("label_xLable")
self.verticalLayout_9.addWidget(self.label_xLable)
self.label_yLable = QtWidgets.QLabel(self.groupBox_6)
self.label_yLable.setObjectName("label_yLable")
self.verticalLayout_9.addWidget(self.label_yLable)
self.label_Legend = QtWidgets.QLabel(self.groupBox_6)
self.label_Legend.setObjectName("label_Legend")
self.verticalLayout_9.addWidget(self.label_Legend)
self.gridLayout_9.addLayout(self.verticalLayout_9, 0, 0, 1, 1)
self.verticalLayout_10 = QtWidgets.QVBoxLayout()
self.verticalLayout_10.setObjectName("verticalLayout_10")
self.lineEdit_PlotLabel = QtWidgets.QLineEdit(self.groupBox_6)
self.lineEdit_PlotLabel.setObjectName("lineEdit_PlotLabel")
self.verticalLayout_10.addWidget(self.lineEdit_PlotLabel)
self.lineEdit_PlotxLabel = QtWidgets.QLineEdit(self.groupBox_6)
self.lineEdit_PlotxLabel.setObjectName("lineEdit_PlotxLabel")
self.verticalLayout_10.addWidget(self.lineEdit_PlotxLabel)
self.lineEdit_PlotyLabel = QtWidgets.QLineEdit(self.groupBox_6)
self.lineEdit_PlotyLabel.setObjectName("lineEdit_PlotyLabel")
self.verticalLayout_10.addWidget(self.lineEdit_PlotyLabel)
self.lineEdit_PlotLegend = QtWidgets.QLineEdit(self.groupBox_6)
self.lineEdit_PlotLegend.setObjectName("lineEdit_PlotLegend")
self.verticalLayout_10.addWidget(self.lineEdit_PlotLegend)
self.gridLayout_9.addLayout(self.verticalLayout_10, 0, 1, 1, 1)
self.gridLayout_4.addWidget(self.groupBox_6, 3, 0, 1, 1)
self.scrollArea.setWidget(self.scrollAreaWidgetContents)
self.gridLayout_3.addWidget(self.scrollArea, 0, 0, 1, 1)
self.tabWidget1.addTab(self.tab_1, "")
self.tab_2 = QtWidgets.QWidget()
self.tab_2.setObjectName("tab_2")
self.gridLayout_5 = QtWidgets.QGridLayout(self.tab_2)
self.gridLayout_5.setObjectName("gridLayout_5")
self.gridLayout_5.setContentsMargins(36, 32, 36, 32)
self.gridLayout_5.setVerticalSpacing(14)
self.label_curve_fit_label_mode = QtWidgets.QLabel(self.tab_2)
self.label_curve_fit_label_mode.setObjectName("label_curve_fit_label_mode")
self.gridLayout_5.addWidget(self.label_curve_fit_label_mode, 0, 0, 1, 1)
self.comboBox_curve_fit_label_mode = QtWidgets.QComboBox(self.tab_2)
self.comboBox_curve_fit_label_mode.setMinimumWidth(220)
self.comboBox_curve_fit_label_mode.setObjectName("comboBox_curve_fit_label_mode")
self.gridLayout_5.addWidget(self.comboBox_curve_fit_label_mode, 1, 0, 1, 1)
self.label_curve_fit_custom_label = QtWidgets.QLabel(self.tab_2)
self.label_curve_fit_custom_label.setObjectName("label_curve_fit_custom_label")
self.gridLayout_5.addWidget(self.label_curve_fit_custom_label, 2, 0, 1, 1)
self.lineEdit_curve_fit_label = QtWidgets.QLineEdit(self.tab_2)
self.lineEdit_curve_fit_label.setMinimumWidth(240)
self.lineEdit_curve_fit_label.setObjectName("lineEdit_curve_fit_label")
self.gridLayout_5.addWidget(self.lineEdit_curve_fit_label, 3, 0, 1, 1)
self.label_curve_fit_type = QtWidgets.QLabel(self.tab_2)
self.label_curve_fit_type.setObjectName("label_curve_fit_type")
self.gridLayout_5.addWidget(self.label_curve_fit_type, 4, 0, 1, 1)
self.listWidget_curve_fit_type = QtWidgets.QListWidget(self.tab_2)
self.listWidget_curve_fit_type.setMinimumWidth(220)
self.listWidget_curve_fit_type.setObjectName("listWidget_curve_fit_type")
self.gridLayout_5.addWidget(self.listWidget_curve_fit_type, 5, 0, 1, 1)
self.gridLayout_5.setColumnStretch(0, 1)
self.gridLayout_5.setRowStretch(0, 0)
self.gridLayout_5.setRowStretch(1, 0)
self.gridLayout_5.setRowStretch(2, 0)
self.gridLayout_5.setRowStretch(3, 0)
self.gridLayout_5.setRowStretch(4, 0)
self.gridLayout_5.setRowStretch(5, 1)
self.tabWidget1.addTab(self.tab_2, "")
self.gridLayout.addWidget(self.tabWidget1, 0, 0, 1, 1)
self.gridLayout_2.addLayout(self.gridLayout, 0, 0, 1, 1)
ConfigWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(ConfigWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 440, 21))
self.menubar.setObjectName("menubar")
ConfigWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(ConfigWindow)
self.statusbar.setObjectName("statusbar")
ConfigWindow.setStatusBar(self.statusbar)
self.retranslateUi(ConfigWindow)
self.tabWidget1.setCurrentIndex(0)
QtCore.QMetaObject.connectSlotsByName(ConfigWindow)
[docs] def retranslateUi(self, ConfigWindow):
"""retranslateUi(self, ConfigWindow) -> None
Configure generated Qt user-interface widgets and signals.
Parameters:
See function signature.
Returns:
None: Result described by the method name and GUI side effects.
"""
_translate = QtCore.QCoreApplication.translate
ConfigWindow.setWindowTitle(_translate("ConfigWindow", "Configuration"))
ConfigWindow.setWindowIcon(QtGui.QIcon(str(APP_ICON_PATH)))
self._apply_configured_texts()
self.sourceScript()
def _curve_fit_radio_name(self, index, mode):
"""_curve_fit_radio_name(self, index, mode) -> None
Curve fit radio name.
Parameters:
See function signature.
Returns:
None: Result described by the method name and GUI side effects.
"""
if mode == "off" and index == 1:
return f"radioButton_off_crvft_{index}"
if mode == "off":
return f"radioButton__off_crvft_{index}"
return f"radioButton_{mode}_crvft_{index}"
def _apply_configured_texts(self):
"""_apply_configured_texts(self) -> None
Apply configured texts.
Parameters:
See function signature.
Returns:
None: Result described by the method name and GUI side effects.
"""
_set_combo_items(self.comboBox_Grid_Style, GRID_STYLE_OPTIONS)
_set_combo_items(self.comboBox_Grid_Color, GRID_COLOR_OPTIONS)
_set_combo_items(self.comboBox_Marker_Style, MARKER_STYLE_OPTIONS)
_set_combo_items(self.comboBox_Marker_Color, MARKER_COLOR_OPTIONS)
_set_combo_items(self.comboBox_Line_Style, LINE_STYLE_OPTIONS)
_set_combo_items(self.comboBox_Line_Color, LINE_COLOR_OPTIONS)
self.pushButton.setText("Apply")
self.groupBox.setTitle("Grid Line")
self.label_Grid_Style.setText("Style:")
self.label_Grid_Width.setText("Width:")
self.label_Grid_Color.setText("Color:")
self.lineEdit_Grid_Width.setText("0.3")
self.groupBox_2.setTitle("Marker")
self.label_Marker_Style.setText("Style:")
self.label_Marker_Size.setText("Size:")
self.label_Marker_Color.setText("Color:")
self.lineEdit_Marker_Size.setText("1")
self.groupBox_3.setTitle("Plot Line")
self.label_Line_Style.setText("Style")
self.label_Line_Width.setText("Width")
self.label_Line_Color.setText("Color")
self.lineEdit_Line_Width.setText("1")
self.groupBox_6.setTitle("Labels")
self.label_title.setText("Title:")
self.label_xLable.setText("xLabel:")
self.label_yLable.setText("yLabel:")
self.label_Legend.setText("Legend:")
self.lineEdit_PlotLabel.setText(PLOT_LABEL_DEFAULTS["title"])
self.lineEdit_PlotxLabel.setText(PLOT_LABEL_DEFAULTS["x_label"])
self.lineEdit_PlotyLabel.setText(PLOT_LABEL_DEFAULTS["y_label"])
self.lineEdit_PlotLegend.setText(PLOT_LABEL_DEFAULTS["legend"])
self.tabWidget1.setTabText(self.tabWidget1.indexOf(self.tab_1), "Plot Formating")
self.label_curve_fit_type.setText("Curve Fit Type")
self.label_curve_fit_label_mode.setText("Label Mode")
self.label_curve_fit_custom_label.setText("Custom Label")
_set_combo_items(
self.listWidget_curve_fit_type,
[fit_definition["display_name"] for fit_definition in CURVE_FIT_DEFINITIONS],
)
if CURVE_FIT_DEFINITIONS:
self.lineEdit_curve_fit_label.setText(CURVE_FIT_DEFINITIONS[0]["default_label"])
self._set_curve_fit_label_modes(0)
self.listWidget_curve_fit_type.clearSelection()
self.listWidget_curve_fit_type.setCurrentRow(-1)
self.tabWidget1.setTabText(self.tabWidget1.indexOf(self.tab_2), "Curve Fitting")
def _set_curve_fit_label_modes(self, index):
"""_set_curve_fit_label_modes(self, index) -> None
Set curve fit label modes.
Parameters:
See function signature.
Returns:
None: Result described by the method name and GUI side effects.
"""
if not CURVE_FIT_DEFINITIONS:
return
current = self.comboBox_curve_fit_label_mode.currentText()
modes = CURVE_FIT_DEFINITIONS[index]["label_modes"]
self.comboBox_curve_fit_label_mode.blockSignals(True)
_set_combo_items(self.comboBox_curve_fit_label_mode, modes)
selected_index = self.comboBox_curve_fit_label_mode.findText(current)
self.comboBox_curve_fit_label_mode.setCurrentIndex(max(selected_index, 0))
self.comboBox_curve_fit_label_mode.blockSignals(False)
def _curve_fit_type_changed(self, index):
"""_curve_fit_type_changed(self, index) -> None
Curve fit type changed.
Parameters:
See function signature.
Returns:
None: Result described by the method name and GUI side effects.
"""
if index < 0 or index >= len(CURVE_FIT_DEFINITIONS):
return
self.lineEdit_curve_fit_label.setText(CURVE_FIT_DEFINITIONS[index]["default_label"])
self._set_curve_fit_label_modes(index)
self._sync_curve_fit_selection()
def _sync_curve_fit_selection(self):
"""_sync_curve_fit_selection(self) -> None
Sync curve fit selection.
Parameters:
See function signature.
Returns:
None: Result described by the method name and GUI side effects.
"""
global plt_LableData
global CURVE_FIT_ROWS
global ACTIVE_CURVE_FIT_DEFINITIONS
index = self.listWidget_curve_fit_type.currentRow()
if not CURVE_FIT_DEFINITIONS or index < 0:
CURVE_FIT_ROWS = []
ACTIVE_CURVE_FIT_DEFINITIONS = []
plt_LableData = np.zeros((0, 4))
mode = self.comboBox_curve_fit_label_mode.currentText().lower()
is_custom_label = mode in {"custom", "label"}
self.label_curve_fit_custom_label.setVisible(is_custom_label)
self.lineEdit_curve_fit_label.setVisible(is_custom_label)
self.lineEdit_curve_fit_label.setEnabled(is_custom_label)
return
ACTIVE_CURVE_FIT_DEFINITIONS = [CURVE_FIT_DEFINITIONS[index]]
CURVE_FIT_ROWS = [{"line_edit": self.lineEdit_curve_fit_label}]
plt_LableData = np.zeros((1, 4))
plt_LableData[0, 0] = True
mode = self.comboBox_curve_fit_label_mode.currentText().lower()
is_custom_label = mode in {"custom", "label"}
self.label_curve_fit_custom_label.setVisible(is_custom_label)
self.lineEdit_curve_fit_label.setVisible(is_custom_label)
self.lineEdit_curve_fit_label.setEnabled(is_custom_label)
if mode == "equation":
plt_LableData[0, 2] = True
elif mode in {"custom", "label"}:
plt_LableData[0, 3] = True
else:
plt_LableData[0, 1] = True
def _setup_file_loader_menu(self):
"""_setup_file_loader_menu(self) -> None
Setup file loader menu.
Parameters:
See function signature.
Returns:
None: Result described by the method name and GUI side effects.
"""
self.file_loader_actions = []
self.active_loader_path = None
self.active_loader_module = None
self._loader_module_cache = {}
self.menuFileLoader.clear()
loader_group = QtWidgets.QActionGroup(self.menuFileLoader)
loader_group.setExclusive(True)
loader_files = _discover_loader_files()
if not loader_files:
empty_action = QtWidgets.QAction("No loaders found", self.menuFileLoader)
empty_action.setEnabled(False)
self.menuFileLoader.addAction(empty_action)
return
for loader_path in loader_files:
action = QtWidgets.QAction(_loader_display_name(loader_path), self.menuFileLoader)
action.setCheckable(True)
action.setData(str(loader_path))
action.triggered.connect(lambda _checked=False, path=loader_path: self._set_active_loader(path))
loader_group.addAction(action)
self.menuFileLoader.addAction(action)
self.file_loader_actions.append(action)
default_loader = next((path for path in loader_files if path.stem == "default_loader"), loader_files[0])
self._set_active_loader(default_loader)
def _set_active_loader(self, loader_path):
"""_set_active_loader(self, loader_path) -> None
Set active loader.
Parameters:
See function signature.
Returns:
None: Result described by the method name and GUI side effects.
"""
loader_path = Path(loader_path)
loader_key = str(loader_path)
cached_module = self._loader_module_cache.get(loader_key)
if cached_module is None:
cached_module = _load_loader_module(loader_path)
self._loader_module_cache[loader_key] = cached_module
self.active_loader_path = loader_path
self.active_loader_module = cached_module
for action in getattr(self, "file_loader_actions", []):
action.setChecked(action.data() == loader_key)
def _load_table_data(self, file_path):
"""_load_table_data(self, file_path) -> None
Load table data.
Parameters:
See function signature.
Returns:
None: Result described by the method name and GUI side effects.
"""
if self.active_loader_module is None:
raise RuntimeError("No file loader is selected.")
table_data = self.active_loader_module.load_data(file_path)
table_data = np.asarray(table_data)
if table_data.ndim == 1:
table_data = np.atleast_2d(table_data).T
if table_data.ndim != 2:
raise ValueError("Loader must return a 2D table-like array.")
return table_data
[docs] def sourceScript(self):
"""sourceScript(self) -> None
Configure generated Qt user-interface widgets and signals.
Parameters:
See function signature.
Returns:
None: Result described by the method name and GUI side effects.
"""
# delayCmd.delay(self)
# Tab 1
# self.comboBox_Grid_Style.activated[str].connect(self.onActivated_Grid_Style)
self.lineEdit_Grid_Width.setText("0.3")
# self.comboBox_Grid_Color.activated[str].connect(self.onActivated_Grid_Color)
# self.comboBox_Marker_Style.activated[str].connect(self.onActivated_Marker_Style)
self.lineEdit_Marker_Size.setText("2")
# self.comboBox_Marker_Color.activated[str].connect(self.onActivated_Marker_Color)
# self.comboBox_Line_Style.activated[str].connect(self.onActivated_Line_Style)
self.lineEdit_Line_Width.setText("1")
# self.comboBox_Line_Color.activated[str].connect(self.onActivated_Line_Style)
self.pushButton.clicked.connect(self.definePlotParameters)
import numpy as np
self.listWidget_curve_fit_type.currentRowChanged.connect(self._curve_fit_type_changed)
self.comboBox_curve_fit_label_mode.currentIndexChanged.connect(lambda _index: self._sync_curve_fit_selection())
self.lineEdit_curve_fit_label.textChanged.connect(lambda _text: self._sync_curve_fit_selection())
self._sync_curve_fit_selection()
global Grid_Style
global Grid_Width
global Grid_Color
global Marker_Style
global Marker_Size
global Marker_Color
global Line_Style
global Line_Width
global Line_Color
global Label_PlotLabel
global Label_PlotxLabel
global Label_PlotyLabel
global Label_PlotLegend
Label_PlotLabel = PLOT_LABEL_DEFAULTS["title"]
Label_PlotxLabel = PLOT_LABEL_DEFAULTS["x_label"]
Label_PlotyLabel = PLOT_LABEL_DEFAULTS["y_label"]
Label_PlotLegend = PLOT_LABEL_DEFAULTS["legend"]
Grid_Style = GRID_STYLE_OPTIONS[0]
Grid_Width = "0.3"
Grid_Color = GRID_COLOR_OPTIONS[0]
Marker_Style = MARKER_STYLE_OPTIONS[1]
Marker_Size = "1"
Marker_Color = MARKER_COLOR_OPTIONS[2]
Line_Style = LINE_STYLE_OPTIONS[0]
Line_Width = "1"
Line_Color = LINE_COLOR_OPTIONS[0]
"""
Label_lineEdit_crvft_1= str(self.lineEdit_crvft_1.text())
Label_lineEdit_crvft_2= str(self.lineEdit_crvft_2.text())
Label_lineEdit_crvft_3= str(self.lineEdit_crvft_3.text())
Label_lineEdit_crvft_4= str(self.lineEdit_crvft_4.text())
Label_lineEdit_crvft_5 = str(self.lineEdit_crvft_5.text())
Label_lineEdit_crvft_6 = str(self.lineEdit_crvft_6.text())
Label_lineEdit_crvft_7 = str(self.lineEdit_crvft_7.text())
Label_lineEdit_crvft_8 = str(self.lineEdit_crvft_8.text())
Label_lineEdit_crvft_9 = str(self.lineEdit_crvft_9.text())
Label_lineEdit_crvft_10 = str(self.lineEdit_crvft_10.text())
Label_lineEdit_crvft_11 = str(self.lineEdit_crvft_11.text())
"""
[docs] def readFitType(self):
"""readFitType(self) -> None
Update curve-fit enable flags from the configuration checkboxes.
Parameters:
self (Ui_ConfigWindow): Active configuration window instance.
Returns:
None
"""
if self.checkBox__crvft_1.isChecked() == True:
plt_LableData[0, 0] = True
else:
plt_LableData[0, 0] = False
if self.checkBox__crvft_2.isChecked() == True:
plt_LableData[1, 0] = True
else:
plt_LableData[1, 0] = False
if self.checkBox__crvft_3.isChecked() == True:
plt_LableData[2, 0] = True
else:
plt_LableData[2, 0] = False
if self.checkBox__crvft_4.isChecked() == True:
plt_LableData[3, 0] = True
else:
plt_LableData[3, 0] = False
if self.checkBox__crvft_5.isChecked() == True:
plt_LableData[4, 0] = True
else:
plt_LableData[4, 0] = False
if self.checkBox__crvft_6.isChecked() == True:
plt_LableData[5, 0] = True
else:
plt_LableData[5, 0] = False
if self.checkBox__crvft_7.isChecked() == True:
plt_LableData[6, 0] = True
else:
plt_LableData[6, 0] = False
if self.checkBox__crvft_8.isChecked() == True:
plt_LableData[7, 0] = True
else:
plt_LableData[7, 0] = False
if self.checkBox__crvft_9.isChecked() == True:
plt_LableData[8, 0] = True
else:
plt_LableData[8, 0] = False
if self.checkBox__crvft_10.isChecked() == True:
plt_LableData[9, 0] = True
else:
plt_LableData[9, 0] = False
if self.checkBox__crvft_11.isChecked() == True:
plt_LableData[10, 0] = True
else:
plt_LableData[10, 0] = False
[docs] def definePlotParameters(self):
"""definePlotParameters(self) -> None
Persist current plot settings and refresh or open the plot window.
Parameters:
self (Ui_ConfigWindow): Active configuration window instance.
Returns:
None
"""
global Grid_Style
global Grid_Width
global Grid_Color
global Marker_Style
global Marker_Size
global Marker_Color
global Line_Style
global Line_Width
global Line_Color
global Label_PlotLabel
global Label_PlotxLabel
global Label_PlotyLabel
global Label_PlotLegend
Label_PlotLabel = str(self.lineEdit_PlotLabel.text())
Label_PlotxLabel = str(self.lineEdit_PlotxLabel.text())
Label_PlotyLabel = str(self.lineEdit_PlotyLabel.text())
Label_PlotLegend = str(self.lineEdit_PlotLegend.text())
Grid_Style = self.comboBox_Grid_Style.currentText()
Grid_Width = self.lineEdit_Grid_Width.text()
Grid_Color = self.comboBox_Grid_Color.currentText()
Marker_Style = self.comboBox_Marker_Style.currentText()
Marker_Size = self.lineEdit_Marker_Size.text()
Marker_Color = self.comboBox_Marker_Color.currentText()
Line_Style = self.comboBox_Line_Style.currentText()
Line_Width = self.lineEdit_Line_Width.text()
Line_Color = self.comboBox_Line_Color.currentText()
try:
if list(tableLabels == 1).count(True) == 1 and list(tableLabels == 3).count(True) == 1:
owner = getattr(self, "owner", None)
if owner is not None and hasattr(owner, "plot_window"):
if owner.plot_window.isVisible():
owner.plot_window.refresh_plot()
owner.plot_window.raise_()
owner.plot_window.activateWindow()
else:
owner.plot_window = Plot_Window(getattr(owner, "_main_window", None))
owner.plot_window.show()
else:
Plot_Window(getattr(owner, "_main_window", None) if owner is not None else None).show()
except Exception as e:
pass
[docs]class about_gui(QWidget):
"""Modal about dialog showing app version, authors, links, and license."""
def __init__(self):
"""__init__(self) -> None
Initialize the object.
Parameters:
See function signature.
Returns:
None: Result described by the method name and GUI side effects.
"""
super().__init__()
self.initUI()
[docs] def initUI(self):
"""initUI(self) -> None
Initui.
Parameters:
See function signature.
Returns:
None: Result described by the method name and GUI side effects.
"""
message = "<p><strong>PhysPlot: Advanced Plotting Made Simple<br /></strong>Version: 2.0.0 (5/15/2026)</p><p>PhysPlot was developed by M. Shiraz Ahmad based on an idea conceptualized by Dr. Sabieh Anwar.</p><p><strong>Details: </strong><a href='https://physplot.readthedocs.io/'>PhysPlot Documentation</a></p><p>For feature enhancement requests or bug reports, visit <a href='https://github.com/MShirazAhmad/PhysPlot/issues'>MShirazAhmad/PhysPlot</a>.</p><p><strong>Licenses:</strong> Code uses PolyForm Noncommercial 1.0.0. Documentation and educational media use CC BY-NC 4.0.</p><p>Commercial use requires written permission from the project originator.</p><p>Copyright © 2019-2026 PhysPlot project originator.</p>"
msg_box = QMessageBox()
msg_box.setWindowIcon(QtGui.QIcon(str(APP_ICON_PATH)))
msg_box.setWindowTitle("About PhysPlot")
msg_box.setIconPixmap(QtGui.QPixmap(str(APP_ICON_PATH)).scaled(
64,
64,
QtCore.Qt.KeepAspectRatio,
QtCore.Qt.SmoothTransformation,
))
msg_box.setTextFormat(QtCore.Qt.RichText)
msg_box.setText(message)
msg_box.setStandardButtons(QMessageBox.Ok)
msg_box.exec_()
[docs]class pick_file_to_append(QWidget):
"""File picker dialog used to select an input dataset for import."""
def __init__(self):
"""__init__(self) -> None
Initialize the object.
Parameters:
See function signature.
Returns:
None: Result described by the method name and GUI side effects.
"""
super().__init__()
self.title = "Please Pick multiple Physlogger' exported files"
self.left = 10
self.top = 10
self.width = 640
self.height = 480
self.initUI()
[docs] def initUI(self):
"""initUI(self) -> None
Initui.
Parameters:
See function signature.
Returns:
None: Result described by the method name and GUI side effects.
"""
self.setWindowTitle(self.title)
self.setWindowIcon(QtGui.QIcon(str(APP_ICON_PATH)))
self.setGeometry(self.left, self.top, self.width, self.height)
self.openFileNamesDialog()
[docs] def openFileNamesDialog(self):
"""openFileNamesDialog(self) -> None
Openfilenamesdialog.
Parameters:
See function signature.
Returns:
None: Result described by the method name and GUI side effects.
"""
global files
options = QFileDialog.Options()
options |= QFileDialog.DontConfirmOverwrite
files, _ = QFileDialog.getOpenFileName(None, "Pick Variables File", "",
"All Files (*);;OES HRF (*.HRF *.hrf);;Excel Files (*.xlsx);; CSV (*.csv);;TSV (*.txt)",
options=options)
[docs]class SaveFile(QWidget):
"""Save dialog wrapper that exports the current output table to text."""
def __init__(self):
"""__init__(self) -> None
Initialize the object.
Parameters:
See function signature.
Returns:
None: Result described by the method name and GUI side effects.
"""
super().__init__()
self.title = 'PyQt5 file dialogs - pythonspot.com'
self.left = 10
self.top = 10
self.width = 640
self.height = 480
self.initUI()
[docs] def initUI(self):
"""initUI(self) -> None
Initui.
Parameters:
See function signature.
Returns:
None: Result described by the method name and GUI side effects.
"""
self.setWindowTitle(self.title)
self.setWindowIcon(QtGui.QIcon(str(APP_ICON_PATH)))
self.setGeometry(self.left, self.top, self.width, self.height)
self.saveFileDialog()
[docs] def saveFileDialog(self):
"""saveFileDialog(self) -> None
Savefiledialog.
Parameters:
See function signature.
Returns:
None: Result described by the method name and GUI side effects.
"""
options = QFileDialog.Options()
fileName, _ = QFileDialog.getSaveFileName(None, "Save File", "",
"Text Files (*.txt);;All Files (*)")
if fileName:
global exportFilePath
exportFilePath = fileName
np.savetxt(exportFilePath, np.around(np.single(OutPut_Table), decimals=6), delimiter='\t', fmt='%.3f')
[docs]class Plot_Window(QDialog):
"""Plot dialog that renders data, errors, legend, and optional fits."""
def __init__(self, parent=None):
"""__init__(self, parent) -> None
Initialize the object.
Parameters:
See function signature.
Returns:
None: Result described by the method name and GUI side effects.
"""
super(Plot_Window, self).__init__(parent)
self.setWindowIcon(QtGui.QIcon(str(APP_ICON_PATH)))
self.setWindowTitle("PhysPlot - Plot Window")
# a figure instance to plot on
self.figure = Figure()
# this is the Canvas Widget that displays the `figure`
# it takes the `figure` instance as a parameter to __init__
self.canvas = FigureCanvas(self.figure)
self.toolbar = NavigationToolbar(self.canvas, self)
# set the layout
layout = QVBoxLayout()
layout.addWidget(self.toolbar)
layout.addWidget(self.canvas)
self.setLayout(layout)
self.refresh_plot()
[docs] def refresh_plot(self):
"""refresh_plot(self) -> None
Redraw the existing plot canvas using current table and config state.
Parameters:
self (Plot_Window): Active plot dialog instance.
Returns:
None
"""
self.figure.clear()
label_counts = {role: int(np.count_nonzero(tableLabels == role)) for role in range(1, 5)}
has_x = label_counts[1] == 1
has_xerr = label_counts[2] == 1
has_y = label_counts[3] == 1
has_yerr = label_counts[4] == 1
if has_x:
xIndex = int(np.where(tableLabels == 1)[0][0])
x = OutPut_Table[:, xIndex]
if has_xerr:
uxIndex = int(np.where(tableLabels == 2)[0][0])
xerr = OutPut_Table[:, uxIndex]
if has_y:
yIndex = int(np.where(tableLabels == 3)[0][0])
y = OutPut_Table[:, yIndex]
if has_yerr:
uyIndex = int(np.where(tableLabels == 4)[0][0])
yerr = OutPut_Table[:, uyIndex]
ax = self.figure.add_subplot(111)
ax.set_xlabel(Label_PlotxLabel)
ax.set_ylabel(Label_PlotyLabel)
ax.set_title(Label_PlotLabel)
ax.grid(color=COLORS[Grid_Color], linestyle=LINESTYLES[Grid_Style], linewidth=float(Grid_Width))
try:
# slope, intercept, r_value, p_value, stderr = linregress(x, y)
# Equation = 'y = ' + str(np.round(slope, 7)) + 'x + ' + str(np.round(intercept, 7))
if has_x and has_y:
errorbar_options = {}
if has_xerr:
errorbar_options["xerr"] = xerr
if has_yerr:
errorbar_options["yerr"] = yerr
ax.errorbar(
x, y,
marker=MARKERS[Marker_Style],
markerfacecolor=COLORS[Marker_Color],
markeredgecolor=COLORS[Marker_Color],
markersize=float(Marker_Size),
linestyle=LINESTYLES[Line_Style],
linewidth=float(Line_Width),
color=COLORS[Line_Color],
elinewidth=1,
capsize=5,
capthick=1,
label=Label_PlotLegend,
**errorbar_options,
)
except Exception as e:
self.errMessage("Generating Plot:", str(e))
try:
fit_rows = globals().get("CURVE_FIT_ROWS", [])
custom_labels = [row["line_edit"].text() for row in fit_rows]
fit_definitions = globals().get("ACTIVE_CURVE_FIT_DEFINITIONS", [])
for index, fit_definition in enumerate(fit_definitions[:len(plt_LableData)]):
try:
if plt_LableData[index, 0]:
custom_label = custom_labels[index] if index < len(custom_labels) else fit_definition["default_label"]
if not custom_label:
custom_label = fit_definition["default_label"]
if fit_definition["kind"] == "poly":
coefficients = np.polyfit(x, y, fit_definition["degree"])
polynomial = np.poly1d(coefficients)
ax.plot(
x,
polynomial(x),
'-',
label=fit_label(plt_LableData, index, coefficients, custom_label),
)
elif fit_definition["kind"] == "callable":
fit_function = fit_definition["function"]
initial_guess = fit_definition.get("initial_guess")
popt, pcov = curve_fit(fit_function, x, y, p0=initial_guess)
ax.plot(
x,
fit_function(x, *popt),
label=fit_label(plt_LableData, index, popt, custom_label),
)
except Exception as e:
self.errMessage(fit_definition["display_name"] + ":", str(e))
except Exception as e:
self.errMessage("Curve Fitting:", str(e))
# ax.text(0.05, 0.95, Equation, transform=ax.transAxes, fontsize=11,
# verticalalignment='top')
if ax.get_legend_handles_labels()[0]:
ax.legend(loc='upper left', fontsize='small')
self.figure.tight_layout()
self.canvas.draw()
[docs]class Ui_MainWindow(object):
"""Primary PhysPlot window for table editing, transforms, and plot launch."""
[docs] def setupUi(self, MainWindow):
"""setupUi(self, MainWindow) -> None
Configure generated Qt user-interface widgets and signals.
Parameters:
See function signature.
Returns:
None: Result described by the method name and GUI side effects.
"""
MainWindow.setObjectName("MainWindow")
MainWindow.resize(601, 643)
self._main_window = MainWindow
MainWindow.setMaximumSize(QtCore.QSize(16777215, 16777215))
MainWindow.setCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor))
MainWindow.setFocusPolicy(QtCore.Qt.ClickFocus)
MainWindow.setLayoutDirection(QtCore.Qt.LeftToRight)
MainWindow.setAutoFillBackground(False)
MainWindow.setLocale(QtCore.QLocale(QtCore.QLocale.English, QtCore.QLocale.Pakistan))
MainWindow.setInputMethodHints(QtCore.Qt.ImhNone)
MainWindow.setDockOptions(
QtWidgets.QMainWindow.AllowTabbedDocks | QtWidgets.QMainWindow.AnimatedDocks | QtWidgets.QMainWindow.VerticalTabs)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setTabletTracking(True)
self.centralwidget.setFocusPolicy(QtCore.Qt.ClickFocus)
self.centralwidget.setAcceptDrops(True)
self.centralwidget.setAutoFillBackground(True)
self.centralwidget.setLocale(QtCore.QLocale(QtCore.QLocale.English, QtCore.QLocale.UnitedStates))
self.centralwidget.setObjectName("centralwidget")
self.gridLayout_2 = QtWidgets.QGridLayout(self.centralwidget)
self.gridLayout_2.setObjectName("gridLayout_2")
self.horizontalLayout_3 = QtWidgets.QHBoxLayout()
self.horizontalLayout_3.setObjectName("horizontalLayout_3")
spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.horizontalLayout_3.addItem(spacerItem)
self.label = QtWidgets.QLabel(self.centralwidget)
self.label.setMaximumSize(QtCore.QSize(220, 91))
self.label.setText("")
self.label.setPixmap(QtGui.QPixmap(str(APP_LOGO_PATH)))
self.label.setScaledContents(True)
self.label.setAlignment(QtCore.Qt.AlignCenter)
self.label.setObjectName("label")
self.horizontalLayout_3.addWidget(self.label)
spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.horizontalLayout_3.addItem(spacerItem1)
self.gridLayout_2.addLayout(self.horizontalLayout_3, 0, 0, 1, 2)
self.tableWidget = QtWidgets.QTableWidget(self.centralwidget)
self.tableWidget.setFocusPolicy(QtCore.Qt.StrongFocus)
self.tableWidget.setAutoFillBackground(True)
self.tableWidget.setInputMethodHints(QtCore.Qt.ImhNone)
self.tableWidget.setEditTriggers(
QtWidgets.QAbstractItemView.AnyKeyPressed | QtWidgets.QAbstractItemView.DoubleClicked | QtWidgets.QAbstractItemView.EditKeyPressed)
self.tableWidget.setDragEnabled(True)
self.tableWidget.setAlternatingRowColors(True)
self.tableWidget.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectItems)
self.tableWidget.setRowCount(10)
self.tableWidget.setColumnCount(4)
self.tableWidget.setObjectName("tableWidget")
font = QtGui.QFont()
font.setPointSize(11)
font.setBold(True)
self.tableWidget.horizontalHeader().font()
self.tableWidget.horizontalHeader().setVisible(True)
self.tableWidget.horizontalHeader().setCascadingSectionResizes(True)
self.tableWidget.horizontalHeader().setHighlightSections(True)
self.tableWidget.horizontalHeader().setSortIndicatorShown(False)
self.tableWidget.horizontalHeader().setStretchLastSection(True)
self.tableWidget.verticalHeader().setCascadingSectionResizes(False)
self.tableWidget.verticalHeader().setSortIndicatorShown(False)
self.tableWidget.verticalHeader().setStretchLastSection(False)
self.gridLayout_2.addWidget(self.tableWidget, 1, 0, 1, 2)
self.groupBox_3 = QtWidgets.QGroupBox(self.centralwidget)
self.groupBox_3.setTitle("")
self.groupBox_3.setObjectName("groupBox_3")
self.gridLayout = QtWidgets.QGridLayout(self.groupBox_3)
self.gridLayout.setObjectName("gridLayout")
self.pushButton_5 = QtWidgets.QPushButton(self.groupBox_3)
font = QtGui.QFont()
font.setPointSize(11)
self.pushButton_5.setFont(font)
self.pushButton_5.setObjectName("pushButton_5")
self.gridLayout.addWidget(self.pushButton_5, 0, 0, 1, 1)
self.checkBox_2 = QtWidgets.QCheckBox(self.groupBox_3)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.checkBox_2.sizePolicy().hasHeightForWidth())
self.checkBox_2.setSizePolicy(sizePolicy)
font = QtGui.QFont()
font.setPointSize(11)
self.checkBox_2.setFont(font)
self.checkBox_2.setObjectName("checkBox_2")
self.gridLayout.addWidget(self.checkBox_2, 1, 0, 1, 1)
self.horizontalLayout_4 = QtWidgets.QHBoxLayout()
self.horizontalLayout_4.setObjectName("horizontalLayout_4")
self.verticalLayout_2 = QtWidgets.QVBoxLayout()
self.verticalLayout_2.setObjectName("verticalLayout_2")
self.Rows_label = QtWidgets.QLabel(self.groupBox_3)
font = QtGui.QFont()
font.setPointSize(11)
self.Rows_label.setFont(font)
self.Rows_label.setObjectName("Rows_label")
self.verticalLayout_2.addWidget(self.Rows_label)
self.Columns_label = QtWidgets.QLabel(self.groupBox_3)
font = QtGui.QFont()
font.setPointSize(11)
self.Columns_label.setFont(font)
self.Columns_label.setObjectName("Columns_label")
self.verticalLayout_2.addWidget(self.Columns_label)
self.horizontalLayout_4.addLayout(self.verticalLayout_2)
self.verticalLayout = QtWidgets.QVBoxLayout()
self.verticalLayout.setObjectName("verticalLayout")
self.Rows_lineEdit = QtWidgets.QLineEdit(self.groupBox_3)
self.Rows_lineEdit.setMaximumSize(QtCore.QSize(16777215, 16777215))
self.Rows_lineEdit.setObjectName("Rows_lineEdit")
self.verticalLayout.addWidget(self.Rows_lineEdit)
self.Columns_lineEdit = QtWidgets.QLineEdit(self.groupBox_3)
self.Columns_lineEdit.setMaximumSize(QtCore.QSize(16777215, 16777215))
self.Columns_lineEdit.setObjectName("Columns_lineEdit")
validator = QtGui.QDoubleValidator()
int_validator = QtGui.QIntValidator(1, 1000000)
self.Rows_lineEdit.setText("10")
self.Columns_lineEdit.setText("4")
self.Rows_lineEdit.setValidator(int_validator)
self.Columns_lineEdit.setValidator(int_validator)
self.verticalLayout.addWidget(self.Columns_lineEdit)
self.horizontalLayout_4.addLayout(self.verticalLayout)
self.verticalLayout_3 = QtWidgets.QVBoxLayout()
self.verticalLayout_3.setObjectName("verticalLayout_3")
self.pushButton_RP = QtWidgets.QPushButton(self.groupBox_3)
self.pushButton_RP.setMaximumSize(QtCore.QSize(40, 29))
font = QtGui.QFont()
font.setPointSize(13)
font.setBold(True)
font.setWeight(75)
self.pushButton_RP.setFont(font)
self.pushButton_RP.setObjectName("pushButton_RP")
self.verticalLayout_3.addWidget(self.pushButton_RP)
self.pushButton_CP = QtWidgets.QPushButton(self.groupBox_3)
self.pushButton_CP.setMaximumSize(QtCore.QSize(40, 29))
font = QtGui.QFont()
font.setPointSize(13)
font.setBold(True)
font.setWeight(75)
self.pushButton_CP.setFont(font)
self.pushButton_CP.setObjectName("pushButton_CP")
self.verticalLayout_3.addWidget(self.pushButton_CP)
self.horizontalLayout_4.addLayout(self.verticalLayout_3)
self.verticalLayout_6 = QtWidgets.QVBoxLayout()
self.verticalLayout_6.setObjectName("verticalLayout_6")
self.pushButton_RM = QtWidgets.QPushButton(self.groupBox_3)
self.pushButton_RM.setMaximumSize(QtCore.QSize(39, 29))
font = QtGui.QFont()
font.setPointSize(13)
font.setBold(True)
font.setWeight(75)
self.pushButton_RM.setFont(font)
self.pushButton_RM.setObjectName("pushButton_RM")
self.verticalLayout_6.addWidget(self.pushButton_RM)
self.pushButton_CM = QtWidgets.QPushButton(self.groupBox_3)
self.pushButton_CM.setMaximumSize(QtCore.QSize(39, 29))
font = QtGui.QFont()
font.setPointSize(13)
font.setBold(True)
font.setWeight(75)
self.pushButton_CM.setFont(font)
self.pushButton_CM.setObjectName("pushButton_CM")
self.verticalLayout_6.addWidget(self.pushButton_CM)
self.horizontalLayout_4.addLayout(self.verticalLayout_6)
self.gridLayout.addLayout(self.horizontalLayout_4, 2, 0, 1, 1)
self.gridLayout_2.addWidget(self.groupBox_3, 2, 0, 1, 1)
self.groupBox_4 = QtWidgets.QGroupBox(self.centralwidget)
self.groupBox_4.setTitle("")
self.groupBox_4.setObjectName("groupBox_4")
self.gridLayout_3 = QtWidgets.QGridLayout(self.groupBox_4)
self.gridLayout_3.setObjectName("gridLayout_3")
self.label_data_loader = QtWidgets.QLabel(self.groupBox_4)
font = QtGui.QFont()
font.setPointSize(11)
self.label_data_loader.setFont(font)
self.label_data_loader.setObjectName("label_data_loader")
self.gridLayout_3.addWidget(self.label_data_loader, 0, 0, 1, 1)
self.comboBox_data_loader = QtWidgets.QComboBox(self.groupBox_4)
self.comboBox_data_loader.setObjectName("comboBox_data_loader")
self.gridLayout_3.addWidget(self.comboBox_data_loader, 1, 0, 1, 1)
self.pushButton = QtWidgets.QPushButton(self.groupBox_4)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.pushButton.sizePolicy().hasHeightForWidth())
self.pushButton.setSizePolicy(sizePolicy)
font = QtGui.QFont()
font.setPointSize(11)
self.pushButton.setFont(font)
self.pushButton.setObjectName("pushButton")
self.gridLayout_3.addWidget(self.pushButton, 2, 0, 1, 1)
self.pushButton_3 = QtWidgets.QPushButton(self.groupBox_4)
font = QtGui.QFont()
font.setPointSize(11)
self.pushButton_3.setFont(font)
self.pushButton_3.setObjectName("pushButton_3")
self.gridLayout_3.addWidget(self.pushButton_3, 3, 0, 1, 1)
self.pushButton_4 = QtWidgets.QPushButton(self.groupBox_4)
font = QtGui.QFont()
font.setPointSize(11)
self.pushButton_4.setFont(font)
self.pushButton_4.setObjectName("pushButton_4")
self.gridLayout_3.addWidget(self.pushButton_4, 4, 0, 1, 1)
self.gridLayout_2.addWidget(self.groupBox_4, 2, 1, 1, 1)
self.groupBox = QtWidgets.QGroupBox(self.centralwidget)
font = QtGui.QFont()
font.setPointSize(11)
self.groupBox.setFont(font)
self.groupBox.setObjectName("groupBox")
self.horizontalLayout_9 = QtWidgets.QHBoxLayout(self.groupBox)
self.horizontalLayout_9.setObjectName("horizontalLayout_9")
self.groupBox_5 = QtWidgets.QGroupBox(self.groupBox)
self.groupBox_5.setTitle("")
self.groupBox_5.setObjectName("groupBox_5")
self.gridLayout_4 = QtWidgets.QGridLayout(self.groupBox_5)
self.gridLayout_4.setObjectName("gridLayout_4")
self.verticalLayout_4 = QtWidgets.QVBoxLayout()
self.verticalLayout_4.setObjectName("verticalLayout_4")
self.Rows_label_2 = QtWidgets.QLabel(self.groupBox_5)
font = QtGui.QFont()
font.setPointSize(11)
self.Rows_label_2.setFont(font)
self.Rows_label_2.setObjectName("Rows_label_2")
self.verticalLayout_4.addWidget(self.Rows_label_2)
self.Columns_label_2 = QtWidgets.QLabel(self.groupBox_5)
font = QtGui.QFont()
font.setPointSize(11)
self.Columns_label_2.setFont(font)
self.Columns_label_2.setObjectName("Columns_label_2")
self.verticalLayout_4.addWidget(self.Columns_label_2)
self.gridLayout_4.addLayout(self.verticalLayout_4, 0, 0, 1, 1)
self.verticalLayout_5 = QtWidgets.QVBoxLayout()
self.verticalLayout_5.setObjectName("verticalLayout_5")
self.Rows_lineEdit_2 = QtWidgets.QLineEdit(self.groupBox_5)
self.Rows_lineEdit_2.setMaximumSize(QtCore.QSize(16777215, 16777215))
self.Rows_lineEdit_2.setObjectName("Rows_lineEdit_2")
self.verticalLayout_5.addWidget(self.Rows_lineEdit_2)
self.Columns_lineEdit_2 = QtWidgets.QLineEdit(self.groupBox_5)
self.Columns_lineEdit_2.setMaximumSize(QtCore.QSize(16777215, 16777215))
self.Columns_lineEdit_2.setObjectName("Columns_lineEdit_2")
self.verticalLayout_5.addWidget(self.Columns_lineEdit_2)
self.gridLayout_4.addLayout(self.verticalLayout_5, 0, 1, 1, 1)
self.horizontalLayout_9.addWidget(self.groupBox_5)
self.groupBox_2 = QtWidgets.QGroupBox(self.groupBox)
self.groupBox_2.setMaximumSize(QtCore.QSize(16777215, 16777215))
font = QtGui.QFont()
font.setPointSize(11)
self.groupBox_2.setFont(font)
self.groupBox_2.setObjectName("groupBox_2")
self.horizontalLayout_8 = QtWidgets.QHBoxLayout(self.groupBox_2)
self.horizontalLayout_8.setObjectName("horizontalLayout_8")
self.comboBox_scale_x = QtWidgets.QComboBox(self.groupBox_2)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.comboBox_scale_x.sizePolicy().hasHeightForWidth())
self.comboBox_scale_x.setSizePolicy(sizePolicy)
self.comboBox_scale_x.setMinimumSize(QtCore.QSize(0, 0))
self.comboBox_scale_x.setMaximumSize(QtCore.QSize(16777215, 16777215))
font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(11)
self.comboBox_scale_x.setFont(font)
self.comboBox_scale_x.setObjectName("comboBox_scale_x")
self.comboBox_scale_x.addItem("")
self.comboBox_scale_x.addItem("")
self.comboBox_scale_x.addItem("")
self.comboBox_scale_x.addItem("")
self.comboBox_scale_x.addItem("")
self.comboBox_scale_x.addItem("")
self.comboBox_scale_x.addItem("")
self.comboBox_scale_x.addItem("")
self.comboBox_scale_x.addItem("")
self.comboBox_scale_x.addItem("")
self.comboBox_scale_x.addItem("")
self.comboBox_scale_x.addItem("")
self.comboBox_scale_x.addItem("")
self.horizontalLayout_8.addWidget(self.comboBox_scale_x)
spacerItem2 = QtWidgets.QSpacerItem(0, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.horizontalLayout_8.addItem(spacerItem2)
self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
self.label_3 = QtWidgets.QLabel(self.groupBox_2)
font = QtGui.QFont()
font.setFamily("Kozuka Gothic Pr6N B")
font.setPointSize(11)
font.setBold(True)
font.setWeight(75)
self.label_3.setFont(font)
self.label_3.setTextFormat(QtCore.Qt.RichText)
self.label_3.setScaledContents(True)
self.label_3.setObjectName("label_3")
self.horizontalLayout_2.addWidget(self.label_3)
self.lineEdit_scale_x_x = QtWidgets.QLineEdit(self.groupBox_2)
self.lineEdit_scale_x_x.setMinimumSize(QtCore.QSize(0, 0))
self.lineEdit_scale_x_x.setMaximumSize(QtCore.QSize(120, 16777215))
font = QtGui.QFont()
font.setPointSize(11)
self.lineEdit_scale_x_x.setFont(font)
self.lineEdit_scale_x_x.setObjectName("lineEdit_scale_x_x")
self.horizontalLayout_2.addWidget(self.lineEdit_scale_x_x)
self.horizontalLayout_8.addLayout(self.horizontalLayout_2)
spacerItem3 = QtWidgets.QSpacerItem(0, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.horizontalLayout_8.addItem(spacerItem3)
self.horizontalLayout = QtWidgets.QHBoxLayout()
self.horizontalLayout.setObjectName("horizontalLayout")
self.label_4 = QtWidgets.QLabel(self.groupBox_2)
font = QtGui.QFont()
font.setFamily("Kozuka Gothic Pr6N B")
font.setPointSize(11)
font.setBold(True)
font.setWeight(75)
self.label_4.setFont(font)
self.label_4.setTextFormat(QtCore.Qt.RichText)
self.label_4.setScaledContents(True)
self.label_4.setObjectName("label_4")
self.horizontalLayout.addWidget(self.label_4)
self.lineEdit_scale_x_plus = QtWidgets.QLineEdit(self.groupBox_2)
self.lineEdit_scale_x_plus.setMaximumSize(QtCore.QSize(107, 16777215))
font = QtGui.QFont()
font.setPointSize(11)
self.lineEdit_scale_x_plus.setFont(font)
self.lineEdit_scale_x_plus.setObjectName("lineEdit_scale_x_plus")
self.horizontalLayout.addWidget(self.lineEdit_scale_x_plus)
self.horizontalLayout_8.addLayout(self.horizontalLayout)
self.pushButton_2 = QtWidgets.QPushButton(self.groupBox_2)
self.pushButton_2.setMaximumSize(QtCore.QSize(16777215, 16777215))
font = QtGui.QFont()
font.setPointSize(11)
self.pushButton_2.setFont(font)
self.pushButton_2.setObjectName("pushButton_2")
self.horizontalLayout_8.addWidget(self.pushButton_2)
self.horizontalLayout_9.addWidget(self.groupBox_2)
self.gridLayout_2.addWidget(self.groupBox, 3, 0, 1, 2)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 601, 21))
self.menubar.setObjectName("menubar")
self.menuSettings = QtWidgets.QMenu(self.menubar)
self.menuSettings.setObjectName("menuSettings")
self.menuFileLoader = QtWidgets.QMenu(self.menuSettings)
self.menuFileLoader.setObjectName("menuFileLoader")
self.menuFunctions = QtWidgets.QMenu(self.menubar)
self.menuFunctions.setObjectName("menuFunctions")
self.menuABC = QtWidgets.QMenu(self.menubar)
self.menuABC.setObjectName("menuABC")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.actionHome_Page = QtWidgets.QAction(MainWindow)
self.actionHome_Page.setObjectName("actionHome_Page")
self.actionHome_Page.setMenuRole(QtWidgets.QAction.NoRole)
self.actionHome_Page_2 = QtWidgets.QAction(MainWindow)
self.actionHome_Page_2.setObjectName("actionHome_Page_2")
self.actionHome_Page_2.setMenuRole(QtWidgets.QAction.NoRole)
self.actionHome_Page_2.triggered.connect(self.open_home_page)
self.menuSettings.addMenu(self.menuFileLoader)
self.menubar.addAction(self.menuSettings.menuAction())
self.menubar.addAction(self.menuFunctions.menuAction())
self.menuABC.addAction(self.actionHome_Page)
self.actionHome_Page.triggered.connect(self.about_gui_command)
self.menuABC.addAction(self.actionHome_Page_2)
self.menubar.addAction(self.menuABC.menuAction())
self.retranslateUi(MainWindow)
self._setup_function_menu()
self._setup_file_loader_menu()
QtCore.QMetaObject.connectSlotsByName(MainWindow)
validator1 = QtGui.QIntValidator(0, 100)
self.Rows_lineEdit_2.setValidator(validator1)
self.Columns_lineEdit_2.setValidator(validator1)
self.Rows_lineEdit_2.setText("0")
self.Columns_lineEdit_2.setText("0")
[docs] def retranslateUi(self, MainWindow):
"""retranslateUi(self, MainWindow) -> None
Configure generated Qt user-interface widgets and signals.
Parameters:
See function signature.
Returns:
None: Result described by the method name and GUI side effects.
"""
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "PhysPlot"))
self.tableWidget.setSortingEnabled(False)
self.pushButton_5.setText(_translate("MainWindow", "New Table"))
self.checkBox_2.setText(_translate("MainWindow", "Delete Old Entries"))
self.Rows_label.setText(_translate("MainWindow", "#Rows:"))
self.Columns_label.setText(_translate("MainWindow", "#Columns:"))
self.pushButton_RP.setText(_translate("MainWindow", "+"))
self.pushButton_CP.setText(_translate("MainWindow", "+"))
self.pushButton_RM.setText(_translate("MainWindow", "-"))
self.pushButton_CM.setText(_translate("MainWindow", "-"))
self.pushButton.setText(_translate("MainWindow", "Import Data"))
self.pushButton_3.setText(_translate("MainWindow", "Export Data"))
self.pushButton_4.setText(_translate("MainWindow", "Generate Plot"))
self.label_data_loader.setText(_translate("MainWindow", "Data Loader:"))
self.groupBox.setTitle(_translate("MainWindow", "Apply Mathematical Transformation to Column"))
self.Rows_label_2.setText(_translate("MainWindow", "Input Col.:"))
self.Columns_label_2.setText(_translate("MainWindow", "Output Col.:"))
self.groupBox_2.setTitle(_translate("MainWindow", "Functions"))
_set_combo_items(self.comboBox_scale_x, SCALE_X_OPTIONS)
self.label_3.setText(_translate("MainWindow", "x"))
self.lineEdit_scale_x_x.setText(_translate("MainWindow", "1"))
self.label_4.setText(_translate("MainWindow", "+"))
self.lineEdit_scale_x_plus.setText(_translate("MainWindow", "0"))
self.pushButton_2.setText(_translate("MainWindow", "Apply"))
self.menuSettings.setTitle(_translate("MainWindow", "Settings"))
self.menuFunctions.setTitle(_translate("MainWindow", "Functions"))
self.menuFileLoader.setTitle(_translate("MainWindow", "File Loader"))
self.menuABC.setTitle(_translate("MainWindow", "Help"))
self.actionHome_Page.setText(_translate("MainWindow", "About"))
self.actionHome_Page_2.setText(_translate("MainWindow", "Documentation"))
self.pushButton.clicked.connect(self.btn_LoadData)
self.pushButton_4.clicked.connect(self.btn_GeneratePlot)
self.pushButton_5.clicked.connect(self.btn_ClearTable)
self.pushButton_3.clicked.connect(self.btn_SaveTable)
self.pushButton_2.clicked.connect(self.readRow)
self.tableWidget.keyPressEvent = self.keyPressEvent
self.pushButton_RP.clicked.connect(self.btn_RP)
self.pushButton_RM.clicked.connect(self.btn_RM)
self.pushButton_CP.clicked.connect(self.btn_CP)
self.pushButton_CM.clicked.connect(self.btn_CM)
validator = QtGui.QDoubleValidator()
self.lineEdit_scale_x_x.setValidator(validator)
self.lineEdit_scale_x_plus.setValidator(validator)
global tableLabels
tableLabels = np.zeros(100)
global xIndex
global uxIndex
global yIndex
global uyIndex
self.btn_ClearTable()
def _setup_file_loader_menu(self):
"""_setup_file_loader_menu(self) -> None
Setup file loader menu.
Parameters:
See function signature.
Returns:
None: Result described by the method name and GUI side effects.
"""
self.file_loader_actions = []
self.active_loader_path = None
self.active_loader_module = None
self._loader_module_cache = {}
self.loader_entries = []
self.menuFileLoader.clear()
self.comboBox_data_loader.blockSignals(True)
self.comboBox_data_loader.clear()
loader_group = QtWidgets.QActionGroup(self.menuFileLoader)
loader_group.setExclusive(True)
loader_files = _discover_loader_files()
if not loader_files:
empty_action = QtWidgets.QAction("No loaders found", self.menuFileLoader)
empty_action.setEnabled(False)
self.menuFileLoader.addAction(empty_action)
self.comboBox_data_loader.addItem("No loaders found")
self.comboBox_data_loader.blockSignals(False)
return
for loader_path in loader_files:
display_name = _loader_display_name(loader_path)
action = QtWidgets.QAction(display_name, self.menuFileLoader)
action.setCheckable(True)
action.setData(str(loader_path))
action.triggered.connect(lambda _checked=False, path=loader_path: self._set_active_loader(path))
loader_group.addAction(action)
self.menuFileLoader.addAction(action)
self.file_loader_actions.append(action)
self.loader_entries.append({"display_name": display_name, "path": loader_path})
self.comboBox_data_loader.addItem(display_name, str(loader_path))
self.comboBox_data_loader.currentIndexChanged.connect(self._on_data_loader_index_changed)
self.comboBox_data_loader.blockSignals(False)
default_loader = next((path for path in loader_files if path.stem == "default_loader"), loader_files[0])
self._set_active_loader(default_loader)
def _on_data_loader_index_changed(self, index):
"""_on_data_loader_index_changed(self, index) -> None
On data loader index changed.
Parameters:
See function signature.
Returns:
None: Result described by the method name and GUI side effects.
"""
if index < 0 or index >= len(getattr(self, "loader_entries", [])):
return
loader_path = self.comboBox_data_loader.itemData(index)
if loader_path:
self._set_active_loader(loader_path)
def _setup_function_menu(self):
"""_setup_function_menu(self) -> None
Setup function menu.
Parameters:
See function signature.
Returns:
None: Result described by the method name and GUI side effects.
"""
self.function_actions = []
self.active_function_path = None
self.active_function_module = None
self._function_module_cache = {}
self.function_entries = []
self.function_lookup = {}
self.menuFunctions.clear()
self.comboBox_scale_x.blockSignals(True)
self.comboBox_scale_x.clear()
function_files = _discover_function_files()
if not function_files:
fallback_items = list(SCALE_X_OPTIONS)
self.comboBox_scale_x.addItems(fallback_items)
self.function_entries = [{"display_name": item, "default_label": item, "path": None, "module": None} for item in fallback_items]
self.function_lookup = {item: None for item in fallback_items}
self.comboBox_scale_x.blockSignals(False)
return
function_group = QtWidgets.QActionGroup(self.menuFunctions)
function_group.setExclusive(True)
for index, function_path in enumerate(function_files):
module = _load_function_module(function_path)
display_name = getattr(module, "DISPLAY_NAME", function_path.stem.replace("_", " ").title())
default_label = getattr(module, "DEFAULT_LABEL", display_name)
self._function_module_cache[str(function_path)] = module
self.function_entries.append(
{
"display_name": display_name,
"default_label": default_label,
"path": function_path,
"module": module,
}
)
self.function_lookup[display_name] = module
action = QtWidgets.QAction(display_name, self.menuFunctions)
action.setCheckable(True)
action.setData(index)
action.triggered.connect(lambda _checked=False, idx=index: self.comboBox_scale_x.setCurrentIndex(idx))
function_group.addAction(action)
self.menuFunctions.addAction(action)
self.function_actions.append(action)
self.comboBox_scale_x.addItems([entry["display_name"] for entry in self.function_entries])
self.comboBox_scale_x.currentIndexChanged.connect(self._sync_function_menu)
self.comboBox_scale_x.blockSignals(False)
if self.function_actions:
self.comboBox_scale_x.setCurrentIndex(0)
self._sync_function_menu(0)
def _sync_function_menu(self, index):
"""_sync_function_menu(self, index) -> None
Sync function menu.
Parameters:
See function signature.
Returns:
None: Result described by the method name and GUI side effects.
"""
for action_index, action in enumerate(getattr(self, "function_actions", [])):
action.setChecked(action_index == index)
def _resolve_function_transform(self, function_name):
"""_resolve_function_transform(self, function_name) -> None
Resolve function transform.
Parameters:
See function signature.
Returns:
None: Result described by the method name and GUI side effects.
"""
function_module = getattr(self, "function_lookup", {}).get(function_name)
if function_module is not None:
return function_module.transform, getattr(function_module, "DEFAULT_LABEL", function_name)
legacy_transforms = {
"x": (lambda values: values, "x"),
"x^2": (lambda values: np.power(values, 2), "x^2"),
"x^3": (lambda values: np.power(values, 3), "x^3"),
"1/x": (lambda values: 1 / values, "1/x"),
"log10(x)": (np.log10, "log10(x)"),
"log(x)": (np.log, "log(x)"),
"e^x": (np.exp, "e^x"),
"cos(x)": (np.cos, "cos(x)"),
"sin(x)": (np.sin, "sin(x)"),
"tan(x)": (np.tan, "tan(x)"),
"arccos(x)": (np.arccos, "arccos(x)"),
"arcsin(x)": (np.arcsin, "arcsin(x)"),
"arctan(x)": (np.arctan, "arctan(x)"),
}
transform, default_label = legacy_transforms.get(function_name, legacy_transforms["x"])
return transform, default_label
def _set_active_loader(self, loader_path):
"""_set_active_loader(self, loader_path) -> None
Set active loader.
Parameters:
See function signature.
Returns:
None: Result described by the method name and GUI side effects.
"""
loader_path = Path(loader_path)
loader_key = str(loader_path)
cached_module = self._loader_module_cache.get(loader_key)
if cached_module is None:
cached_module = _load_loader_module(loader_path)
self._loader_module_cache[loader_key] = cached_module
self.active_loader_path = loader_path
self.active_loader_module = cached_module
for action in getattr(self, "file_loader_actions", []):
action.setChecked(action.data() == loader_key)
combo_index = self.comboBox_data_loader.findData(loader_key)
if combo_index != -1 and self.comboBox_data_loader.currentIndex() != combo_index:
self.comboBox_data_loader.blockSignals(True)
self.comboBox_data_loader.setCurrentIndex(combo_index)
self.comboBox_data_loader.blockSignals(False)
def _load_table_data(self, file_path):
"""_load_table_data(self, file_path) -> None
Load table data.
Parameters:
See function signature.
Returns:
None: Result described by the method name and GUI side effects.
"""
if self.active_loader_module is None:
raise RuntimeError("No file loader is selected.")
table_data = self.active_loader_module.load_data(file_path)
table_data = np.asarray(table_data)
if table_data.ndim == 1:
table_data = np.atleast_2d(table_data).T
if table_data.ndim != 2:
raise ValueError("Loader must return a 2D table-like array.")
return table_data
def _apply_loader_column_roles(self, column_count):
"""_apply_loader_column_roles(self, column_count) -> None
Apply loader column roles.
Parameters:
See function signature.
Returns:
None: Result described by the method name and GUI side effects.
"""
global tableLabels
tableLabels = np.zeros(100)
roles = getattr(self.active_loader_module, "DEFAULT_COLUMN_ROLES", [])
for column, role_name in enumerate(roles[:column_count]):
role_value = _role_index(role_name)
combo = self.tableWidget.cellWidget(0, column)
if combo is not None:
combo.setCurrentIndex(role_value)
else:
self.btn_combobox_changed(role_value, column)
[docs] def keyPressEvent(self, e):
"""keyPressEvent(self, e) -> None
Keypressevent.
Parameters:
See function signature.
Returns:
None: Result described by the method name and GUI side effects.
"""
if e.key() == Qt.Key_Delete:
self.delRows()
self.Rows_lineEdit.setText(str(self.tableWidget.rowCount()))
self.Columns_lineEdit.setText(str(self.tableWidget.columnCount()))
else:
e.ignore()
[docs] def delRows(self):
"""delRows(self) -> None
Delrows.
Parameters:
See function signature.
Returns:
None: Result described by the method name and GUI side effects.
"""
indices = self.tableWidget.selectionModel().selectedRows()
for index in sorted(indices, reverse=True):
if index != 0:
self.tableWidget.removeRow(index.row())
[docs] def shiftVal(self):
"""shiftVal(self) -> None
Shiftval.
Parameters:
See function signature.
Returns:
None: Result described by the method name and GUI side effects.
"""
if int(self.Rows_lineEdit_2.text()) > int(self.tableWidget.rowCount()):
self.Rows_lineEdit_2.setText("0")
if int(self.Columns_lineEdit_2.text()) > int(self.tableWidget.columnCount()):
self.Columns_lineEdit_2.setText("0")
[docs] def btn_RP(self):
"""btn_RP(self) -> None
Handle the matching GUI button action.
Parameters:
See function signature.
Returns:
None: Result described by the method name and GUI side effects.
"""
self.tableWidget.setRowCount(self.tableWidget.rowCount() + 1)
self.Rows_lineEdit.setText(str(self.tableWidget.rowCount()))
[docs] def btn_RM(self):
"""btn_RM(self) -> None
Handle the matching GUI button action.
Parameters:
See function signature.
Returns:
None: Result described by the method name and GUI side effects.
"""
if int(self.tableWidget.rowCount()) > 4:
self.tableWidget.setRowCount(self.tableWidget.rowCount() - 1)
self.Rows_lineEdit.setText(str(self.tableWidget.rowCount()))
[docs] def btn_CP(self):
"""btn_CP(self) -> None
Handle the matching GUI button action.
Parameters:
See function signature.
Returns:
None: Result described by the method name and GUI side effects.
"""
self.tableWidget.setColumnCount(self.tableWidget.columnCount() + 1)
self.Columns_lineEdit.setText(str(self.tableWidget.columnCount()))
combo = QtWidgets.QComboBox()
_set_combo_items(combo, AXIS_ROLE_OPTIONS)
self.tableWidget.setCellWidget(0, self.tableWidget.columnCount() - 1, combo)
column = self.tableWidget.columnCount() - 1
self.tableWidget.cellWidget(0, column).currentIndexChanged.connect(
lambda value, col=column: self.btn_combobox_changed(value, col))
self.shiftVal()
[docs] def btn_CM(self):
"""btn_CM(self) -> None
Handle the matching GUI button action.
Parameters:
See function signature.
Returns:
None: Result described by the method name and GUI side effects.
"""
if int(self.tableWidget.columnCount()) > 2:
# print("CM", self.tableWidget.columnCount())
tableLabels[self.tableWidget.columnCount():99] = 0
self.tableWidget.setColumnCount(self.tableWidget.columnCount() - 1)
self.Columns_lineEdit.setText(str(self.tableWidget.columnCount()))
self.shiftVal()
[docs] def readRow(self):
"""readRow(self) -> None
Read transform input/output column choices and apply the transform.
Parameters:
self (Ui_MainWindow): Active main window UI instance.
Returns:
None
"""
if (int(self.Rows_lineEdit_2.text()) <= int(self.tableWidget.rowCount())) and (
int(self.Columns_lineEdit_2.text()) <= int(self.tableWidget.columnCount())) and (
int(self.Rows_lineEdit_2.text()) > 0) and (int(self.Columns_lineEdit_2.text()) > 0):
# print("Condition True")
global inputRow
global outputRow
inputRow = int(self.Rows_lineEdit_2.text()) - 1
outputRow = int(self.Columns_lineEdit_2.text()) - 1
self.readTableRow()
self.writeTableRow()
[docs] def readTableRow(self):
"""readTableRow(self) -> None
Readtablerow.
Parameters:
See function signature.
Returns:
None: Result described by the method name and GUI side effects.
"""
global xFormula
global yFormula
global xTimes
global yTimes
global xPlus
global yPlus
xFormula = self.comboBox_scale_x.currentText()
transform, _default_label = self._resolve_function_transform(xFormula)
xTimes = np.double(self.lineEdit_scale_x_x.text())
xPlus = np.double(self.lineEdit_scale_x_plus.text())
try:
global rowData
data_rows = self.tableWidget.rowCount() - 1
rowData = np.array([
table_item_float(self.tableWidget, row + 1, inputRow)
for row in range(data_rows)
], dtype=float)
rowData = transform(rowData) * xTimes + xPlus
except Exception as e:
self.errMessage("readTableRow:", str(e))
[docs] def writeTableRow(self):
"""writeTableRow(self) -> None
Writetablerow.
Parameters:
See function signature.
Returns:
None: Result described by the method name and GUI side effects.
"""
try:
for row, value in enumerate(rowData, start=1):
self.tableWidget.setItem(row, outputRow, QTableWidgetItem(str(np.round(value, 6))))
input_role = int(tableLabels[inputRow]) if inputRow < len(tableLabels) else 0
if input_role in {1, 2, 3, 4}:
input_combo = self.tableWidget.cellWidget(0, inputRow)
output_combo = self.tableWidget.cellWidget(0, outputRow)
if input_combo is not None:
input_combo.setCurrentIndex(0)
if output_combo is not None:
output_combo.setCurrentIndex(input_role)
else:
self.btn_combobox_changed(input_role, outputRow)
except Exception as e:
self.errMessage("writeTableRow:", str(e))
[docs] def btn_LoadData(self):
"""btn_LoadData(self) -> None
Load a selected dataset file and print values to the table.
Parameters:
self (Ui_MainWindow): Active main window UI instance.
Returns:
None
"""
self.file_picker = pick_file_to_append()
if files:
try:
table_data = self._load_table_data(files)
self.printTOTable(table_data)
except Exception as e:
self.errMessage("Loading Data:", str(e))
[docs] def printTOTable(self, table_data): # Prints data file to table
"""printTOTable(self, table_data) -> None
Printtotable.
Parameters:
See function signature.
Returns:
None: Result described by the method name and GUI side effects.
"""
try:
global tableDimensions
global data
data = np.asarray(table_data)
tableDimensions = [int(data.shape[0]) + 1, int(data.shape[1])]
self.tableWidget.setRowCount(data.shape[0] + 1)
self.tableWidget.setColumnCount(data.shape[1])
for row in range(data.shape[1]):
combo = QtWidgets.QComboBox()
_set_combo_items(combo, AXIS_ROLE_OPTIONS)
self.tableWidget.setCellWidget(0, row, combo)
self._wire_role_combos(data.shape[1])
self._apply_loader_column_roles(data.shape[1])
for column in range(data.shape[1]):
for row in range(data.shape[0]):
self.tableWidget.setItem(row + 1, column, QTableWidgetItem(str(data[row, column])))
self.Columns_lineEdit.setText(str(self.tableWidget.columnCount()))
self.Rows_lineEdit.setText(str(self.tableWidget.rowCount()))
except Exception as e:
self.errMessage("Printing to Table:", str(e))
[docs] def btn_combobox_index(self, value):
"""btn_combobox_index(self, value) -> None
Handle the matching GUI button action.
Parameters:
See function signature.
Returns:
None: Result described by the method name and GUI side effects.
"""
global plot_AxisIndex
plot_AxisIndex = value
# print("btn_combobox_index:", plot_AxisIndex)
[docs] def btn_combobox_changed(self, value, column=None):
"""btn_combobox_changed(self, value, column) -> None
Handle the matching GUI button action.
Parameters:
See function signature.
Returns:
None: Result described by the method name and GUI side effects.
"""
global combobox_Val
btn_combobox_Val = value
if column is None:
column = plot_AxisIndex
if value == 1:
global xIndex
xIndex = column
if value == 2:
global uxIndex
uxIndex = column
if value == 3:
global yIndex
yIndex = column
if value == 4:
global uyIndex
uyIndex = column
tableLabels[int(column)] = int(value)
def _wire_role_combos(self, column_count):
"""_wire_role_combos(self, column_count) -> None
Wire role combos.
Parameters:
See function signature.
Returns:
None: Result described by the method name and GUI side effects.
"""
limit = column_count
if 'tableLabels' in globals():
limit = min(column_count, len(tableLabels))
for column in range(limit):
combo = self.tableWidget.cellWidget(0, column)
if combo is not None:
combo.currentIndexChanged.connect(lambda value, col=column: self.btn_combobox_changed(value, col))
[docs] def btn_ClearTable(self):
"""btn_ClearTable(self) -> None
Reset table dimensions/content and recreate axis-role combobox headers.
Parameters:
self (Ui_MainWindow): Active main window UI instance.
Returns:
None
"""
##print("Clear Table")
# self.Rows_lineEdit.text()
# self.Columns_lineEdit.text()
self.tableWidget.setRowCount(int(self.Rows_lineEdit.text()))
self.tableWidget.setColumnCount(int(self.Columns_lineEdit.text()))
global tableLabels
global tableDimensions
tableLabels = np.zeros(100)
tableDimensions = [int(self.Rows_lineEdit.text()), int(self.Columns_lineEdit.text())]
##print("tableDimensions set to:", tableDimensions[0],"R, ", tableDimensions[1],"C")
if self.checkBox_2.isChecked() == True:
for column in range(int(self.Columns_lineEdit.text())):
for row in range(1, int(self.Rows_lineEdit.text()) + 1):
self.tableWidget.setItem(row, column, QtWidgets.QTableWidgetItem(""))
for col in range(tableDimensions[1]):
combo = QtWidgets.QComboBox()
_set_combo_items(combo, AXIS_ROLE_OPTIONS)
# self.tableWidget.setItem(data.shape[1], data.shape[0], cellinfo)
self.tableWidget.setCellWidget(0, col, combo)
self._wire_role_combos(tableDimensions[1])
[docs] def btn_SaveTable(self):
"""btn_SaveTable(self) -> None
Read the current table and open the export save-file dialog.
Parameters:
self (Ui_MainWindow): Active main window UI instance.
Returns:
None
"""
##print("Save Table")
self.readTable()
self.save_dialog = SaveFile()
[docs] def readTable(self):
"""readTable(self) -> None
Readtable.
Parameters:
See function signature.
Returns:
None: Result described by the method name and GUI side effects.
"""
try:
global OutPut_Table
tableDimensions = [int(self.tableWidget.rowCount()), int(self.tableWidget.columnCount())]
OutPut_Table = np.array([
[
table_item_float(self.tableWidget, row + 1, column)
for column in range(tableDimensions[1])
]
for row in range(tableDimensions[0] - 1)
], dtype=float)
# print(OutPut_Table)
except Exception as e:
self.errMessage("Reading Table:", str(e))
[docs] def pltConfigWindow(self):
"""pltConfigWindow(self) -> None
Pltconfigwindow.
Parameters:
See function signature.
Returns:
None: Result described by the method name and GUI side effects.
"""
self.Ui_ConfigWindow = QtWidgets.QMainWindow()
self.ui = Ui_ConfigWindow()
self.ui.setupUiConfigWindow(self.Ui_ConfigWindow)
self.ui.owner = self
self.Ui_ConfigWindow.show()
[docs] def btn_GeneratePlot(self):
"""btn_GeneratePlot(self) -> None
Validate axis selections and open configuration and plot windows.
Parameters:
self (Ui_MainWindow): Active main window UI instance.
Returns:
None
"""
self.readTable()
try:
if np.count_nonzero(tableLabels == 1) == 1 and np.count_nonzero(tableLabels == 3) == 1:
self.pltConfigWindow()
self.plot_window = Plot_Window(getattr(self, "_main_window", None))
self.plot_window.show()
else:
self.errMessage("The inappropriate combination is selected from the dropdown buttons on the table.",
"Possible Solution: Click on 'New Table' button with 'Delete Old Entries' button unchecked and select the proper labels combination.")
except Exception as e:
self.errMessage("Generating Plot:", str(e))
[docs] def about_gui_command(self):
"""about_gui_command(self) -> None
About gui command.
Parameters:
See function signature.
Returns:
None: Result described by the method name and GUI side effects.
"""
self.about_window = about_gui()
[docs] def open_home_page(self):
"""open_home_page(self) -> None
Open home page.
Parameters:
See function signature.
Returns:
None: Result described by the method name and GUI side effects.
"""
webbrowser.open('https://physplot.readthedocs.io/', new=2)
[docs] def errMessage(self, Text, InformativeText):
"""errMessage(self, Text, InformativeText) -> None
Errmessage.
Parameters:
See function signature.
Returns:
None: Result described by the method name and GUI side effects.
"""
msgBox = QMessageBox()
msgBox.setWindowIcon(QtGui.QIcon(str(APP_ICON_PATH)))
msgBox.setWindowTitle("PhysPlot - Plot Window")
msgBox.setIcon(QMessageBox.Critical)
msgBox.setText(Text)
msgBox.setInformativeText(InformativeText)
msgBox.setWindowTitle("Warning")
msgBox.exec_()
if __name__ == "__main__":
project_root = Path(__file__).resolve().parent.parent
if str(project_root) not in sys.path:
sys.path.insert(0, str(project_root))
from physplot.runner import run_app
run_app()