From ce04ace4329ab9a00f9579fc6bcbb12c01517ec3 Mon Sep 17 00:00:00 2001 From: Marius Retegan Date: Thu, 26 Sep 2024 18:59:54 +0200 Subject: [PATCH] Add external data loading --- src/crispy/__main__.py | 29 ++++++++++++++++++++++++---- src/crispy/quanty/details.py | 7 +++++++ src/crispy/quanty/external.py | 17 +++++++++++++++++ src/crispy/quanty/main.py | 36 ++++++++++++++++++++++++----------- 4 files changed, 74 insertions(+), 15 deletions(-) create mode 100644 src/crispy/quanty/external.py diff --git a/src/crispy/__main__.py b/src/crispy/__main__.py index dbe5006..6db5d49 100644 --- a/src/crispy/__main__.py +++ b/src/crispy/__main__.py @@ -10,6 +10,7 @@ import json import logging +import numpy as np import os import socket import sys @@ -32,6 +33,7 @@ Qt, QThread, QProcess, + QFileDialog, pyqtSignal, ) @@ -84,10 +86,15 @@ def __init__(self, parent=None): menu.addAction(self.quantyDockWidget.showHideAction) menu = self.menuBar().addMenu("Tools") - self.runJupyterAction = QAction( - "Start Jupyter Lab", self, triggered=self.runJupyter + self.loadExternalDataAction = QAction( + "Load External Data", self, triggered=self.loadExternalData ) - menu.addAction(self.runJupyterAction) + menu.addAction(self.loadExternalDataAction) + + self.runJupyterLabAction = QAction( + "Start Jupyter Lab", self, triggered=self.runJupyterLab + ) + menu.addAction(self.runJupyterLabAction) menu = self.menuBar().addMenu("Help") self.openAboutDialogAction = QAction( @@ -151,7 +158,21 @@ def saveSettings(self): def openAboutDialog(self): self.aboutDialog.exec() - def runJupyter(self): + def loadExternalData(self): + dialog = QFileDialog() + path, _ = dialog.getOpenFileName(self, "Select File") + + if path: + try: + x, y = np.loadtxt(path, unpack=True) + except ValueError: + logger.error(f"Failed to load data from {path}") + return + + name = os.path.splitext(os.path.basename(path))[0] + self.quantyDockWidget.addExternalData(name, x, y) + + def runJupyterLab(self): process = QProcess() process.setProgram("jupyter-lab") process.setArguments([f"--notebook-dir={os.path.expanduser('~')}"]) diff --git a/src/crispy/quanty/details.py b/src/crispy/quanty/details.py index 36dd1dc..a4b48c5 100644 --- a/src/crispy/quanty/details.py +++ b/src/crispy/quanty/details.py @@ -16,6 +16,7 @@ from crispy.config import Config from crispy.uic import loadUi from crispy.utils import fixedFont, setMappings +from crispy.quanty.external import ExternalData settings = Config().read() @@ -93,6 +94,12 @@ def clear(self): def populate(self, result): self.clear() + if isinstance(result, ExternalData): + self.spectraView.setModel(result.model()) + index = result.model().indexFromItem(result) + self.spectraView.setRootIndex(index) + return + if result is None: return diff --git a/src/crispy/quanty/external.py b/src/crispy/quanty/external.py new file mode 100644 index 0000000..485ae11 --- /dev/null +++ b/src/crispy/quanty/external.py @@ -0,0 +1,17 @@ +import logging +from crispy.items import SelectableItem + +logger = logging.getLogger(__name__) + + +class ExternalData(SelectableItem): + def __init__(self, parent=None, name="Experiment", x=None, y=None): + super().__init__(parent=parent, name=name) + self.x = x + self.y = y + self.enable() + + def plot(self, plotWidget): + index = self.childPosition() + legend = f"{index + 1}-{self.name}" + plotWidget.addCurve(self.x, self.y, legend=legend) diff --git a/src/crispy/quanty/main.py b/src/crispy/quanty/main.py index 4f3a692..4a95f31 100644 --- a/src/crispy/quanty/main.py +++ b/src/crispy/quanty/main.py @@ -31,6 +31,7 @@ from crispy.models import TreeModel from crispy.quanty.calculation import Calculation from crispy.quanty.details import DetailsDialog +from crispy.quanty.external import ExternalData from crispy.quanty.preferences import PreferencesDialog from crispy.quanty.progress import ProgressDialog from crispy.uic import loadUi @@ -331,12 +332,12 @@ def load(self): pass def plot(self, *args): - calculations = self.model.rootItem().children() + children = self.model.rootItem().children() index, *_ = args # Return if the index is invalid but there are still calculations in # the model. - if not index.isValid() and calculations: + if not index.isValid() and children: return # Get the last item the user has changed. last = index.internalPointer() @@ -345,29 +346,34 @@ def plot(self, *args): plotWidget = findQtObject(name="plotWidget") plotWidget.reset() - if not calculations: + if not children: return if isinstance(last, Calculation): self.model.blockSignals(True) - for calculation in calculations: + for child in children: + if isinstance(child, ExternalData): + continue if ( last.experiment.isTwoDimensional - and last != calculation + and last != child or not last.experiment.isTwoDimensional - and calculation.experiment.isTwoDimensional + and child.experiment.isTwoDimensional ): - calculation.checkState = Qt.CheckState.Unchecked + child.checkState = Qt.CheckState.Unchecked self.model.blockSignals(False) # Remove the calculations that are not checked. - calculations = [c for c in calculations if c.isEnabled()] + children = [c for c in children if c.isEnabled()] - if not calculations: + if not children: return - for calculation in calculations: - calculation.spectra.plot(plotWidget) + for child in children: + if isinstance(child, Calculation): + child.spectra.plot(plotWidget) + elif isinstance(child, ExternalData): + child.plot(plotWidget) # Reset the plot widget if nothing new was plotted. if plotWidget.isEmpty(): @@ -494,6 +500,8 @@ def populate(self, index=None): child.setParent(None) result = index.internalPointer() if index is not None else None + if isinstance(result, ExternalData): + return if result is not None: symbol = result.element.symbol @@ -538,6 +546,12 @@ def populate(self, index=None): self.state = state logger.debug("Finished populating the widgets.") + def addExternalData(self, name, x, y): + parent = self.resultsPage.model.rootItem() + experiment = ExternalData(parent, name, x, y) + index = experiment.index() + self.resultsPage.view.setCurrentIndex(index) + def run(self): progress = ProgressDialog(self) progress.rejected.connect(self.state.stop)