Load, Process and Display Modular Programming Example


#pragma rtGlobals=3		// Use modern global access method.

// This is an answer to the question:
//	How do I load a delimited text file, do a histogram of each loaded wave,
//	and create a graph showing the histograms?
// Or more generally:
//	How do I load waves from a file, process them, and display the results.
//
// To illustrate modular programming, the procedures are organized into the following steps:
//	Load Waves					// Load waves from a file
//	Process Waves				// Create histograms of loaded waves
//	Display Processed Waves		// Create a graph showing histograms
// This modularity makes it possible to test and use the modules separately which
// makes development easier, results in more comprehensible code and increases reusability.
//
// The LoadProcessAndDisplay function does everything (loads, processes and displays).
//
// The best way to understand the procedures is to read the highest level
// (LoadProcessAndDisplay, at the bottom of the file) first.
// Then read the subroutines (LoadDelimitedFile, ProcessWaves and DisplayProcessedWaves).
//
// To try the routine, choose Macros->Load, Process and Display.
// Then select a delimited text file.

// Allow comma, tab or spaces as the delimiter in the delimited text file.
static StrConstant kDelimitersStr = ",\t "

Menu "Macros"
	"Load, Process, and Display...", LoadProcessAndDisplay()
End

// LoadDelimitedFile(pathName, fileName)
// Returns a semicolon-separated list of waves loaded or "" if cancel.
Function/S LoadDelimitedFile(pathName, fileName)
	String pathName		// Name of an Igor symbolic path or "".
	String fileName		// Name of file or full path to file.

	// First get a valid reference to a file.
	if ((strlen(pathName)==0) || (strlen(fileName)==0))
		// Display dialog looking for file.
		Variable refNum
		Open/D/R/P=$pathName refNum as fileName
		fileName = S_fileName			// S_fileName is set by Open/D
		if (strlen(fileName) == 0)			// User cancelled?
			return ""
		endif
	endif
	
	// Now load the data. The /V flag specifies the accepted delimiters in the data file.
	// Add the /A flag if you don't want the "Loading Delimited Text" dialog.
	// Add the /O flag if you want to overwrite existing waves with the same names.
	LoadWave /J /D /E=1 /K=0 /W /V={kDelimitersStr,"",0,0} /P=$pathName fileName
	Variable numWavesLoaded = V_flag			// V_flag is set by LoadWave
	if (numWavesLoaded == 0)
		return ""
	endif
	
	String listOfWavesLoaded = S_waveNames	// S_waveNames is set by LoadWave
	
	return listOfWavesLoaded
End

// ProcessWave(w, index)
// Processes a single input wave creating an output wave.
// Returns name of output wave.
Function/S ProcessWave(wIn, index)
	Wave wIn
	Variable index						// Currently not used
	
	Variable numHistBins = 10		// Desired number of bins
	
	String destWaveName = NameOfWave(wIn) + "_hist"
	Make /O /N=(numHistBins) $destWaveName
	Histogram /B=1 wIn, $destWaveName
	
	return destWaveName
End

// ProcessWaves(listIn)
// Processes a list of waves.
// list is a semicolon-separated list of input waves.
// The function result is a semicolon-separated list of output waves.
Function/S ProcessWaves(listIn)
	String listIn											// Semicolon-separated list
	
	Variable numItems = ItemsInList(listIn)
	String listOut = ""									// Semicolon-separated list
	
	Variable i
	for(i=0; i<numItems; i+=1)
		String nameIn = StringFromList(i, listIn)
		Wave wIn = $nameIn							// Create wave reference
		String nameOut = ProcessWave(wIn, i)
		listOut += nameOut + ";"
	endfor
	
	return listOut
End

// GetIndexedRGBColor(colorIndex, red, green, blue)
// Returns distinct RGB colors for different traces.
// colorIndex is 0..15 and selects the color that is returned.
// red, green and blue are outputs.
// See below for an example.
Function GetIndexedRGBColor(colorIndex, red, green, blue)
	Variable colorIndex
	Variable &red, &green, &blue				// Outputs

	Variable numColors = 16					// Number of colors in the following switch
	
	colorIndex = mod(colorIndex, numColors)			// Wrap around if necessary
	switch(colorIndex)
		case 0:		// Time wave
			red = 0; green = 0; blue = 0;								// Black
			break
			
		case 1:
			red = 65535; green = 16385; blue = 16385;			// Red
			break
			
		case 2:
			red = 2; green = 39321; blue = 1;						// Green
			break
			
		case 3:
			red = 0; green = 0; blue = 65535;						// Blue
			break
			
		case 4:
			red = 39321; green = 1; blue = 31457;					// Purple
			break
			
		case 5:
			red = 39321; green = 39321; blue = 39321;			// Gray
			break
			
		case 6:
			red = 65535; green = 32768; blue = 32768;			// Salmon
			break
			
		case 7:
			red = 0; green = 65535; blue = 0;						// Lime
			break
			
		case 8:
			red = 16385; green = 65535; blue = 65535;			// Turquoise
			break
			
		case 9:
			red = 65535; green = 32768; blue = 58981;			// Light purple
			break
			
		case 10:
			red = 39321; green = 26208; blue = 1;					// Brown
			break
			
		case 11:
			red = 52428; green = 34958; blue = 1;					// Light brown
			break

		case 12:
			red = 65535; green = 32764; blue = 16385;			// Orange
			break

		case 13:
			red = 1; green = 52428; blue = 26586;					// Teal
			break

		case 14:
			red = 1; green = 3; blue = 39321;						// Dark blue
			break

		case 15:
			red = 65535; green = 49151; blue = 55704;			// Pink
			break
	endswitch
End

// DisplayProcessedWave(w, index)
// Displays a single wave in a new graph, if index is zero, or in the top graph, if index is non-zero.
Function DisplayProcessedWave(w, index)
	Wave w
	Variable index
	
	if (index == 0)
		Display w
	else
		AppendToGraph w
	endif
	
	ModifyGraph mode=5		// Bars display mode
	
	// Get name of last trace added
	String traceList = TraceNameList("", ";", 1)
	Variable numTraces = ItemsInList(traceList)
	String traceName = StringFromList(numTraces-1, traceList)

	Variable red, green, blue
	GetIndexedRGBColor(index, red, green, blue)
	ModifyGraph rgb($traceName) = (red, green, blue)
End

// DisplayProcessedWaves(processedWaveList)
// Displays a list of waves.
// processedWaveList is a semicolon-separated list of waves to be displayed.
Function DisplayProcessedWaves(processedWaveList)
	String processedWaveList		// Semicolon-separated list

	Variable numItems = ItemsInList(processedWaveList)
	
	Variable i
	for(i=0; i<numItems; i+=1)
		String name = StringFromList(i, processedWaveList)
		Wave w = $name						// Create wave reference
		DisplayProcessedWave(w, i)
	endfor
End

// LoadProcessAndDisplay()
// Loads data from a delimited text file, processes the data and displays the processed result.
Function LoadProcessAndDisplay()
	String loadedWavesList = LoadDelimitedFile("", ",")
	if (strlen(loadedWavesList) == 0)
		return -1				// Load cancelled
	endif
	
	String processedWaveList = ProcessWaves(loadedWavesList)
	if (strlen(loadedWavesList) == 0)
		return -1				// Should not happen
	endif

	DisplayProcessedWaves(processedWaveList)
End

Hi Mr Rodstein,

I am new with IgorPro and I am struggling a little
I have tried to break up your LoadProcessAndDisplay(). I would like to use the already loaded data to ProcessAndDisplay.
I attempted to break up your Procedure by changing the Menu "Macros" into

Menu "Macros"
"Load, Process, and Display...", LoadProcessAndDisplay()
"Load", LoadDelimitedFile("", "")
"Process", ProcessWaves("")
"Display", DisplayProcessedWaves("")

The Loading part, off course, runs on its own. The Process and Display miss their input. I would like to have ProccessWaves and DisplayProccessedWaves run on a variable amount of waves that are already plotted. Could you please help me out? Thanks


Forum

Support

Gallery

Igor Pro 10

Learn More

Igor XOP Toolkit

Learn More

Igor NIDAQ Tools MX

Learn More