added phasng for signal

This commit is contained in:
markusro committed 2026-10-22 00:17:01 +02:00
1 parent 12d7323851
commit 9d60eeabf6
4 files changed
+131 -24

No files matched your search

+71 -23
View File
@@ -717,8 +717,6 @@ class DamarisGUI:
# cleanup
self.si = None
if self.monitor.overflow_job_ids:
logger.warning( "ADC overflow occurred in jobs: %s", ', '.join( [str( j ) for j in self.monitor.overflow_job_ids] ))
self.state = DamarisGUI.Edit_State
self.sw.enable_editing( )
self.toolbar_run_button.set_sensitive( True )
@@ -922,8 +920,6 @@ class DamarisGUI:
self.lockfile.del_experiment(self.id)
# now everything is stopped
if self.monitor.overflow_job_ids:
logger.warning( "ADC overflow occurred in jobs: %s", ', '.join( [str( j ) for j in self.monitor.overflow_job_ids] ))
self.state = DamarisGUI.Edit_State
self.sw.enable_editing( )
self.toolbar_run_button.set_sensitive( True )
@@ -2979,7 +2975,6 @@ class MonitorWidgets:
css.load_from_data( b".adc_ok { background-image: none; background-color: #4caf50; }"
b".adc_error { background-image: none; background-color: #e53935; }" )
gtk.StyleContext.add_provider_for_screen( gdk.Screen.get_default( ), css, gtk.STYLE_PROVIDER_PRIORITY_APPLICATION )
self.overflow_css = css
self.overflow_indicator_button = gtk.Button( label="ADC" )
self.overflow_indicator_button.set_tooltip_text( "ADC overflow indicator, red if an overflow occurred" )
self.overflow_job_ids = [ ]
@@ -3062,6 +3057,11 @@ class MonitorWidgets:
self.display_source_combobox.add_attribute( display_source_cell, 'text', 0 )
# GTK3 fix: Prevent blank space from child tree nodes in popup
self.display_source_combobox.set_wrap_width(1)
# interactive display phase rotation: display only, never stored in HDF
self.display_phase_scale = self.xml_gui.get_object( "display_phase_scale" )
self.display_phase_value_label = self.xml_gui.get_object( "display_phase_value_label" )
self.display_phase = 0
self.display_phase_scale.connect( "value-changed", self.display_phase_changed )
self.source_list_reset( )
self.display_source_path_label = self.xml_gui.get_object( "display_source_path_label" )
@@ -3095,6 +3095,7 @@ class MonitorWidgets:
self.source_list_cache = {}
def source_list_reset( self ):
self.display_phase_scale.set_value( 0 )
self.display_source_combobox.set_model(None)
try:
# OPTIMIZATION: Replacing the TreeStore is much faster than clear() for large trees
@@ -3463,6 +3464,25 @@ class MonitorWidgets:
event = DataPool.Event( DataPool.Event.updated_value, new_data_name )
glib.idle_add(self.datapool_idle_listener, event, priority=glib.PRIORITY_DEFAULT_IDLE )
def display_phase_changed( self, widget, data=None ):
"""
set the display phase in degrees (0-360) for the plotted signal
Example: monitor.display_phase_scale.set_value(90)
"""
self.display_phase = widget.get_value( )
self.display_phase_value_label.set_label( "%.0f°" % self.display_phase )
source = self.displayed_data[ 1 ]
if source is not None and isinstance( source, (Accumulation, ADC_Result) ) \
and source.get_number_of_channels( ) == 2:
# coalesce like the other display updates, dragging the slider
# emits one event per pointer motion
self.update_counter_lock.acquire( )
self.update_counter += 1
self.update_counter_lock.release( )
glib.idle_add( self.update_display_idle_event, self.displayed_data[ 0 ][ : ],
priority=glib.PRIORITY_DEFAULT_IDLE )
def display_autoscaling_toggled( self, widget, data=None ):
self.matplot_axes.set_autoscale_on( self.display_autoscaling_checkbutton.get_active( ) )
if self.displayed_data[ 0 ] is not None:
@@ -3737,7 +3757,7 @@ class MonitorWidgets:
Set the background color of the ADC indicator button: green if
clipped is False, red if clipped is True.
>>> monitor.set_overflow_indicator(True) # button turns red
Example: monitor.set_overflow_indicator(True)
"""
style = self.overflow_indicator_button.get_style_context( )
style.remove_class( "adc_ok" )
@@ -3750,7 +3770,7 @@ class MonitorWidgets:
the list of job ids where an ADC overflow occurred, right click
opens a menu to reset the overflow state.
>>> monitor.overflow_indicator_button_press(button, event)
Example: monitor.overflow_indicator_button_press(button, event)
"""
if event.button == 1:
if self.overflow_job_ids:
@@ -3760,7 +3780,7 @@ class MonitorWidgets:
dialog = gtk.MessageDialog(parent=self.main_window,
type=gtk.MessageType.WARNING,
flags=gtk.DialogFlags.MODAL,
buttons=("_OK", gtk.ResponseType.OK))
buttons=gtk.ButtonsType.OK)
dialog.set_markup("ADC OVERFLOW in jobs:")
dialog.format_secondary_text( text )
dialog.run( )
@@ -3776,11 +3796,11 @@ class MonitorWidgets:
def clear_overflow_indicator( self, widget=None, event=None ):
"""
Reset handler for the ADC overflow warning: sets the circle back to
Reset handler for the ADC overflow warning: sets the indicator back to
green and clears the status bar warning, without starting a new
experiment.
>>> monitor.clear_overflow_indicator()
Example: monitor.clear_overflow_indicator()
"""
self.statusbar_overflow_label.set_text( "" )
self.set_overflow_indicator( False )
@@ -3885,11 +3905,41 @@ class MonitorWidgets:
return
if isinstance( in_result, Accumulation ) or isinstance( in_result, ADC_Result ) or isinstance( in_result, TemperatureResult ):
xmin = in_result.get_xmin( )
xmax = in_result.get_xmax( )
plot_result = in_result
if self.display_phase and isinstance( in_result, (Accumulation, ADC_Result) ) \
and in_result.get_number_of_channels( ) == 2:
# display only: plot a rotated copy, the pool object itself and
# any HDF storage keep the unrotated data. The rotation reads
# the raw channel arrays, so take the snapshot while holding the
# lock that the result scripts use to update them in place.
in_result.lock.acquire( )
try:
plot_result = in_result.phase( self.display_phase )
finally:
in_result.lock.release( )
if isinstance( plot_result, Accumulation ):
# the copy's y_square is not rotated, so its own error
# calculation would produce nonsense limits
plot_result.use_error = False
ymin = in_result.get_ymin( )
ymax = in_result.get_ymax( )
# error bars are read from the pool object, i.e. they are not
# phase rotated, and the rotated copy would derive them from
# mismatched y_square anyway
show_errors = (self.display_statistics_checkbutton.get_active( ) and
in_result.uses_statistics( ) and in_result.ready_for_drawing_error( ))
xmin = plot_result.get_xmin( )
xmax = plot_result.get_xmax( )
ymin = plot_result.get_ymin( )
ymax = plot_result.get_ymax( )
if plot_result is not in_result and show_errors:
# the plot draws the unrotated pool errors on the rotated data,
# so the axis limits must use that same combination
for i in range( plot_result.get_number_of_channels( ) ):
err = in_result.get_yerr( i )
ymin = min( ymin, (plot_result.get_ydata( i ) - err).min( ) )
ymax = max( ymax, (plot_result.get_ydata( i ) + err).max( ) )
# Initial rescaling needed?
if self.__rescale:
@@ -3900,7 +3950,7 @@ class MonitorWidgets:
self.matplot_axes.set_xscale( "linear" )
self.matplot_axes.set_xlim(xmin, xmax)
elif x_scale == "log10":
xminpos = in_result.get_xminpos( )
xminpos = plot_result.get_xminpos( )
self.matplot_axes.set_xscale("log", base=10, nonpositive="mask")
self.matplot_axes.set_xlim(xminpos, xmax)
elif x_scale == "ppm":
@@ -3914,7 +3964,7 @@ class MonitorWidgets:
self.matplot_axes.set_yscale( "linear" )
self.matplot_axes.set_ylim(ymin, ymax)
elif y_scale == "log10":
yminpos = in_result.get_yminpos()
yminpos = plot_result.get_yminpos()
self.matplot_axes.set_yscale("log", base=10, nonpositive="mask")
self.matplot_axes.set_ylim( yminpos, ymax )
self.__rescale = False
@@ -3954,14 +4004,14 @@ class MonitorWidgets:
ylim_max > ymax + 0.2 * ydiff or ylim_min < ymin - 0.2 * ydiff):
self.matplot_axes.set_ylim(ymin, ymax)
xdata = in_result.get_xdata( )
chans = in_result.get_number_of_channels( )
xdata = plot_result.get_xdata( )
chans = plot_result.get_number_of_channels( )
data = [ ]
colors = [ (0, 0, 0.8, 1), (0.7, 0, 0, 1), (0, 0.7, 0, 1), (0.7, 0.5, 0, 1),
(0, 0, 0, 1) ] # rgba tuples: blue, red, green, yellow
for i in range( chans ):
data.append( in_result.get_ydata( i ) )
data.append( plot_result.get_ydata( i ) )
moving_average = data_slice = None
if max_points_to_display > 0 and len( xdata ) > max_points_to_display:
@@ -3990,8 +4040,7 @@ class MonitorWidgets:
self.graphen[ i ].set_data( xdata, data[ i ] )
# Statistics activated?
if (self.display_statistics_checkbutton.get_active( ) and
in_result.uses_statistics( ) and in_result.ready_for_drawing_error( )):
if show_errors:
for i in range( chans ):
err = in_result.get_yerr( i )
if moving_average is not None:
@@ -4067,11 +4116,10 @@ class MonitorWidgets:
# the warning is only justified for results with a valid job_id;
# results without job id (e.g. backend errors) only get the plot marker
if getattr(in_result, "job_id", None) is not None:
if self.statusbar_overflow_label.get_text() == "":
self.statusbar_overflow_label.set_markup('<span foreground="red" weight="bold">ADC OVERFLOW</span>')
self.set_overflow_indicator( True )
if in_result.job_id not in self.overflow_job_ids:
self.overflow_job_ids.append( in_result.job_id )
self.statusbar_overflow_label.set_markup( '<span foreground="red" weight="bold">ADC OVERFLOW</span>' )
logger.warning( "ADC overflow detected in job %s", in_result.job_id )
elif self.clipping_marker is not None:
try:
+47
View File
@@ -37,6 +37,12 @@
<property name="step-increment">1</property>
<property name="page-increment">1</property>
</object>
<object class="GtkAdjustment" id="display_phase_adjustment">
<property name="upper">360</property>
<property name="value">0</property>
<property name="step-increment">1</property>
<property name="page-increment">10</property>
</object>
<object class="GtkMenu" id="documentation_menu">
<property name="visible">True</property>
<property name="can-focus">False</property>
@@ -1096,6 +1102,47 @@ Public License instead of this License.
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="display_phase_label">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes"> Phase:</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkScale" id="display_phase_scale">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="width-request">150</property>
<property name="draw-value">False</property>
<property name="digits">0</property>
<property name="round-digits">0</property>
<property name="adjustment">display_phase_adjustment</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">3</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="display_phase_value_label">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">0°</property>
<property name="width-chars">4</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">4</property>
</packing>
</child>
</object>
<packing>
<property name="y-options"/>