Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

2107 idf plot selection #2145

Merged
merged 25 commits into from
Aug 19, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
7b12817
Main changes made
lucas-wilkins Aug 15, 2022
e227f57
Some debugging
lucas-wilkins Aug 15, 2022
2bf848d
Default tab change
lucas-wilkins Aug 15, 2022
bda4054
Default tab on load
lucas-wilkins Aug 15, 2022
5c391f6
More debugging
lucas-wilkins Aug 15, 2022
eb3c35a
Idiomatised calcthread, fixed bug
lucas-wilkins Aug 15, 2022
78ac216
Fixed test bug
lucas-wilkins Aug 15, 2022
7240c1c
Fixed unnecessary circular import
lucas-wilkins Aug 15, 2022
d972051
Merge branch 'main' into 2107-idf-plot-selection
lucas-wilkins Aug 16, 2022
1b1e750
Merge branch 'main' into 2107-idf-plot-selection
lucas-wilkins Aug 16, 2022
a7852a0
removed unused input
lucas-wilkins Aug 16, 2022
6220537
Removed commented text
lucas-wilkins Aug 16, 2022
dc1a8d6
Fixed bug from merge
lucas-wilkins Aug 16, 2022
c88ff8b
Reverted rename
lucas-wilkins Aug 17, 2022
150f9b3
Fixed reversion bug
lucas-wilkins Aug 17, 2022
19b2e36
Removed empty legend
lucas-wilkins Aug 17, 2022
8bc0081
Fixed empty legend in IDF, typing in CorfuncCanvas, and made one-line…
lucas-wilkins Aug 17, 2022
38e170f
Merge branch 'main' into 2107-idf-plot-selection
lucas-wilkins Aug 18, 2022
806754e
Added scroll bar to corfunc window
lucas-wilkins Aug 18, 2022
af975d2
Missing comma prevented css addition
lucas-wilkins Aug 19, 2022
a7517f4
Added <p> tags for each plot in report
lucas-wilkins Aug 19, 2022
192954f
Merge branch 'main' into 2107-idf-plot-selection
lucas-wilkins Aug 19, 2022
9f00160
Added .css to .spec
lucas-wilkins Aug 19, 2022
c900a90
Comma
lucas-wilkins Aug 19, 2022
2108910
spec file can't cope with (source_file, target_file) format, must be …
lucas-wilkins Aug 19, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion installers/sasview.spec
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ PYTHON_LOC = sys.exec_prefix
datas = [
('../src/sas/sasview/images', 'images'),
('../src/sas/sasview/media', 'media'),
('../src/sas/example_data', 'example_data'),
('../src/sas/example_data', 'example_data'),
('../src/sas/qtgui/Utilities/Reports/report_style.css', 'sas/qtgui/Utilities/Reports'),
('../src/sas/sasview/custom_config.py', '.'),
('../src/sas/sasview/local_config.py', '.'),
# ('../src/sas/sasview/wxcruft.py', '.'),
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ def run(self):
'Plotting/UI/*',
'Utilities/UI/*',
'Utilities/Reports/UI/*',
'Utilities/Reports/*.css'
'Utilities/Reports/*.css',
'UI/*',
'UI/res/*',
]
Expand Down
59 changes: 59 additions & 0 deletions src/sas/qtgui/Perspectives/Corfunc/CorfuncCanvas.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
from __future__ import annotations

from abc import ABCMeta, abstractmethod

from typing import Optional, Union, List, Iterable, TYPE_CHECKING

from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure

from sas.sascalc.dataloader.data_info import Data1D


if TYPE_CHECKING:
from sas.qtgui.Perspectives.Corfunc.CorfuncPerspective import CorfuncWindow


class CorfuncCanvasMeta(type(FigureCanvas), ABCMeta):
""" Metaclass for both ABC and matplotlib figure

This is needed to enable the mixin of CorfuncCanvas
"""


class CorfuncCanvas(FigureCanvas, metaclass=CorfuncCanvasMeta):
""" Base class for the canvases in corfunc"""

def __init__(self, parent: CorfuncWindow, width=5, height=4, dpi=100):
self.parent = parent
self.fig = Figure(figsize=(width, height), dpi=dpi)
self.axes = self.fig.add_subplot(111)

FigureCanvas.__init__(self, self.fig)

self._data: Optional[List[Data1D]] = None

def clear(self):
""" Remove data from plots"""
self._data = None

@abstractmethod
def draw_data(self):
pass

@property
def data(self) -> Optional[List[Data1D]]:
""" The data currently shown by the plots """
return self._data

@data.setter
def data(self, target_data: Optional[Union[Data1D, Iterable[Data1D]]]):
# I'm not 100% sure this is good practice, but it will make things cleaner in the short term
if target_data is None:
self._data = None
elif isinstance(target_data, Data1D):
self._data = [target_data]
else:
self._data = list(target_data)
lucas-wilkins marked this conversation as resolved.
Show resolved Hide resolved

self.draw_data()
102 changes: 50 additions & 52 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
from typing import Optional, List, Tuple

import logging

Expand All @@ -22,18 +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.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

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

Expand All @@ -49,7 +51,7 @@ def title(self):
""" Window title """
return "Corfunc Perspective"

trigger = QtCore.pyqtSignal(tuple)
trigger = QtCore.pyqtSignal(TransformedData)

# pylint: disable=unused-argument
def __init__(self, parent=None):
Expand All @@ -67,7 +69,8 @@ def __init__(self, parent=None):
self._calculator = CorfuncCalculator()
self._allow_close = False
self._model_item: Optional[QStandardItem] = None
self.data = None
self.data: Optional[Data1D] = None
self.extrap: Optional[Data1D] = None
self.has_data = False
self.txtLowerQMin.setText("0.0")
self.txtLowerQMin.setEnabled(False)
Expand All @@ -86,10 +89,15 @@ def __init__(self, parent=None):
self.realSpaceLayout.insertWidget(0, self._real_space_plot)
self.realSpaceLayout.insertWidget(1, NavigationToolbar2QT(self._real_space_plot, self))

self._idf_plot = IDFCanvas(self)
self.idfLayout.insertWidget(0, self._idf_plot)
self.idfLayout.insertWidget(1, NavigationToolbar2QT(self._idf_plot, self))

# Things to make the corfunc panel behave
self.mainLayout.setStretch(0, 0)
self.mainLayout.setStretch(1, 1)
self.controlFrame.setFixedWidth(583)
self.horizontalLayout_3.setStretch(0, 0)
self.horizontalLayout_3.setStretch(1, 1)
self.scrollArea.setFixedWidth(600)
self.adjustSize()

# Connect buttons to slots.
# Needs to be done early so default values propagate properly.
Expand Down Expand Up @@ -193,10 +201,10 @@ def removeData(self, data_list=None):
# Clear data plots
self._q_space_plot.data = None
self._q_space_plot.extrap = None
self._q_space_plot.draw_data()

self._real_space_plot.data = None
self._real_space_plot.extrap = None
self._real_space_plot.draw_data()
self._idf_plot.data = None

self.slider.setEnabled(False)
# Clear calculator, model, and data path
self._calculator = CorfuncCalculator()
Expand Down Expand Up @@ -249,6 +257,7 @@ def extrapolate(self):
self.model.setItem(WIDGETS.W_PORODSIGMA,
QtGui.QStandardItem("{:.4g}".format(params['sigma'])))

self.extrap = extrapolation
self._q_space_plot.extrap = extrapolation
self.model_changed(None)
self.cmdTransform.setEnabled(True)
Expand All @@ -263,16 +272,16 @@ def transform(self):

method = "fourier"

extrap = self._q_space_plot.extrap
extrap = self.extrap
background = float(self.model.item(WIDGETS.W_BACKGROUND).text())

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

def completefn(transforms):
def completefn(transformed_data: Tuple[Data1D, Data1D, Data1D]):
"""Extract the values from the transforms and plot"""
self.trigger.emit(transforms)
self.trigger.emit(TransformedData(*transformed_data)) # TODO: Make this return more structured data earlier
lucas-wilkins marked this conversation as resolved.
Show resolved Hide resolved

self._update_calculator()
self._calculator.compute_transform(extrap, method, background,
Expand All @@ -281,20 +290,27 @@ def completefn(transforms):



def finish_transform(self, transforms):
self._real_space_plot.data = transforms
def finish_transform(self, data: TransformedData):

self.transformed_data = data

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

self.update_real_space_plot(transforms)
# self.update_real_space_plot(transforms)

self._idf_plot.data = data.idf

self._real_space_plot.draw_data()
self.cmdExtract.setEnabled(True)
self.cmdSave.setEnabled(True)

self.tabWidget.setCurrentIndex(1)

def extract(self):
transforms = self._real_space_plot.data

params = self._calculator.extract_parameters(transforms[0])
if self.transformed_data is None:
return

params = self._calculator.extract_parameters(self.transformed_data[0])

if params is not None:

Expand All @@ -313,29 +329,6 @@ def extract(self):
self.model_changed(None)


def update_real_space_plot(self, datas):
"""take the datas tuple and create a plot in DE"""

assert isinstance(datas, tuple)
plot_id = id(self)
titles = [f"1D Correlation [{self._path}]", f"3D Correlation [{self._path}]",
'Interface Distribution Function']
for i, plot in enumerate(datas):
plot_to_add = self.parent.createGuiData(plot)
# set plot properties
title = plot_to_add.title
plot_to_add.scale = 'linear'
plot_to_add.symbol = 'Line'
plot_to_add._xaxis = "x"
plot_to_add._xunit = "A"
plot_to_add._yaxis = "\Gamma"
if i < len(titles):
title = titles[i]
plot_to_add.name = titles[i]
GuiUtils.updateModelItemWithPlot(self._model_item, plot_to_add, title)
#self.axes.set_xlim(min(data1.x), max(data1.x) / 4)
pass

def setup_mapper(self):
"""Creating mapping between model and gui elements."""
self.mapper = QtWidgets.QDataWidgetMapper(self)
Expand Down Expand Up @@ -480,11 +473,15 @@ def fractional_position(f):
self.cmdTransform.setEnabled(False)
self._path = data.name
self.model.setItem(WIDGETS.W_FILENAME, QtGui.QStandardItem(self._path))

self._real_space_plot.data = None
self._real_space_plot.draw_data()
self._idf_plot.data = None

self.set_text_enable(True)
self.has_data = True

self.tabWidget.setCurrentIndex(0)


def setClosable(self, value=True):
"""
Expand Down Expand Up @@ -609,12 +606,15 @@ def on_save(self):
if "." not in f_name:
f_name += ".csv"

data1, data3, data_idf = self._real_space_plot.data

with open(f_name, "w") as outfile:
outfile.write("X,1D,3D,IDF\n")
np.savetxt(outfile,
np.vstack([(data1.x, data1.y, data3.y, data_idf.y)]).T,
np.vstack([(
self.transformed_data.gamma_1.x,
self.transformed_data.gamma_1.y,
self.transformed_data.gamma_3.y,
self.transformed_data.idf.y)]).T,
delimiter=",")
# pylint: enable=invalid-name

Expand Down Expand Up @@ -765,13 +765,6 @@ def updateFromParameters(self, params):
if params.get('long_period', '0') != '0':
self.transform()

def get_figures(self):
"""
Get plots for the report
"""

return [self._real_space_plot.fig]

@property
def real_space_figure(self):
return self._real_space_plot.fig
Expand All @@ -780,6 +773,10 @@ def real_space_figure(self):
def q_space_figure(self):
return self._q_space_plot.fig

@property
def idf_figure(self):
return self._idf_plot.fig

@property
def supports_reports(self) -> bool:
return True
Expand All @@ -805,5 +802,6 @@ def getReport(self) -> Optional[ReportData]:
report.add_table_dict(fancy_parameters, ("Parameter", "Value"))
report.add_plot(self.q_space_figure)
report.add_plot(self.real_space_figure)
report.add_plot(self.idf_figure)

return report.report_data
32 changes: 32 additions & 0 deletions src/sas/qtgui/Perspectives/Corfunc/IDFCanvas.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@

from sas.qtgui.Perspectives.Corfunc.CorfuncCanvas import CorfuncCanvas


class IDFCanvas(CorfuncCanvas):
""" Canvas for displaying real space representation"""

def draw_data(self):
"""
This function draws the real space data onto the plot

The 1d correlation function in self.data, the 3d correlation function
in self.data3, and the interface distribution function in self.data_idf
are all draw in on the plot in linear cooredinates."""


self.fig.clf()

self.axes = self.fig.add_subplot(111)
self.axes.set_xscale("linear")
self.axes.set_yscale("linear")
self.axes.set_xlabel("Z [$\AA$]")
self.axes.set_ylabel("IDF")
lucas-wilkins marked this conversation as resolved.
Show resolved Hide resolved
self.axes.set_title("Interface Distribution Function")
self.fig.tight_layout()

if self.data is not None and len(self.data) > 0:
self.axes.plot(self.data[0].x, self.data[0].y)
self.axes.set_xlim(0, max(self.data[0].x) / 4)

self.draw()

Loading