Supported File Formats
SurfaceTopography supports reading surface topography data from a wide variety of file formats commonly used by commercial profilometers, AFMs, and other surface measurement instruments.
File Format Table
Format Name |
Extensions |
Description |
|---|---|---|
Alicona Imaging AL3D |
|
AL3D format of Alicona Imaging optical 3D measurement systems |
BCR-STM |
|
BCR-STM and BCRF file formats for scanning tunneling microscopy |
Bruker/Veeco/DI Nanoscope |
|
Digital Instruments, Veeco, and Bruker Dimension AFM formats |
Bruker Dektak OPDx |
|
File format of the Bruker Dektak XT series stylus profilometer |
Bruker Wyko OPD |
|
Files generated by Vision software of Bruker Wyko white-light interferometers |
Digital Metrology OmniSurf3D |
|
OmniSurf3D format from Digital Metrology |
Digital Surf Mountains MNT |
|
Digital Surf Mountains OLE-based format with compressed height data (see Digital Surf Mountains MNT Format) |
Digital Surf SUR |
|
Digital Surf SUR data files |
Gwyddion |
|
Native file format of the open-source SPM visualization software Gwyddion |
Hierarchical Data Format (HDF5) |
|
HDF5 files with 2D arrays (e.g., contact mechanics challenge data) |
Igor Binary Wave |
|
Igor binary wave container format (WaveMetrics Igor Pro) |
ISO 25178-71 SDF |
|
ISO 25178-71 Surface Data File format (ASCII and binary variants) |
JPK Image Scan |
|
TIFF-based file format of JPK instruments (now Bruker) |
Keyence VK |
|
VK3/VK4/VK6/VK7 formats of Keyence laser confocal microscopes |
Keyence ZON |
|
ZON files from some Keyence instruments |
KLA Zeta |
|
KLA Zeta ZMG profilometry data files |
MATLAB |
|
MATLAB workspace files containing topography data |
Microprof FRT |
|
MicroProf FRT profilometry data |
Mitutoyo SurfTest |
|
Excel spreadsheets from Mitutoyo SurfTest instruments |
Molecular Imaging (MI) |
|
Agilent Technologies (Molecular Imaging) AFM format |
Nanofocus |
|
Nanofocus NMS profilometry data files |
NanoSurf easyScan |
|
NanoSurf easyScan data files |
Nanomeasuring Machine (NMM) |
|
ZIP-packaged nanomeasuring machine files |
NASA SRTM |
|
NASA Shuttle Radar Topography Mission elevation data |
NetCDF |
|
Network Common Data Format (classic and HDF5-based NetCDF4) |
NumPy Array |
|
NumPy binary array format |
Olympus LEXT |
|
TIFF-based format of Olympus LEXT confocal microscopes |
Olympus OIR |
|
Olympus OIR data files |
Olympus Packed OIR |
|
ZIP-packaged Olympus OIR files |
Park Systems TIFF |
|
TIFF-based format of Park Systems AFM instruments |
Plain Text (ASCII) |
|
Plain text files with optional headers |
Plain Text (XYZ) |
|
Coordinate data as (x, y, z) tuples |
Sensofar PLU |
|
Sensofar SPM file format |
Sensofar PLUX |
|
Sensofar XML-based SPM file format |
TrueMap |
|
TrueMap TMD profilometry data files |
WSxM |
|
WSxM SPM data files |
X3P |
|
ISO 5436-2 XML 3D surface profile container format |
Zygo DATX |
|
Zygo DATX HDF5-based format |
Zygo MetroPro |
|
Zygo MetroPro data files |
Container Formats
In addition to individual topography files, SurfaceTopography can read container formats that bundle multiple topographies:
Format Name |
Extensions |
Description |
|---|---|---|
contact.engineering |
|
Digital surface twin containers from contact.engineering |
Keyence ZAG |
|
Keyence ZAG container format |
Basic Usage
from SurfaceTopography import open_topography, read_topography
# Auto-detect format and open file
reader = open_topography("measurement.vk4")
topography = reader.topography()
# Or read directly
topography = read_topography("measurement.vk4")
For formats that don’t store physical sizes or units (e.g., NPY, HDF5), you must provide them:
topography = read_topography("data.npy", physical_sizes=(10.0, 10.0), unit="um")
Working with Channels
Many file formats support multiple data channels (e.g., height, phase, amplitude error). You can inspect available channels and select which one to load.
Inspecting Channels
from SurfaceTopography import open_topography
reader = open_topography("afm_scan.ibw")
# List all channels
for ch in reader.channels:
print(f" {ch.name}: {ch.channel_id} (height={ch.is_height_channel})")
# Access only height channels (backwards compatible)
for ch in reader.height_channels:
print(f" Height channel: {ch.name}")
Channel Selection Methods
There are three ways to select which channel to load:
# Method 1: By channel index (default behavior)
topo = reader.topography(channel_index=0)
# Method 2: By stable channel ID (recommended for database storage)
topo = reader.topography(channel_id="Height")
# Method 3: By height channel index (backwards compatible, only counts height channels)
topo = reader.topography(height_channel_index=0)
Channel Properties
Each channel (ChannelInfo) has the following properties:
name- Human-readable channel name from the filechannel_id- Stable unique identifier (e.g., “Height”, “Phase#2” for duplicates)is_height_channel-Trueif channel contains height/topography dataheight_index- Index among height channels only (Nonefor non-height channels)data_kind- Type of data (HEIGHT, VOLTAGE, PHASE, AMPLITUDE, etc.)dim- Dimensionality (1 for line scans, 2 for maps)nb_grid_pts- Number of grid pointsphysical_sizes- Physical dimensionsunit- Unit of measurement
Stable Channel Identification
For applications that store channel references in databases, use channel_id instead of channel_index. The channel_id is:
Stable: Remains the same across different reads of the same file
Order-independent: Doesn’t depend on the internal order channels appear
Unique: Automatically disambiguated for duplicate names (e.g., “Height#1”, “Height#2”)
Example for database storage:
# When saving to database, store the channel_id
channel_to_store = reader.channels[0].channel_id # e.g., "Height"
# Later, when loading from database
topo = reader.topography(channel_id=channel_to_store)
Migrating from Height Index to Channel ID
For databases that previously stored height_channel_index values, utility functions are provided to convert between the old and new systems:
from SurfaceTopography import open_topography
reader = open_topography("scan.ibw")
# Convert old height index to new channel_id
old_index = 0 # stored in database
new_id = reader.height_index_to_channel_id(old_index)
# new_id is now something like "Height" or "ZSensor"
# Convert back if needed (only works for height channels)
recovered_index = reader.channel_id_to_height_index(new_id)
assert recovered_index == old_index
Migration script example:
from SurfaceTopography import open_topography
def migrate_database_entry(file_path, old_height_index):
"""Migrate a database entry from height_index to channel_id."""
reader = open_topography(file_path)
new_channel_id = reader.height_index_to_channel_id(old_height_index)
return new_channel_id
# Example usage
# old_entry = {"file": "scan.ibw", "channel": 0}
# new_entry = {"file": "scan.ibw", "channel_id": migrate_database_entry("scan.ibw", 0)}
Notes
File format is auto-detected from file content (magic bytes) when possible
Some formats support multiple channels - use
reader.channelsto inspectMost readers support both file paths and file-like objects
Some readers support MPI-parallel reading for large datasets