Skip to content

Commit

Permalink
Merge branch 'main' into ticket-2237-cli-2
Browse files Browse the repository at this point in the history
  • Loading branch information
butlerpd authored Mar 14, 2023
2 parents efe6564 + b956b61 commit de26080
Show file tree
Hide file tree
Showing 21 changed files with 595 additions and 176 deletions.
19 changes: 10 additions & 9 deletions src/sas/qtgui/MainWindow/DataExplorer.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

from sas.qtgui.Plotting.PlotterData import Data1D
from sas.qtgui.Plotting.PlotterData import Data2D
from sas.qtgui.Plotting.PlotterData import DataRole
from sas.qtgui.Plotting.Plotter import Plotter
from sas.qtgui.Plotting.Plotter2D import Plotter2D
from sas.qtgui.Plotting.MaskEditor import MaskEditor
Expand Down Expand Up @@ -1043,7 +1044,7 @@ def displayDataByName(self, name=None, is_data=True, id=None):
or name in plot.name
or name == plot.filename):
# Residuals get their own plot
if plot.plot_role == Data1D.ROLE_RESIDUAL:
if plot.plot_role in [DataRole.ROLE_RESIDUAL, DataRole.ROLE_STAND_ALONE]:
plot.yscale = 'linear'
self.plotData([(item, plot)])
else:
Expand Down Expand Up @@ -1090,13 +1091,13 @@ def displayData(self, data_list, id=None):

plot_name = plot_to_show.name
role = plot_to_show.plot_role
stand_alone_types = [DataRole.ROLE_RESIDUAL, DataRole.ROLE_STAND_ALONE]

if (role == Data1D.ROLE_RESIDUAL and shown) or role == Data1D.ROLE_DELETABLE:
# Nothing to do if separate plot already shown or to be deleted
if (role in stand_alone_types and shown) or role == DataRole.ROLE_DELETABLE:
# Nothing to do if stand-alone plot already shown or plot to be deleted
continue
elif role == Data1D.ROLE_RESIDUAL:
# Residual plots should always be separate
plot_to_show.yscale='linear'
elif role in stand_alone_types:
# Stand-alone plots should always be separate
self.plotData([(plot_item, plot_to_show)])
elif append:
# Assume all other plots sent together should be on the same chart if a previous plot exists
Expand Down Expand Up @@ -1128,7 +1129,7 @@ def isPlotShown(self, plot):
if not hasattr(plot, 'name'):
return False
ids_vals = [val.data[0].name for val in self.active_plots.values()]
#if val.data[0].plot_role != Data1D.ROLE_DATA]
#if val.data[0].plot_role != DataRole.ROLE_DATA]

return plot.name in ids_vals

Expand Down Expand Up @@ -1271,13 +1272,13 @@ def updatePlot(self, data):
data_id = data.name
if data_id in ids_keys:
# We have data, let's replace data that needs replacing
if data.plot_role != Data1D.ROLE_DATA:
if data.plot_role != DataRole.ROLE_DATA:
self.active_plots[data_id].replacePlot(data_id, data)
# restore minimized window, if applicable
self.active_plots[data_id].showNormal()
return True
#elif data_id in ids_vals:
# if data.plot_role != Data1D.ROLE_DATA:
# if data.plot_role != DataRole.ROLE_DATA:
# list(self.active_plots.values())[ids_vals.index(data_id)].replacePlot(data_id, data)
# self.active_plots[data_id].showNormal()
# return True
Expand Down
4 changes: 2 additions & 2 deletions src/sas/qtgui/MainWindow/DataManager.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
from io import BytesIO
import numpy as np

from sas.qtgui.Plotting.PlotterData import Data1D
from sas.qtgui.Plotting.PlotterData import Data1D, DataRole
from sas.qtgui.Plotting.PlotterData import Data2D
from sas.qtgui.Plotting.Plottables import PlottableTheory1D
from sas.qtgui.Plotting.Plottables import PlottableFit1D
Expand Down Expand Up @@ -128,7 +128,7 @@ def create_gui_data(self, data, path=None):
new_plot.path = path
new_plot.list_group_id = []
# Assign the plot role to data
new_plot.plot_role = Data1D.ROLE_DATA
new_plot.plot_role = DataRole.ROLE_DATA
##post data to plot
# plot data
return new_plot
Expand Down
19 changes: 9 additions & 10 deletions src/sas/qtgui/MainWindow/UnitTesting/DataExplorerTest.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from mpl_toolkits.mplot3d import Axes3D

# Local
from sas.qtgui.Plotting.PlotterData import Data1D, Data2D
from sas.qtgui.Plotting.PlotterData import Data1D, Data2D, DataRole
from sasdata.dataloader.loader import Loader
from sas.qtgui.MainWindow.DataManager import DataManager

Expand Down Expand Up @@ -1132,7 +1132,6 @@ def testClosePlotsForItem(self, form):
assert len(PlotHelper.currentPlotIds()) == 0
assert len(form.plot_widgets) == 0

@pytest.mark.xfail(reason="2022-09 already broken")
def testPlotsFromMultipleData1D(self, form):
"""
Tests interplay between plotting 1D datasets and plotting
Expand All @@ -1143,19 +1142,19 @@ def testPlotsFromMultipleData1D(self, form):
plot1 = Plotter(parent=form)
data1 = Data1D()
data1.name = 'p1'
data1.plot_role = Data1D.ROLE_DATA
data1.plot_role = DataRole.ROLE_DATA
plot1.data = data1

plot2 = Plotter(parent=form)
data2 = Data1D()
data2.name = 'M2 [p1]'
data2.plot_role = Data1D.ROLE_DEFAULT
data2.plot_role = DataRole.ROLE_DEFAULT
plot2.data = data2

plot3 = Plotter(parent=form)
data3 = Data1D()
data3.name = 'Residuals for M2[p1]'
data3.plot_role = Data1D.ROLE_RESIDUAL
data3.plot_role = DataRole.ROLE_RESIDUAL
plot3.data = data3

# pretend we're displaying three plots
Expand All @@ -1165,7 +1164,7 @@ def testPlotsFromMultipleData1D(self, form):

# redoing plots from the same tab
# data -> must be shown
assert not form.isPlotShown(data1)
assert form.isPlotShown(data1)

# model and residuals are already shown
assert form.isPlotShown(data2)
Expand All @@ -1175,7 +1174,7 @@ def testPlotsFromMultipleData1D(self, form):
plot4 = Plotter(parent=form)
data4 = Data1D()
data4.name = 'M1 [p1]'
data4.plot_role = Data1D.ROLE_DEFAULT
data4.plot_role = DataRole.ROLE_DEFAULT
plot4.data = data1
# same data but must show, since different model
assert not form.isPlotShown(data4)
Expand All @@ -1190,19 +1189,19 @@ def testPlotsFromMultipleData2D(self, form):
plot1 = Plotter(parent=form)
data1 = Data2D()
data1.name = 'p1'
data1.plot_role = Data1D.ROLE_DATA
data1.plot_role = DataRole.ROLE_DATA
plot1.data = data1

plot2 = Plotter(parent=form)
data2 = Data2D()
data2.name = 'M2 [p1]'
data2.plot_role = Data1D.ROLE_DEFAULT
data2.plot_role = DataRole.ROLE_DEFAULT
plot2.data = data2

plot3 = Plotter(parent=form)
data3 = Data2D()
data3.name = 'Residuals for M2[p1]'
data3.plot_role = Data1D.ROLE_RESIDUAL
data3.plot_role = DataRole.ROLE_RESIDUAL
plot3.data = data3

# pretend we're displaying three plots
Expand Down
65 changes: 56 additions & 9 deletions src/sas/qtgui/Perspectives/Corfunc/CorfuncPerspective.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from numpy.linalg.linalg import LinAlgError


from typing import Optional, List, Tuple
from typing import Optional, List, Tuple, Callable

import logging

Expand All @@ -22,20 +22,20 @@
from sas.qtgui.Perspectives.Corfunc.CorfunSlider import CorfuncSlider
from sas.qtgui.Perspectives.Corfunc.QSpaceCanvas import QSpaceCanvas
from sas.qtgui.Perspectives.Corfunc.RealSpaceCanvas import RealSpaceCanvas
from sas.qtgui.Perspectives.Corfunc.ExtractionCanvas import ExtractionCanvas
from sas.qtgui.Perspectives.Corfunc.IDFCanvas import IDFCanvas
from sas.sascalc.corfunc.extrapolation_data import ExtrapolationParameters, ExtrapolationInteractionState

import sas.qtgui.Utilities.GuiUtils as GuiUtils
from sas.qtgui.Utilities.Reports.reportdata import ReportData
from sas.qtgui.Utilities.Reports import ReportBase
from sas.qtgui.Plotting.PlotterData import Data1D

from sas.sascalc.corfunc.corfunc_calculator import CorfuncCalculator
# pylint: enable=import-error, no-name-in-module
from sas.sascalc.corfunc.extrapolation_data import ExtrapolationParameters, ExtrapolationInteractionState
from sas.sascalc.corfunc.calculation_data import TransformedData, TangentMethod, LongPeriodMethod

# local
from .UI.CorfuncPanel import Ui_CorfuncDialog
from .util import WIDGETS, safe_float, TransformedData
from .util import WIDGETS, safe_float
from .SaveExtrapolatedPopup import SaveExtrapolatedPopup
from ..perspective import Perspective

Expand Down Expand Up @@ -75,6 +75,8 @@ def __init__(self, parent=None):
self.txtLowerQMin.setText("0.0")
self.txtLowerQMin.setEnabled(False)
self.extrapolation_curve = None
self.long_period_method: Optional[LongPeriodMethod] = None
self.tangent_method: Optional[TangentMethod] = None

# Add slider widget
self.slider = CorfuncSlider()
Expand All @@ -89,6 +91,10 @@ def __init__(self, parent=None):
self.realSpaceLayout.insertWidget(0, self._real_space_plot)
self.realSpaceLayout.insertWidget(1, NavigationToolbar2QT(self._real_space_plot, self))

self._extraction_plot = ExtractionCanvas(self)
self.diagramLayout.insertWidget(0, self._extraction_plot)
self.diagramLayout.insertWidget(1, NavigationToolbar2QT(self._extraction_plot, self))

self._idf_plot = IDFCanvas(self)
self.idfLayout.insertWidget(0, self._idf_plot)
self.idfLayout.insertWidget(1, NavigationToolbar2QT(self._idf_plot, self))
Expand Down Expand Up @@ -150,6 +156,16 @@ def setup_slots(self):
self.txtUpperQMax.textEdited.connect(self.on_extrapolation_text_changed_3)
self.set_text_enable(False)

# Calculation Options
self.radTangentAuto.clicked.connect(self.set_tangent_method(None))
self.radTangentInflection.clicked.connect(self.set_tangent_method(TangentMethod.INFLECTION))
self.radTangentMidpoint.clicked.connect(self.set_tangent_method(TangentMethod.HALF_MIN))

self.radLongPeriodAuto.clicked.connect(self.set_long_period_method(None))
self.radLongPeriodMax.clicked.connect(self.set_long_period_method(LongPeriodMethod.MAX))
self.radLongPeriodDouble.clicked.connect(self.set_long_period_method(LongPeriodMethod.DOUBLE_MIN))

# Slider values
self.slider.valueEdited.connect(self.on_extrapolation_slider_changed)
self.slider.valueEditing.connect(self.on_extrapolation_slider_changing)

Expand All @@ -161,6 +177,20 @@ def set_text_enable(self, state: bool):
self.txtUpperQMin.setEnabled(state)
self.txtUpperQMax.setEnabled(state)

def set_long_period_method(self, value: Optional[LongPeriodMethod]) -> Callable[[bool], None]:
""" Function to set the long period method"""
def setter_function(state: bool):
self.long_period_method = value

return setter_function

def set_tangent_method(self, value: Optional[TangentMethod]) -> Callable[[bool], None]:
""" Function to set the tangent method"""
def setter_function(state: bool):
self.tangent_method = value

return setter_function

def setup_model(self):
"""Populate the model with default data."""
# filename
Expand Down Expand Up @@ -274,14 +304,21 @@ def transform(self):

extrap = self.extrap
background = float(self.model.item(WIDGETS.W_BACKGROUND).text())
q_range = self.data.x[0], self.data.x[-1]

def updatefn(msg):
"""Report progress of transformation."""
self.communicate.statusBarUpdateSignal.emit(msg)

def completefn(transformed_data: Tuple[Data1D, Data1D, Data1D]):
def completefn(transform_result: Tuple[Data1D, Data1D, Data1D]):
"""Extract the values from the transforms and plot"""
self.trigger.emit(TransformedData(*transformed_data)) # TODO: Make this return more structured data earlier
td = TransformedData(
gamma_1=transform_result[0],
gamma_3=transform_result[1],
idf=transform_result[2],
q_range=q_range)

self.trigger.emit(td) # TODO: Make this return more structured data earlier

self._update_calculator()
self._calculator.compute_transform(extrap, method, background,
Expand All @@ -295,6 +332,7 @@ def finish_transform(self, data: TransformedData):
self.transformed_data = data

self._real_space_plot.data = data.gamma_1, data.gamma_3
self._extraction_plot.data = data.gamma_1

# self.update_real_space_plot(transforms)

Expand All @@ -310,9 +348,16 @@ def extract(self):
if self.transformed_data is None:
return

params = self._calculator.extract_parameters(self.transformed_data[0])
extracted = self._calculator.extract_parameters(
transformed_data=self.transformed_data,
long_period_method=self.long_period_method,
tangent_method=self.tangent_method)

if params is not None:
if extracted is not None:

params, supp = extracted

self._extraction_plot.supplementary = supp

self.model.itemChanged.disconnect(self.model_changed)

Expand All @@ -328,6 +373,8 @@ def extract(self):
self.model.itemChanged.connect(self.model_changed)
self.model_changed(None)

self.tabWidget.setCurrentIndex(2)


def setup_mapper(self):
"""Creating mapping between model and gui elements."""
Expand Down
Loading

0 comments on commit de26080

Please sign in to comment.