code: def _read_proj(fid, node, *, ch_names_mapping=None, verbose=None):
      ch_names_mapping = (
          {} if ch_names_mapping is None else ch_names_mapping
      )
      projs = list()
  
      #   Locate the projection data
      nodes = dir_tree_find(node, FIFF.FIFFB_PROJ)
      if len(nodes) == 0:
          return projs
  
      # This might exist but we won't use it:
      # global_nchan = None
      # tag = find_tag(fid, nodes[0], FIFF.FIFF_NCHAN)
      # if tag is not None:
      #     global_nchan = int(tag.data.item())
  
      items = dir_tree_find(nodes[0], FIFF.FIFFB_PROJ_ITEM)
      for item in items:
          #   Find all desired tags in one item
  
          # This probably also exists but used to be written incorrectly
          # sometimes
          # tag = find_tag(fid, item, FIFF.FIFF_NCHAN)
          # if tag is not None:
          #     nchan = int(tag.data.item())
          # else:
          #     nchan = global_nchan
  
          tag = find_tag(fid, item, FIFF.FIFF_DESCRIPTION)
          if tag is not None:
              desc = tag.data
          else:
              tag = find_tag(fid, item, FIFF.FIFF_NAME)
              if tag is not None:
                  desc = tag.data
              else:
                  raise ValueError(
                      "Projection item description missing"
                  )
  
          tag = find_tag(fid, item, FIFF.FIFF_PROJ_ITEM_KIND)
          if tag is not None:
              kind = int(tag.data.item())
          else:
              raise ValueError("Projection item kind missing")
  
          tag = find_tag(fid, item, FIFF.FIFF_PROJ_ITEM_NVEC)
          if tag is not None:
              nvec = int(tag.data.item())
          else:
              raise ValueError(
                  "Number of projection vectors not specified"
              )
  
          tag = find_tag(fid, item, FIFF.FIFF_PROJ_ITEM_CH_NAME_LIST)
          if tag is not None:
              names = _safe_name_list(tag.data, "read", "names")
          else:
              raise ValueError("Projection item channel list missing")
  
          tag = find_tag(fid, item, FIFF.FIFF_PROJ_ITEM_VECTORS)
          if tag is not None:
              data = tag.data
          else:
              raise ValueError("Projection item data missing")
  
          tag = find_tag(fid, item, FIFF.FIFF_MNE_PROJ_ITEM_ACTIVE)
          if tag is not None:
              active = bool(tag.data.item())
          else:
              active = False
  
          tag = find_tag(fid, item, FIFF.FIFF_MNE_ICA_PCA_EXPLAINED_VAR)
          if tag is not None:
              explained_var = float(tag.data.item())
          else:
              explained_var = None
  
          # handle the case when data is transposed for some reason
          if data.shape[0] == len(names) and data.shape[1] == nvec:
              data = data.T
  
          if data.shape[1] != len(names):
              raise ValueError(
                  "Number of channel names does not match the "
                  "size of data matrix"
              )
  
          # just always use this, we used to have bugs with writing the
          # number correctly...
          nchan = len(names)
          names[:] = _rename_list(names, ch_names_mapping)
          #   Use exactly the same fields in data as in a named matrix
          one = Projection(
              kind=kind,
              active=active,
              desc=desc,
              data=dict(
                  nrow=nvec,
                  ncol=nchan,
                  row_names=None,
                  col_names=names,
                  data=data,
              ),
              explained_var=explained_var,
          )
  
          projs.append(one)
  
      if len(projs) > 0:
          logger.info(
              "    Read a total of %d projection items:" % len(projs)
          )
          for proj in projs:
              misc = "active" if proj["active"] else " idle"
              logger.info(
                  f'        {proj["desc"]} '
                  f'({proj["data"]["nrow"]} x '
                  f'{len(proj["data"]["col_names"])}) {misc}'
              )
  
      return projs
  
imports: import re
  from copy import deepcopy
  from itertools import count
  import numpy
  from ..defaults import _BORDER_DEFAULT, _EXTRAPOLATE_DEFAULT, _INTERPOLATION_DEFAULT
  from ..fixes import _safe_svd
  from ..utils import _check_option, _validate_type, fill_doc, logger, object_diff, verbose, warn
  from .constants import FIFF
  from .pick import _ELECTRODE_CH_TYPES, _electrode_types, pick_info, pick_types
  from .tag import _rename_list, find_tag
  from .tree import dir_tree_find
  from .write import _safe_name_list, end_block, start_block, write_float, write_float_matrix, write_int, write_name_list_sanitized, write_string
label_desc: Use image node_id 2 for calling a global function with example usage: _read_proj(fid, node) and returns: projs, projs