diff --git a/src/sas/qtgui/MainWindow/DataExplorer.py b/src/sas/qtgui/MainWindow/DataExplorer.py index 3484817a6b..486a80ed2e 100644 --- a/src/sas/qtgui/MainWindow/DataExplorer.py +++ b/src/sas/qtgui/MainWindow/DataExplorer.py @@ -1123,18 +1123,17 @@ 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, DataRole.ROLE_POLYDISPERSITY] - if (role in stand_alone_types and shown) or role == DataRole.ROLE_DELETABLE: + if (role.stand_alone and shown) or role == DataRole.ROLE_DELETABLE: # Nothing to do if stand-alone plot already shown or plot to be deleted continue - elif role == DataRole.ROLE_RESIDUAL and config.DISABLE_RESIDUAL_PLOT: + elif role in [DataRole.ROLE_RESIDUAL, DataRole.ROLE_RESIDUAL_SESANS] and config.DISABLE_RESIDUAL_PLOT: # Nothing to do if residuals are not plotted continue - elif role == DataRole.ROLE_POLYDISPERSITY and config.DISABLE_POLYDISPERSITY_PLOT: + elif role in [DataRole.ROLE_POLYDISPERSITY] and config.DISABLE_POLYDISPERSITY_PLOT: # Nothing to do if polydispersity plot is not plotted continue - elif role in stand_alone_types: + elif role.stand_alone: # Stand-alone plots should always be separate self.plotData([(plot_item, plot_to_show)]) elif append: @@ -1200,15 +1199,13 @@ def plotData(self, plots, transform=True): """ # Call show on requested plots # All same-type charts in one plot + new_plot = PlotterWidget(manager=self, parent=self) + new_plot.item = None for item, plot_set in plots: if isinstance(plot_set, Data1D): - if 'new_plot' not in locals(): - new_plot = PlotterWidget(manager=self, parent=self) + if not new_plot.item: new_plot.item = item - # Ensure new plots use the default transform, not the transform of any previous plots the data were in - # TODO: The transform should be part of the PLOT, NOT the data - plot_set.xtransform = None - plot_set.ytransform = None + # Ensure new plots use the default transform, not the transform of any previous plots new_plot.plot(plot_set, transform=transform) # active_plots may contain multiple charts self.active_plots[plot_set.name] = new_plot @@ -1218,9 +1215,7 @@ def plotData(self, plots, transform=True): msg = "Incorrect data type passed to Plotting" raise AttributeError(msg) - if 'new_plot' in locals() and \ - hasattr(new_plot, 'data') and \ - isinstance(new_plot.data[0], Data1D): + if hasattr(new_plot, 'data') and isinstance(new_plot.data[0], Data1D): self.addPlot(new_plot) def newPlot(self): diff --git a/src/sas/qtgui/Perspectives/Fitting/FittingUtilities.py b/src/sas/qtgui/Perspectives/Fitting/FittingUtilities.py index fcee175c81..e1ce73a77d 100644 --- a/src/sas/qtgui/Perspectives/Fitting/FittingUtilities.py +++ b/src/sas/qtgui/Perspectives/Fitting/FittingUtilities.py @@ -547,12 +547,12 @@ def residualsData1D(reference_data, current_data, weights): residuals.dx = None residuals.dxl = None residuals.dxw = None - residuals.ytransform = 'y' if reference_data.isSesans: - residuals.xtransform = 'x' + residuals.plot_role = DataRole.ROLE_RESIDUAL_SESANS residuals.xaxis('\\delta ', 'A') # For latter scale changes else: + residuals.plot_role = DataRole.ROLE_RESIDUAL residuals.xaxis('\\rm{Q} ', 'A^{-1}') residuals.yaxis('\\rm{Residuals} ', 'normalized') @@ -636,8 +636,6 @@ def plotPolydispersities(model): # similar to FittingLogic._create1DPlot() but different data/axes data1d = Data1D(x=xarr, y=yarr) xunit = model.details[name][0] - data1d.xtransform = 'x' - data1d.ytransform = 'y' data1d.xaxis(r'\rm{{{}}}'.format(name.replace('_', '\_')), xunit) data1d.yaxis(r'\rm{probability}', 'normalized') data1d.scale = 'linear' diff --git a/src/sas/qtgui/Perspectives/Fitting/FittingWidget.py b/src/sas/qtgui/Perspectives/Fitting/FittingWidget.py index 3a93a2cac8..4dfbd21f83 100644 --- a/src/sas/qtgui/Perspectives/Fitting/FittingWidget.py +++ b/src/sas/qtgui/Perspectives/Fitting/FittingWidget.py @@ -3267,8 +3267,7 @@ def complete1D(self, return_data): # Fits of Sesans data are in real space if return_data["data"].isSesans: - fitted_data.xtransform="x" - fitted_data.ytransform="y" + fitted_data.plot_role = DataRole.ROLE_LIN_LIN # assure the current index is set properly for batch if len(self._logic) > 1: @@ -3922,8 +3921,7 @@ def onShowSLDProfile(self): profile_data._xunit = "\AA" profile_data._yaxis = "SLD" profile_data._yunit = "10^{-6}\AA^{-2}" - profile_data.ytransform='y' - profile_data.xtransform='x' + profile_data.data_role = DataRole.ROLE_LIN_LIN profile_data.id = "sld" diff --git a/src/sas/qtgui/Perspectives/Inversion/InversionLogic.py b/src/sas/qtgui/Perspectives/Inversion/InversionLogic.py index 6640feacdc..89b9bec76b 100644 --- a/src/sas/qtgui/Perspectives/Inversion/InversionLogic.py +++ b/src/sas/qtgui/Perspectives/Inversion/InversionLogic.py @@ -2,7 +2,7 @@ import logging import numpy as np -from sas.qtgui.Plotting.PlotterData import Data1D +from sas.qtgui.Plotting.PlotterData import Data1D, DataRole PR_FIT_LABEL = r"$P_{fit}(r)$" PR_LOADED_LABEL = r"$P_{loaded}(r)$" @@ -129,8 +129,7 @@ def newPRPlot(self, out, pr, cov=None): new_plot.yaxis("\\rm{P(r)} ", "cm^{-3}") new_plot.title = "P(r) fit" new_plot.id = PR_FIT_LABEL - new_plot.xtransform = "x" - new_plot.ytransform = "y" + new_plot.data_role = DataRole.ROLE_LIN_LIN new_plot.group_id = GROUP_ID_PR_FIT return new_plot diff --git a/src/sas/qtgui/Plotting/Plotter.py b/src/sas/qtgui/Plotting/Plotter.py index 1f7ffa3399..31c80a3bd5 100644 --- a/src/sas/qtgui/Plotting/Plotter.py +++ b/src/sas/qtgui/Plotting/Plotter.py @@ -112,23 +112,23 @@ def plot(self, data=None, color=None, marker=None, hide_error=False, transform=T if not is_fit: # make sure we have some function to operate on - if data.xtransform is None: + if self.xLogLabel is None: if data.isSesans: - data.xtransform='x' + self.xLogLabel = 'x' else: - data.xtransform = 'log10(x)' - if data.ytransform is None: + self.xLogLabel = 'log10(x)' + if self.yLogLabel is None: if data.isSesans: - data.ytransform='y' + self.yLogLabel = 'y' else: - data.ytransform = 'log10(y)' + self.yLogLabel = 'log10(y)' #Added condition to Dmax explorer from P(r) perspective if data._xaxis == 'D_{max}': self.xscale = 'linear' # Transform data if required. - if transform and (data.xtransform is not None or data.ytransform is not None): + if transform: self.xLabel, self.yLabel, xscale, yscale = \ - GuiUtils.xyTransform(data, data.xtransform, data.ytransform) + GuiUtils.xyTransform(data, self.xLogLabel, self.yLogLabel) if xscale != 'log' and xscale != self.xscale: self.xscale = xscale if yscale != 'log' and yscale != self.yscale: @@ -136,8 +136,8 @@ def plot(self, data=None, color=None, marker=None, hide_error=False, transform=T # Redefine the Scale properties dialog self.properties = ScaleProperties(self, - init_scale_x=data.xtransform, - init_scale_y=data.ytransform) + init_scale_x=self.xLogLabel, + init_scale_y=self.yLogLabel) # Shortcuts ax = self.ax @@ -178,13 +178,13 @@ def plot(self, data=None, color=None, marker=None, hide_error=False, transform=T markersize = data.markersize + # Use the plot role to define the x and y scales + self.xscale = data.plot_role.x_scale + self.yscale = data.plot_role.y_scale + # Include scaling (log vs. linear) - if version.parse(mpl.__version__) < version.parse("3.3"): - ax.set_xscale(self.xscale, nonposx='clip') if self.xscale != 'linear' else self.ax.set_xscale(self.xscale) - ax.set_yscale(self.yscale, nonposy='clip') if self.yscale != 'linear' else self.ax.set_yscale(self.yscale) - else: - ax.set_xscale(self.xscale, nonpositive='clip') if self.xscale != 'linear' else self.ax.set_xscale(self.xscale) - ax.set_yscale(self.yscale, nonpositive='clip') if self.yscale != 'linear' else self.ax.set_yscale(self.yscale) + ax.set_xscale(self.xscale, nonpositive='clip') if self.xscale != 'linear' else self.ax.set_xscale(self.xscale) + ax.set_yscale(self.yscale, nonpositive='clip') if self.yscale != 'linear' else self.ax.set_yscale(self.yscale) # Draw non-standard markers l_width = markersize * 0.4 @@ -502,9 +502,6 @@ def onScaleChange(self): """ if self.properties.exec_() == QtWidgets.QDialog.Accepted: self.xLogLabel, self.yLogLabel = self.properties.getValues() - for d in self.data: - d.xtransform = self.xLogLabel - d.ytransform = self.yLogLabel self.xyTransform(self.xLogLabel, self.yLogLabel) def onAddText(self): @@ -682,8 +679,6 @@ def replacePlot(self, id, new_plot, retain_dimensions=True): # Pull the current transform settings from the old plot selected_plot = self.plot_dict[id] - new_plot.xtransform = selected_plot.xtransform - new_plot.ytransform = selected_plot.ytransform #Adding few properties ftom ModifyPlot to preserve them in future changes new_plot.title = selected_plot.title new_plot.custom_color = selected_plot.custom_color diff --git a/src/sas/qtgui/Plotting/Plotter2D.py b/src/sas/qtgui/Plotting/Plotter2D.py index c3f7af0f14..db5845408f 100644 --- a/src/sas/qtgui/Plotting/Plotter2D.py +++ b/src/sas/qtgui/Plotting/Plotter2D.py @@ -334,7 +334,6 @@ def circularAverage(self): new_plot.xaxis("\\rm{Q}", "A^{-1}") if hasattr(self.data0, "scale") and \ self.data0.scale == 'linear': - new_plot.ytransform = 'y' new_plot.yaxis("\\rm{Residuals} ", "normalized") else: new_plot.yaxis("\\rm{Intensity} ", "cm^{-1}") diff --git a/src/sas/qtgui/Plotting/PlotterData.py b/src/sas/qtgui/Plotting/PlotterData.py index e43539dcc0..a339f73669 100644 --- a/src/sas/qtgui/Plotting/PlotterData.py +++ b/src/sas/qtgui/Plotting/PlotterData.py @@ -4,7 +4,7 @@ import copy import numpy import math -from enum import Enum +from enum import Enum, auto from sasdata.data_util.uncertainty import Uncertainty @@ -18,17 +18,25 @@ class DataRole(Enum): """Labels to apply to different plot types.""" # Data is for imported data - ROLE_DATA = 0 + ROLE_DATA = ("log", "log") # Default is for fits of the imported data - ROLE_DEFAULT = 1 + ROLE_DEFAULT = ("log", "log") # Deletable is for orphaned plots - ROLE_DELETABLE = 2 + ROLE_DELETABLE = (None, None) # Residual is for stand-alone residual plots - ROLE_RESIDUAL = 3 + ROLE_RESIDUAL = ("log", "linear") + # Residual sesans is for stand-alone sesans residual plots + ROLE_RESIDUAL_SESANS = ("linear", "linear") # Stand alone is for plots that should be plotted separately - ROLE_STAND_ALONE = 4 - # Polydispersity is for stand-alone polydispersity plot - ROLE_POLYDISPERSITY = 5 + ROLE_STAND_ALONE = ("linear", "linear") + # LIN_LIN is for stand-alone plots on a linear-linear scale + ROLE_LIN_LIN = ("linear", "linear") + # POLYDISPERSITY role is to tag polydispersity plots to be able to suppress auto displaying them + ROLE_POLYDISPERSITY = ("linear", "linear") + + def __init__(self, x_scale, y_scale): + self.x_scale = x_scale + self.y_scale = y_scale class Data1D(PlottableData1D, LoadData1D): @@ -48,8 +56,6 @@ def __init__(self, x=None, y=None, dx=None, dy=None): self.group_id = None self.is_data = True self.path = None - self.xtransform = None - self.ytransform = None self.title = "" self.scale = None # plot_role: @@ -218,8 +224,6 @@ def __init__(self, image=None, err_image=None, self.group_id = None self.is_data = True self.path = None - self.xtransform = None - self.ytransform = None self.title = "" self.scale = None # Always default diff --git a/src/sas/qtgui/Plotting/Slicers/AnnulusSlicer.py b/src/sas/qtgui/Plotting/Slicers/AnnulusSlicer.py index 6e2c1f07b0..530654856f 100644 --- a/src/sas/qtgui/Plotting/Slicers/AnnulusSlicer.py +++ b/src/sas/qtgui/Plotting/Slicers/AnnulusSlicer.py @@ -2,7 +2,7 @@ import sas.qtgui.Utilities.GuiUtils as GuiUtils from .BaseInteractor import BaseInteractor -from sas.qtgui.Plotting.PlotterData import Data1D +from sas.qtgui.Plotting.PlotterData import Data1D, DataRole from sas.qtgui.Utilities.GuiUtils import formatNumber from sas.qtgui.Plotting.SlicerModel import SlicerModel @@ -133,16 +133,13 @@ def _post_data(self, nbins=None): # If the data file does not tell us what the axes are, just assume... new_plot.xaxis("\\rm{\phi}", 'degrees') new_plot.yaxis("\\rm{Intensity} ", "cm^{-1}") - if hasattr(data, "scale") and data.scale == 'linear' and \ - self.data.name.count("Residuals") > 0: - new_plot.ytransform = 'y' + if hasattr(data, "scale") and data.scale == 'linear' and self.data.name.count("Residuals") > 0: new_plot.yaxis("\\rm{Residuals} ", "/") new_plot.id = "AnnulusPhi" + self.data.name new_plot.type_id = "Slicer" + self.data.name # Used to remove plots after changing slicer so they don't keep showing up after closed new_plot.is_data = True - new_plot.xtransform = "x" - new_plot.ytransform = "y" + new_plot.plot_role = DataRole.ROLE_LIN_LIN item = self._item if self._item.parent() is not None: item = self._item.parent() diff --git a/src/sas/qtgui/Plotting/Slicers/WedgeSlicer.py b/src/sas/qtgui/Plotting/Slicers/WedgeSlicer.py index 6f75c6f850..91392367df 100644 --- a/src/sas/qtgui/Plotting/Slicers/WedgeSlicer.py +++ b/src/sas/qtgui/Plotting/Slicers/WedgeSlicer.py @@ -2,7 +2,7 @@ from sas.qtgui.Plotting.Slicers.BaseInteractor import BaseInteractor from sas.qtgui.Plotting.SlicerModel import SlicerModel -from sas.qtgui.Plotting.PlotterData import Data1D +from sas.qtgui.Plotting.PlotterData import Data1D, DataRole import sas.qtgui.Utilities.GuiUtils as GuiUtils from sas.qtgui.Plotting.Slicers.ArcInteractor import ArcInteractor @@ -205,8 +205,7 @@ def _post_data(self, new_sector=None, nbins=None): # angular plots usually require a linear x scale and better with # a linear y scale as well. new_plot.xaxis("\\rm{\phi}", "degrees") - new_plot.xtransform = 'x' - new_plot.ytransform = 'y' + new_plot.plot_role = DataRole.ROLE_LIN_LIN else: new_plot.xaxis("\\rm{Q}", 'A^{-1}') new_plot.yaxis("\\rm{Intensity} ", "cm^{-1}")