class_docstr: Raw object from a BOXY optical imaging file.
  
  Parameters
  ----------
  fname : path-like
      Path to the BOXY data file.
  %(preload)s
  %(verbose)s
  
  See Also
  --------
  mne.io.Raw : Documentation of attributes and methods.
code: def __init__(self, fname, preload=False, verbose=None):
      logger.info("Loading %s" % fname)
  
      # Read header file and grab some info.
      start_line = np.inf
      col_names = mrk_col = filetype = mrk_data = end_line = None
      raw_extras = dict()
      raw_extras["offsets"] = list()  # keep track of our offsets
      sfreq = None
      fname = str(_check_fname(fname, "read", True, "fname"))
      with open(fname) as fid:
          line_num = 0
          i_line = fid.readline()
          while i_line:
              # most of our lines will be data lines, so check that first
              if line_num >= start_line:
                  assert col_names is not None
                  assert filetype is not None
                  if "#DATA ENDS" in i_line:
                      # Data ends just before this.
                      end_line = line_num
                      break
                  if mrk_col is not None:
                      if filetype == "non-parsed":
                          # Non-parsed files have different lines lengths.
                          crnt_line = i_line.rsplit(" ")[0]
                          temp_data = re.findall(
                              r"[-+]?\d*\.?\d+", crnt_line
                          )
                          if len(temp_data) == len(col_names):
                              mrk_data.append(
                                  float(
                                      re.findall(
                                          r"[-+]?\d*\.?\d+", crnt_line
                                      )[mrk_col]
                                  )
                              )
                      else:
                          crnt_line = i_line.rsplit(" ")[0]
                          mrk_data.append(
                              float(
                                  re.findall(
                                      r"[-+]?\d*\.?\d+", crnt_line
                                  )[mrk_col]
                              )
                          )
                  raw_extras["offsets"].append(fid.tell())
              # now proceed with more standard header parsing
              elif "BOXY.EXE:" in i_line:
                  boxy_ver = re.findall(
                      r"\d*\.\d+", i_line.rsplit(" ")[-1]
                  )[0]
                  # Check that the BOXY version is supported
                  if boxy_ver not in ["0.40", "0.84"]:
                      raise RuntimeError(
                          "MNE has not been tested with BOXY "
                          "version (%s)" % boxy_ver
                      )
              elif "Detector Channels" in i_line:
                  raw_extras["detect_num"] = int(i_line.rsplit(" ")[0])
              elif "External MUX Channels" in i_line:
                  raw_extras["source_num"] = int(i_line.rsplit(" ")[0])
              elif (
                  "Update Rate (Hz)" in i_line
                  or "Updata Rate (Hz)" in i_line
              ):
                  # Version 0.40 of the BOXY recording software
                  # (and possibly other versions lower than 0.84) contains a
                  # typo in the raw data file where 'Update Rate' is spelled
                  # "Updata Rate. This will account for this typo.
                  sfreq = float(i_line.rsplit(" ")[0])
              elif "#DATA BEGINS" in i_line:
                  # Data should start a couple lines later.
                  start_line = line_num + 3
              elif line_num == start_line - 2:
                  # Grab names for each column of data.
                  raw_extras["col_names"] = col_names = re.findall(
                      r"\w+\-\w+|\w+\-\d+|\w+", i_line.rsplit(" ")[0]
                  )
                  if "exmux" in col_names:
                      # Change filetype based on data organisation.
                      filetype = "non-parsed"
                  else:
                      filetype = "parsed"
                  if "digaux" in col_names:
                      mrk_col = col_names.index("digaux")
                      mrk_data = list()
                  # raw_extras['offsets'].append(fid.tell())
              elif line_num == start_line - 1:
                  raw_extras["offsets"].append(fid.tell())
              line_num += 1
              i_line = fid.readline()
      assert sfreq is not None
      raw_extras.update(
          filetype=filetype, start_line=start_line, end_line=end_line
      )
  
      # Label each channel in our data, for each data type (DC, AC, Ph).
      # Data is organised by channels x timepoint, where the first
      # 'source_num' rows correspond to the first detector, the next
      # 'source_num' rows correspond to the second detector, and so on.
      ch_names = list()
      ch_types = list()
      cals = list()
      for det_num in range(raw_extras["detect_num"]):
          for src_num in range(raw_extras["source_num"]):
              for i_type, ch_type in [
                  ("DC", "fnirs_cw_amplitude"),
                  ("AC", "fnirs_fd_ac_amplitude"),
                  ("Ph", "fnirs_fd_phase"),
              ]:
                  ch_names.append(
                      f"S{src_num + 1}_D{det_num + 1} {i_type}"
                  )
                  ch_types.append(ch_type)
                  cals.append(np.pi / 180.0 if i_type == "Ph" else 1.0)
  
      # Create info structure.
      info = create_info(ch_names, sfreq, ch_types)
      for ch, cal in zip(info["chs"], cals):
          ch["cal"] = cal
  
      # Determine how long our data is.
      delta = end_line - start_line
      assert len(raw_extras["offsets"]) == delta + 1
      if filetype == "non-parsed":
          delta //= raw_extras["source_num"]
      super().__init__(
          info,
          preload,
          filenames=[fname],
          first_samps=[0],
          last_samps=[delta - 1],
          raw_extras=[raw_extras],
          verbose=verbose,
      )
  
      # Now let's grab our markers, if they are present.
      if mrk_data is not None:
          mrk_data = np.array(mrk_data, float)
          # We only want the first instance of each trigger.
          prev_mrk = 0
          mrk_idx = list()
          duration = list()
          tmp_dur = 0
          for i_num, i_mrk in enumerate(mrk_data):
              if i_mrk != 0 and i_mrk != prev_mrk:
                  mrk_idx.append(i_num)
              if i_mrk != 0 and i_mrk == prev_mrk:
                  tmp_dur += 1
              if i_mrk == 0 and i_mrk != prev_mrk:
                  duration.append((tmp_dur + 1) / sfreq)
                  tmp_dur = 0
              prev_mrk = i_mrk
          onset = np.array(mrk_idx) / sfreq
          description = mrk_data[mrk_idx]
          annot = Annotations(onset, duration, description)
          self.set_annotations(annot)
  
file_path: mne-python/mne/io/boxy/boxy.py
imports: import re
  import numpy
  from ..._fiff.meas_info import create_info
  from ..._fiff.utils import _mult_cal_one
  from ...annotations import Annotations
  from ...utils import _check_fname, fill_doc, logger, verbose
  from ..base import BaseRaw
label_desc: Use image node_id 1 to create a new RawBOXY object from inherited base classes: BaseRaw with example: obj = RawBOXY(fname, preload, verbose)