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