Commit 179e42f8 authored by Carsten Richter's avatar Carsten Richter

improved fit widget and moved Max Fit to Centroid

parent f2c7e975
......@@ -43,46 +43,25 @@ from ..process.fit.fitresults import FitResult
class CentroidFitter(Fitter):
def fit(self, i_fit, i_cube, qx_profile, qy_profile, qz_profile):
zSum = qz_profile.sum()
if sum != 0:
com = self._qz.dot(qz_profile) / zSum
idx = np.abs(self._qz - com).argmin()
i_max = qz_profile.max()
self._shared_results.set_qz_results(i_fit,
[qz_profile[idx], com, i_max],
FitStatus.OK)
else:
self._shared_results.set_qz_results(i_fit,
[np.nan, np.nan, np.nan],
FitStatus.FAILED)
ySum = qy_profile.sum()
if ySum != 0:
com = self._qy.dot(qy_profile) / ySum
idx = np.abs(self._qy - com).argmin()
i_max = qy_profile.max()
self._shared_results.set_qy_results(i_fit,
[qy_profile[idx], com, i_max],
FitStatus.OK)
else:
self._shared_results.set_qy_results(i_fit,
[np.nan, np.nan, np.nan],
FitStatus.FAILED)
xSum = qx_profile.sum()
if xSum != 0:
com = self._qx.dot(qx_profile) / xSum
idx = np.abs(self._qx - com).argmin()
i_max = qx_profile.max()
self._shared_results.set_qx_results(i_fit,
[qx_profile[idx], com, i_max],
FitStatus.OK)
else:
self._shared_results.set_qx_results(i_fit,
[np.nan, np.nan, np.nan],
FitStatus.FAILED)
profiles = qx_profile, qy_profile, qz_profile
for iax, axis in enumerate(self._AXIS_NAMES):
y = profiles[iax]
Sum = y.sum()
if Sum != 0:
x = getattr(self, "_%s"%axis)
com = x.dot(y) / Sum
#idx = np.abs(x - com).argmin()
max_idx = y.argmax()
I_max = y[max_idx]
x_max = x[max_idx]
self._shared_results.set_results(axis, i_fit,
[com, Sum, I_max, x_max],
FitStatus.OK)
else:
self._shared_results.set_results(axis, i_fit,
[np.nan, np.nan, np.nan, np.nan],
FitStatus.FAILED)
class CentroidResults(FitSharedResults):
def __init__(self,
......@@ -91,47 +70,24 @@ class CentroidResults(FitSharedResults):
shared_status=None,
**kwargs):
super(CentroidResults, self).__init__(n_points=n_points,
n_params=3,
n_params=4,
n_peaks=1,
shared_results=shared_results,
shared_status=shared_status)
def fit_results(self, *args, **kwargs):
qx_results = self._npy_qx_results
qy_results = self._npy_qy_results
qz_results = self._npy_qz_results
fit_name = 'Centroid'
fitresults = FitResult(fit_name, *args, **kwargs)
for axis in self._AXIS_NAMES:
results = getattr(self, "_npy_%s_results"%axis)
status = getattr(self, "_npy_%s_status"%axis)
qx_status = self._npy_qx_status
qy_status = self._npy_qy_status
qz_status = self._npy_qz_status
for i_p, param in enumerate(("COM", "I_sum", "I_max", "Pos_max")):
fitresults.add_result(axis, 'centroid', param, results[:, 0+i_p].ravel())
fit_name = 'Centroid'
results = FitResult(fit_name, *args, **kwargs)
results.add_qx_result('centroid', 'I', qx_results[:, 0].ravel())
results.add_qx_result('centroid', 'COM',
qx_results[:, 1].ravel())
results.add_qx_result('centroid', 'Max',
qx_results[:, 2].ravel())
results.set_qx_status(qx_status)
results.add_qy_result('centroid', 'I', qy_results[:, 0].ravel())
results.add_qy_result('centroid',
'COM',
qy_results[:, 1].ravel())
results.add_qy_result('centroid', 'Max',
qy_results[:, 2].ravel())
results.set_qy_status(qy_status)
results.add_qz_result('centroid', 'I', qz_results[:, 0].ravel())
results.add_qz_result('centroid',
'COM',
qz_results[:, 1].ravel())
results.add_qz_result('centroid', 'Max',
qz_results[:, 2].ravel())
results.set_qz_status(qz_status)
return results
fitresults.set_status(axis, status)
return fitresults
class CentroidPlotter(Plotter):
......@@ -139,9 +95,13 @@ class CentroidPlotter(Plotter):
plot.setGraphTitle('center of mass')
for peakName, peak in peakParams.items():
center = peak.get('COM')
xmax = peak.get('Pos_max')
if np.isfinite(center):
plot.addXMarker(center, legend='center of mass')
plot.addXMarker(center, legend='center of mass', text="com")
plot.addXMarker(xmax, legend='maximum position',
text="max",
color="gray")
def getPlotTitle(self):
return 'Center Of Mass'
......
......@@ -52,23 +52,29 @@ class GaussianFitter(Fitter):
super(GaussianFitter, self).__init__(*args, **kwargs)
self._n_peaks = self._shared_results._n_peaks
self._z_0 = np.tile([1.0, self._qz.mean(), 1.0],
self._shared_results._n_peaks)
self._y_0 = np.tile([1.0, self._qy.mean(), 1.0],
self._shared_results._n_peaks)
self._x_0 = np.tile([1.0, self._qx.mean(), .1],
self._shared_results._n_peaks)
def fit(self, i_fit, i_cube, qx_profile, qy_profile, qz_profile):
z_fit, success_z = gaussian_fit(self._qz, qz_profile, self._z_0)
y_fit, success_y = gaussian_fit(self._qy, qy_profile, self._y_0)
x_fit, success_x = gaussian_fit(self._qx, qx_profile, self._x_0)
self._shared_results.set_qz_results(i_fit, z_fit, success_z)
self._shared_results.set_qy_results(i_fit, y_fit, success_y)
self._shared_results.set_qx_results(i_fit, x_fit, success_x)
profiles = dict(zip(self._AXIS_NAMES,
[qx_profile, qy_profile, qz_profile]))
for axis in self._AXIS_NAMES: # qx, qy, qz
x = getattr(self, "_%s"%axis)
y = profiles[axis]
# compute guess:
area = y.sum()/self._n_peaks * (x[-1]-x[0])/len(x)
cen = x[y.argmax()]
sigma = area / (y.max() * _const_inv_2_pi_)
guess = np.tile([area, cen, sigma],self._n_peaks)
#print(axis, guess)
if self._n_peaks>1: # we don't actually use many peaks yet
# a stupid way to distribute the starting values...
idx = np.where(y>(y.max()/20.))[0]
i_cen = idx[np.arange(0, len(idx), len(idx)//self._n_peaks)]
cens = x[i_cen]
guess[1::3] = cens
fit, success = gaussian_fit(x, y, guess)
self._shared_results.set_results(axis, i_fit, fit, success)
class GaussianResults(FitSharedResults):
......@@ -84,48 +90,23 @@ class GaussianResults(FitSharedResults):
shared_status=shared_status)
def fit_results(self, *args, **kwargs):
qx_results = self._npy_qx_results
qy_results = self._npy_qy_results
qz_results = self._npy_qz_results
qx_status = self._npy_qx_status
qy_status = self._npy_qy_status
qz_status = self._npy_qz_status
fit_name = 'Gaussian'
results = FitResult(fit_name, *args, **kwargs)
for i_peak in range(self._n_peaks):
peak_name = 'gauss_{0}'.format(i_peak)
i_start = i_peak * 3
results.add_qx_result(peak_name, 'intensity',
qx_results[:, i_start].ravel())
results.add_qx_result(peak_name, 'position',
qx_results[:, i_start + 1].ravel())
results.add_qx_result(peak_name, 'width',
qx_results[:, i_start + 2].ravel())
results.add_qy_result(peak_name, 'intensity',
qy_results[:, i_start].ravel())
results.add_qy_result(peak_name, 'position',
qy_results[:, i_start + 1].ravel())
results.add_qy_result(peak_name, 'width',
qy_results[:, i_start + 2].ravel())
results.add_qz_result(peak_name, 'intensity',
qz_results[:, i_start].ravel())
results.add_qz_result(peak_name, 'position',
qz_results[:, i_start + 1].ravel())
results.add_qz_result(peak_name, 'width',
qz_results[:, i_start + 2].ravel())
fitresults = FitResult(fit_name, *args, **kwargs)
results.set_qy_status(qy_status)
results.set_qx_status(qx_status)
results.set_qz_status(qz_status)
for axis in self._AXIS_NAMES:
results = getattr(self, "_npy_%s_results"%axis)
status = getattr(self, "_npy_%s_status"%axis)
for i_peak in range(self._n_peaks):
peak_name = 'gauss_{0}'.format(i_peak)
return results
i_start = i_peak * 3 # 3 parameters
for i_p, param in enumerate(("Area", "Center", "Sigma")):
fitresults.add_result(axis, peak_name, param,
results[:, i_start+i_p].ravel())
fitresults.set_status(axis, status)
return fitresults
# 1d Gaussian func
......@@ -201,9 +182,9 @@ class GaussianPlotter(Plotter):
def plotFit(self, plot, x, peakParams):
for peakName, peak in peakParams.items():
height = peak.get('intensity')
position = peak.get('position')
width = peak.get('width')
height = peak.get('Area')
position = peak.get('Center')
width = peak.get('Sigma')
params = [height, position, width]
......
#!/usr/bin/python
# coding: utf8
# /*##########################################################################
#
# Copyright (c) 2015-2017 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
# ###########################################################################*/
from __future__ import absolute_import
__authors__ = ["D. Naudet"]
__date__ = "01/01/2017"
__license__ = "MIT"
from .Plotter import Plotter
from ..process.fit.Fitter import Fitter
from ..process.fit.fitresults import FitStatus
from ..process.fit.sharedresults import FitSharedResults
from ..process.fit.fitresults import FitResult
class MaxFitter(Fitter):
"""
Fitter that returns the maximum and its position.
"""
def fit(self, i_fit, i_cube, qx_profile, qy_profile, qz_profile):
idx_max = qx_profile.argmax()
self._shared_results.set_qx_results(i_fit,
[qx_profile[idx_max],
self._qx[idx_max]],
FitStatus.OK)
idx_max = qy_profile.argmax()
self._shared_results.set_qy_results(i_fit,
[qy_profile[idx_max],
self._qy[idx_max]],
FitStatus.OK)
idx_max = qz_profile.argmax()
self._shared_results.set_qz_results(i_fit,
[qz_profile[idx_max],
self._qz[idx_max]],
FitStatus.OK)
class MaxResults(FitSharedResults):
def __init__(self,
n_points=None,
shared_results=None,
shared_status=None):
super(MaxResults, self).__init__(n_points=n_points,
n_params=2,
n_peaks=1,
shared_results=shared_results,
shared_status=shared_status)
def fit_results(self, *args, **kwargs):
qx_results = self._npy_qx_results
qy_results = self._npy_qy_results
qz_results = self._npy_qz_results
qx_status = self._npy_qx_status
qy_status = self._npy_qy_status
qz_status = self._npy_qz_status
fit_name = 'Max'
results = FitResult(fit_name, *args, **kwargs)
results.add_qx_result('max', 'max', qx_results[:, 0].ravel())
results.add_qx_result('max', 'position',
qx_results[:, 1].ravel())
results.set_qx_status(qx_status)
results.add_qy_result('max', 'max', qy_results[:, 0].ravel())
results.add_qy_result('max', 'position',
qy_results[:, 1].ravel())
results.set_qy_status(qy_status)
results.add_qz_result('max', 'max', qz_results[:, 0].ravel())
results.add_qz_result('max', 'position',
qz_results[:, 1].ravel())
results.set_qz_status(qz_status)
return results
class MaxPlotter(Plotter):
def plotFit(self, plot, x, peakParams):
plot.setGraphTitle('Maximum')
for peakName, peak in peakParams.items():
maximum = peak.get('max')
position = peak.get('position')
plot.addXMarker(position, legend='max_position')
def getPlotTitle(self):
return 'Maximum'
if __name__ == '__main__':
pass
......@@ -59,96 +59,43 @@ class SilxFitter(Fitter):
self._results = np.zeros(3 * self._n_peaks)
def fit(self, i_fit, i_cube, qx_profile, qy_profile, qz_profile):
profiles = qx_profile, qy_profile, qz_profile
fit = self._fit
results = self._results
failed = False
fit.setdata(x=self._qx, y=qx_profile)
try:
fit.estimate()
fit.runfit()
except Exception as ex:
failed = True
results[:] = np.nan
if not failed:
for param in fit.fit_results:
p_name = param['name']
p_type = p_name[0]
peak_idx = int(p_name[-1]) - 1
if peak_idx >= self._n_peaks:
continue
# TODO : error management
param_idx = self.p_types.index(p_type)
results[peak_idx * 3 + param_idx] = param['fitresult']
self._shared_results.set_qx_results(i_fit, results, FitStatus.OK)
else:
self._shared_results.set_qx_results(i_fit, results,
FitStatus.FAILED)
failed = False
fit.setdata(x=self._qy, y=qy_profile)
for iax, axis in enumerate(self._AXIS_NAMES):
failed = False
x = getattr(self, "_%s"%axis)
y = profiles[iax]
try:
fit.estimate()
fit.runfit()
except Exception as ex:
failed = True
fit.setdata(x=x, y=y)
results[:] = np.nan
try:
fit.estimate()
fit.runfit()
except Exception as ex:
failed = True
if not failed:
for param in fit.fit_results:
p_name = param['name']
p_type = p_name[0]
peak_idx = int(p_name[-1]) - 1
results[:] = np.nan
if peak_idx >= self._n_peaks:
continue
if not failed:
for param in fit.fit_results:
p_name = param['name']
p_type = p_name[0]
peak_idx = int(p_name[-1]) - 1
# TODO : error management
param_idx = self.p_types.index(p_type)
results[peak_idx * 3 + param_idx] = param['fitresult']
self._shared_results.set_qy_results(i_fit, results, FitStatus.OK)
else:
self._shared_results.set_qy_results(i_fit, results,
FitStatus.FAILED)
if peak_idx >= self._n_peaks:
continue
failed = False
fit.setdata(x=self._qz, y=qz_profile)
try:
fit.estimate()
fit.runfit()
except Exception as ex:
failed = True
results[:] = np.nan
if not failed:
for param in fit.fit_results:
p_name = param['name']
p_type = p_name[0]
peak_idx = int(p_name[-1]) - 1
if peak_idx >= self._n_peaks:
continue
# TODO : error management
param_idx = self.p_types.index(p_type)
results[peak_idx * 3 + param_idx] = param['fitresult']
self._shared_results.set_qz_results(i_fit, results, FitStatus.OK)
else:
self._shared_results.set_qz_results(i_fit, results,
FitStatus.FAILED)
# TODO : error management
param_idx = self.p_types.index(p_type)
results[peak_idx * 3 + param_idx] = param['fitresult']
self._shared_results.set_results(axis, i_fit, results,
FitStatus.OK)
else:
self._shared_results.set_results(axis, i_fit, results,
FitStatus.FAILED)
class SilxResults(FitSharedResults):
......@@ -164,56 +111,33 @@ class SilxResults(FitSharedResults):
shared_status=shared_status)
def fit_results(self, *args, **kwargs):
qx_results = self._npy_qx_results
qy_results = self._npy_qy_results
qz_results = self._npy_qz_results
qx_status = self._npy_qx_status
qy_status = self._npy_qy_status
qz_status = self._npy_qz_status
fit_name = 'SilxFit'
results = FitResult(fit_name, *args, **kwargs)
for i_peak in range(self._n_peaks):
peak_name = 'gauss_{0}'.format(i_peak)
i_start = i_peak * 3
fitresults = FitResult(fit_name, *args, **kwargs)
results.add_qx_result(peak_name, 'area',
qx_results[:, i_start].ravel())
results.add_qx_result(peak_name, 'position',
qx_results[:, i_start + 1].ravel())
results.add_qx_result(peak_name, 'fwhm',
qx_results[:, i_start + 2].ravel())
for axis in self._AXIS_NAMES:
results = getattr(self, "_npy_%s_results"%axis)
status = getattr(self, "_npy_%s_status"%axis)
for i_peak in range(self._n_peaks):
peak_name = 'gauss_{0}'.format(i_peak)
results.add_qy_result(peak_name, 'area',
qy_results[:, i_start].ravel())
results.add_qy_result(peak_name, 'position',
qy_results[:, i_start + 1].ravel())
results.add_qy_result(peak_name, 'fwhm',
qy_results[:, i_start + 2].ravel())
i_start = i_peak * 3
results.add_qz_result(peak_name, 'area',
qz_results[:, i_start].ravel())
results.add_qz_result(peak_name, 'position',
qz_results[:, i_start + 1].ravel())
results.add_qz_result(peak_name, 'fwhm',
qz_results[:, i_start + 2].ravel())
for i_p, param in enumerate(("Area", "Center", "FWHM")):
fitresults.add_result(axis, peak_name, param,
results[:, i_start+i_p].ravel())
results.set_qy_status(qy_status)
results.set_qx_status(qx_status)
results.set_qz_status(qz_status)
fitresults.set_status(axis, status)
return results
return fitresults
class SilxPlotter(Plotter):
def plotFit(self, plot, x, peakParams):
for peakName, peak in peakParams.items():
area = peak.get('area')
position = peak.get('position')
width = peak.get('fwhm')
area = peak.get('Area')
position = peak.get('Center')
width = peak.get('FWHM')
params = [area, position, width]
......
......@@ -33,5 +33,5 @@ __license__ = "MIT"
from .Gaussian import GaussianFitter, GaussianResults, GaussianPlotter
from .Centroid import CentroidFitter, CentroidResults, CentroidPlotter
from .MaxFitter import MaxFitter, MaxResults, MaxPlotter
#from .MaxFitter import MaxFitter, MaxResults, MaxPlotter
from .SilxFitter import SilxFitter, SilxResults, SilxPlotter
......@@ -162,8 +162,8 @@ class FitWidget(Qt.QWidget):
"""
FitTypes = OrderedDict([('Gaussian', FitTypes.GAUSSIAN),
('Centroid', FitTypes.CENTROID),
('Maximum', FitTypes.MAX)])\
('Centroid', FitTypes.CENTROID)])
# ('Maximum', FitTypes.MAX)])\
# ,
# ('Silx', FitTypes.SILX)])
......
......@@ -44,7 +44,13 @@ from ..project.QSpaceGroup import QSpaceItem
from .fitview.FitModel import FitModel, FitH5Node
from .fitview.DropPlotWidget import DropPlotWidget
from ...fit import GaussianPlotter, CentroidPlotter, SilxPlotter, MaxPlotter
from ...fit import GaussianPlotter, CentroidPlotter, SilxPlotter
class FitTreeView(TreeView):
def sizeHint(self):
return Qt.QSize(400, 175)
class FitView(Qt.QMainWindow):
......@@ -77,19 +83,16 @@ class FitView(Qt.QMainWindow):
# only one entry per file supposed right now
self.__entry = fitH5.entries()[0]
centralWid = Qt.QWidget()
layout = Qt.QGridLayout(centralWid)
self.__plots = []
self.__fitPlots = []
treeDock = Qt.QDockWidget()
self.__model = FitModel()
rootNode = FitH5Node(fitItem.fitFile)
self.__model.appendGroup(rootNode)
tree = self.__tree = TreeView()
tree = self.__tree = FitTreeView()
tree.setMinimumWidth(410) # TODO: is there a better way?
#tree.resize(420, tree.height())
tree.setModel(self.__model)
# tree.setRootIndex(self.__model.index(0, 0, tree.rootIndex()))
tree.setSelectionBehavior(Qt.QAbstractItemView.SelectItems)
......@@ -100,72 +103,50 @@ class FitView(Qt.QMainWindow):
treeDock.setWidget(tree)
self.addDockWidget(Qt.Qt.LeftDockWidgetArea, treeDock)
centralWid = Qt.QWidget()
layout = Qt.QGridLayout(centralWid)
self.__plots = []
self.__fitPlots = []
grpBox = GroupBox('Maps')
grpLayout = Qt.QVBoxLayout(grpBox)
plot = DropPlotWidget(grid=False,
curveStyle=False,
colormap=False,
roi=False,
mask=False,
yInverted=False)
grpLayout.addWidget(plot)
self.__plots.append(plot)
plot.sigPointSelected.connect(self.__slotPointSelected)
plot = DropPlotWidget(grid=False,
curveStyle=False,
colormap=False,
roi=False,
mask=False,
yInverted=False)
grpLayout.addWidget(plot)
self.__plots.append(plot)
plot.sigPointSelected.connect(self.__slotPointSelected)
plot = DropPlotWidget(grid=False,
curveStyle=False,
colormap=False,
roi=False,
mask=False,
yInverted=False)
grpLayout.addWidget(plot)
self.__plots.append(plot)
plot.sigPointSelected.connect(self.__slotPointSelected)
for axis in FitH5QAxis.axis_names:
plot = DropPlotWidget(grid=False,
curveStyle=False,
colormap=False,
roi=False,
mask=False,
yInverted=False)
grpLayout.addWidget(plot)
self.__plots.append(plot)
plot.sigPointSelected.connect(self.__slotPointSelected)
layout.addWidget(grpBox, 0, 1)
# =================================
# =================================
grpBox = GroupBox('Fit')
grpLayout = Qt.QVBoxLayout(grpBox)
plot = XsocsPlot2D()
plot.setKeepDataAspectRatio(False)
grpLayout.addWidget(plot)
self.__fitPlots.append(plot)
plot.setGraphTitle('Qx fit')
plot.setShowMousePosition(True)
plot = XsocsPlot2D()
plot.setKeepDataAspectRatio(False)
grpLayout.addWidget(plot)
self.__fitPlots.append(plot)
plot.setGraphTitle('Qy fit')
plot.setShowMousePosition(True)