
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