Skip to content

Commit

Permalink
Merge pull request #3 from nanthony21/dev
Browse files Browse the repository at this point in the history
Dev
  • Loading branch information
nanthony21 authored Apr 8, 2021
2 parents 74d020b + 1e06670 commit e66612f
Show file tree
Hide file tree
Showing 32 changed files with 1,259 additions and 846 deletions.
5 changes: 3 additions & 2 deletions conda.recipe/meta.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,10 @@ requirements:
- google-auth-httplib2
- google-auth-oauthlib
- pyqt =5
- pwspy >=0.2.3 # Core pws package, available on backmanlab anaconda cloud account.
- pwspy >=0.2.4 # Core pws package, available on backmanlab anaconda cloud account.
- mpl_qt_viz >=1.0.7 # Plotting package available on PyPi and the backmanlab anaconda cloud account. Written for this project by Nick Anthony

- descartes
- cachetools >=4
app:
entry: PWSAnalysis
icon: cellLogo64.png #The logo doesn't work :(
Expand Down
6 changes: 4 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,10 @@
'google-auth-httplib2',
'google-auth-oauthlib',
'PyQt5',
'pwspy>=0.2.3', # Core pws package, available on backmanlab anaconda cloud account.
'mpl_qt_viz>=1.0.7'], # Plotting package available on PyPi and the backmanlab anaconda cloud account. Written for this project by Nick Anthony
'pwspy>=0.2.4', # Core pws package, available on backmanlab anaconda cloud account.
'mpl_qt_viz>=1.0.7', # Plotting package available on PyPi and the backmanlab anaconda cloud account. Written for this project by Nick Anthony
'descartes',
'cachetools>=4'],
package_dir={'': 'src'},
package_data={'pwspy_gui': ['_resources/*',
'PWSAnalysisApp/_resources/*']},
Expand Down
5 changes: 2 additions & 3 deletions src/pwspy_gui/ExtraReflectanceCreator/ERWorkFlow.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ def plot(self, numericalAperture: float, saveToPdf: bool = False, saveDir: str =

print("Select an ROI")
verts = cubes['cube'].sample(n=1).iloc[0].selectLassoROI() # Select an ROI to analyze
mask = Roi.fromVerts('doesntmatter', 1, verts, cubes['cube'].sample(n=1).iloc[0].data.shape[:-1])
mask = Roi.fromVerts(verts, cubes['cube'].sample(n=1).iloc[0].data.shape[:-1])
self.figs.extend(er.plotExtraReflection(cubes, theoryR, matCombos, numericalAperture, mask, plotReflectionImages=True)) # TODO rather than opening a million new figures open a single window that lets you flip through them.
if saveToPdf:
with PdfPages(os.path.join(saveDir, f"fig_{datetime.strftime(datetime.now(), '%d-%m-%Y %HH%MM%SS')}.pdf")) as pp:
Expand Down Expand Up @@ -199,8 +199,7 @@ def compareDates(self):
anis = []
figs = [] # These lists just maintain references to matplotlib figures to keep them responsive.
verts = self.cubes['cube'].sample(n=1).iloc[0].selectLassoROI() # Select a random of the selected cubes and use it to prompt the user for an analysis ROI
mask = Roi.fromVerts('doesntmatter', 1, verts=verts,
dataShape=self.cubes['cube'].sample(n=1).iloc[0].data.shape[:-1])
mask = Roi.fromVerts(verts=verts, dataShape=self.cubes['cube'].sample(n=1).iloc[0].data.shape[:-1])
for mat in set(self.cubes['material']):
c = self.cubes[self.cubes['material'] == mat]
fig, ax = plt.subplots()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ def processIm(im):
matCombos = er.generateMaterialCombos(list(zip(*materials))[1])
if plotResults:
verts = random.choice(df['cube']).selectLassoROI()
roi = Roi.fromVerts('plottingArea', 1, verts, df['cube'][0].data.shape[:2])
roi = Roi.fromVerts(verts, df['cube'][0].data.shape[:2])
er.plotExtraReflection(df, theoryR, matCombos, na, roi, plotReflectionImages=False)
with PdfPages(os.path.join(rootDir, "figs.pdf")) as pp:
for i in plt.get_fignums():
Expand Down
22 changes: 19 additions & 3 deletions src/pwspy_gui/PWSAnalysisApp/App.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
from PyQt5.QtGui import QPixmap
from PyQt5.QtWidgets import QApplication, QMessageBox, QSplashScreen
from pwspy_gui import __version__ as version
from pwspy_gui.PWSAnalysisApp._roiManager import _DefaultROIManager, ROIManager
from pwspy_gui.PWSAnalysisApp.utilities import BlinderDialog, RoiConverter
from .dialogs import AnalysisSummaryDisplay
from ._taskManagers.analysisManager import AnalysisManager
Expand All @@ -41,21 +42,24 @@
import pwspy.dataTypes as pwsdt


class PWSApp(QApplication): # TODO add a scriptable interface to load files, open roi window, run analysis etc.
class PWSApp(QApplication):
def __init__(self, args):
logger = logging.getLogger(__name__)
logger.debug("About to call PWSApp superclass constructor")
super().__init__(args)
logger.debug("PWSApp superclass constructor is finished")

self.roiManager: ROIManager = _DefaultROIManager()

self.setApplicationName(f"PWS Analysis v{version.split('-')[0]}")
splash = QSplashScreen(QPixmap(os.path.join(resources, 'pwsLogo.png')))
splash.show()
logger.debug("Initialize ERManager")
self.ERManager = ERManager(applicationVars.extraReflectionDirectory)
logger.debug("Finish constructing ERManager")
self.window = PWSWindow(self.ERManager)
logger.debug("Finish constructing window")
self.window = PWSWindow(self.ERManager, self.roiManager)
splash.finish(self.window)
logger.debug("Finish constructing window")
self.anMan = AnalysisManager(self)
self.window.runAction.connect(self.anMan.runList)
availableRamGigs = psutil.virtual_memory().available / 1024**3
Expand All @@ -72,6 +76,12 @@ def __init__(self, args):
self.window.roiConvertAction.triggered.connect(self.convertRois)
self.workingDirectory = None

# import qdarkstyle # This looks bad
# dark_stylesheet = qdarkstyle.load_stylesheet_pyqt5()
# self.setStyleSheet(dark_stylesheet)

self.window.show()

### API
def changeDirectory(self, directory: str, recursive: bool):
from glob import glob
Expand Down Expand Up @@ -129,3 +139,9 @@ def plotSelectedCells(self, analysisName: str = None):
analysisName = ''
self.window.plots.setAnalysisName(analysisName)
self.window.plots.refreshPlots()

def __del__(self):
try:
self.roiManager.close()
except AttributeError: # If an error occured in the constructor the attribute may have never been created.
pass
15 changes: 6 additions & 9 deletions src/pwspy_gui/PWSAnalysisApp/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,28 +85,25 @@ def exception_hook(exctype, value, traceBack):
fHandler = logging.FileHandler(os.path.join(applicationVars.dataDirectory, f'log{datetime.now().strftime("%d%m%Y%H%M%S")}.txt'))
fHandler.setFormatter(logging.Formatter('%(levelname)s: %(asctime)s %(name)s.%(funcName)s(%(lineno)d) - %(message)s', datefmt='%Y-%m-%d %H:%M:%S'))
logger.addHandler(fHandler)
logger.setLevel(logging.INFO)
if debugMode:
logger.setLevel(logging.DEBUG)
logging.getLogger("pwspy_gui").setLevel(logging.DEBUG)
logging.getLogger("pwspy").setLevel(logging.DEBUG)
logger.info("Logger set to debug mode.")
else:
logger.setLevel(logging.INFO)


try:
os.environ["QT_AUTO_SCREEN_SCALE_FACTOR"] = "1" # TODO replace these options with proper high dpi handling. no pixel specific widths.
QApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling)
logger.debug("About to construct `PWSApp`")
app = PWSApp(sys.argv)
logger.debug("Finished constructing `PWSApp`")

#Testing script
# app.changeDirectory(r'\\backmanlabnas.myqnapcloud.com\home\Year3\zstack_focusSensitivity\again', False)
# app.setSelectedCells([app.getLoadedCells()[0]])
# app.setSelectedCells(app.getLoadedCells()[:3])
# app.plotSelectedCells()
# app.window.plots._startRoiDrawing()

# import qdarkstyle
# dark_stylesheet = qdarkstyle.load_stylesheet_pyqt5()
# app.setStyleSheet(dark_stylesheet)

if not isIpython(): # IPython runs its own QApplication so we handle things slightly different.
sys.exit(app.exec_())
except Exception as e: # Save error to text file.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@

from PyQt5 import QtCore, QtGui
from PyQt5.QtWidgets import QScrollArea, QGridLayout, QLineEdit, QLabel, QGroupBox, QHBoxLayout, QWidget, QRadioButton, \
QFrame, QCheckBox
QFrame, QCheckBox, QDoubleSpinBox

from pwspy.analysis.pws import PWSAnalysisSettings
from pwspy_gui.PWSAnalysisApp import applicationVars
Expand Down Expand Up @@ -112,20 +112,29 @@ def __init__(self, erManager: ERManager, cellSelector: CellSelector):
layout = QGridLayout()
layout.setContentsMargins(5, 1, 5, 5)
_ = layout.addWidget

orderLabel = QLabel("Filter Order")
self.filterOrder = QHSpinBox()
self.filterOrder.setRange(0, 6)
self.filterOrder.setToolTip("A lowpass filter is applied to the spectral signal to reduce noise. This determines the `order` of the digital filter.")
self.filterOrder.setToolTip("A low-pass filter is applied to the spectral signal to reduce noise. This determines the `order` of the digital filter.")
orderLabel.setToolTip(self.filterOrder.toolTip())
cutoffLabel = QLabel("Cutoff Freq.")
self.filterCutoff = QHDoubleSpinBox()
self.filterCutoff: QDoubleSpinBox = QHDoubleSpinBox()
self.filterCutoff.setToolTip("The frequency in units of 1/wavelength for the filter cutoff.")
self.filterCutoff.setDecimals(3) # Greater precision than default
cutoffLabel.setToolTip(self.filterCutoff.toolTip())
_(orderLabel, 0, 0, 1, 1)
_(self.filterOrder, 0, 1, 1, 1)
_(cutoffLabel, 1, 0, 1, 1)
_(self.filterCutoff, 1, 1, 1, 1)
_(QLabel("nm<sup>-1</sup>"), 1, 2, 1, 1)
self.filterCheckbox = QCheckBox("Low-pass Filtering", self)
def stateChange(state: bool):
self.filterOrder.setEnabled(state)
self.filterCutoff.setEnabled(state)
self.filterCheckbox.stateChanged.connect(stateChange)
self.filterCheckbox.setChecked(True) # This is just to initialize the proper state
_(self.filterCheckbox, 0, 0, 1, 2)
_(orderLabel, 1, 0, 1, 1)
_(self.filterOrder, 1, 1, 1, 1)
_(cutoffLabel, 2, 0, 1, 1)
_(self.filterCutoff, 2, 1, 1, 1)
_(QLabel("nm<sup>-1</sup>"), 2, 2, 1, 1)
self.signalPrep.setLayout(layout)
self._layout.addWidget(self.signalPrep, row, 0, 1, 2)

Expand All @@ -142,10 +151,17 @@ def __init__(self, erManager: ERManager, cellSelector: CellSelector):
self.wavelengthStop.setToolTip("Sometimes the beginning and end of the spectrum can have very high noise. For this reason we crop the data before analysis.")
self.wavelengthStart.setRange(300, 800)
self.wavelengthStop.setRange(300, 800)
_(QLabel("Start"), 0, 0)
_(QLabel("Stop"), 0, 1)
_(self.wavelengthStart, 1, 0)
_(self.wavelengthStop, 1, 1)
self.croppingCheckbox = QCheckBox("Enable Cropping", self)
def cropStateChanged(state: bool):
self.wavelengthStop.setEnabled(state)
self.wavelengthStart.setEnabled(state)
self.croppingCheckbox.stateChanged.connect(cropStateChanged)
self.croppingCheckbox.setChecked(True) # This is just to initialze the propert state.
_(self.croppingCheckbox, 0, 0, 1, 2)
_(QLabel("Start"), 1, 0)
_(QLabel("Stop"), 1, 1)
_(self.wavelengthStart, 2, 0)
_(self.wavelengthStop, 2, 1)
self.cropping.setLayout(layout)
self._layout.addWidget(self.cropping, row, 2, 1, 2)
row += 1
Expand Down Expand Up @@ -200,12 +216,20 @@ def _updateSize(self):
self._frame.setFixedHeight(height)

def loadFromSettings(self, settings: PWSAnalysisSettings):
if settings.filterCutoff is None:
self.filterCheckbox.setChecked(False)
else:
self.filterCheckbox.setChecked(True)
self.filterCutoff.setValue(settings.filterCutoff)
self.filterOrder.setValue(settings.filterOrder)
self.filterCutoff.setValue(settings.filterCutoff)
self.polynomialOrder.setValue(settings.polynomialOrder)
self.extraReflection.loadFromSettings(settings.numericalAperture, settings.referenceMaterial, settings.extraReflectanceId)
self.wavelengthStop.setValue(settings.wavelengthStop)
self.wavelengthStart.setValue(settings.wavelengthStart)
if settings.wavelengthStop is None:
self.croppingCheckbox.setChecked(False)
else:
self.croppingCheckbox.setChecked(True)
self.wavelengthStop.setValue(settings.wavelengthStop)
self.wavelengthStart.setValue(settings.wavelengthStart)
self.advanced.setCheckState(2 if settings.skipAdvanced else 0)
self.autoCorrStopIndex.setValue(settings.autoCorrStopIndex)
self.minSubCheckBox.setCheckState(2 if settings.autoCorrMinSub else 0)
Expand All @@ -229,12 +253,15 @@ def getSettings(self) -> PWSRuntimeAnalysisSettings:
raise ValueError("The selected reference acquisition has no valid PWS data.")
if len(cellMeta) == 0:
raise ValueError("No valid PWS acquisitions were selected.")
cutoff = self.filterCutoff.value() if self.filterCheckbox.checkState() else None
wvStart = self.wavelengthStart.value() if self.croppingCheckbox.checkState() else None
wvStop = self.wavelengthStop.value() if self.croppingCheckbox.checkState() else None
return PWSRuntimeAnalysisSettings(settings=PWSAnalysisSettings(filterOrder=self.filterOrder.value(),
filterCutoff=self.filterCutoff.value(),
filterCutoff=cutoff,
polynomialOrder=self.polynomialOrder.value(),
referenceMaterial=refMaterial,
wavelengthStart=self.wavelengthStart.value(),
wavelengthStop=self.wavelengthStop.value(),
wavelengthStart=wvStart,
wavelengthStop=wvStop,
skipAdvanced=self.advanced.checkState() != 0,
autoCorrMinSub=self.minSubCheckBox.checkState() != 0,
autoCorrStopIndex=self.autoCorrStopIndex.value(),
Expand Down
Loading

0 comments on commit e66612f

Please sign in to comment.