deeptools — 정렬된 리드를 신호 트랙으로: bamCoverage·computeMatrix·plotHeatmap

CODE BENCH · NGS PIPELINES
deeptools — 정렬된 리드를 신호 트랙으로: bamCoverage·computeMatrix·plotHeatmap
TL;DR — deeptools는 정렬된 리드(BAM)를 유전체 위의 신호 트랙(bigWig)으로 바꾸고, 그 신호를 특정 구간 주변에서 메타플롯·히트맵으로 시각화하는 파이썬 도구 모음입니다. ChIP-seq·ATAC-seq·CUT&RUN처럼 '어디에 신호가 얼마나 쌓였나'를 봐야 하는 분석의 표준 후처리죠.
뼈대는 네 갈래입니다. bamCoverage로 BAM을 정규화된 bigWig 커버리지 트랙으로 만들고, multiBamSummary + plotCorrelation·plotPCA로 반복 실험(replicate)의 재현성을 확인하고, bamCompare로 ChIP 대 input을 log2 비율로 견주고, computeMatrix → plotHeatmap·plotProfile로 TSS 같은 기준점 둘레의 신호를 히트맵과 평균 곡선으로 그립니다.
작은 BAM 예제로 명령을 한 줄씩 따라간 뒤, 정렬된 BAM에서 bamCoverage로 트랙을 만들고 computeMatrix로 행렬을 뽑아 plotHeatmap까지 잇는 전체 워크플로를 완성합니다. 0-based 좌표와 bigWig 포맷도 함께 짚죠. 명령은 deeptools 3.5 기준입니다.
🔗 관련 글 · deeptools가 신호로 바꾸는 리드는 대개 앞선 도구의 산출물입니다 — 정렬 결과의 포맷은 SAM/BAM 파일이란?, 그 BAM을 정렬·인덱싱하는 samtools·bcftools 실전, 신호 트랙의 대표 사용처인 ChIP-seq, 그리고 같은 방식으로 트랙을 읽는 또 다른 후성유전체 분석 Hi-C·3D 유전체에서 이어집니다.
이 글에서 만들 것
ChIP-seq나 ATAC-seq를 돌리면 결국 손에 남는 건 정렬된 리드가 담긴 BAM 파일입니다. 그런데 BAM을 IGV로 열어 봐도 리드 하나하나가 늘어서 있을 뿐, "이 프로모터에 신호가 얼마나 몰렸나", "샘플 두 개가 서로 닮았나" 같은 질문에는 바로 답이 안 나오죠. 리드를 세어 트랙으로 요약하고, 그 트랙을 관심 구간에 맞춰 정렬해 그림으로 만들어야 비로소 읽힙니다.
deeptools는 그 요약과 시각화를 전담합니다. BAM을 유전체 커버리지 트랙(bigWig)으로 바꾸고(bamCoverage), 여러 샘플의 커버리지를 모아 상관·주성분으로 재현성을 보고(multiBamSummary·plotCorrelation·plotPCA), ChIP과 input을 비율로 견주고(bamCompare), 유전자 시작점(TSS) 같은 기준점 주변의 신호를 히트맵·메타플롯으로 펼칩니다(computeMatrix·plotHeatmap·plotProfile). 입력은 BAM과 bigWig, 출력은 bigWig·PNG·npz라 앞뒤 도구와 자연스럽게 이어지죠.
이 글은 그 deeptools를 처음부터 익힙니다. 구체적으로 ① 설치와 예제 BAM을 준비하고, ② bamCoverage로 정규화된 신호 트랙을 만들고, ③ multiBamSummary로 샘플 간 재현성을 확인하고, ④ bamCompare로 ChIP 대 input을 비교하고, ⑤ computeMatrix로 TSS 주변 신호를 히트맵·메타플롯으로 그린 뒤, ⑥ 이 조각들을 하나의 워크플로로 묶습니다.
# 핵심 흐름 한눈에
bamCoverage -b aln.sorted.bam -o signal.bw --normalizeUsing RPKM # ① BAM → bigWig 트랙
computeMatrix reference-point -S signal.bw -R genes.bed -o mat.gz # ② TSS 주변 신호 행렬
plotHeatmap -m mat.gz -o heatmap.png # ③ 히트맵·메타플롯
1. 사전 준비 — 설치와 예제 데이터
deeptools는 파이썬으로 짠 명령줄 도구 모음입니다. conda로 까는 게 가장 간편한데, 의존성 해결을 위해 conda-forge와 bioconda 채널을 함께 지정합니다.
# conda — conda-forge·bioconda 두 채널을 함께(권장)
conda install -c conda-forge -c bioconda deeptools
# 또는 pip
pip install deeptools
# 설치 확인(버전 출력)
deeptools --version
deeptools 3.5.6
deeptools의 입력은 좌표순으로 정렬된 BAM이고, 대부분의 명령은 그 옆에 인덱스 파일(.bai)이 있어야 돕니다. 정렬·인덱싱은 samtools가 맡습니다.
# 좌표순 정렬 → 인덱싱(.bai 생성) — deeptools가 요구
samtools sort aln.bam -o aln.sorted.bam
samtools index aln.sorted.bam
예제 데이터는 두 갈래로 구할 수 있습니다. 하나는 deeptools 저장소가 함께 배포하는 테스트 파일(deeptools/test/test_data/의 test1.bam·testA.bw·test.bed3 등)이고, 다른 하나는 ENCODE 포털에서 내려받는 공개 ChIP-seq BAM·bigWig입니다. 아래 예제는 이런 작은 BAM 한두 개가 있다고 치고 진행합니다.
출력으로 자주 나오는 bigWig는 유전체 전체에 걸친 연속적인 수치(커버리지·점수)를 담는 색인된 이진 포맷입니다. 텍스트인 BedGraph와 달리 압축·색인이 되어 있어 IGV·UCSC 같은 브라우저가 특정 구간만 빠르게 꺼내 그릴 수 있죠. 좌표는 BED와 마찬가지로 0-based 반열림이라, 다른 포맷과 맞댈 때는 좌표계를 먼저 확인해야 합니다.
2. bamCoverage — BAM을 bigWig 신호 트랙으로
가장 먼저 쓰는 명령이 bamCoverage입니다. 유전체를 일정 크기의 구간(bin)으로 잘라 각 bin에 겹치는 리드 수를 세고, 이를 정규화해 bigWig 트랙으로 내보냅니다.

# BAM → bigWig, 10bp bin, RPKM 정규화, 리드를 fragment 길이로 확장
bamCoverage -b aln.sorted.bam -o signal.bw \
--binSize 10 --normalizeUsing RPKM --extendReads
--binSize는 해상도를 정합니다(기본 50bp). 작게 잡으면 신호가 더 촘촘해지지만 파일이 커지죠. --extendReads는 단일-끝(single-end) 리드를 실제 fragment 길이만큼 늘려, 리드가 짧아 생기는 신호 끊김을 메웁니다. ChIP처럼 fragment 전체가 신호인 실험에서 특히 중요합니다.
결과가 이진 포맷인 bigWig라 눈으로 바로 보긴 어려우니, 확인용으로 같은 계산을 텍스트인 BedGraph로 한 번 뽑아 봅니다.
# 확인용 — BedGraph로 출력해 앞 몇 줄 들여다보기
bamCoverage -b aln.sorted.bam -o signal.bedgraph -of bedgraph \
--binSize 50 --normalizeUsing CPM
head -3 signal.bedgraph
chr1 0 50 0.00
chr1 50 100 1.83
chr1 100 150 4.57
각 줄은 '이 50bp 구간의 정규화된 커버리지가 이 값'이라는 뜻입니다. 정규화 방식은 --normalizeUsing으로 고르는데, 실험·목적에 따라 갈립니다.
| 옵션 | 뜻 | 언제 |
|---|---|---|
| RPKM | 리드 수를 구간 길이(kb)와 총 리드 수(백만)로 나눔 | 일반적 깊이 보정 |
| CPM | 백만 리드당 카운트(길이 보정 없음) | 단순 깊이 보정 |
| BPM | 백만당 bin 값(RNA-seq의 TPM에 해당) | 샘플 간 총합 통일 |
| RPGC | 유전체 함량당 리드 = 1x 정규화 | 커버리지 배수를 맞출 때 |
| None | 정규화 안 함(원시 카운트) | 뒤에서 직접 보정 |
RPGC (1x 정규화)만은 매핑 가능한 유전체 크기를 알려 줘야 합니다. --effectiveGenomeSize에 값을 넘기는데, 이 값은 리드 길이에 따라 달라집니다. 예컨대 사람 GRCh38·리드 100bp 기준은 2,805,636,231이고, 정확한 표는 deeptools 공식 문서에 정리돼 있습니다.
# RPGC 1x 정규화 — 유효 유전체 크기 필요(GRCh38·100bp)
bamCoverage -b aln.sorted.bam -o signal_1x.bw \
--normalizeUsing RPGC --effectiveGenomeSize 2805636231 --binSize 10
3. multiBamSummary — 샘플 간 재현성(상관·PCA)
트랙을 만들었다면, 그림을 그리기 전에 반복 실험이 서로 닮았는지부터 확인하는 게 순서입니다. multiBamSummary는 여러 BAM의 커버리지를 한꺼번에 요약해 압축 배열(.npz)로 저장합니다. 유전체를 일정 bin으로 훑는 bins 모드가 기본이고, 특정 구간만 볼 땐 BED-file 모드를 씁니다.
# 여러 BAM의 커버리지를 bin 단위로 요약 → .npz
multiBamSummary bins \
-b chip_rep1.bam chip_rep2.bam input.bam \
--labels ChIP_rep1 ChIP_rep2 input \
-o readCounts.npz
이 .npz를 plotCorrelation에 넘기면 샘플 간 상관 히트맵이, plotPCA에 넘기면 주성분 그림이 나옵니다.
# 스피어만 상관을 히트맵으로(숫자도 표시)
plotCorrelation -in readCounts.npz \
--corMethod spearman --whatToPlot heatmap \
--plotNumbers -o correlation.png
# 주성분 분석(PCA)
plotPCA -in readCounts.npz -o pca.png
잘 된 실험이라면 같은 조건의 반복끼리(ChIP_rep1·ChIP_rep2) 상관이 높게 뭉치고, 배경인 input과는 뚜렷이 갈립니다. PCA에서도 반복은 가까이, 조건이 다른 샘플은 멀찍이 떨어지죠. 여기서 한 반복만 엉뚱하게 튄다면, 히트맵을 그리기 전에 그 샘플부터 들여다보는 게 낫습니다. --corMethod는 pearson으로, --whatToPlot은 scatterplot으로도 바꿀 수 있습니다.
4. bamCompare — ChIP 대 input을 log2 비율로
ChIP-seq 신호에는 진짜 결합 신호뿐 아니라 열린 염색질·매핑 편향 같은 배경이 섞입니다. 이 배경을 걷어 내려면 대조군(input)과 견줘야 하는데, 그 일을 bamCompare가 합니다. 두 BAM을 같은 bin에서 비교해 비율 트랙 하나로 내보내죠.
# ChIP 대 input의 log2 비율 트랙
bamCompare -b1 chip.bam -b2 input.bam \
--operation log2 --binSize 20 \
-o log2_chip_vs_input.bw
--operation은 기본이 log2(두 값의 log2 비율)이고, ratio·subtract·mean 등으로도 바꿀 수 있습니다. 깊이가 다른 두 BAM을 공정하게 맞추기 위해 bamCompare는 먼저 스케일 인자를 계산하는데, 그 방식은 --scaleFactorsMethod로 고릅니다(기본 readCount, ChIP 농축이 강할 땐 SES). 출력 트랙에서 값이 0보다 크면 ChIP이 input보다 높은 구간, 곧 신호가 실제로 농축된 자리입니다.
5. computeMatrix → plotHeatmap·plotProfile — 기준점 둘레의 신호

이제 핵심입니다. 만든 트랙(bigWig)을 관심 구간 집합(BED/GTF) 둘레에서 정렬해, 히트맵과 평균 곡선으로 펼치는 단계죠. 먼저 computeMatrix가 신호 행렬을 만들고, 그 행렬을 plotHeatmap·plotProfile이 그림으로 바꿉니다. computeMatrix는 두 가지 모드로 씁니다.
reference-point 모드는 각 구간의 한 지점(TSS·TES·center)을 기준으로 위아래 일정 구간을 잘라 냅니다. 유전자 시작점(TSS) 둘레의 신호를 볼 때 씁니다.
# TSS 기준 ±3kb 구간의 신호 행렬
computeMatrix reference-point --referencePoint TSS \
-S signal.bw -R genes.bed \
-b 3000 -a 3000 --skipZeros \
-o matrix_TSS.gz
-S는 점수가 담긴 bigWig, -R는 구간이 담긴 BED/GTF, -o는 gzip으로 압축된 행렬입니다. -b(before)와 -a(after)는 기준점 위·아래로 몇 bp를 볼지 정하고, --skipZeros는 신호가 아예 없는 구간을 빼 그림을 깔끔하게 합니다.
scale-regions 모드는 길이가 제각각인 구간(유전자 몸통)을 같은 길이로 늘이거나 줄여 맞춥니다. 유전자 전체(TSS→TES)에 걸친 신호 모양을 볼 때 유용하죠.
# 유전자 몸통을 5kb로 스케일 + 양옆 3kb
computeMatrix scale-regions \
-S signal.bw -R genes.bed \
--regionBodyLength 5000 -b 3000 -a 3000 \
-o matrix_body.gz
행렬이 준비되면 두 가지로 그립니다. plotProfile은 모든 구간의 신호를 위치별로 평균 낸 메타플롯(평균 곡선)을, plotHeatmap은 구간을 행으로, 위치를 열로 놓은 히트맵을 그립니다.
# 메타플롯(평균 신호 곡선)
plotProfile -m matrix_TSS.gz -o profile_TSS.png --perGroup
# 히트맵(구간 × 위치) + 위쪽에 메타플롯
plotHeatmap -m matrix_TSS.gz -o heatmap_TSS.png \
--colorMap Blues --sortUsing sum
plotProfile에서 곡선이 TSS 자리에서 봉우리를 이루면, 그 신호가 전사 시작점에 몰려 있다는 뜻입니다. plotHeatmap은 같은 정보를 구간별로 펼쳐, 어떤 유전자에서 신호가 세고 약한지를 한눈에 보여 주죠. 히트맵 행은 --sortUsing으로 신호 세기순으로 정렬하고, --kmeans를 주면 신호 패턴이 비슷한 구간끼리 자동으로 묶어 줍니다.
6. 실전 — BAM에서 히트맵까지 한 번에

이제 조각을 이어 붙입니다. 정렬된 ChIP BAM에서 시작해 트랙을 만들고, TSS 주변 신호를 뽑아 히트맵까지 가는 전체 흐름입니다.
# 1) 정렬·인덱싱(아직 안 했다면)
samtools sort chip.bam -o chip.sorted.bam
samtools index chip.sorted.bam
# 2) BAM → 정규화된 bigWig 트랙
bamCoverage -b chip.sorted.bam -o chip.bw \
--binSize 10 --normalizeUsing RPKM --extendReads
# 3) TSS ±3kb 신호 행렬
computeMatrix reference-point --referencePoint TSS \
-S chip.bw -R genes.bed -b 3000 -a 3000 --skipZeros \
-o matrix.gz
# 4) 히트맵 + 메타플롯
plotHeatmap -m matrix.gz -o chip_TSS_heatmap.png --colorMap Blues
ChIP과 input을 함께 보고 싶다면, 2번에서 bamCompare로 log2 비율 트랙을 만들어 -S에 넣으면 됩니다. 트랙을 여러 개 넣으면(-S a.bw b.bw) computeMatrix가 나란히 처리해, plotHeatmap이 조건별 패널을 한 그림에 그려 주죠. bigWig만 있으면 원본 BAM 없이도 3~4단계를 반복할 수 있어, 파라미터를 바꿔 가며 그림을 다듬기 좋습니다.
7. 자주 발생하는 에러 & 해결
The file ... does not have an index— deeptools는 BAM에 인덱스(.bai)가 함께 있어야 돕니다.samtools index aln.sorted.bam으로 인덱스를 먼저 만드세요. 인덱싱은 좌표순 정렬이 끝난 뒤라야 되므로, 정렬이 안 됐으면samtools sort부터 돌립니다.--effectiveGenomeSize관련 오류(RPGC) — RPGC (1x) 정규화는 유효 유전체 크기가 반드시 필요합니다. 값은 유전체·리드 길이마다 다르니 공식 문서 표에서 맞는 값을 찾아 넣으세요(GRCh38·100bp면 2,805,636,231).- 히트맵이 텅 비거나 신호가 0 — bigWig와 BED의 염색체 이름 규칙이 다른 경우가 흔합니다. 한쪽은
chr1, 다른 쪽은1이면 겹침이 0으로 나오죠. 이름을 한쪽으로 통일하고,computeMatrix에--skipZeros가 과하게 걸리지 않았는지도 확인합니다. computeMatrix가 너무 느리거나 메모리 부족 — 구간·트랙이 많으면 무거워집니다.-p(또는--numberOfProcessors)로 코어를 늘리고, bamCoverage 단계의--binSize를 키워 트랙을 가볍게 만드세요.- 신호에 잡음·중복이 섞임 — 낮은 품질 매핑이나 PCR 중복이 트랙을 흐립니다. bamCoverage에
--minMappingQuality 30으로 낮은 MAPQ 리드를,--ignoreDuplicates로 중복 리드를 걸러 냅니다.
8. 확장 — 더 해 볼 것
- plotFingerprint로 ChIP 품질 보기 —
plotFingerprint는 리드가 소수 구간에 얼마나 몰렸는지를 누적 곡선으로 그려, ChIP의 신호 대 잡음(signal-to-noise)을 한눈에 판단하게 해 줍니다. 히트맵 전 QC 단계로 좋죠. - computeGCBias·correctGCBias로 GC 편향 보정 — 라이브러리 준비에서 생기는 GC 편향을 진단(
computeGCBias)하고 보정(correctGCBias)합니다. 커버리지가 GC 함량에 휘둘릴 때 씁니다. - multiBigwigSummary로 트랙끼리 비교 — BAM이 아니라 이미 만든 bigWig 여러 개의 상관을 볼 땐
multiBigwigSummary가 짝입니다. 공개 ENCODE bigWig와 내 트랙을 견줄 때 편하죠. - alignmentSieve로 ATAC-seq 전처리 —
alignmentSieve는 리드를 필터링하거나 ATAC-seq용 Tn5 이동 보정(shift)을 넣어 줍니다. ATAC 신호 트랙을 만들기 전 단계로 자주 씁니다. - pyGenomeTracks로 출판용 트랙 그림 — deeptools 계열인
pyGenomeTracks는 bigWig·BED·유전자 모델을 한 창에 겹쳐 그려, 특정 유전자좌위(locus)의 트랙 그림을 논문 그림 수준으로 만듭니다.
다음 학습
• (정렬 결과 포맷) SAM/BAM 파일이란? — deeptools가 입력으로 받는 BAM의 구조와 좌표
• (BAM 정렬·인덱싱) samtools·bcftools 실전 — deeptools 앞단에서 BAM을 정렬·인덱싱하는 짝 도구
• (신호의 대표 사용처) ChIP-seq란? — 트랙·피크·메타플롯이 실제로 쓰이는 실험
• (또 다른 후성유전체 트랙) Hi-C·3D 유전체란? — 접촉 지도를 트랙으로 읽는 3차원 유전체 분석
References
- Ramírez, F., Ryan, D. P., Grüning, B., Bhardwaj, V., Kilpert, F., Richter, A. S., Heyne, S., Dündar, F., & Manke, T. (2016). deepTools2: a next generation web server for deep-sequencing data analysis. Nucleic Acids Research, 44(W1), W160–W165. doi:10.1093/nar/gkw257 (deeptools 원논문)
- Ramírez, F., Dündar, F., Diehl, S., Grüning, B. A., & Manke, T. (2014). deepTools: a flexible platform for exploring deep-sequencing data. Nucleic Acids Research, 42(W1), W187–W191. doi:10.1093/nar/gku365 (초판)
- Bhardwaj, V., et al. (2024). deepTools documentation (v3.5) — tools to process and analyze deep sequencing data. deeptools.readthedocs.io
- deepTools. Effective genome size — mappable genome sizes per read length. deeptools.readthedocs.io/effectiveGenomeSize
Pipette & Pipeline · A bio portfolio journal
'Code Bench > NGS Pipelines' 카테고리의 다른 글
| bedtools — 유전체 구간 연산: intersect·merge·coverage와 BED 포맷 (0) | 2026.07.15 |
|---|---|
| Snakemake 재현 파이프라인 — rule·wildcard·DAG로 NGS 워크플로 자동화 (0) | 2026.07.10 |
| salmon으로 전사체 정량 — 유사정렬·RNA-seq 업스트림 (0) | 2026.07.08 |
| samtools·bcftools 실전 — BAM 정렬·인덱싱과 VCF 변이 필터링 (0) | 2026.07.06 |
| GATK으로 변이 호출하기 — BAM에서 VCF까지 (NGS Pipelines 3) (0) | 2026.06.24 |




































