[NGS DNA-SEQ] Functional Equivalence pipeline: CROMWELL, WDL

gnomAD, TOPMed 등 대규모 유전체 코호트들이 만들어지면서, 여기서 생산된 데이터를 이용하는데 중요한 문제가 부각되었는데, 바로 분석 결과 간의 재현성호환성에 있었습니다. 즉, 연구자가 GATK Best practice를 이용하여 Exome 또는 Genome 시퀀싱 분석을 진행하더라도 어떤 설정과 파라미터 값을 넣느냐에 따라, 최종 검출 변이의 결과가 달라지고, 이것은 연구 결과 간의 재현성의 측면에서 매우 중요한 문제가 되었던 것이지요. 참고논문에서 진행한 실험 결과를 보면, 동일한 샘플로 생산된 FASTQ 파일을 서로 다른 5개의 기관에 보내 각각의 파이프 라인으로 분석한 결과, Call된 변이들 간에 많은 차이가 있었다고 보고하고 있습니다.

[관련 포스팅 보기]

따라서, 점점 늘어나는 유전체 데이터만큼 유전체 분석 파이프 라인을 하나의 표준화된 파이프 라인으로 통합하는 것이 매우 중요해졌고, 그 결과 개발된 것이 “Functional Equivalence (FE)” Pipeline (기능적으로 동등한 파이프라인) 입니다. 사실 NGS 분석을 하는 사용자의 입장에서는 Input만 넣고, Output만 나오면 편한데, 그동안 개발된 툴들은 이를 모두 아우르는 것이 아니라, 그때 그때마다 필요한 부분들을 개발했기 때문에, 분석 파이프 라인도 이제야 어느 정도 성숙 단계에 이르렀다고 할 수 있습니다. 따라서 최근의 대규모 유전체 컨소시엄들은 모두 “Functional Equivalence ” Pipeline 을 통해 생산된 유전체 데이터를 생산하는 것으로 채택하고 있습니다. (그래서 저도 functional equivalent한 결과를 얻기 위해서 최근에 새롭게 공부를 하게 되었습니다.)

[ Functional Equivalence Pipeline Overview]

FE 파이프라인을 제공하기 위해서, Broad Institute의 개발진들은 WDL (Workflow Description Langauge)과 Cromwell이라고 하는 프로그래밍 언어를 개발하는데, 하나의 파이프라인을 패키지로 묶은 WDL 파일을 만들고, 이를 Cromwell이라는 프로그램으로 구동시켜주는 원리라고 합니다. 사실 사용자의 입장에서는 과거에 개별 프로그램을 설치하고, 개별 스텝을 따로 돌려야했다면, 지금은 이러한 것들이 모두 하나의 패키지 형태로 제공되기에 더욱 편해졌다고 할 수 있습니다 (?).

[Cromwell 페이지 바로 가기] https://cromwell.readthedocs.io/en/stable/

[WARP 페이지 바로가기] https://broadinstitute.github.io/warp/docs/get-started/

Cromwell의 로고: 꼬마돼지 베이브와 스타트렉에 출연한 배우 James Cromwell을 오마주한 로고라고 합니다 🙂

병원 검사실을 운영하는데, 검사 장비와 보고 방법을 표준화하는 것은 매우 중요한데, 유전체 분석 파이프 라인에도 이제야 이러한 개념이 들어왔다는 점이 반갑습니다. (분석 파이프 라인 하나도 이렇게 표준화하기가 어렵습니다.) Genome의 경우에는 처리해야할 데이터의 크기가 워낙 방대하기때문에 더욱 어려운 점이 있는 것 같습니다. 현재 이쪽 분야도 많은 Computational Scienctist들이 뛰어들어서 개발을 진행하고 있는 중이기 때문에, 추후에 더 User-friendly하고 간편한 파이프 라인이 개발되어 제공되기를 기대해 봅니다. (점차 대세는 클라우드로 옮겨가지 않을까 합니다?)

[References]

Regier, Allison A., et al. “Functional equivalence of genome sequencing analysis pipelines enables harmonized variant calling across human genetics projects.” Nature communications 9.1 (2018): 1-8.

광고

NGS 분석 파이프 라인의 이해: GATK Best Practice

최근들어 제 블로그의 방문자들이 눈에 띄게 증가했습니다. 대부분 구글 검색을 통해서 유입되는 분들인데, 검색어 통계를 보니 NGS 관련 내용에 대해서 검색하다가 들어오는 사람들이 많았습니다. 그래서 저에게는 쉬운 내용들이라 하더라도, 일반인들이 궁금해하는 내용에 대해서도 정리해두어야 겠다는 생각이 들어서 이번 포스팅은 NGS 장비를 통해서 생산된 데이터를 어떻게 분석하는지, 전반적인 파이프 라인에 대해서 개념을 소개하는 포스팅을 올려볼까 합니다.

우선, 차세대 염기 서열 분석법 Next-generation sequencing (이하 NGS)은 다양한 이름으로 불리는데, 이미 널리 사용하는 기술이기 때문에 현재는 차세대 기술이라고 보기 어렵습니다. 따라서, NGS라고 부르는 건 misnomer라고 할 수 있죠. 좀 더 정확한 명칭으로는 Massively parallel sequencing, High-throughput sequencing 등이 있는데, 동일 기술을 가르킨다고 생각하면 됩니다.

관련 포스팅 보기 >

휴먼 게놈 프로젝트, 그 이후.. 그리고 정밀 의료시대까지

NGS 검사: Whole Genome & Exome, Targeted Sequencing 비교

시퀀싱 기술의 발전으로 현재는 NGS를 널리 사용하게 되었는데, 다양한 방식이 있지만 지금은 Illumina 사의 Flow cell 기반의 short-read 시퀀싱 방식이 대부분의 시장을 독점하고 있는 상태입니다. 따라서, 아래의 NGS 분석 방법은 Illumina 시퀀싱 방식으로 생산되는 read를 기준으로 설명하도록 하겠습니다.

[Illumina sequencing 과정 소개 You-tube 영상]

 

시퀀싱 데이터 분석 과정은 위의 과정을 통해서 생산된 매우 많은 짧은 가닥의 read (50~150 bp 염기)들을 적절한 유전체의 위치에 퍼즐로 끼워 맞추고, 기존에 알려진 표준 유전체 (Reference sequence)와 대조하여, 바뀐 염기나 변이가 있는지를 검출하는 전체 과정을 말합니다. 따라서, 크게 아래와 같은 과정을 거쳐야, 생산된 read들로 부터 변이를 검출할 수가 있습니다.

GATK에서는 Germline 또는 Somatic variant 에 따라, 그리고 타겟 변이의 특성에 따라, 서로 다른 Best practice를 제공하고 있습니다. 이 중에서 아래는 가장 보편적인 Germline short variant 발굴 과정을 나타내고 있습니다.

[GATK Best Practice 보기]

Germline short variant discovery

Germline copy number variant discovery

Somatic short variant discovery

Somatic copy number variant discovery

 

gatk
[GATK best practice] GATK에서는 생산된 read로부터 변이를 검출하는 전체 과정에 대한 표준화 지침을 제공하고 있는데, 이를 GATK best practice라고 하며 자세한 과정은 GATK forum에서 step-by-step으로 제공해주고 있습니다.
 

I. 표준 유전체 서열에 read를 정렬하기 (FASTQ to SAM): 보통 NGS를 통해서 생산되는 개별 Read의 개수는 백만개 이상의 단위가 됩니다. 이때, 개별 read의 정보는 FASTQ 파일로 저장되고 그 크기는 수십~수백 Gb 단위가 됩니다. 각각의 생산된 read는 이미 알려진 인간 표준 유전체 서열에 가장 잘 맞는 위치에 정렬시키게 됩니다. 예로, 100 bp read를 기준으로 하여, 100개의 서열이 모두 일치하는 경우는 거의 유일하게 되므로, 해당 위치에 잘 찾아가게 됩니다. 다만, 반복 서열이나 특이적이지 않은 서열의 read는 제대로 mapping이 되지 않을 수가 있는데, 이는 Illumina 방식이 가진 한계점입니다. 보통 이 과정은 BWA (Burrow-Wheeler Aligner)라고 하는 프로그램으로 진행하게 됩니다.

fastq
개별 Read는 위의 그림과 같은 정보를 포함한 FASTQ 파일 형식으로 생산됩니다.

 

II. 정렬된 정보를 binary format으로 변경하기 (SAM to BAM): 위의 과정을 거친 SAM 파일은 여전히 용량이 매우 큽니다. 따라서, 용량을 절약하기 위해서 컴퓨터가 이해하는 2진법의 binary 형식으로 변경하면서 용량을 줄이고 연산 속도를 올립니다. 이 과정을 거친 파일이 흔히 말하는 1차적인 BAM 파일이 됩니다.

bam
인간 표준 유전체 서열에 개별 Read들이 정렬된 모습. BAM 파일

 

III. 개별 위치의 Base quality 보정하기 (Quality Control 과정): 1차적으로 read들이 표준 유전체에 정렬되면, 이것이 제대로 찾아 들어간 것인지를 평가하기 위해, 유전체 개별 위치에 대해 각각의 read 정보를 토대로 제대로 정렬된 것인지를 평가하고, 보정해주는 과정을 거칩니다. 특히, Indel이 발생한 read들의 경우, bias가 크기 때문에 따로 Indel realignment 라는 과정을 거치고, 개별 염기 위치에 대해서도 다시 한번 보정을 해주는 Base Recalibration 과정이 존재하게 됩니다.

IV. Variant Calling (BAM to VCF): 마지막 과정은 BAM 파일에서 실제로 변이를 검출하여, 변이들만 추출하는 과정입니다. Germline인지 Somatic mutation 인지에 따라서 다양한 알고리즘을 이용하게 되는데, Germline의 경우 가장 대표적으로 Haplotypecaller를 이용하게 됩니다.

V. Variant Annotation: 4번 단계까지 거치면, 무수히 많은 변이 정보를 포함하는 VCF 파일이 얻어지게 됩니다. 이렇게 call된 변이들 중 일부는 error를 일부 포함하고 있기 때문에, 보정 및 QC 과정을 한번더 거치게 됩니다. (Variant Recalibrator) 이후에 QC 과정을 거쳐서 Filtering된 변이들 중에서 관심 있는 변이만 얻기 위해서는, 기존 데이터 베이스의 자료를 토대로 각각의 검출 변이에 대해서 신원을 식별하고, ID를 발급하는 일종의 annotation 하는 과정이 필요합니다. 보통 이 과정에서 다양한 툴들이 이용되는데, 가장 대표적으로 Annovar 프로그램을 이용하여, gnomAD DB 등의 자료를 이용하게 됩니다. 최근에는 GATK의 Funcotator에서 기본적인 annotation을 지원하고 있습니다.

 

개별 과정의 코드까지 전부 올리기에는 너무 양이 많아질 것 같아서, 이번 포스팅에서는 전체 흐름에 대해서만 간략히 다루도록 하겠습니다. 다음 포스팅에서는 개별 변이를 해석하는 방법에 대해서 조금 더 자세히 다루도록 하고, 이번 포스팅은 여기서 마치도록 하겠습니다.

 

[Reference]

GATK Best Practice Forum https://software.broadinstitute.org/gatk/

Annovar http://annovar.openbioinformatics.org/en/latest/

암유전체 분석: Waterfall plot

최근에 종양 내과에 계신 선배와 함께 담관암 (Biliary tract cancer) 환자들의 암유전체 (Cancer Genomics) 관련 NGS 분석을 시작했습니다. 확실히 작년부터 다양한 질환과 환자들의 다양한 유전체 데이터를 접하다보니, 데이터셋의 특성에 따라서 분석 및 접근 방법이 많이 다른 것을 느낍니다. 사실 그동안 저는 주로 Germline variant 분석을 했었는데, Somatic variant 가 더 중요한 암 환자들을 분석하기 위해서는 추가로 더 공부하고 알아야 할 내용들이 많은 것 같습니다. 특히 암과 같은 경우는 선천적으로 가지고 있는 Germline variant와 살면서 축적된 Somatic mutation을 종합적으로 함께 고려해야하기 때문에, 더 복잡한 측면이 있는 것 같습니다.

관련 포스팅 보기 > [유전학 중요개념 정리] Germline vs. Somatic mutation

오늘은 암유전체 분석 관련 논문들의 Figure 1을 차지하는 Waterfall plot을 만드는 법을 잘 소개하고 있는 페이지가 있어 관련 내용을 스크랩 합니다.

다운로드

Waterfall plot: 환자군에서 나타나는 Mutation을 유전자별로 나타내어, 전체 암 유전체의 특성을 잘 나타내주는 plot으로 마치 폭포가 떨어지는 모양과 비슷한데서 그 이름의 유래가 있습니다.

관련 설명 링크 가기:

Waterfall plot: introduction

Introduction to waterfall plots (Griffith Lab)

 

이제 연구자들에게 Bioconductor와 R과 같은 프로그램은 필수죠. 다행히 저와 같은 코드를 잘 모르는 사람을 위해서 R package가 잘 만들어져 있습니다. 위 페이지에서 소개하는 필수 코드를 약간 정리하여 올립니다.


library(GenVisR)
setwd("c:/BTC_R/sample")

# Load data file
mutationData <- read.csv("BKM120_mutationdata.csv")
clinicalData <- read.csv("BKM120_clinical.csv")
mutationBurden <- read.csv("BKM120_mutationburden.csv")

# Reformat the mutation data for waterfall()
mutationData <- mutationData[,c("patient", "gene.name", "trv.type", "amino.acid.change")]
colnames(mutationData) <- c("sample", "gene", "variant_class", "amino.acid.change")

# Create a vector to save mutation priority order for plotting
mutation_priority <- as.character(unique(mutationData$variant_class))

# Create an initial plot
waterfall(mutationData, fileType = "Custom", variant_class_order=mutation_priority)

# Define a mutation hierarchy
mutationHierarchy <- c("nonsense", "frame_shift_del", "frame_shift_ins", "in_frame_del", "splice_site_del", "splice_site", "missense", "splice_region", "rna")

# define colours for all mutations
mutationColours <- c("nonsense"='#4f00A8', "frame_shift_del"='#A80100', "frame_shift_ins"='#CF5A59', "in_frame_del"='#ff9b34', "splice_site_del"='#750054', "splice_site"='#A80079', "missense"='#009933', "splice_region"='#ca66ae', "rna"='#888811')

# Find which samples are not in the mutationBurden data frame
# First, let's look at the sample names in the mutationData and mutationBurden
mutationData$sample
mutationBurden$sample

# Now, determine the non-overlap between these values
sampleVec <- unique(mutationData$sample)
sampleVec[!sampleVec %in% mutationBurden$sample]

# Fix mutationBurden to match mutationData
mutationBurden$sample <- gsub("^WU(0)+", "", mutationBurden$sample)

# Check for non-overlap again
sampleVec[!sampleVec %in% mutationBurden$sample]
# reformat clinical data to long format
library(reshape2)
clinicalData_2 <- clinicalData[,c(1,2,3,5)]
colnames(clinicalData_2) <- c("sample", "Months on Study", "Best Response", "Treatment Setting")
clinicalData_2 <- melt(data=clinicalData_2, id.vars=c("sample"))

# find which samples are not in the mutationBurden data frame
sampleVec <- unique(mutationData$sample)
sampleVec[!sampleVec %in% clinicalData$sample]

# fix mutationBurden to match mutationData
clinicalData_2$sample <- gsub("^WU(0)+", "", clinicalData_2$sample)

# create the waterfall plot
waterfall(mutationData, fileType = "Custom", variant_class_order=mutationHierarchy, mainPalette=mutationColours, mutBurden=mutationBurden, clinData=clinicalData_2, clinLegCol=3, clinVarCol=c('0-6'='#ccbadc', '6.1-12'='#9975b9', '12.1+'='#663096', 'Partial Response'='#c2ed67', 'Progressive Disease'='#E63A27', 'Stable Disease'='#e69127', '1'='#90ddee', '2'='#649aa6', '3+'='#486e77'), clinVarOrder=c('1', '2', '3+', 'Partial Response', 'Stable Disease', 'Progressive Disease', '0-6', '6.1-12', '12.1+'), section_heights=c(1, 5, 1), mainLabelCol="amino.acid.change", mainLabelSize = 3)
# Create a sample ordering
sample_ordering <- c("19", "5", "31", "22", "12", "2", "32", "8", "28", "18", "4", "24", "23", "17", "11", "14")

# Create a gene ordering
gene_ordering <- c("CDH1", "MALAT1", "RUNX1", "NCOR1", "GATA3", "FOXA1", "ESR1", "CBFB", "TBX3", "TAB1", "MED12", "XBP1", "TP53", "RB1CC1", "BRCA2", "ATM", "SMARCD1", "MLL3", "MLL2", "ARID1A", "FBXW7", "CAV1", "MAP3K1", "MAP2K4", "NOTCH4", "PDGFRA", "ERBB3", "ERBB2", "RELN", "MAGI3", "MTOR", "AKT2", "AKT1", "PTEN", "PIK3CA")

# Create a gene ordering
waterfall(mutationData, fileType = "Custom", variant_class_order=mutationHierarchy, mainPalette=mutationColours, mutBurden=mutationBurden, clinData=clinicalData_2, clinLegCol=3, clinVarCol=c('0-6'='#ccbadc', '6.1-12'='#9975b9', '12.1+'='#663096', 'Partial Response'='#c2ed67', 'Progressive Disease'='#E63A27', 'Stable Disease'='#e69127', '1'='#90ddee', '2'='#649aa6', '3+'='#486e77'), clinVarOrder=c('1', '2', '3+', 'Partial Response', 'Stable Disease', 'Progressive Disease', '0-6', '6.1-12', '12.1+'), section_heights=c(1, 5, 1), mainLabelCol="amino.acid.change", mainLabelSize=3, sampOrder=sample_ordering, geneOrder=gene_ordering)

 

GenVisR Bioconductor 페이지 바로가기

 

[Reference]

Skidmore, Zachary L., et al. “GenVisR: genomic visualizations in R.” Bioinformatics 32.19 (2016): 3012-3014.