GitLab will be upgraded on June 23rd evening. During the upgrade the service will be unavailable, sorry for the inconvenience.

Commit 14765f07 authored by Thomas Vincent's avatar Thomas Vincent

simpler update of progress bar using generator.

This replaces the use of thread, signal and callback by a generator.
parent 93ec4f86
......@@ -114,15 +114,12 @@ class FitWidget(Qt.QWidget):
Argument is the name of the file containing the results.
"""
__sigFitDone = Qt.Signal()
__PROGRESS_DELAY = 500
def __init__(self, qspaceFile, **kwargs):
super(FitWidget, self).__init__(**kwargs)
self.__qspaceH5 = QSpaceH5(qspaceFile)
self.__progTimer = None
self.__outputFile = None
......@@ -178,8 +175,6 @@ class FitWidget(Qt.QWidget):
slider.setRange(min_, max_)
slider.setValues(min_, max_)
self.__sigFitDone.connect(self.__slotFitDone)
def roiWidget(self):
"""Returns the Roi3DSelectorWidget instance.
......@@ -249,25 +244,20 @@ class FitWidget(Qt.QWidget):
background=background)
self.__statusLabel.setText('Running...')
self.__progTimer = Qt.QTimer()
self.__progTimer.setSingleShot(True)
self.__progTimer.timeout.connect(self.__slotProgTimer)
self.sigProcessStarted.emit()
try:
self.sigProcessStarted.emit()
self.__fitter.peak_fit(blocking=False, callback=self.__sigFitDone.emit)
self.__progTimer.start(self.__PROGRESS_DELAY)
for progress in self.__fitter.peak_fit(blocking=False):
self.__progBar.setValue(int(100 * progress))
Qt.QApplication.processEvents()
except Exception as ex:
# TODO : popup
self.__statusLabel.setText('ERROR')
_logger.error(ex)
self.__lock(False)
self.sigProcessDone.emit(None)
def __slotProgTimer(self):
if self.__fitter:
self.__progBar.setValue(self.__fitter.progress())
self.__progTimer.start(self.__PROGRESS_DELAY)
else:
self.__slotFitDone()
def __lock(self, lock):
enable = not lock
......@@ -277,8 +267,6 @@ class FitWidget(Qt.QWidget):
self.__runButton.setEnabled(enable)
def __slotFitDone(self):
self.__progTimer.stop()
self.__progTimer = None
self.__lock(False)
status = self.__fitter.status
......
......@@ -33,7 +33,6 @@ __license__ = "MIT"
import logging
import functools
import multiprocessing
from threading import Thread
import numpy as np
from scipy.optimize import leastsq
......@@ -85,20 +84,18 @@ class FitTypes(object):
GAUSSIAN, CENTROID = ALLOWED
class PeakFitter(Thread):
"""
:param str qspace_f: path to the HDF5 file containing the qspace cubes
class PeakFitter(object):
"""Class performing fit/com processing
:param str qspace_f: path to the HDF5 file containing the qspace cubes
:param FitTypes fit_type:
:param indices: indices of the cubes (in the input HDF5 dataset) for which
:param Union[numpy.ndarray,None] indices:
indices of the cubes (in the input HDF5 dataset) for which
the dim0/dim1/dim2 peaks coordinates will be computed. E.g : if the array
[1, 2, 3] is provided, only those cubes will be fitted.
:type indices: *optional* `array_like`
:param Union[int,None] n_proc:
Number of process to use. If None, the config value is used.
:param Union[List[List[int]],None] roi_indices: QSpace ROI to process
:param BackgroundTypes background: The background subtraction to perform
"""
......@@ -113,15 +110,9 @@ class PeakFitter(Thread):
background=BackgroundTypes.NONE):
super(PeakFitter, self).__init__()
self.__progress = 0
self.__results = None
self.__thread = None
self.__callback = None
self.__status = self.READY
self.__indices = None
self.__qspace_f = qspace_f
self.__fit_type = fit_type
self.__background = background
......@@ -145,18 +136,15 @@ class PeakFitter(Thread):
with QSpaceH5.QSpaceH5(qspace_f) as qspace_h5:
with qspace_h5.qspace_dset_ctx() as dset:
qdata_shape = dset.shape
n_points = qdata_shape[0]
if indices is None:
indices = list(range(n_points))
else:
indices = indices[:]
except IOError:
self.__set_status(self.ERROR)
raise
self.__indices = np.array(indices)
if indices is None:
n_points = qdata_shape[0]
self.__indices = np.arange(n_points)
else:
self.__indices = np.array(indices, copy=True)
def __set_status(self, status):
assert status in self.__STATUSES
......@@ -166,24 +154,23 @@ class PeakFitter(Thread):
results = property(lambda self: self.__results)
def peak_fit(self, blocking=True, callback=None):
if self.__thread and self.__thread.is_alive():
raise RuntimeError('A fit is already in progress.')
def peak_fit(self, blocking=True):
"""Run fit/com processing
:param bool blocking:
True for blocking until the end of the processing,
False for yielding progress during the processing.
"""
self.__results = None
if blocking:
return self.__peak_fit()
for _ in self.__peak_fit():
pass
else:
self.__thread = Thread(target=self.__peak_fit)
self.__callback = callback
self.__thread.start()
def progress(self):
return 100 * self.__progress / len(self.__indices)
for progress, _ in enumerate(self.__peak_fit()):
yield progress / len(self.__indices)
def __peak_fit(self):
self.__progress = 0
self.__set_status(self.RUNNING)
pool = multiprocessing.Pool(self.__n_proc)
......@@ -197,7 +184,7 @@ class PeakFitter(Thread):
roiIndices=self.__roi_indices),
self.__indices):
fit_results.append(result)
self.__progress += 1
yield result
pool.close()
pool.join()
......@@ -248,14 +235,8 @@ class PeakFitter(Thread):
results._set_axis_status(axis_index, array['Status'])
self.__results = results
self.__set_status(self.DONE)
if self.__callback:
self.__callback()
return results
# Per process cache for fit process
_per_process_cache = None
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment