Load EC-Lab Data File
#pragma TextEncoding = "UTF-8"
#pragma rtGlobals=3 // Use modern global access method and strict wave access.
// About "Load EC-Lab Data File" procedures
// To use this procedure, execute a command such as:
// LoadECLabDataFile(pathName, filePath)
// where
// String pathName // Name of an Igor symbolic path or ""
// String filePath // Name of file or full path to file
// If you are not familiar with Igor symbolic paths, execute:
// DisplayHelpTopic "Symbolic Paths"
// LoadECLabDataFile automatically determines the name line, first data line, and delimiter character.
// If it gets those parameters wrong, you can use LoadECLabDataFile2 instead. With LoadECLabDataFile2,
// you specify those parameters in addition to the pathName and filePath.
// These procedures solve issues raised by the column names in EC-Lab data files.
// There are two categories of wave names in Igor: standard and liberal. Standard names start
// with a letter and can include letters, numbers, and the underscore character. Liberal names
// can include any character except for single-quote, double-quote, colon, and semicolon.
// For further discussion of standard and liberal names, execute:
// DisplayHelpTopic "Object Names"
// Programming with liberal names is tricky and most Igor procedures do not work with
// liberal names. Consequently, LoadWaves, by default, "cleans up" column names to produce
// standard wave names. Using LoadWave/B, you can load waves with liberal names but this
// is usually a bad idea because liberal names cause issues down the road unless you are
// very careful.
// The EC-Lab data file from Bio-Logic uses column names that contain characters that
// are not legal in Igor standard names. Examples are "<Ewe>/V" and "|Ewe|/V". Furthermore,
// when LoadWaves cleans these up, they both evaluate to X_Ewe__V, causing a name conflict.
// And, there are some EC-Lab data files that contain columns with the exact same name
// more than once - see https://www.wavemetrics.com/node/21003.
// The LoadECLabDataFile procedure handles these issues by removing characters that
// are not legal in standard Igor names and then by making sure that each name is unique.
// As a result, you wind up with waves named, for example, Ewe_V and Ewe_V1.
//
// Here is a more extensive, though not complete, list of wave names produced by LoadECLabDataFile:
// freq_Hz, ReZ_Ohm, ImZ_Ohm, Z_Ohm, PhaseZ_deg, time_s, Ewe_V, I_mA
// Cs_uF, Cp_uF, cyclenumber, IRange, Ewe_V1, I_A, Q_Qo_mA_h, ReY_Ohm_1
// ImY_Ohm_1, Y_Ohm_1, PhaseY_deg, I_mA1, dq_mA_h, x1
static Function/S MakeNameUnique(name, nameList)
String name // Name that we are about to add to /B flag
String nameList // List of names already added to /B flag
String originalName = name
Variable index = 0
do
if (WhichListItem(name, nameList) < 0)
break // name is not in the list
endif
index += 1
sprintf name, "%s%d", originalName, index // Generate new name by appending a number
while(1)
return name
End
// RemoveIllegalCharacters(name)
// Removes characters that we know are not legal in Igor standard names.
// Here are typical resulting wave names:
// freq_Hz, ReZ_Ohm, ImZ_Ohm, Z_Ohm, PhaseZ_deg, time_s, Ewe_V, I_mA
// Cs_uF, Cp_uF, cyclenumber, IRange, Ewe_V1, I_A, Q_Qo_mA_h, ReY_Ohm_1
// ImY_Ohm_1, Y_Ohm_1, PhaseY_deg, I_mA1, dq_mA_h, x1
static Function/S RemoveIllegalCharacters(name)
String name
name = ReplaceString("|", name, "")
name = ReplaceString("<", name, "")
name = ReplaceString(">", name, "")
name = ReplaceString("(", name, "")
name = ReplaceString(")", name, "")
name = ReplaceString("/", name, "_")
name = ReplaceString(" ", name, "")
return name
End
Function/S GenerateColumnInfoStr(pathName, filePath, nameLine, delimiter)
String pathName // Name of an Igor symbolic path or ""
String filePath // Name of file or full path to file
Variable nameLine // 0-based number of line containing column names
String delimiter // Typically "," or "\t" (tab)
Variable refNum
Open/R/P=$pathName refNum as filePath
Variable lineNumber = 0
do
String text
FReadLine refNum, text
if (lineNumber == nameLine)
break
endif
lineNumber += 1
while(1)
text = ReplaceString("\r", text, "") // Remove any CR terminator character
text = ReplaceString("\n", text, "") // Remove any LF terminator character
Close refNum
String nameList = "" // Accumulates names
String columnInfoStr = ""
Variable numNames = ItemsInList(text, delimiter)
Variable index
for(index=0; index<numNames; index+=1)
String name = StringFromList(index, text, delimiter)
if (strlen(name) == 0)
name = "_skip_"
endif
// Remove characters that we know are not legal in Igor standard names
name = RemoveIllegalCharacters(name)
// Make sure this is a legal standard wave name
name = CleanupName(name, 0)
// Make the name unique if it conflicts with a name already added to nameList
name = MakeNameUnique(name, nameList)
columnInfoStr += "N='" + name + "';"
nameList += name + ";"
endfor
return columnInfoStr
End
// GetFileToLoad(pathName, filePath)
// If necessary, displays an Open File dialog to allow user to choose the file.
// Returns -1 if cancelled, 0 if OK.
// If the function result is 0 then, on return, pathName and filePath are suitable
// for use by LoadWave.
static Function GetFileToLoad(pathName, filePath)
String& pathName // Input and output: Name of an Igor symbolic path or ""
String& filePath // Input and output: Name of file or full path to file
if ((strlen(pathName)==0) || (strlen(filePath)==0))
// Display dialog looking for file.
String fileFilters = "Text Files (*.txt):.txt;"
fileFilters += "CSV Files (*.csv):.csv;"
fileFilters += "DAT Files (*.dat):.dat;"
fileFilters += "All Files:.*;"
Variable refNum
Open/D/R/F=fileFilters/P=$pathName refNum as filePath
filePath = S_fileName // S_fileName is full path set by Open/D
if (strlen(filePath) == 0) // User cancelled?
return -1
endif
endif
return 0
End
Function LoadECLabDataFile2(pathName, filePath, nameLine, firstDataLine, delimiter)
String pathName // Name of an Igor symbolic path or ""
String filePath // Name of file or full path to file
Variable nameLine // Zero-based line number of names line
Variable firstDataLine // Zero-based line number of first data line
String delimiter // Delimiter between names and numbers, typically "," or "\t" (tab)
// First get a valid reference to a file
Variable result = GetFileToLoad(pathName, filePath)
if (result != 0)
return result // User cancelled Open File dialog
endif
String columnInfoStr = GenerateColumnInfoStr(pathName, filePath, nameLine, delimiter)
// Print columnInfoStr
LoadWave/J/Q/L={nameLine,firstDataLine,0,0,0}/A/B=columnInfoStr/E=1/P=$pathName filePath
return 0
End
static Function FindFirstDataLineAndDelimiter(pathName, filePath, firstDataLine, delimiter)
String pathName // Name of an Igor symbolic path or ""
String filePath // Name of file or full path to file
Variable& firstDataLine // Output
String& delimiter // Output
Variable refNum = 0
Open/R/P=$pathName refNum as filePath
if (refNum == 0)
return -1 // Unexpected error
endif
Variable lineNum = 0
do
String text
FReadLine refNum, text
if (strlen(text) == 0)
Close refNum
return -1 // Did not find first data line - Should not happen if this is a valid EC-Lab file
endif
Variable num
sscanf text, "%g", num
if (V_Flag == 1)
// The line starts with a number
firstDataLine = lineNum
String junk
sscanf text, "%[^\t ,]", junk // Deposit all characters other than tab, space, or comma into junk
int len = strlen(junk)
delimiter = text[len]
break
endif
lineNum += 1
while(1)
Close refNum
return 0
End
// LoadECLabDataFile(pathName, filePath)
// Automatically determines the name line, first data line, and delimiter,
// and then calls LoadECLabDataFile2.
// It is assumed that the first line that starts with a valid number is the first
// data line and that the line before the first data line is the name line.
Function LoadECLabDataFile(pathName, filePath)
String pathName // Name of an Igor symbolic path or ""
String filePath // Name of file or full path to file
// First get a valid reference to a file
Variable result = GetFileToLoad(pathName, filePath)
if (result != 0)
return result // User cancelled Open File dialog
endif
Variable nameLine = 0 // Zero-based line number of names line
Variable firstDataLine = 0 // Zero-based line number of first data line
String delimiter = "" // Delimiter between names and numbers, typically "," or "\t" (tab)
result = FindFirstDataLineAndDelimiter(pathName, filePath, firstDataLine, delimiter)
if (result != 0)
return result // Should not happen if this is a valid EC-Lab file
endif
nameLine = firstDataLine - 1
// For debugging only
// Printf "Name line = %d, first data line = %d, delimiter = %d\r", nameLine, firstDataLine, char2num(delimiter)
String columnInfoStr = GenerateColumnInfoStr(pathName, filePath, nameLine, delimiter)
// Print columnInfoStr
LoadWave/J/Q/L={nameLine,firstDataLine,0,0,0}/A/B=columnInfoStr/E=1/P=$pathName filePath
return 0
End
Forum
Support
Gallery
Igor Pro 10
Learn More
Igor XOP Toolkit
Learn More
Igor NIDAQ Tools MX
Learn More
This procedure illustrates how to clean up wave names and prevent duplicate names when loading a file, such as the EC-Labs data file from Bio-Logic, that uses characters that are not legal in standard Igor names.
See the comments in the procedures above for details.
October 8, 2019 at 07:03 am - Permalink
The version committed today automatically skips header lines.
In this version, the LoadECLabDataFile function takes only two parameters: pathName and filePath. It automatically determines nameLine, firstDataLine, and delimiter based on two assumptions: that the first line which starts with a valid number is the firstDataLine and that the nameLine is the line before the firstDataLine.
The procedures include a LoadECLabDataFile2 function which is the same as the old LoadECLabDataFile function and takes five parameters: pathName, filePath, nameLine, firstDataLine, delimiter. LoadECLabDataFile2 is for use only if LoadECLabDataFile does not automatically find the correct nameLine, firstDataLine, and delimiter parameters.
October 17, 2019 at 07:51 am - Permalink
I would like to used EC-lab macro for opening my EC-lab data. But unfortunately due to the error of "int" command in the following line I couldn't compile the macro
int len = strlen(junk)
could you please tell me how can I manage this error?
July 1, 2020 at 10:28 am - Permalink
The "int" declaration was added in Igor version 7. What version are you using?
July 1, 2020 at 01:05 pm - Permalink
thanks for reply. I am using version 6.3. How can I replace "int" in Igor version 6.3?
July 3, 2020 at 05:12 am - Permalink