Gatan | AMETEKSkip to Main Content
No options found

Monitor a value over time

DigitalMicrograph Script

This example script monitors a value and plots it in regular intervals, creating a growing LinePlot. The script is a template that can easily be modified to create time-logging of any script-accessible value.

Preview

//////////////////////////////////////////////////////
// Time-Monitor-Script	
//////////////////////////////////////////////////////
// This general script monitors a value and plots it 
// in regular intervals. When launched, a Lineplot is 
// created and values are ploted on the right-most 
// channel regularly. Previous values are shifted to 
// the left. The following key-strokes are registered:
//	<S>		Start or ReStart the measurement
//	<P> 	Pause or UnPause the measurement
//	<ESC>	Stop the script
//	<+>		Double plot range
//	<->		Half plot range
//////////////////////////////////////////////////////
// To customize the script, derive a new class from 
// CMonitor class and override the following three 
// methods:
//
// number GetCurrentPlotValue( object self ) 
//		Return the value to be plotted at time of call
//
// string GetCurrentPlotLabel( object self )
//		Return the legend label of the plotted value 
//
// string GetCurrentValueUnit( object self )
//		Return the intensity unit for the graph
//////////////////////////////////////////////////////
class CMonitor
{
	number wtime_sec, taskID, WListenerID, KeyListenerID 
	image plot 
	
	number GetCurrentPlotValue( object self ) {return random();}
	string GetCurrentPlotLabel( object self ) {return "Random value";}
	string GetCurrentValueUnit( object self ) {return "unit";}
		
	void TUpdate( object self )
	{
		plot.SetStringNote( "Measurement last point", GetTime(1) )
		number nch = plot.ImageGetDimensionSize(0)
		plot.slice1(0,0,0,0,nch-1,1) = plot.slice1(1,0,0,0,nch-1,1)
		plot[0,nch-1,1,nch] = self.GetCurrentPlotValue()
	}
	
	void Reset( object self ){	plot = 0;}
	object StartMeasure( object self )
	{
		if ( taskID )
			RemoveMainThreadTask( taskID )
			
		taskID	= self.AddMainThreadPeriodicTask( "TUpdate", wtime_sec )
	}
	
	object StopMeasure( object self )
	{
		RemoveMainThreadTask( taskID )
		taskID = 0
	}
	
	void ResizePlot( object self, number factor )
	{
		number nch = plot.ImageGetDimensionSize( 0 )
		number newCh = trunc( nCh * factor )
		if ( newCh < 2 ) newCH = 2
		number lastP = nCh < newCh ? nCh : newCh
		image plotCopy := plot.ImageClone()
		
		plot.ImageResize( 1, newCH )
		plot.ImageSetDimensionCalibration( 0, -wtime_sec * newCH, wtime_sec, "sec", 0 )
		plot.slice1( newCh - lastP, 0, 0, 0, lastP, 1 ) = plotCopy.slice1( nCh - lastP, 0, 0, 0, lastP, 1 )
		plot.ImageGetImageDisplay( 0 ).LinePlotImageDisplaySetDisplayedChannels( 0, newCH )
	}
	
	void WClose( object self, number e_fl, DocumentWindow Win )
	{
		result( GetTime( 1 ) + ": Script window closed.\n" )
		self.StopMeasure()
	}
	
	number 	KeyListenAction( object self, ImageDisplay disp, object keydesc ) 
	{
		if ( keydesc.MatchesKeyDescriptor( "esc" ) ) 
		{
			self.StopMeasure()
			disp.ImageDisplayRemoveKeyHandler( KeyListenerID )
			documentWindow win = disp.ImageDisplayGetImage().ImageGetOrCreateImageDocument().ImageDocumentGetwindow()
			win.WindowRemoveWindowListener( WListenerID )
			result( GetTime(1) + ": Script stopped\n" )
		}
		else if ( keydesc.MatchesKeyDescriptor( "s" ) ) 
		{
			if ( taskID )
			{
				self.StopMeasure()
				self.Reset()
				self.StartMeasure()
				result( GetTime(1) + ": Measurement Re-Started\n" )
			}
			else
			{
				self.StartMeasure()
				result( GetTime(1) + ": Measurement Started\n" )
			}
		}
		else if ( keydesc.MatchesKeyDescriptor( "p" ) ) 
		{
			if ( taskID )
			{
				self.StopMeasure()
				result( GetTime(1) + ": Measurement Paused\n" )
			}
			else
			{
				self.StartMeasure()
				result( GetTime(1) + ": Measurement Continued\n" )
			}
		}
		else if ( keydesc.MatchesKeyDescriptor( "add" ) ) 
		{
			self.ResizePlot( 2 )
		}
		else if ( keydesc.MatchesKeyDescriptor( "subtract" ) ) 
		{
			self.ResizePlot( 0.5 )
		}
		else 
			return 0
			
		return 1
	}
	
	object Init( object self, number waitTime_sec, number bufferChannels )
	{
		wtime_sec = waitTime_sec
		plot := RealImage( "Value Graph", 4, bufferChannels )
		plot.ImageSetDimensionCalibration( 0, -waitTime_sec * bufferChannels, waitTime_sec, "sec", 0 )
		plot.ImageSetIntensityUnitString( self.GetCurrentValueUnit() )

		plot.ShowImage()
		DocumentWindow	win = plot.imageGetOrCreateImageDocument().ImageDocumentGetWindow()
		ImageDisplay disp = plot.ImageGetImageDisplay( 0 )
		
		disp.LinePlotImageDisplaySetLegendShown( 1 )
		disp.LinePlotImageDisplaySetSliceDrawingStyle( 0, 1 )
		disp.LinePlotImageDisplaySetSliceLineThickness( 0, 3 )
		object sliceID = disp.ImageDisplayGetSliceIDByIndex( 0 ) 
		disp.ImageDisplaySetSliceLabelByID( sliceID, self.GetCurrentPlotLabel() )
						
		WListenerID = win.WindowAddWindowListener( self, "window_about_to_close:WClose;" )
		KeyListenerID = disp.ImageDisplayAddKeyHandler( self, "KeyListenAction" )
		
		return self
	}
}


////////////////////////////////////////////////
// Memory-Monitor-Script	
////////////////////////////////////////////////
// Plot the size of the largest contiguous free
// memory block over time.
Class CMemMonitor : CMonitor
{
	number GetCurrentPlotValue( object self ) 
	{
		return ApplicationGetLargestFreeMemoryBlock()
	}
	
	string GetCurrentPlotLabel( object self )
	{
		return "Free Memory"
	}
	string GetCurrentValueUnit( object self )
	{
		return "Byte"
	}
}

// Start the monitor
alloc(CMemMonitor).Init(0.2,100)