
Reading XPS Header and Data From the Same File


hrodstein
This snippet is a solution for an Igor user who wanted to use header information to set the scaling of a matrix loaded from an XPS file. This solution uses the technique of storing the header information in a list of keyword-value pairs and later querying that list for specific fields.
This simplified solution stems from https://www.wavemetrics.com/forum/general/loading-2d-data-matrix-its-fi…
For background information and links to other solutions, see https://www.wavemetrics.com/code-snippet/reading-header-and-data-same-f…
#pragma TextEncoding = "UTF-8" #pragma rtGlobals=3 // Use modern global access method and strict wave access #pragma DefaultTab={3,20,4} // Set default tab width in Igor Pro 9 and later // Reads header information and numeric data from a text file with a format like this: // # // # ImageWidth: 1376 pixel // # ImageHeight: 1040 pixel // # KineticEnergy: 14 eV // # PassEnergy: 160 eV // # EnergyScalingOffset: 3.44767 eV // # EnergyScalingFactor: 0.0153488 eV/pixel // # AzimuthalScalingOffset: 6.99327 deg // # AzimuthalScalingFactor: -0.0134615 deg/pixel // # // 00003800 00002400 00001200 00003800 00002400 ... (start of numeric data) // The numeric data is matrix data to be loaded into a 2D wave. // The user wanted to use the AzimuthalScalingOffset and AzimuthalScalingFactor // fields to set the matrix X scaling and the EnergyScalingOffset and EnergyScalingFactor // fields to set the matrix Y scaling. He also wanted to store all header information // in the wave note. // // To understand this file it is best to read it from the bottom (high-level) up. // GetFieldNameAndValueStrFromHeaderLine(headerLine, fieldName, valueStr) // headerLine is a possible line of header from the file. static Function GetFieldNameAndValueStrFromHeaderLine(headerLine, fieldName, valueStr) String headerLine // Input String& fieldName // Output String& valueStr // Output int lineLength = strlen(headerLine) String prefix = "# " // Header lines start with # followed by two spaces if (CmpStr(headerLine[0,2],prefix) != 0) return -1 // Not a header line endif headerLine = headerLine[3,lineLength] // Strip prefix lineLength -= 3 // Header lines after prefix start with "<Field Name>: " int pos = strsearch(headerLine, ": ", 0) if (pos < 0) // Did not find ": " return -1 // Failure endif fieldName = headerLine[0,pos-1] valueStr = headerLine[pos+2,lineLength-2] return 0 // Success End // ReadHeaderInfo(pathName, fileName, maxHeaderLines) // Returns a list of field names and values as colon-separated keyword-value pairs. static Function/S ReadHeaderInfo(pathName, fileName, maxHeaderLines) String pathName // Name of symbolic path. Ignored if filePath is full path. String fileName // File name, relative path or full path int maxHeaderLines // Maximum lines of header at start of file Variable refNum Open/R/P=$pathName refNum as fileName if (refNum == 0) // File not opened - bad pathName or fileName return "" endif String resultStr = "" int lineNumber = 0 do String line FReadLine refNum, line if (strlen(line) == 0) break // No more text in file endif String fieldName // e.g., "EnergyScalingOffset" String valueStr // e.g., "3.44767 eV" if (GetFieldNameAndValueStrFromHeaderLine(line, fieldName, valueStr) != 0) // No field on this line lineNumber += 1 continue endif resultStr += fieldName + ":" + valueStr + ";" lineNumber += 1 if (lineNumber >= maxHeaderLines) // There are no more header lines to examine break endif while(1) Close refNum return resultStr End // DemoReadXPSHeaderAndData(pathName, fileName) // Demonstrates reading header information and data from a file like the "XPS Sample Data.txt" file. // In this case, the file contains about 30 header lines followed by one column // of numeric data. The user wants to use certain header fields to form the wave name. // // To display an Open File dialog, execute: // DemoReadXPSHeaderAndData("", "") // // To load a file without an Open File dialog dialog, execute: // Create a symbolic path named "XPSData" and then execute // DemoReadXPSHeaderAndData("XPSData", "XPS Sample Data.txt") // If you are not familiar with Igor's "symbolic path" concept, execute this: // DisplayHelpTopic "Symbolic Paths" // // If the wave already exists, this routine overwrites it. Function DemoReadXPSHeaderAndData(pathName, fileName) String pathName // Name of an Igor symbolic path or "" to get an Open File dialog String fileName // Name of file or full path to file or "" to get an Open File dialog // If necessary, display an Open File dialog to get a valid reference to a file if ((strlen(pathName)==0) || (strlen(fileName)==0)) // Display dialog looking for file Variable refNum String fileFilters = "Data Files (*.txt,*.dat,*.csv):.txt,.dat,.csv;" fileFilters += "All Files:.*;" Open /D /R /F=fileFilters /P=$pathName refNum as fileName fileName = S_fileName // S_fileName is set by Open/D if (strlen(fileName) == 0) // User cancelled? return -1 endif endif // Read header information String headerInfo = ReadHeaderInfo(pathName, fileName, 100) // Printf "headerInfo=%s\r" // For debugging only // Load matrix wave LoadWave/G/P=$pathName/A=image/O/M/Q fileName if (V_Flag != 1) // We expect 1 wave to be created return -1 // Failure endif // Create wave reference String name = StringFromList(0, S_waveNames) // S_waveNames is created by LoadWave WAVE w = $name // Store header information in wave note String noteText = ReplaceString(";", headerInfo, "\r") // Each field on separate line Note w, noteText // Set X scaling double x0 = NumberByKey("AzimuthalScalingOffset", headerInfo) double dx = NumberByKey("AzimuthalScalingFactor", headerInfo) SetScale/P x x0, dx, "eV", w // Set Y scaling double y0 = NumberByKey("EnergyScalingOffset", headerInfo) double dy = NumberByKey("EnergyScalingFactor", headerInfo) SetScale/P y y0, dy, "°", w return 0 // Success End

Forum

Support

Gallery
Igor Pro 9
Learn More
Igor XOP Toolkit
Learn More
Igor NIDAQ Tools MX
Learn More
Sample XPS data file (from https://www.wavemetrics.com/comment/9726#comment-9726).
September 13, 2021 at 01:25 pm - Permalink