Source code for afmformats.formats.fmt_igor

import pathlib

from igor2 import binarywave
import numpy as np

__all__ = ["load_igor"]


[docs]def load_igor(path, callback=None, meta_override=None): """Load Asylum Research (Igor) binarywave .ibw files The raw data are loaded with the Python module "igor" (http://blog.tremily.us/posts/igor/). The way column labels are assigend to the data is kind of hacky. The metadata assignment is largely guessed. Test data were provided by Nicolas Hauck :cite:`Hauck2018`. Parameters ---------- path: str or pathlib.Path path to in .ibw data file callback: callable function for progress tracking; must accept a float in [0, 1] as an argument. meta_override: dict if specified, contains key-value pairs of metadata that are used when loading the files (see :data:`afmformats.meta.META_FIELDS`) """ if meta_override is None: meta_override = {} else: # just make sure nobody expects a different result for the forces for key in ["sensitivity", "spring constant"]: if key in meta_override: raise NotImplementedError( f"Setting metadata such as '{key}' is not implemented!") ibw = binarywave.load(path) wdata = ibw["wave"]["wData"] notes = {} for line in str(ibw["wave"]["note"]).split("\\r"): if line.count(":"): key, val = line.split(":", 1) notes[key] = val.strip() # Metadata metadata = {} # acquisition metadata["imaging mode"] = "force-distance" metadata["feedback mode"] = notes["ImagingMode"].lower() metadata["rate approach"] = float(notes["NumPtsPerSec"]) metadata["rate retract"] = float(notes["NumPtsPerSec"]) metadata["sensitivity"] = float(notes["InvOLS"]) if notes["TriggerChannel"] == "Force": metadata["setpoint"] = float(notes["TriggerPoint"]) metadata["spring constant"] = float(notes["SpringConstant"]) # dataset metadata["duration"] = float(notes["InputTime"]) metadata["enum"] = 1 metadata["speed approach"] = float(notes["ApproachVelocity"]) metadata["speed retract"] = float(notes["RetractVelocity"]) # setup metadata["instrument"] = notes["MicroscopeModel"] metadata["software"] = "Asylum Research" metadata["software version"] = notes["Version"] # storage metadata["date"] = notes["Date"] metadata["path"] = pathlib.Path(path) metadata["point count"] = wdata.shape[0] metadata["time"] = notes["Time"] # Data labels = [] # deal with something like this: # 'labels': [[], [b'', b'Raw', b'Defl', b'ZSnsr'], [], []], for ll in ibw["wave"]["labels"]: for li in ll: if li: labels.append(li.decode()) assert len(labels) == wdata.shape[1] data = {} for pkey in ["Raw", "Height"]: if pkey in labels: # height is in [m] data["height (piezo)"] = -wdata[:, labels.index(pkey)] break for mkey in ["ZSnsr", "ZSensor"]: if mkey in labels: # height is in [m] data["height (measured)"] = -wdata[:, labels.index(mkey)] break for fkey in ["Defl", "Deflection"]: if fkey in labels: # force is in [m] (convert to [N]) data["force"] = wdata[:, labels.index(fkey)] \ * metadata["spring constant"] break data["segment"] = np.zeros(wdata.shape[0], dtype=np.uint8) # missing metadata metadata["z range"] = np.ptp(data["height (piezo)"]) metadata.update(meta_override) dataset = [{"data": data, "metadata": metadata, }] if callback is not None: callback(1) return dataset
recipe_ibw = { "descr": "binarywave", "loader": load_igor, "suffix": ".ibw", "modalities": ["force-distance"], "maker": "Asylum Research", }