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
3939import 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