教程-1:BIOMAMBA
进入华大单细胞教程-1-biomamba
- 来源:BIOMAMBA 生信基地 C4 平台原理与代码流程教程。
- 内容:C4/DNBSEQ 原理、dnbc4tools 2.1.3 上游定量、R/Seurat 与 Python/Scanpy 四种下游读取方式。
- 目录:原文存档、平台原理、上游定量、下游读取、
data/和result/均已归拢到该模块。
plot4 · 代码 12 · 图 0 · 笔记 10 · 代码库专题
本目录按教程来源和 dnbc4tools 版本拆分,避免旧版学习记录与新版流程混用。
1.3 华大 DNBelab C4 单细胞分析(自动生成占位图)
图源:(自动生成占位图)
从专题 README 抽取;原文顺序保留,未跑过的部分照实标注。
本目录按教程来源和 dnbc4tools 版本拆分,避免旧版学习记录与新版流程混用。
进入华大单细胞教程-1-biomamba
data/ 和 result/ 均已归拢到该模块。进入华大单细胞上游教程-2
outs/ 结果检查。先确认测序平台、试剂版本和 dnbc4tools 版本,再选择对应模块。教程-1 的脚本保留原始学习路径,教程-2 提供更适合新样本复用的参数化入口。两套流程生成的结果目录结构可能不同,读取脚本应以实际 outs/ 或 output/ 文件为准。
8 个源码文件,按目录顺序;本机绝对路径已替换为 ~。 代码可复制,但需要按自己的数据改路径与参数。
#!/usr/bin/env bash
# ============================================================================
# Install dnbc4tools 3.1 for DNBelab C-series HT scRNA-seq
#
# The package is self-contained. This script only manages the archive,
# extraction, checksum, and an optional symlink into the active conda env.
# ============================================================================
set -euo pipefail
VERSION="3.1"
DEFAULT_URL="ftp://ftp.cngb.org/pub/CNSA/data7/CNP0008672/Single_Cell/CSE0000574/dnbc4tools-3.1.tar.gz"
DEFAULT_MD5="d7d1282871180486dae55d87b237134c"
INSTALL_ROOT="${HOME}/DNBC4tools"
ARCHIVE=""
BIN_DIR=""
URL="$DEFAULT_URL"
EXPECTED_MD5="$DEFAULT_MD5"
FORCE=0
usage() {
cat <<'USAGE'
用法:
bash 01_install_dnbc4tools3.1.sh [选项]
选项:
--install-root DIR 解压根目录 (默认: ~/DNBC4tools)
--archive FILE 使用本地安装包;未提供且文件不存在时自动下载
--bin-dir DIR 创建 dnbc4tools 软链接的 bin 目录
(默认: $CONDA_PREFIX/bin;未激活 conda 时不创建)
--url URL 覆盖官方 FTP 下载地址
--md5 HASH 覆盖 MD5;设为 none 可跳过校验
--force 允许覆盖已存在的安装目录中的同名文件
-h, --help 显示帮助
示例:
conda create -n dnbc4 -y python=3.10
conda activate dnbc4
bash 01_install_dnbc4tools3.1.sh --install-root "$HOME/DNBC4tools"
USAGE
}
while [ "$#" -gt 0 ]; do
case "$1" in
--install-root)
[ "$#" -ge 2 ] || { echo "错误: --install-root 需要目录" >&2; exit 2; }
INSTALL_ROOT="$2"; shift 2 ;;
--archive)
[ "$#" -ge 2 ] || { echo "错误: --archive 需要文件" >&2; exit 2; }
ARCHIVE="$2"; shift 2 ;;
--bin-dir)
[ "$#" -ge 2 ] || { echo "错误: --bin-dir 需要目录" >&2; exit 2; }
BIN_DIR="$2"; shift 2 ;;
--url)
[ "$#" -ge 2 ] || { echo "错误: --url 需要地址" >&2; exit 2; }
URL="$2"; shift 2 ;;
--md5)
[ "$#" -ge 2 ] || { echo "错误: --md5 需要 HASH 或 none" >&2; exit 2; }
EXPECTED_MD5="$2"; shift 2 ;;
--force) FORCE=1; shift ;;
-h|--help) usage; exit 0 ;;
*) echo "错误: 未知参数 $1" >&2; usage >&2; exit 2 ;;
esac
done
if [ -z "$ARCHIVE" ]; then
ARCHIVE="${INSTALL_ROOT}/dnbc4tools-${VERSION}.tar.gz"
fi
mkdir -p "$INSTALL_ROOT"
if [ ! -s "$ARCHIVE" ]; then
if ! command -v curl >/dev/null 2>&1 && ! command -v wget >/dev/null 2>&1; then
echo "错误: 需要 curl 或 wget 下载安装包" >&2
exit 1
fi
echo "下载 dnbc4tools ${VERSION}: $URL"
if command -v curl >/dev/null 2>&1; then
curl -fL --retry 3 -o "$ARCHIVE" "$URL"
else
wget -O "$ARCHIVE" "$URL"
fi
fi
if [ "$EXPECTED_MD5" != "none" ]; then
command -v md5sum >/dev/null 2>&1 || {
echo "错误: 未找到 md5sum,无法校验安装包" >&2
exit 1
}
ACTUAL_MD5="$(md5sum "$ARCHIVE" | awk '{print $1}')"
if [ "$ACTUAL_MD5" != "$EXPECTED_MD5" ]; then
echo "错误: MD5 校验失败" >&2
echo " 期望: $EXPECTED_MD5" >&2
echo " 实际: $ACTUAL_MD5" >&2
exit 1
fi
echo "MD5 校验通过: $ACTUAL_MD5"
fi
TOOL_DIR="${INSTALL_ROOT}/dnbc4tools${VERSION}"
if [ -e "$TOOL_DIR" ] && [ "$FORCE" -ne 1 ]; then
echo "提示: $TOOL_DIR 已存在;如需覆盖请加 --force" >&2
else
tar -xzf "$ARCHIVE" -C "$INSTALL_ROOT"
fi
TOOL_BIN="${TOOL_DIR}/dnbc4tools"
if [ ! -x "$TOOL_BIN" ]; then
echo "错误: 未找到可执行文件 $TOOL_BIN" >&2
echo " 请检查压缩包目录名,或使用 --install-root 指定正确位置" >&2
exit 1
fi
if [ -z "$BIN_DIR" ] && [ -n "${CONDA_PREFIX:-}" ]; then
BIN_DIR="${CONDA_PREFIX}/bin"
fi
if [ -n "$BIN_DIR" ]; then
mkdir -p "$BIN_DIR"
LINK_PATH="${BIN_DIR}/dnbc4tools"
if [ -e "$LINK_PATH" ] && [ ! -L "$LINK_PATH" ]; then
echo "错误: $LINK_PATH 已存在且不是软链接;请手动处理后重试" >&2
exit 1
fi
ln -sfn "$TOOL_BIN" "$LINK_PATH"
echo "软链接已创建: $LINK_PATH -> $TOOL_BIN"
fi
echo "安装目录: $TOOL_DIR"
"$TOOL_BIN" --version
echo "安装完成。"
#!/usr/bin/env bash
# ============================================================================
# Prepare an Ensembl release-115 reference and build a dnbc4tools 3.1 index.
# Supports human (GRCh38) and mouse (GRCm39). The command is intentionally
# explicit so the FASTA/GTF release and output directory remain traceable.
# ============================================================================
set -euo pipefail
SPECIES=""
RELEASE="115"
OUTDIR=""
THREADS="8"
TOOL=""
IN_FASTA=""
IN_GTF=""
INCLUDE="protein_coding,lncRNA,lincRNA,antisense,IG_V_gene,IG_LV_gene,IG_D_gene,IG_J_gene,IG_C_gene,IG_V_pseudogene,IG_J_pseudogene,IG_C_pseudogene,TR_V_gene,TR_D_gene,TR_J_gene,TR_C_gene"
SKIP_DOWNLOAD=0
usage() {
cat <<'USAGE'
用法:
bash 02_prepare_reference.sh --species human|mouse --outdir DIR [选项]
选项:
--species NAME human 或 mouse;用于选择 Ensembl 文件
--release N Ensembl release (默认: 115)
--outdir DIR 参考数据库输出目录 (必需)
--threads N mkref 使用的线程数 (默认: 8)
--tool PATH dnbc4tools 可执行文件 (默认: PATH 中的命令)
--fasta FILE 使用本地 FASTA;与 --gtf 一起可跳过下载
--gtf FILE 使用本地 GTF;与 --fasta 一起可跳过下载
--include LIST gene_biotype 保留列表,逗号分隔
--skip-download 不下载;必须同时提供 --fasta 和 --gtf
-h, --help 显示帮助
示例:
bash 02_prepare_reference.sh --species mouse \
--outdir "$HOME/reference/mouse" --threads 8
USAGE
}
while [ "$#" -gt 0 ]; do
case "$1" in
--species) [ "$#" -ge 2 ] || { echo "错误: --species 需要值" >&2; exit 2; }; SPECIES="$2"; shift 2 ;;
--release) [ "$#" -ge 2 ] || { echo "错误: --release 需要值" >&2; exit 2; }; RELEASE="$2"; shift 2 ;;
--outdir) [ "$#" -ge 2 ] || { echo "错误: --outdir 需要目录" >&2; exit 2; }; OUTDIR="$2"; shift 2 ;;
--threads) [ "$#" -ge 2 ] || { echo "错误: --threads 需要数值" >&2; exit 2; }; THREADS="$2"; shift 2 ;;
--tool) [ "$#" -ge 2 ] || { echo "错误: --tool 需要路径" >&2; exit 2; }; TOOL="$2"; shift 2 ;;
--fasta) [ "$#" -ge 2 ] || { echo "错误: --fasta 需要文件" >&2; exit 2; }; IN_FASTA="$2"; shift 2 ;;
--gtf) [ "$#" -ge 2 ] || { echo "错误: --gtf 需要文件" >&2; exit 2; }; IN_GTF="$2"; shift 2 ;;
--include) [ "$#" -ge 2 ] || { echo "错误: --include 需要列表" >&2; exit 2; }; INCLUDE="$2"; shift 2 ;;
--skip-download) SKIP_DOWNLOAD=1; shift ;;
-h|--help) usage; exit 0 ;;
*) echo "错误: 未知参数 $1" >&2; usage >&2; exit 2 ;;
esac
done
[ -n "$SPECIES" ] || { echo "错误: 必须提供 --species human 或 mouse" >&2; exit 2; }
[ -n "$OUTDIR" ] || { echo "错误: 必须提供 --outdir" >&2; exit 2; }
case "$SPECIES" in
human)
ENSEMBL_NAME="homo_sapiens"
ASSEMBLY="GRCh38"
SPECIES_ID="Homo_sapiens"
FASTA_NAME="Homo_sapiens.GRCh38.dna.toplevel.fa"
GTF_NAME="Homo_sapiens.GRCh38.${RELEASE}.gtf"
;;
mouse)
ENSEMBL_NAME="mus_musculus"
ASSEMBLY="GRCm39"
SPECIES_ID="Mus_musculus"
FASTA_NAME="Mus_musculus.GRCm39.dna.toplevel.fa"
GTF_NAME="Mus_musculus.GRCm39.${RELEASE}.gtf"
;;
*) echo "错误: --species 仅支持 human 或 mouse" >&2; exit 2 ;;
esac
if [ -z "$TOOL" ]; then
TOOL="$(command -v dnbc4tools || true)"
fi
[ -n "$TOOL" ] && [ -x "$TOOL" ] || {
echo "错误: 找不到可执行的 dnbc4tools;请先安装或用 --tool 指定" >&2
exit 1
}
mkdir -p "$OUTDIR"
if [ "$SKIP_DOWNLOAD" -eq 1 ]; then
[ -n "$IN_FASTA" ] && [ -n "$IN_GTF" ] || {
echo "错误: --skip-download 必须同时提供 --fasta 和 --gtf" >&2
exit 2
}
else
if [ -z "$IN_FASTA" ]; then IN_FASTA="${OUTDIR}/${FASTA_NAME}"; fi
if [ -z "$IN_GTF" ]; then IN_GTF="${OUTDIR}/${GTF_NAME}"; fi
BASE_URL="https://ftp.ensembl.org/pub/release-${RELEASE}"
if [ ! -s "$IN_FASTA" ]; then
if command -v curl >/dev/null 2>&1; then
curl -fL --retry 3 -o "${IN_FASTA}.gz" \
"${BASE_URL}/fasta/${ENSEMBL_NAME}/dna/${FASTA_NAME}.gz"
else
wget -O "${IN_FASTA}.gz" \
"${BASE_URL}/fasta/${ENSEMBL_NAME}/dna/${FASTA_NAME}.gz"
fi
gunzip -f "${IN_FASTA}.gz"
fi
if [ ! -s "$IN_GTF" ]; then
if command -v curl >/dev/null 2>&1; then
curl -fL --retry 3 -o "${IN_GTF}.gz" \
"${BASE_URL}/gtf/${ENSEMBL_NAME}/${GTF_NAME}.gz"
else
wget -O "${IN_GTF}.gz" \
"${BASE_URL}/gtf/${ENSEMBL_NAME}/${GTF_NAME}.gz"
fi
gunzip -f "${IN_GTF}.gz"
fi
fi
[ -s "$IN_FASTA" ] || { echo "错误: FASTA 不存在或为空: $IN_FASTA" >&2; exit 1; }
[ -s "$IN_GTF" ] || { echo "错误: GTF 不存在或为空: $IN_GTF" >&2; exit 1; }
PREFIX="${OUTDIR}/${ASSEMBLY}.${RELEASE}"
CORRECTED_GTF="${PREFIX}.corrected.gtf"
FILTERED_GTF="${PREFIX}.filtered.gtf"
STATS_TXT="${PREFIX}.gene_biotype.stats.txt"
echo "统计 GTF gene_biotype: $STATS_TXT"
"$TOOL" tools mkgtf --action stats --ingtf "$IN_GTF" --output "$STATS_TXT"
echo "校正 GTF: $CORRECTED_GTF"
"$TOOL" tools mkgtf --action check --ingtf "$IN_GTF" --output "$CORRECTED_GTF"
echo "过滤 GTF: $FILTERED_GTF"
"$TOOL" tools mkgtf \
--ingtf "$CORRECTED_GTF" \
--output "$FILTERED_GTF" \
--type gene_biotype \
--include "$INCLUDE"
REF_DIR="${OUTDIR}/reference"
echo "构建参考数据库: $REF_DIR"
"$TOOL" rna mkref \
--fasta "$IN_FASTA" \
--ingtf "$FILTERED_GTF" \
--genomeDir "$REF_DIR" \
--species "$SPECIES_ID" \
--threads "$THREADS"
[ -s "${REF_DIR}/ref.json" ] || {
echo "错误: mkref 未生成 ${REF_DIR}/ref.json" >&2
exit 1
}
echo "参考数据库构建完成: $REF_DIR"
#!/usr/bin/env bash
# ============================================================================
# Run one DNBelab C4 scRNA sample with dnbc4tools 3.1.
# Choose either --fastqs (directory mode) or all four explicit FASTQ options.
# ============================================================================
set -euo pipefail
TOOL=""
NAME=""
GENOME_DIR=""
OUTDIR=""
THREADS="10"
FASTQS=""
CDNA_R1=""
CDNA_R2=""
OLIGO_R1=""
OLIGO_R2=""
CALLING_METHOD=""
EXPECT_CELLS=""
FORCE_CELLS=""
MIN_UMI=""
CHEMISTRY=""
DARK_REACTION=""
SAMPLE_READ_PAIRS=""
NO_INTRONS=0
NO_BAM=0
DRY_RUN=0
usage() {
cat <<'USAGE'
用法:
# 目录方式(推荐)
bash 03_run_single_sample.sh --name SAMPLE --fastqs DIR \
--genome-dir REF --outdir OUT --threads 10
# 单独 FASTQ 参数方式
bash 03_run_single_sample.sh --name SAMPLE \
--cdna-r1 R1[,R1...] --cdna-r2 R2[,R2...] \
--oligo-r1 R1[,R1...] --oligo-r2 R2[,R2...] \
--genome-dir REF --outdir OUT --threads 10
选项:
--tool PATH dnbc4tools 可执行文件 (默认: PATH 中的命令)
--name NAME 样本名 (必需)
--genome-dir DIR mkref 生成的参考目录 (必需)
--outdir DIR 结果输出目录 (必需)
--threads N 线程数 (默认: 10)
--fastqs DIR 含 cDNA/ 和 oligo/ 子目录的输入目录
--cdna-r1 LIST cDNA R1;多个 lane 用逗号分隔
--cdna-r2 LIST cDNA R2;顺序需与 --cdna-r1 一致
--oligo-r1 LIST oligo R1;多个 lane 用逗号分隔
--oligo-r2 LIST oligo R2;顺序需与 --oligo-r1 一致
--calling-method NAME emptydrops 或 barcoderanks
--expectcells N 期望细胞数
--forcecells N 强制细胞数
--minumi N 最低 UMI 阈值
--chemistry NAME auto/scRNAv1HT/scRNAv2HT/scRNAv3HT/scRNA5Pv1
--darkreaction C,O cDNA 与 oligo 暗反应设置,如 auto,auto
--sample-read-pairs N 试跑时抽取的 cDNA read pairs 数
--no-introns 不统计内含子 reads
--no-bam 不生成 BAM,节省磁盘
--dry-run 只打印命令,不执行
-h, --help 显示帮助
USAGE
}
while [ "$#" -gt 0 ]; do
case "$1" in
--tool) [ "$#" -ge 2 ] || { echo "错误: --tool 需要路径" >&2; exit 2; }; TOOL="$2"; shift 2 ;;
--name) [ "$#" -ge 2 ] || { echo "错误: --name 需要值" >&2; exit 2; }; NAME="$2"; shift 2 ;;
--genome-dir) [ "$#" -ge 2 ] || { echo "错误: --genome-dir 需要目录" >&2; exit 2; }; GENOME_DIR="$2"; shift 2 ;;
--outdir) [ "$#" -ge 2 ] || { echo "错误: --outdir 需要目录" >&2; exit 2; }; OUTDIR="$2"; shift 2 ;;
--threads) [ "$#" -ge 2 ] || { echo "错误: --threads 需要数值" >&2; exit 2; }; THREADS="$2"; shift 2 ;;
--fastqs) [ "$#" -ge 2 ] || { echo "错误: --fastqs 需要目录" >&2; exit 2; }; FASTQS="$2"; shift 2 ;;
--cdna-r1) [ "$#" -ge 2 ] || { echo "错误: --cdna-r1 需要文件列表" >&2; exit 2; }; CDNA_R1="$2"; shift 2 ;;
--cdna-r2) [ "$#" -ge 2 ] || { echo "错误: --cdna-r2 需要文件列表" >&2; exit 2; }; CDNA_R2="$2"; shift 2 ;;
--oligo-r1) [ "$#" -ge 2 ] || { echo "错误: --oligo-r1 需要文件列表" >&2; exit 2; }; OLIGO_R1="$2"; shift 2 ;;
--oligo-r2) [ "$#" -ge 2 ] || { echo "错误: --oligo-r2 需要文件列表" >&2; exit 2; }; OLIGO_R2="$2"; shift 2 ;;
--calling-method) [ "$#" -ge 2 ] || { echo "错误: --calling-method 需要值" >&2; exit 2; }; CALLING_METHOD="$2"; shift 2 ;;
--expectcells) [ "$#" -ge 2 ] || { echo "错误: --expectcells 需要数值" >&2; exit 2; }; EXPECT_CELLS="$2"; shift 2 ;;
--forcecells) [ "$#" -ge 2 ] || { echo "错误: --forcecells 需要数值" >&2; exit 2; }; FORCE_CELLS="$2"; shift 2 ;;
--minumi) [ "$#" -ge 2 ] || { echo "错误: --minumi 需要数值" >&2; exit 2; }; MIN_UMI="$2"; shift 2 ;;
--chemistry) [ "$#" -ge 2 ] || { echo "错误: --chemistry 需要值" >&2; exit 2; }; CHEMISTRY="$2"; shift 2 ;;
--darkreaction) [ "$#" -ge 2 ] || { echo "错误: --darkreaction 需要值" >&2; exit 2; }; DARK_REACTION="$2"; shift 2 ;;
--sample-read-pairs) [ "$#" -ge 2 ] || { echo "错误: --sample-read-pairs 需要数值" >&2; exit 2; }; SAMPLE_READ_PAIRS="$2"; shift 2 ;;
--no-introns) NO_INTRONS=1; shift ;;
--no-bam) NO_BAM=1; shift ;;
--dry-run) DRY_RUN=1; shift ;;
-h|--help) usage; exit 0 ;;
*) echo "错误: 未知参数 $1" >&2; usage >&2; exit 2 ;;
esac
done
[ -n "$NAME" ] || { echo "错误: 必须提供 --name" >&2; exit 2; }
[ -n "$GENOME_DIR" ] || { echo "错误: 必须提供 --genome-dir" >&2; exit 2; }
[ -n "$OUTDIR" ] || { echo "错误: 必须提供 --outdir" >&2; exit 2; }
[ -d "$GENOME_DIR" ] || { echo "错误: 参考目录不存在: $GENOME_DIR" >&2; exit 1; }
[ -s "${GENOME_DIR}/ref.json" ] || { echo "错误: 参考目录缺少 ref.json: $GENOME_DIR" >&2; exit 1; }
if [ -z "$TOOL" ]; then TOOL="$(command -v dnbc4tools || true)"; fi
[ -n "$TOOL" ] && [ -x "$TOOL" ] || {
echo "错误: 找不到可执行的 dnbc4tools;请先安装或用 --tool 指定" >&2
exit 1
}
EXPLICIT_COUNT=0
for value in "$CDNA_R1" "$CDNA_R2" "$OLIGO_R1" "$OLIGO_R2"; do
[ -n "$value" ] && EXPLICIT_COUNT=$((EXPLICIT_COUNT + 1))
done
if [ -n "$FASTQS" ] && [ "$EXPLICIT_COUNT" -ne 0 ]; then
echo "错误: --fastqs 不能与四个显式 FASTQ 参数混用" >&2
exit 2
fi
if [ -z "$FASTQS" ] && [ "$EXPLICIT_COUNT" -ne 4 ]; then
echo "错误: 必须在 --fastqs 与四个显式 FASTQ 参数之间选择一种完整输入方式" >&2
exit 2
fi
if [ -n "$FASTQS" ]; then
[ -d "$FASTQS/cDNA" ] || { echo "错误: 缺少 $FASTQS/cDNA" >&2; exit 1; }
[ -d "$FASTQS/oligo" ] || { echo "错误: 缺少 $FASTQS/oligo" >&2; exit 1; }
else
[ -n "$CDNA_R2" ] && [ -n "$OLIGO_R1" ] && [ -n "$OLIGO_R2" ] || {
echo "错误: 显式输入必须同时提供 --cdna-r1/2 和 --oligo-r1/2" >&2
exit 2
}
check_file_list() {
local list="$1" label="$2" item
IFS=',' read -r -a items <<< "$list"
for item in "${items[@]}"; do
[ -s "$item" ] || { echo "错误: $label 文件不存在或为空: $item" >&2; exit 1; }
done
}
check_file_list "$CDNA_R1" cDNA_R1
check_file_list "$CDNA_R2" cDNA_R2
check_file_list "$OLIGO_R1" oligo_R1
check_file_list "$OLIGO_R2" oligo_R2
fi
mkdir -p "$OUTDIR"
CMD=("$TOOL" rna run --name "$NAME" --genomeDir "$GENOME_DIR" --outdir "$OUTDIR" --threads "$THREADS")
if [ -n "$FASTQS" ]; then
CMD+=(--fastqs "$FASTQS")
else
CMD+=(--cDNAfastq1 "$CDNA_R1" --cDNAfastq2 "$CDNA_R2" --oligofastq1 "$OLIGO_R1" --oligofastq2 "$OLIGO_R2")
fi
[ -n "$CALLING_METHOD" ] && CMD+=(--calling_method "$CALLING_METHOD")
[ -n "$EXPECT_CELLS" ] && CMD+=(--expectcells "$EXPECT_CELLS")
[ -n "$FORCE_CELLS" ] && CMD+=(--forcecells "$FORCE_CELLS")
[ -n "$MIN_UMI" ] && CMD+=(--minumi "$MIN_UMI")
[ -n "$CHEMISTRY" ] && CMD+=(--chemistry "$CHEMISTRY")
[ -n "$DARK_REACTION" ] && CMD+=(--darkreaction "$DARK_REACTION")
[ -n "$SAMPLE_READ_PAIRS" ] && CMD+=(--sample_read_pairs "$SAMPLE_READ_PAIRS")
[ "$NO_INTRONS" -eq 1 ] && CMD+=(--no_introns)
[ "$NO_BAM" -eq 1 ] && CMD+=(--no_bam)
printf '将执行:'; printf ' %q' "${CMD[@]}"; printf '\n'
if [ "$DRY_RUN" -eq 0 ]; then
"${CMD[@]}"
echo "主流程结束;成功标志通常为日志中的: Analysis Finished"
fi
#!/usr/bin/env bash
# Generate per-sample scripts with dnbc4tools rna multi.
set -euo pipefail
TOOL=""
LIST=""
GENOME_DIR=""
OUTDIR=""
THREADS="10"
END5=0
DRY_RUN=0
usage() {
cat <<'USAGE'
用法:
bash 04_run_multi_sample.sh --list sample.tsv --genome-dir REF \
--outdir OUT --threads 10
选项:
--tool PATH dnbc4tools 可执行文件 (默认: PATH 中的命令)
--list FILE 三列制表符文件:样本名、cDNA、oligo (必需)
--genome-dir DIR 参考数据库目录 (必需)
--outdir DIR 生成脚本/结果目录 (必需)
--threads N 线程数 (默认: 10)
--end5 启用 5' 端单细胞转录组分析
--dry-run 只打印命令,不执行
-h, --help 显示帮助
USAGE
}
while [ "$#" -gt 0 ]; do
case "$1" in
--tool) [ "$#" -ge 2 ] || { echo "错误: --tool 需要路径" >&2; exit 2; }; TOOL="$2"; shift 2 ;;
--list) [ "$#" -ge 2 ] || { echo "错误: --list 需要文件" >&2; exit 2; }; LIST="$2"; shift 2 ;;
--genome-dir) [ "$#" -ge 2 ] || { echo "错误: --genome-dir 需要目录" >&2; exit 2; }; GENOME_DIR="$2"; shift 2 ;;
--outdir) [ "$#" -ge 2 ] || { echo "错误: --outdir 需要目录" >&2; exit 2; }; OUTDIR="$2"; shift 2 ;;
--threads) [ "$#" -ge 2 ] || { echo "错误: --threads 需要数值" >&2; exit 2; }; THREADS="$2"; shift 2 ;;
--end5) END5=1; shift ;;
--dry-run) DRY_RUN=1; shift ;;
-h|--help) usage; exit 0 ;;
*) echo "错误: 未知参数 $1" >&2; usage >&2; exit 2 ;;
esac
done
[ -n "$LIST" ] || { echo "错误: 必须提供 --list" >&2; exit 2; }
[ -n "$GENOME_DIR" ] || { echo "错误: 必须提供 --genome-dir" >&2; exit 2; }
[ -n "$OUTDIR" ] || { echo "错误: 必须提供 --outdir" >&2; exit 2; }
[ -s "$LIST" ] || { echo "错误: sample list 不存在或为空: $LIST" >&2; exit 1; }
[ -d "$GENOME_DIR" ] || { echo "错误: 参考目录不存在: $GENOME_DIR" >&2; exit 1; }
[ -s "${GENOME_DIR}/ref.json" ] || { echo "错误: 参考目录缺少 ref.json: $GENOME_DIR" >&2; exit 1; }
if [ -z "$TOOL" ]; then TOOL="$(command -v dnbc4tools || true)"; fi
[ -n "$TOOL" ] && [ -x "$TOOL" ] || {
echo "错误: 找不到可执行的 dnbc4tools;请先安装或用 --tool 指定" >&2
exit 1
}
# Ignore empty/comment lines but reject malformed records before invoking MGI code.
awk -F '\t' '
/^[[:space:]]*$/ || /^[[:space:]]*#/ { next }
{ seen=1 }
NF != 3 { printf "错误: 第 %d 行不是 3 列制表符格式 (实际 %d 列)\n", NR, NF > "/dev/stderr"; bad=1 }
END {
if (!seen) { print "错误: sample list 没有有效样本行" > "/dev/stderr"; exit 1 }
exit bad
}
' "$LIST"
mkdir -p "$OUTDIR"
CMD=("$TOOL" rna multi --list "$LIST" --genomeDir "$GENOME_DIR" --outdir "$OUTDIR" --threads "$THREADS")
[ "$END5" -eq 1 ] && CMD+=(--end5)
printf '将执行:'; printf ' %q' "${CMD[@]}"; printf '\n'
if [ "$DRY_RUN" -eq 0 ]; then
"${CMD[@]}"
echo "已生成多样本运行脚本;请逐个检查并执行 OUTDIR 中的 .sh 文件。"
fi
#!/usr/bin/env bash
# Check the minimum output contract of a completed dnbc4tools rna run.
set -euo pipefail
if [ "$#" -eq 1 ] && { [ "$1" = "-h" ] || [ "$1" = "--help" ]; }; then
echo "用法: bash 05_check_outputs.sh <run_outdir_or_outs_dir>"
exit 0
fi
ROOT="${1:-}"
if [ -z "$ROOT" ]; then
echo "用法: bash 05_check_outputs.sh <run_outdir_or_outs_dir>" >&2
exit 2
fi
if [ -d "$ROOT/outs" ]; then
OUTS="$ROOT/outs"
else
OUTS="$ROOT"
fi
[ -d "$OUTS" ] || { echo "错误: 目录不存在: $OUTS" >&2; exit 1; }
required=(
"filter_feature.h5ad"
"filter_matrix/barcodes.tsv.gz"
"filter_matrix/features.tsv.gz"
"filter_matrix/matrix.mtx.gz"
"raw_matrix/barcodes.tsv.gz"
"raw_matrix/features.tsv.gz"
"raw_matrix/matrix.mtx.gz"
"metrics_summary.xls"
"singlecell.csv"
"analysis/cluster.csv"
"analysis/marker.csv"
"analysis/QC_Cluster.h5ad"
)
missing=0
for rel in "${required[@]}"; do
if [ -s "$OUTS/$rel" ]; then
printf 'OK %s\n' "$rel"
else
printf 'MISSING %s\n' "$rel"
missing=1
fi
done
report_count="$(find "$OUTS" -maxdepth 1 -type f -name '*_scRNA_report.html' | wc -l)"
if [ "$report_count" -gt 0 ]; then
echo "OK *_scRNA_report.html ($report_count)"
else
echo "MISSING *_scRNA_report.html"
missing=1
fi
if [ -s "$OUTS/anno_decon_sorted.bam" ] && [ -s "$OUTS/anno_decon_sorted.bam.bai" ]; then
echo "OK anno_decon_sorted.bam + .bai"
else
echo "INFO BAM 未找到(若使用 --no_bam,这是预期行为)"
fi
if [ "$missing" -ne 0 ]; then
echo "结果检查失败:请查看 logs/ 和主流程日志。" >&2
exit 1
fi
echo "结果检查通过: $OUTS"
#!/usr/bin/env bash
# ================================================================================
# dnbc4tools 下载与安装
# dnbc4tools: 用于分析高通量 DNBelab C 系列™ 单细胞数据集的开源且灵活的流程
# ================================================================================
set -euo pipefail
## 切换工作目录
cd ~/workspace/protocol/C4_sc
## 使用 wget 下载
wget -O dnbc4tools2.1.3.tar.gz "ftp://ftp2.cngb.org/pub/CNSA/data7/CNP0006367/Single_Cell/CSE0000448/dnbc4tools2.1.3.tar.gz"
## 使用 curl 下载(备选)
# curl -o dnbc4tools2.1.3.tar.gz "ftp://ftp2.cngb.org/pub/CNSA/data7/CNP0006367/Single_Cell/CSE0000448/dnbc4tools2.1.3.tar.gz"
## 执行解压
tar -xzvf dnbc4tools2.1.3.tar.gz
## 查看生成的文件目录
ls dnbc4tools2.1.3
# 期望结构:
# dnbc4tools
# external
# lib
# misc
# sourceC4.bash
# 至此完成安装,dnbc4tools 可以使用了
#!/usr/bin/env bash
# ================================================================================
# 参考基因组准备: 下载 FASTA/GTF → 校正/过滤 GTF → 构建参考数据库 (mkref)
# ================================================================================
set -euo pipefail
# ============ 3.1 下载物种参考基因组文件 ============
# 基因组文件: FASTA 格式, 包含特定物种完整基因组序列(染色体/线粒体等), 通常为主装配版本
# 注释文件: GTF 格式, 包含基因/转录本/外显子等功能区域信息
# 至少需包含 "gene" 或 "transcript" 类型 + "exon" 类型注释
# 属性必须包含 gene_id 或 gene_name, 以及 transcript_id 或 transcript_name
# 建议: 可从 Ensembl 获取的物种优先用 Ensembl 文件(GTF 含可选标签便于 mkgtf 过滤)
# 注意: 必需 GTF, 不支持 GFF; 基因组与注释文件需对应
## 下载参考基因组(以小鼠为例)
curl -O https://ftp.ensembl.org/pub/release-115/fasta/mus_musculus/dna/Mus_musculus.GRCm39.dna.toplevel.fa.gz
## 下载注释文件
curl -O https://ftp.ensembl.org/pub/release-115/gtf/mus_musculus/Mus_musculus.GRCm39.115.gtf.gz
## 解压
gunzip Mus_musculus.GRCm39.dna.toplevel.fa.gz
gunzip Mus_musculus.GRCm39.115.gtf.gz
# ============ 3.2 过滤 GTF 文件(可选) ============
# 从 ENSEMBL/UCSC 下载的 GTF 通常含多种基因类型, 过滤可减少重叠注释
# (与多个基因非唯一比对的 reads 会被过滤)
# dnbc4tools 提供: 基因类型统计、基因类型过滤、校正 GTF
## 3.2.1 基因类型数量统计(可选)
dnbc4tools2.1.3/dnbc4tools tools mkgtf --action stat --ingtf Mus_musculus.GRCm39.115.gtf --output gtfstat.txt --type gene_biotype
cat gtfstat.txt
# 输出示例:
# Type Count
# lncRNA 35034
# protein_coding 20121
# processed_pseudogene 9489
# ...
## 3.2.2 校正 GTF 文件(可选)
# 内容缺失的 GTF 会导致主分析流程无法注释而报错
# 软件会主动填补 gene/transcript 行缺失的信息, 根据 gene_id 和 gene_name 及 transcript_id 和 transcript_name 互相填补
dnbc4tools2.1.3/dnbc4tools tools mkgtf --action check --ingtf Mus_musculus.GRCm39.115.gtf --output Mus_musculus.GRCm39_corrected.gtf
## 3.2.3 基因类型过滤(可选)
# 默认保留: protein_coding, lncRNA/lincRNA, antisense, IG_V_gene, IG_LV_gene, IG_D_gene,
# IG_J_gene, IG_C_gene, IG_V_pseudogene, IG_J_pseudogene, IG_C_pseudogene,
# TR_V_gene, TR_D_gene, TR_J_gene, TR_C_gene
# 类似 Cellranger 过滤步骤
dnbc4tools2.1.3/dnbc4tools tools mkgtf --ingtf Mus_musculus.GRCm39_corrected.gtf --output Mus_musculus.GRCm39_filtered.gtf --type gene_biotype \
--include protein_coding,lncRNA,lincRNA,antisense,IG_V_gene,IG_LV_gene,IG_J_gene,IG_C_gene,IG_V_pseudogene,IG_J_pseudogene,IG_C_pseudogene,TR_V_gene,TR_D_gene,TR_J_gene,TR_C_gene
# ============ 3.3 构建参考数据库 ============
# 需要注释文件 GTF 和参考基因组 FASTA 构建索引文件, 用于测序 reads 的比对和注释
dnbc4tools2.1.3/dnbc4tools rna mkref --fasta Mus_musculus.GRCm39.dna.toplevel.fa --ingtf Mus_musculus.GRCm39_filtered.gtf --species Mus_musculus --threads 30
## 查看输出的参考基因组文件结构
ls GRCm39
# _bt_log chrLength.txt chrNameLength.txt chrName.txt chrStart.txt
# exonGeTrInfo.tab exonInfo.tab geneInfo.tab Genome genomeParameters.txt
# Log.out mtgene.list ref.json SA SAindex sjdbInfo.txt
# sjdbList.fromGTF.out.tab sjdbList.out.tab transcriptInfo.tab
# ============ 3.4 准备 Fastq 文件 ============
# 单样本: 直接准备好 cDNA fastq 文件和 oligo fastq 文件
# 多样本(可选): 用配置文件生成包含多个样本的主流程 shell 脚本
# 示例:
# dnbc4tools rna multi --list sample.tsv --genomeDir /opt/database/Homo_sapiens --threads 10
# sample.tsv 用制表符分隔, 第一列样本名, 第二列 cDNA 文库数据, 第三列寡核苷酸文库数据
# 多个 fastq 以逗号分隔, R1 和 R2 文件以分号分隔
# 运行完成后输出 sample1.sh/sample2.sh/sample3.sh
#!/usr/bin/env bash
# ================================================================================
# 定量分析流程: 单样本 RNA 主分析流程 (rna run)
# 处理单个样本单细胞 RNA 的 cDNA 和 oligo 文库测序数据
# 包括: 质量控制 → 比对 → 功能区域注释 → 合并磁珠识别细胞
# → 生成原始/过滤基因表达矩阵 → 细胞过滤/降维/聚类/注释 → HTML 报告
# ================================================================================
set -euo pipefail
# PS: 注意参考基因组中 ref.json 文件, 其中 genomeDir 指定了参考基因组路径
# 成功运行会以 Analysis Finished 结束
dnbc4tools2.1.3/dnbc4tools rna run \
--name test \
--cDNAfastq1 data/E150004608_L01_21_1.fq.gz \
--cDNAfastq2 data/E150004608_L01_21_2.fq.gz \
--oligofastq1 data/E150004608_L01_12_1.fq.gz \
--oligofastq2 data/E150004608_L01_12_2.fq.gz \
--genomeDir GRCm39 \
--threads 30
## 结果文件目录示例
ls test
# 01.data
# 02.count
# 03.analysis
# 04.report
# log
# output
## 多样本模式(备选): 生成每个样本单独的 shell 脚本
# dnbc4tools rna multi --list sample.tsv --genomeDir /opt/database/Homo_sapiens --threads 10
## 生成的 sample1.sh 示例:
# dnbc4tools2.1.3/dnbc4tools rna run --name sample1 \
# --cDNAfastq1 /data/cDNA1_R1.fq.gz --cDNAfastq2 /data/cDNA1_R2.fq.gz \
# --oligofastq1 /data/oligo1_R1.fq.gz,/data/oligo4_R1.fq.gz \
# --oligofastq2 /data/oligo1_R2.fq.gz,/data/oligo4_R2.fq.gz \
# --genomeDir /database/scRNA/Mus_musculus/mm10 --threads 10