Skip to content

Commit a03ed0c

Browse files
authored
Merge pull request #2731 from kif/2729_expose_medfilt_in_GUI
Expose medfilt in GUI
2 parents ff208a9 + 380200a commit a03ed0c

File tree

4 files changed

+132
-99
lines changed

4 files changed

+132
-99
lines changed

src/pyFAI/geometry/core.py

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
__contact__ = "Jerome.Kieffer@ESRF.eu"
4141
__license__ = "MIT"
4242
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
43-
__date__ = "04/12/2025"
43+
__date__ = "10/12/2025"
4444
__status__ = "production"
4545
__docformat__ = "restructuredtext"
4646

@@ -2176,22 +2176,19 @@ def make_headers(self, type_="list"):
21762176
f2d = self.getFit2D()
21772177
res = [
21782178
"== pyFAI calibration ==",
2179-
"Distance Sample to Detector: %s m" % self.dist,
2180-
"PONI: %.3e, %.3e m" % (self.poni1, self.poni2),
2181-
"Rotations: %.6f %.6f %.6f rad" % (self.rot1, self.rot2, self.rot3),
2179+
f"Distance Sample to Detector: {self.dist} m",
2180+
f"PONI: {self.poni1:.3e}, {self.poni2:.3e} m",
2181+
f"Rotations: {self.rot1:.6f} {self.rot2:.6f} {self.rot3:.6f} rad",
21822182
"",
21832183
"== Fit2d calibration ==",
2184-
"Distance Sample-beamCenter: %.3f mm" % f2d["directDist"],
2185-
"Center: x=%.3f, y=%.3f pix" % (f2d["centerX"], f2d["centerY"]),
2186-
"Tilt: %.3f deg TiltPlanRot: %.3f deg"
2187-
% (f2d["tilt"], f2d["tiltPlanRotation"]),
2184+
f"Distance Sample-beamCenter: {f2d.directDist:.3f} mm",
2185+
f"Center: x={f2d.centerX:.3f}, y={f2d.centerY:.3f} pix",
2186+
f"Tilt: {f2d.tilt:.3f} deg TiltPlanRot: {f2d.tiltPlanRotation:.3f} deg",
21882187
"",
21892188
str(self.detector),
21902189
" Detector has a mask: %s " % (self.detector.mask is not None),
2191-
" Detector has a dark current: %s "
2192-
% (self.detector.darkcurrent is not None),
2193-
" detector has a flat field: %s "
2194-
% (self.detector.flatfield is not None),
2190+
f" Detector has a dark current: {self.detector.darkcurrent is not None}",
2191+
f" Detector has a flat field: {self.detector.flatfield is not None}",
21952192
"",
21962193
]
21972194

src/pyFAI/gui/IntegrationDialog.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
__contact__ = "Jerome.Kieffer@ESRF.eu"
3737
__license__ = "MIT"
3838
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
39-
__date__ = "08/12/2025"
39+
__date__ = "10/12/2025"
4040
__status__ = "development"
4141

4242
import logging
@@ -227,6 +227,8 @@ def createObserver(self, qtSafe=True):
227227

228228
class IntegrationDialog(qt.QWidget):
229229
"""Dialog to configure an azimuthal integration.
230+
231+
TODO: this is not a Dialog !!!
230232
"""
231233

232234
batchProcessRequested = qt.Signal()

src/pyFAI/gui/widgets/WorkerConfigurator.py

Lines changed: 41 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
__contact__ = "Jerome.Kieffer@ESRF.eu"
3434
__license__ = "MIT"
3535
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
36-
__date__ = "05/12/2025"
36+
__date__ = "10/12/2025"
3737
__status__ = "production"
3838

3939
import logging
@@ -75,6 +75,9 @@ class WorkerConfigurator(qt.QWidget):
7575
"""Frame displaying integration configuration which can be used as input
7676
param of the ~`pyFAI.worker.Worker`.
7777
"""
78+
INTEGRATOR_METHODS = {"integrate/average": "integrate1d_ng",
79+
"sigma-clip": "sigma_clip_ng",
80+
"median-filter": "medfilt1d_ng"}
7881

7982
def __init__(self, parent=None):
8083
qt.QWidget.__init__(self, parent)
@@ -140,24 +143,24 @@ def __init__(self, parent=None):
140143
self.radial_unit.setShortNameDisplay(True)
141144
self.radial_unit.model().changed.connect(self.__radialUnitUpdated)
142145
self.__radialUnitUpdated()
143-
146+
144147
# Fiber integration parameters
145148
fiber_units = [v for v in RADIAL_UNITS.values() if isinstance(v, UnitFiber)]
146149
self.ip_unit.setUnits(fiber_units)
147150
self.ip_unit.model().setValue(RADIAL_UNITS["qip_nm^-1"])
148151

149152
self.oop_unit.setUnits(fiber_units)
150153
self.oop_unit.model().setValue(RADIAL_UNITS["qoop_nm^-1"])
151-
154+
152155
self.nbpt_ip.setValidator(npt_validator)
153156
self.nbpt_oop.setValidator(npt_validator)
154-
157+
155158
so_validator = qt.QIntValidator()
156159
so_validator.setBottom(1)
157160
so_validator.setTop(8)
158161
self.sample_orientation.setValidator(so_validator)
159162
#
160-
163+
161164
doubleOrEmptyValidator = validators.AdvancedDoubleValidator(self)
162165
doubleOrEmptyValidator.setAllowEmpty(True)
163166
self.normalization_factor.setValidator(doubleOrEmptyValidator)
@@ -168,17 +171,17 @@ def __init__(self, parent=None):
168171
self.error_model.addItem(text, value)
169172
self.error_model.setCurrentIndex(0)
170173

171-
for value in ["integrate",
172-
"sigma_clip_ng",
173-
"medfilt_ng"
174-
]:
175-
text = value
174+
for text, value in self.INTEGRATOR_METHODS.items():
176175
self.integrator_name.addItem(text, value)
177176
self.integrator_name.setCurrentIndex(0)
178177
self.sigmaclip_threshold.setValidator(qt.QDoubleValidator(0.0, 100.0, 1))
179178
self.sigmaclip_threshold.setText("5.0")
180179
self.sigmaclip_maxiter.setValidator(qt.QIntValidator(0, 100))
181180
self.sigmaclip_maxiter.setText("5")
181+
self.medfilt_lower.setValidator(qt.QDoubleValidator(0.0, 100.0, 1))
182+
self.medfilt_upper.setValidator(qt.QDoubleValidator(0.0, 100.0, 1))
183+
self.medfilt_upper.setText("50.0")
184+
self.medfilt_lower.setText("50.0")
182185

183186
self.__configureDisabledStates()
184187

@@ -222,11 +225,13 @@ def __updateDisabledStates(self):
222225
self.oop_range_max.setEnabled(enabled)
223226
enabled = self.do_1d_integration.isChecked()
224227
self.vertical_integration.setEnabled(enabled)
225-
228+
226229
self.normalization_factor.setEnabled(self.do_normalization.isChecked())
227230
self.monitor_name.setEnabled(self.do_normalization.isChecked())
228-
self.sigmaclip_threshold.setEnabled(self.integrator_name.currentText() == "sigma_clip_ng")
229-
self.sigmaclip_maxiter.setEnabled(self.integrator_name.currentText() == "sigma_clip_ng")
231+
self.sigmaclip_threshold.setEnabled(self.integrator_name.currentText() == "sigma-clip")
232+
self.sigmaclip_maxiter.setEnabled(self.integrator_name.currentText() == "sigma-clip")
233+
self.medfilt_lower.setEnabled(self.integrator_name.currentText() == "median-filter")
234+
self.medfilt_upper.setEnabled(self.integrator_name.currentText() == "median-filter")
230235

231236
def __unitChanged(self):
232237
unit = self.wavelengthUnit.getUnit()
@@ -265,21 +270,21 @@ def __getAzimuthalNbpt(self):
265270
if value == "":
266271
return None
267272
return int(value)
268-
273+
269274
def __getInPlaneNbpt(self):
270275
# Only for WorkerFiberConfig
271276
value = str(self.nbpt_ip.text()).strip()
272277
if value == "":
273278
return None
274279
return int(value)
275-
280+
276281
def __getOutOfPlaneNbpt(self):
277282
# Only for WorkerFiberConfig
278283
value = str(self.nbpt_oop.text()).strip()
279284
if value == "":
280285
return None
281286
return int(value)
282-
287+
283288
def getPoni(self):
284289
poni = {"wavelength": self.__geometryModel.wavelength().value(),
285290
"dist": self.__geometryModel.distance().value(),
@@ -297,13 +302,13 @@ def getPoni(self):
297302

298303
def getPoniDict(self):
299304
return self.getPoni().as_dict()
300-
305+
301306
def _getIntegrationActiveTab(self) -> int:
302307
# tab_index = 0 -> Azimuthal integration
303308
# tab_index = 1 -> Fiber integration
304309
tab_index = int(self.tabWidget.currentIndex())
305310
return tab_index
306-
311+
307312
def getWorkerConfigGeneric(self):
308313
"""Read the configuration of the plugin and returns it as a WorkerConfig / WorkerFiberConfig instance
309314
@@ -387,11 +392,17 @@ def splitFiles(filenames):
387392
value = str(value)
388393
wc.monitor_name = value
389394

390-
if self.integrator_name.currentText() == "sigma_clip_ng":
395+
if self.integrator_name.currentText() == "sigma-clip":
391396
wc.nbpt_azim = 1
392397
wc.integrator_method = "sigma_clip_ng"
393398
wc.extra_options = {"thres": float(self.sigmaclip_threshold.text()),
394-
"max_iter": float(self.sigmaclip_maxiter.text()),
399+
"max_iter": int(self.sigmaclip_maxiter.text()),
400+
}
401+
elif self.integrator_name.currentText() == "median-filter":
402+
wc.nbpt_azim = 1
403+
wc.integrator_method = "medfilt1d_ng"
404+
wc.extra_options = {"percentile":(float(self.medfilt_lower.text()),
405+
float(self.medfilt_upper.text())),
395406
}
396407
return wc
397408

@@ -448,7 +459,7 @@ def splitFiles(filenames):
448459
if self.do_oop_range.isChecked():
449460
wc.oop_range = [self._float("oop_range_min", -numpy.inf),
450461
self._float("oop_range_max", numpy.inf)]
451-
462+
452463
wc.vertical_integration = self.vertical_integration.isChecked()
453464
wc.integration_1d = self.do_1d_integration.isChecked()
454465

@@ -492,7 +503,7 @@ def getConfig(self):
492503
:return: dict with all information
493504
"""
494505
return self.getWorkerConfig().as_dict()
495-
506+
496507
def setConfig(self, dico):
497508
"""Setup the widget from its description
498509
@@ -508,7 +519,7 @@ def setConfig(self, dico):
508519
self.tabWidget.setCurrentIndex(1)
509520
else:
510521
raise ValueError(f"{integrator_class} is not a valid Integrator class")
511-
522+
512523
def setWorkerConfig(self, wc):
513524
"""Setup the widget from its description
514525
@@ -571,7 +582,7 @@ def normalizeFiles(filenames):
571582
self.polarization_factor.setValue(wc.polarization_factor)
572583
elif isinstance(wc.polarization_factor, (tuple, list)):
573584
self.polarization_factor.setValue(wc.polarization_factor[0])
574-
585+
575586
if type(wc) is integration_config.WorkerConfig:
576587
self.nbpt_rad.setText(str_(wc.nbpt_rad))
577588
self.nbpt_azim.setText(str_(wc.nbpt_azim))
@@ -597,25 +608,25 @@ def normalizeFiles(filenames):
597608
self.vertical_integration.setChecked(wc.vertical_integration)
598609
self.do_1d_integration.setChecked(wc.integration_1d)
599610
unit_ip = parse_fiber_unit(**wc.unit_ip)
600-
611+
601612
# In UnitSelector, searching the unit is made with 'is' not '==', not valid for FiberUnit (which are copies)
602613
for index in range(self.ip_unit.count()):
603614
item = self.ip_unit.itemData(index)
604-
if item == unit_ip:
615+
if item == unit_ip:
605616
self.ip_unit.setCurrentIndex(index)
606617
break
607-
618+
608619
unit_oop = parse_fiber_unit(**wc.unit_oop)
609620
for index in range(self.oop_unit.count()):
610621
item = self.oop_unit.itemData(index)
611-
if item == unit_oop:
622+
if item == unit_oop:
612623
self.oop_unit.setCurrentIndex(index)
613624
break
614625

615626
self.incident_angle_deg.setText(f"{numpy.rad2deg(unit_ip.incident_angle):.2f}")
616627
self.tilt_angle_deg.setText(f"{numpy.rad2deg(unit_ip.tilt_angle):.2f}")
617628
self.sample_orientation.setText(str(unit_ip.sample_orientation))
618-
629+
619630
self.do_solid_angle.setChecked(bool(wc.correct_solid_angle))
620631
self.do_dummy.setChecked(wc.do_dummy)
621632
self.do_dark.setChecked(wc.do_dark)
@@ -664,7 +675,7 @@ def normalizeFiles(filenames):
664675
self.sigmaclip_maxiter.setText(str(extra_options.get("max_iter", 5)))
665676

666677
self.__updateDisabledStates()
667-
678+
668679
def getOpenFileName(self, title):
669680
"""Display a dialog to select a filename and return it.
670681

0 commit comments

Comments
 (0)