Source code for neurokit2.data.read_bitalino

# -*- coding: utf-8 -*-
import json
import os
from warnings import warn

import numpy as np
import pandas as pd

from ..misc import NeuroKitWarning


[docs] def read_bitalino(filename): """**Read an OpenSignals file (from BITalino)** Reads and loads a BITalino file into a Pandas DataFrame. The function outputs both the dataframe and the information (such as the sampling rate) retrieved from the OpenSignals file. Parameters ---------- filename : str Path (with or without the extension) of an OpenSignals file (e.g., ``"data.txt"``). Returns ---------- df : DataFrame, dict The BITalino file as a pandas dataframe if one device was read, or a dictionary of pandas dataframes (one dataframe per device) if multiple devices are read. info : dict The metadata information containing the sensors, corresponding channel names, sampling rate, and the events annotation timings if ``events_annotation`` is ``True``. See Also -------- .read_acqknowledge, .signal_resample Examples -------- .. ipython:: python import neurokit2 as nk # data, info = nk.read_bitalino("data.txt") # sampling_rate = info["sampling_rate"] """ # Read metadata # ------------------------------------------------------------------------- with open(filename, "r") as f: lines = f.readlines() if "OpenSignals" not in lines[0]: raise ValueError("Text file is not in OpenSignals format.") metadata = json.loads(lines[1][1:]) # read second line + skip '#' # Remove ":" metadata = {k.replace(":", ""): metadata[k] for k in metadata.keys()} # Try find events annotations # ------------------------------------------------------------------------- annotations = _read_bitalino_annotations(filename) if annotations is not None: for k in annotations.keys(): if k in metadata.keys(): metadata[k]["Annotations"] = annotations[k] else: warn( f"Device {k} not found in metadata ({metadata.keys()})." + " Something might be wrong.", category=NeuroKitWarning, ) # Read data # ------------------------------------------------------------------------- data = {k: None for k in metadata.keys()} raw = pd.read_csv(filename, sep="\t", header=None, comment="#") # Read file for each device for i, k in enumerate(metadata.keys()): # Select right columns ch = np.array(metadata[k]["column"]) data[k] = raw.iloc[:, i * len(ch) : (i + 1) * len(ch)] for j, s in enumerate(metadata[k]["label"]): ch[ch == s] = metadata[k]["sensor"][j] data[k].columns = ch # Add annotations if "Annotations" in metadata[k].keys(): sr = metadata[k]["sampling rate"] data[k]["Events"] = 0 annot = metadata[k]["Annotations"] annot = annot[annot["CHANNEL"].isin(metadata[k]["label"])] annot = annot.drop_duplicates(["START", "END"]) for _, row in annot.iterrows(): data[k]["Events"][int(row["START"] * sr) : int(row["END"] * sr) + 1] = 1 # Format metadata names metadata[k] = {x.replace(" ", "_"): v for x, v in metadata[k].items()} # If only one device is detected, extract from dict if i == 0: data = data[k] metadata = metadata[k] return data, metadata
# ============================================================================= # Internals # ============================================================================= def _read_bitalino_annotations(filename): """Read events that are annotated during BITalino signal acquisition. Returns a dictionary containing the start and stop times (in seconds) in each channel detected per unique event (label) within each device.""" file = filename.replace(".txt", "_EventsAnnotation.txt") if os.path.isfile(file) is False: return None with open(file, "r") as f: lines = f.readlines() if "OpenSignals" not in lines[0]: raise ValueError("Text file is not in OpenSignals format.") metadata = json.loads(lines[1][1:]) # read second line + skip '#' data = pd.read_csv(file, sep="\t", header=None, comment="#") data = data.dropna(axis=1, how="all") data.columns = metadata["columns"]["labels"] return {k: data[data["MAC"] == k] for k in data["MAC"].unique()}