Metadata-Version: 2.4
Name: linxi
Version: 1.0.1
Summary: Linxi Engine for iBCI data processing and analysis
Requires-Python: >=3.12
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: pyinstaller
Requires-Dist: numpy>=2.3.2
Requires-Dist: spikeinterface
Requires-Dist: probeinterface
Requires-Dist: nicegui
Requires-Dist: pandas
Requires-Dist: openpyxl
Requires-Dist: matplotlib
Requires-Dist: pynwb
Requires-Dist: hdmf==4.3.1
Requires-Dist: neuroconv>=0.9.1
Requires-Dist: nwbinspector
Requires-Dist: zstandard
Requires-Dist: hdf5plugin
Requires-Dist: numba
Requires-Dist: deprecated
Requires-Dist: ndx-events
Requires-Dist: linxi-trodes
Requires-Dist: linshu-format
Requires-Dist: mne
Requires-Dist: remfile
Requires-Dist: hdmf-zarr
Provides-Extra: advanced
Requires-Dist: submitit; extra == "advanced"
Requires-Dist: snakemake; extra == "advanced"
Requires-Dist: snakemake-executor-plugin-slurm; extra == "advanced"
Provides-Extra: mcp
Requires-Dist: mcp<2,>=1.12; extra == "mcp"
Provides-Extra: dev
Requires-Dist: jupyter; extra == "dev"
Requires-Dist: pytest; extra == "dev"
Requires-Dist: pytest-asyncio; extra == "dev"
Requires-Dist: paramiko; extra == "dev"
Requires-Dist: pre-commit; extra == "dev"
Requires-Dist: types-PyYAML; extra == "dev"
Requires-Dist: mcp<2,>=1.12; extra == "dev"
Provides-Extra: sorters
Requires-Dist: torch>=2.9.0; extra == "sorters"
Requires-Dist: hdbscan; extra == "sorters"
Requires-Dist: herdingspikes; extra == "sorters"
Requires-Dist: kilosort>=4.1.7; extra == "sorters"
Requires-Dist: linxi-mountainsort5; extra == "sorters"
Requires-Dist: linxi-tridesclous; extra == "sorters"
Requires-Dist: phy; extra == "sorters"
Requires-Dist: phylib; extra == "sorters"
Requires-Dist: bombcell; extra == "sorters"
Dynamic: license-file

# 临析数据处理软件

## 目录

- [临析数据处理软件](#临析数据处理软件)
  - [目录](#目录)
    - [进阶内容](#进阶内容)
  - [简介](#简介)
    - [核心功能](#核心功能)
    - [典型数据流](#典型数据流)
  - [安装](#安装)
    - [前提条件](#前提条件)
    - [步骤 1：创建 Conda 环境](#步骤-1创建-conda-环境)
    - [步骤 2：克隆仓库](#步骤-2克隆仓库)
    - [步骤 3：安装 Linxi](#步骤-3安装-linxi)
    - [步骤 4：（可选）安装 Spike Sorter 依赖](#步骤-4可选安装-spike-sorter-依赖)
    - [步骤 5：（可选）安装批量处理依赖](#步骤-5可选安装批量处理依赖)
    - [步骤 6：验证安装](#步骤-6验证安装)
  - [处理神经电生理数据](#处理神经电生理数据)
    - [基本用法](#基本用法)
    - [高级选项](#高级选项)
    - [配置文件示例](#配置文件示例)
    - [会话元数据与 BIDS 命名](#会话元数据与-bids-命名)
    - [其他 CLI 命令](#其他-cli-命令)
  - [如何贡献](#如何贡献)
    - [运行测试](#运行测试)
    - [项目结构概览](#项目结构概览)

### 进阶内容

- [开发者说明](./doc/DeveloperNotes.md)
- [插件系统](./doc/PlugIn-zh.md)
- [解码功能框架](./doc/Decoding_Module.md)

---

## 简介

**临析**是由临港实验室维护的脑机接口数据处理与格式标准化工具。它通过可配置的 YAML 处理管线，将原始记录数据转换为标准化的 LinshuFile（`.ls`）格式，实现从数据加载到导出的一站式自动化处理。

### 核心功能

- **多数据源支持**：兼容 SpikeGadgets（`.rec`）、SpikeGLX（`.bin`）、Intan 等主流神经电生理采集系统，并支持加载 NWB 文件。
- **模块化管线**：以 YAML 配置文件定义处理流程，用户可灵活组合加载、预处理、分选、后处理、质控、分析与导出等模块，像搭积木一样构建自己的管线。
- **Spike Sorting**：集成 Kilosort 4、MountainSort 5、HerdingSpikes 等多种主流分选算法（通过 [SpikeInterface](https://github.com/SpikeInterface/spikeinterface)）。
- **质量控制**：自动计算 SNR、ISI 违规率、Firing Rate 等质控指标，并支持基于指标的自动筛选。
- **LinshuFile 标准化导出**：将处理结果（原始数据、分选结果、行为试次、电极脑区映射等）写入标准 LinshuFile（`.ls`）文件。
- **批量处理**：通过 Snakemake 工作流对大量记录进行批量编排和增量处理。
- **可复现**：所有处理参数集中于配置文件，确保实验结果可追溯和复现。

### 典型数据流

```
原始数据 (.rec / .bin / .rhd 等)
    ↓
[Load] → SpikeInterface Recording 对象
    ↓
[Probe] → 附加电极几何信息
    ↓
[Preprocess] → 滤波、白化后的 Recording
    ↓
[Sort] → Sorting 对象 (spike times + labels)
    ↓
[Postprocess] → SortingAnalyzer (波形、模板等)
    ↓
[Quality] → 质量指标评估
    ↓
[Curate] → 过滤低质量单元
    ↓
[Analyze] → 统计表格 & 可视化图表
    ↓
[Export] → LinshuFile（.ls）文件 / SpikeInterface 对象
```

---

## 安装

### 前提条件

- Linux 操作系统（推荐 Ubuntu 20.04+）
- [Conda](https://docs.conda.io/en/latest/miniconda.html) 或 [Miniforge](https://github.com/conda-forge/miniforge)
- Git
- （可选）NVIDIA GPU + CUDA 驱动（用于 Kilosort 4 等 GPU 加速分选算法）

### 步骤 1：创建 Conda 环境

```bash
conda create -n linxi python=3.12 -y
conda activate linxi
```

### 步骤 2：克隆仓库

```bash
# 平台改名尚未完成：仓库地址仍为旧名；后续平台改名完成后更新为 Linxi.git
git clone https://gitee.com/lgl-dbci/Linxi.git
cd Linxi
```

### 步骤 3：安装 Linxi

推荐使用 [uv](https://github.com/astral-sh/uv) 加速安装：

```bash
pip install uv
uv pip install .
```

也可以直接使用 pip：

```bash
pip install .
```

### 步骤 4：（可选）安装 Spike Sorter 依赖

如果需要使用 Kilosort 4、MountainSort 5 等分选算法，还需安装 `sorters` 依赖组：

```bash
uv pip install ".[sorters]"
```

> ⚠️ `sorters` 依赖组包含 PyTorch 和 cupy 等 GPU 相关包。请确保已安装兼容的 CUDA 驱动。

### 步骤 5：（可选）安装批量处理依赖

如需使用 Snakemake 批量编排或 SLURM 集群提交：

```bash
uv pip install ".[advanced]"
```

### 步骤 6：验证安装

```bash
linxi --help
```

你应该看到如下输出：

```
usage: linxi [-h] {convert,check,index,stat} ...

Linxi CLI

positional arguments:
  {convert,process,check,index,stat}
                        Available subcommands
    convert             Run data conversion pipeline
    process             Run data processing pipeline
    check               Check for incomplete processing lockfiles
    index               Count samples based on probe structure
    stat                Generate statistics report

options:
  -h, --help            show this help message and exit
```

---

## 处理神经电生理数据

Linxi 通过 YAML 配置文件定义处理管线，可以使用 `linxi convert` 或 `linxi process` 命令执行。

### 基本用法

```bash
linxi convert \
    <INPUT_PATH> \
    --output <OUTPUT_DIR> \
    --config <CONFIG_YAML>
```

```bash
linxi process \
  --input-path <INPUT_PATH> \ # 或使用 -i
  --work-dir <WORK_DIR> \ # 或使用 -o / --output
  --config <CONFIG_YAML> # 或使用 -c
```

| 参数 | 说明 |
|------|------|
| `<INPUT_PATH>` | 输入数据的文件或文件夹路径 |
| `--input-path`, `-i` | `linxi process` 的可选输入路径参数，作用与 `linxi convert` 的 `<INPUT_PATH>` 相同 |
| `--work-dir`, `--output`, `-o` | `linxi process` 的工作目录参数。CLI 未提供时，会尝试读取配置文件一级 `work_dir` |
| `--config`, `-c` | 管线配置文件路径（YAML） |

### 高级选项

```bash
linxi convert <INPUT_PATH> -o <OUTPUT_DIR> -c <CONFIG_YAML> \
    --skip-dry-run \                          # 跳过预验证
    --raise-errors \                          # 遇错即停（默认仅记录日志）
    --update-completed \                      # 对已完成的输出重新执行优化后的管线
    --incomplete-workdir-strategy resume \     # 对中断的任务选择 delete | raise | resume
    --cfg-option ProcessorName.param.key:value  # 在命令行覆盖配置参数
```

`linxi process` 可以不提供输入路径，让具体 load processor 在配置文件参数中声明 `input_path`。为了向后兼容，它也支持通过 `-i`, `--input-path` 传入输入路径，此时作用与 `linxi convert` 的 `<INPUT_PATH>` 完全一致。

举例，以下几种用法都能让 `LoadIntan` 成功读取，并让 `process` 获得工作目录。

```bash
linxi process -i <INPUT_PATH> --work-dir <WORK_DIR> -c <CONFIG_YAML>
```

```bash
linxi process -o <WORK_DIR> -c <CONFIG_YAML> \
  --cfg-option LoadIntan.input_path:/data/session_01.rhd
```

```bash
linxi process -c <CONFIG_YAML>
```

当 `linxi process` 没有通过 CLI 提供 `--work-dir`、`--output` 或 `-o` 时，会尝试读取配置文件一级 `work_dir`。如果 CLI 和配置文件都提供了工作目录，以 CLI 为准。

### 配置文件示例

对一组SpikeGLX数据进行kilosort4分选，解析基本结果，并打包导出为LinshuFile（.ls）文件。

```yaml
name: "SpikeGLX_Sort_Analyze_ExportLinshuFile"
description: "对一组SpikeGLX数据进行kilosort4分选，解析基本结果，并打包导出为LinshuFile（.ls）文件。"
work_dir: "/data/subject01/processing"

spikeinterface_njobs: 48

steps:
  # 1. 载入数据
  - stage: load
    processor_name: "LoadSpikeGLX"
    params:
      input_path: "/data/subject01/session01"

  # 2. 预处理
  - stage: preprocess
    processor_name: "SpikeInterfacePreprocessPipeline"
    params:
      pipeline_dict:
        bandpass_filter:
          freq_min: 300
          freq_max: 6000
        whiten:
          dtype: "float32"
        common_reference:
          reference: "global"
          operator: "median"
        zscore: {}
      apply_precomputed_kwargs: true

  # 3. 分选
  - stage: sort
    processor_name: "SpikeInterfaceSorter"
    params:
      resume: true
      sorter_name: "kilosort4"
      sorter_params:
        batch_size: 32768  # default: 60000
        max_cluster_subset: 15000  # default: 25000
        n_pcs: 5  # default: 6
        n_templates: 5  # default: 6
        do_CAR: false
        do_correction: true
        # NOTE TODO
        # set `use_binary_file` to true will trigger spikeinterface improper handling of `filename` meta,
        # which will be used to generate `sorter_output/params.py`'s `dat_path`.
        # And further, causing phylib unable to parse the phy params file.
        # Finally cause our `ParseUnitChannelMap_Kilosort4` processor to fail.
        use_binary_file: true
        clear_cache: true

  # 4. 分析与筛选 (包含前置分析、筛选、完整分析三个步骤)
  - stage: postprocess
    processor_name: "AnalyzeWithCurate"
    params:
      resume: true

  # 5. 质量评估
  - stage: quality
    processor_name: "SpikeInterfaceQualityMetrics"
    params:
      metric_names:
        - "snr"
        - "isi_violation"
        - "presence_ratio"
        - "firing_rate"
        - "amplitude_cutoff"
      min_snr_for_qc: 5.0
      max_isi_violations_ratio_for_qc: 0.1
      min_presence_ratio_for_qc: 0.9
      min_firing_rate_for_qc: 0.1

  # 6. 分析、可视化
  - stage: analyze
    processor_name: "CalculateDatasetStatistics"
  - stage: analyze
    processor_name: "UnitTableExporter"
    params:
      format: "xlsx"
  - stage: analyze
    processor_name: "SpikeInterfaceVisualizer"

  # 7. 导出
  - stage: export
    processor_name: "WriteLinshuFile"
    params:
      ecephys_key: "ap"
      overwrite: true
```

> 💡 更多内置配置文件可参考 `config/` 目录。你也可以复制并修改已有配置，创建适合自己实验的管线。
>
> Bombcell 模式下需将参数聚合到 `bombcell_params` 字典中传入（key 与 `SpikeInterfaceBombcell` 的具名参数同名，例如 `mua_presence_ratio_min`）：
>
> ```yaml
> - stage: postprocess
>   processor_name: "AnalyzeWithCurate"
>   params:
>     curation_method: "bombcell"
>     bombcell_params:
>       apply_curation: true
>       keep_unit_types: ["good", "mua"]
>       mua_presence_ratio_min: 0.7
>       mua_rp_contamination_max: 0.1
> ```

### 会话元数据与 BIDS 命名

配置文件支持 `metadata` 与 `output_name` 两个一级字段，在 context 构造期生效，无需在某个处理器中逐项声明。

**会话元数据**

`metadata` 写入导出 LinshuFile（`.ls`）文件的根级会话元数据。key 白名单为 `LinshuFile` 根级字段（如 `lab`、`institution`、`session_id`、`task_name`、`subject`、`brain_regions` 等），白名单之外的 key 会立即报错。其中 `run` 为整数，表示同一会话内的采集实例序号。

```yaml
metadata:
  lab: "Lin Gang Lab"
  session_id: "session01"
  task_name: "screenview"
  run: 1
  subject:
    id: "mouse01"
    species: "Mus musculus"
    strain: "C57BL/6J"
    sex: "M"
  brain_regions:
    - "VIS"
```

**导出文件名**

导出文件名由数据自身派生：`linxi.fabric.bids_naming.to_bids_name` 按 BIDS entity table 顺序（`sub-` < `ses-` < `task-` < `acq-` < `run-` < `recording-`）将下列来源字段投影为文件名实体，来源字段缺失时对应实体省略。

| 实体 | 来源字段 |
|------|----------|
| `sub-` | 根级 `subject.id`，缺省为 `unknown` |
| `ses-` | 根级 `session_id`，缺省回退输入路径的文件名 |
| `task-` | 根级 `task_name`，缺省回退管线名称 |
| `acq-` | 记录字段 `acquisition` |
| `run-` | 根级 `run` |
| `recording-` | 记录字段 `device` |

文件名形如 `sub-<subject>_ses-<session>_task-<task>_acq-<acq>_run-<run>_recording-<device>.ls`。参与同一次导出的全部记录的 `acquisition` 与 `device` 取值必须一致，冲突时报错并指明字段与对应记录。

记录字段 `acquisition` 与 `device` 有两种写入途径：在 load 步骤参数中显式声明，或由 loader 从源数据自动物化（SpikeGLX 由探头标签推导 `device`，NWB 由电极关联的 Device 推导 `device`）。

```yaml
  - stage: load
    processor_name: "LoadSpikeGLX"
    params:
      input_path: "/data/subject01/session01"
      # device: "NP2"      # 可选：覆盖由源文件推导的设备标签（写入 recording- 实体）
      # acquisition: "epi" # 可选：区分采集参数集的自定义标签（写入 acq- 实体）
```

**手动命名**

一级字段 `output_name` 是手动命名的唯一通道：设置后导出文件名固定为 `<output_name>.<ext>`，上述派生整体跳过。适用于需要固定文件名或规避标签取值冲突的场景。该字段也可以在命令行按次设置：使用 `--cfg-option output_name:<名称>` 直接写入一级 `output_name`，为单次运行覆盖文件名而无需修改配置文件。

```yaml
output_name: "mouse01_session01_export"
```

### 其他 CLI 命令

| 命令 | 说明 | 示例 |
|------|------|------|
| `linxi check <DIR>` | 检查目录中未完成的处理任务（lockfile） | `linxi check /data/output -o /data/report` |
| `linxi index <SYSTEM> <PATH>` | 统计指定路径下可处理的数据样本数 | `linxi index spikeglx /data/raw` |
| `linxi stat <DIR>` | 对已导出的 NWB 文件生成统计报告（Excel） | `linxi stat /data/output -n 16` |

---

## 如何贡献

欢迎贡献代码！请按照以下步骤操作：

1. **Fork 仓库**：在 Gitee 上 Fork [Linxi 仓库](https://gitee.com/dbci/Linxi)。
2. **创建开发分支**：
   ```bash
   git switch -c dev/YourFeatureName
   ```
3. **安装开发依赖**：
   ```bash
   uv pip install ".[dev]"
   ```
4. **安装 pre-commit 钩子**（自动执行代码格式化和静态检查）：
   ```bash
   pip install pre-commit
   pre-commit install
   ```
5. **开发你的功能**：编写代码和对应的测试。
6. **提交代码**：
   ```bash
   git add .
   git commit -m "feat: add amazing feature"
   ```
   > 提交时 pre-commit 会自动运行代码检查，如有问题请根据提示修复后重新提交。
7. **推送并创建 Pull Request**：
   ```bash
   git push origin dev/YourFeatureName
   ```
   在 Gitee 上创建 Pull Request，等待代码审阅和合并。

### 运行测试

```bash
pytest
```

### 项目结构概览

```
Linxi/
├── src/linxi/
│   ├── CLI/              # 命令行入口
│   ├── fabric/           # 管线编排框架 (TaskRunner, PipelineContext, ...)
│   ├── processor/        # 处理器模块
│   │   ├── load/         #   数据加载 (SpikeGadgets, SpikeGLX, Intan, ...)
│   │   ├── probe/        #   电极配置
│   │   ├── preprocess/   #   预处理 (滤波、白化、通道重映射)
│   │   ├── sort/         #   Spike Sorting
│   │   ├── postprocess/  #   后处理 (波形提取、LFP、单元-通道映射)
│   │   ├── quality/      #   质量评估
│   │   ├── curate/       #   数据清洗 & 筛选
│   │   ├── analyze/      #   分析 & 可视化 (PSTH, 脑区映射, ...)
│   │   └── export/       #   导出 (LinshuFile, SpikeInterface, 行为试次, ...)
│   ├── logger/           # 日志系统
│   └── tools/            # 工具函数
├── config/               # 内置管线配置文件 (YAML)
├── tests/                # 测试用例
├── doc/                  # 文档
├── docker/               # Docker 构建文件
└── snakemake/            # Snakemake 批量处理工作流
```

> 更多开发细节请参阅 `doc/DeveloperNotes.md`。
