From a40d583878f693114c4896b3013937e23670e0b7 Mon Sep 17 00:00:00 2001 From: HD Yi Date: Tue, 16 Jan 2024 13:11:52 -0500 Subject: [PATCH] Update 3.x into 4.1.2 version (#153) --- .gitattributes | 1 - docker/Dockerfile => Dockerfile | 0 conda-recipe/meta.yaml | 8 +- dbcan.yml | 3 +- dbcan/cli/run_dbcan.py | 340 +++++------ dbcan/utils/dbcan_build.py | 123 ++++ dbcan/utils/plots.py | 8 +- docker/cazyme_annotation/Dockerfile | 14 + docs/_static/img/Fig1.png | Bin 0 -> 177576 bytes docs/installation.rst | 24 +- docs/references.bib | 40 ++ docs/user_guide/database_preparation.rst | 10 +- docs/user_guide/index.rst | 2 + docs/user_guide/run_from_DNA_sequence.rst | 2 +- docs/user_guide/run_from_raw_reads.rst | 711 ++++++++++++++-------- docs/user_guide/run_from_raw_reads_ex.rst | 546 +++++++++++++++++ docs/user_guide/run_from_raw_reads_pr.rst | 369 +++++++++++ pyproject.toml | 9 +- 18 files changed, 1730 insertions(+), 480 deletions(-) delete mode 100644 .gitattributes rename docker/Dockerfile => Dockerfile (100%) create mode 100644 dbcan/utils/dbcan_build.py create mode 100644 docker/cazyme_annotation/Dockerfile create mode 100644 docs/_static/img/Fig1.png create mode 100644 docs/user_guide/run_from_raw_reads_ex.rst create mode 100644 docs/user_guide/run_from_raw_reads_pr.rst diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index 3670473cf..000000000 --- a/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -db/** filter=lfs diff=lfs merge=lfs -text diff --git a/docker/Dockerfile b/Dockerfile similarity index 100% rename from docker/Dockerfile rename to Dockerfile diff --git a/conda-recipe/meta.yaml b/conda-recipe/meta.yaml index 48ce2a3bd..7be1bbfbd 100644 --- a/conda-recipe/meta.yaml +++ b/conda-recipe/meta.yaml @@ -1,5 +1,5 @@ {% set name = "dbcan" %} -{% set version = "4.1.0" %} +{% set version = "4.1.2" %} package: name: "{{ name|lower }}" @@ -9,7 +9,7 @@ source: # the sha256 sum is generated by doing # wget -0- [URL] | shasum -a 256 url: https://github.com/linnabrown/run_dbcan/releases/download/{{ version }}/dbcan-{{ version }}.tar.gz - sha256: cb0907eb10eb916bcf676c58f54e67a67dd4ed559152e5547bb44d071f063b8f + sha256: 3a675683379d1afc9f3444fc9894272f1485956df266a6ee4fc11a8f628e6d51 build: number: 0 @@ -22,6 +22,7 @@ build: - dbcan_utils = dbcan.utils.utils:main - dbcan_plot = dbcan.utils.plots:main - dbcan_asmfree = dbcan.utils.diamond_unassembly:main + - dbcan_build = dbcan.utils.dbcan_build:main run_exports: - {{ pin_subpackage(name, max_pin="x") }} @@ -41,6 +42,9 @@ requirements: - numpy >1.19 - biopython - pandas + - tqdm + - openpyxl + - matplotlib-base - session-info test: diff --git a/dbcan.yml b/dbcan.yml index 863d385bd..18264048f 100644 --- a/dbcan.yml +++ b/dbcan.yml @@ -28,4 +28,5 @@ dependencies: - matplotlib - openpyxl - biopython - - bbtools \ No newline at end of file + - bbtools + - seaborn \ No newline at end of file diff --git a/dbcan/cli/run_dbcan.py b/dbcan/cli/run_dbcan.py index 9e1ea3075..e45ca9e15 100755 --- a/dbcan/cli/run_dbcan.py +++ b/dbcan/cli/run_dbcan.py @@ -13,7 +13,7 @@ import time # Recent updated information: -# Jan/01/23: Add doc code +# Jan/01/23: Add doc code [Haidong Yi, Le Huang] # Oct/10/23: Recontructed the run_dbcan [Haidong Yi] # Sep/07/23: Replace hmmscan with hmmsearch. Update perl code [Le Huang, Yanbin Yin] # Dec/15/22: 1.adding function to convert cgc_standard.out to json format. 2. adding function cgc_[Jinfang Zheng] @@ -60,8 +60,21 @@ def runHmmer(outPath, hmm_cpu, dbDir, hmm_eval, hmm_cov, db_name): hmm_file = f"{dbDir}{db_name}.hmm" uniInput_file = f"{outPath}uniInput" - hmmer = Popen( - [ + # hmmer = Popen( + # [ + # "hmmsearch", + # "--domtblout", + # domtblout_file, + # "--cpu", + # str(hmm_cpu), + # "-o", + # "/dev/null", + # hmm_file, + # uniInput_file, + # ] + # ) + # hmmer.wait() + hmmer_list = [ "hmmsearch", "--domtblout", domtblout_file, @@ -72,8 +85,9 @@ def runHmmer(outPath, hmm_cpu, dbDir, hmm_eval, hmm_cov, db_name): hmm_file, uniInput_file, ] - ) - hmmer.wait() + cmd_str = " ".join(hmmer_list) + os.system(cmd_str) + parsed_hmm_output = hmmer_parser.run(input_file=f"{outPath}h{db_name}.out", eval_num=hmm_eval, coverage=hmm_cov) with open(f"{outPath}{db_name}.out", "w") as f: f.write(parsed_hmm_output) @@ -108,85 +122,40 @@ def split_uniInput(uniInput, dbcan_thread, outPath, dbDir, hmm_eval, hmm_cov, hm - Time taken for execution is printed at the end of the function's run. """ ticks = time.time() - file = open(uniInput) - uniInput_file = file.readlines() - file.close() - signal_count = 0 - min_files = dbcan_thread - file_number = None - split_files = [] - fsize = int(os.path.getsize(uniInput) / float(1024 * 1024) * dbcan_offset) - - if fsize < 1: - fsize = 1 - - for line in uniInput_file: - if ">" in line: - signal_count += 1 - print(f"Count of proteins: {signal_count}") - - if signal_count >= min_files: - for i in range(fsize): - with open(f"{outPath}{i}.txt", "w") as f: - pass - split_files.append(f"{i}.txt") - for i in range(len(uniInput_file)): - if ">" in uniInput_file[i]: - file_number = i % fsize - with open(f"{outPath}{file_number}.txt", "a") as f: - f.write(uniInput_file[i]) - - ths = [] - for j in split_files: - ths.append( - Popen( - [ - "hmmsearch", - "--domtblout", - f"{outPath}d{j}", - "--cpu", - str(hmm_cpu), - "-o", - "/dev/null", - f"{dbDir}dbCAN_sub.hmm", - f"{outPath}{j}", - ] - ) - ) - for th in ths: - th.wait() - for m in split_files: - hmm_parser_output = hmmer_parser.run(f"{outPath}d{m}", eval_num=hmm_eval, coverage=hmm_cov) - with open(f"{outPath}temp_{m}", "w") as temp_hmmer_file: - temp_hmmer_file.write(hmm_parser_output) - os.remove(f"{outPath}d{m}") - os.remove(f"{outPath}{m}") - with open(f"{outPath}dtemp.out", "w"): pass - for n in split_files: - with open(f"{outPath}temp_{n}") as file_read: - files_lines = file_read.readlines() - os.remove(f"{outPath}temp_{n}") - with open(f"{outPath}dtemp.out", "a") as f: - f.writelines(files_lines) - else: - dbsub = Popen( - [ - "hmmsearch", - "--domtblout", - f"{outPath}d.txt", - "--cpu", - str(hmm_cpu), - "-o", - "/dev/null", - f"{dbDir}dbCAN_sub.hmm", - f"{outPath}uniInput", - ] - ) - dbsub.wait() + + # dbsub = Popen( + # [ + # "hmmsearch", + # "--domtblout", + # f"{outPath}d.txt", + # "--cpu", + # str(hmm_cpu), + # "-o", + # "/dev/null", + # f"{dbDir}dbCAN_sub.hmm", + # f"{outPath}uniInput", + # ] + # ) + # dbsub.wait() + + dbsub_list = [ + "hmmsearch", + "--domtblout", + f"{outPath}d.txt", + "--cpu", + str(hmm_cpu), + "-o", + "/dev/null", + f"{dbDir}dbCAN_sub.hmm", + f"{outPath}uniInput", + ] + + dbsub_str = " ".join(dbsub_list) + os.system(dbsub_str) - hmm_parser_output = hmmer_parser.run(f"{outPath}d.txt", eval_num=hmm_eval, coverage=hmm_cov) - with open(f"{outPath}dtemp.out", "w") as temp_hmmer_file: - temp_hmmer_file.write(hmm_parser_output) + hmm_parser_output = hmmer_parser.run(f"{outPath}d.txt", eval_num=hmm_eval, coverage=hmm_cov) + with open(f"{outPath}dtemp.out", "w") as temp_hmmer_file: + temp_hmmer_file.write(hmm_parser_output) print("total time:", time.time() - ticks) @@ -197,10 +166,10 @@ def run_dbCAN( cluster=None, dbCANFile="dbCAN.txt", dia_eval=1e-102, - dia_cpu=4, + dia_cpu=8, hmm_eval=1e-15, hmm_cov=0.35, - hmm_cpu=4, + hmm_cpu=8, dbcan_thread=5, dbcan_offset=2, tf_eval=1e-4, @@ -418,10 +387,10 @@ def run_dbCAN( processed_lines = [] for line in f: row = line.rstrip().split("\t") - row.append(float(int(row[6]) - int(row[5])) / int(row[1])) + row.append(str(float(int(row[6]) - int(row[5])) / int(row[1]))) if float(row[4]) <= 1e-15 and float(row[-1]) >= 0.35: - # out.write("\t".join([str(x) for x in row]) + "\n") - processed_lines.append("\t".join([str(x) for x in row])) + processed_lines.append("\t".join(row)) + # Process dbcan-sub.hmm.out content updated_lines = [line for line in processed_lines if line.strip()] @@ -713,8 +682,8 @@ def run_dbCAN( with open(auxFile) as f: with open(outDir + prefix + "cgc.gff", "w") as out: for line in f: - if not line.startswith("#"): - row = line.rstrip().split("\t") + row = line.rstrip().split("\t") + if (not line.startswith("#")) and len(row) >= 9: if row[2] == "CDS": note = row[8].strip().rstrip(";").split(";") gene = "" @@ -825,135 +794,98 @@ def run_dbCAN( # End SignalP combination ####################### ####################### - # start Overview + # start overview Generation + def unique(sequence): + """ Remove duplicates from a list while keeping the original order. """ + seen = set() + return [x for x in sequence if not (x in seen or seen.add(x))] + + def read_lines_if_file_exists(filepath): + """ Read non-empty lines from a file if it exists, return an empty list otherwise. """ + if os.path.exists(filepath): + with open(filepath, 'r') as file: + return [line.strip() for line in file if line.strip()] + return [] + print("Preparing overview table from hmmer, dbCAN_sub and diamond output...") - workdir = outDir + prefix - - # a function to remove duplicates from lists while keeping original order - def unique(seq): - exists = set() - return [x for x in seq if not (x in exists or exists.add(x))] - - arr_dbsub = None - arr_hmmer = None - - # check if files exist. if so, read files and get the gene numbers - if tools[0]: - arr_diamond = open(workdir + "diamond.out").readlines() - diamond_genes = [arr_diamond[i].split()[0] for i in range(1, len(arr_diamond))] # or diamond_genes = [] - - if tools[1]: - arr_hmmer = open(workdir + "hmmer.out").readlines() - hmmer_genes = [arr_hmmer[i].split()[2] for i in range(1, len(arr_hmmer))] # or hmmer_genes = [] - - if tools[2]: - arr_dbsub = open(workdir + "dbcan-sub.hmm.out").readlines() - dbsub_genes = [arr_dbsub[i].split("\t")[5] for i in range(1, len(arr_dbsub))] # or dbsub_genes = [] - - if use_signalP and (os.path.exists(workdir + "signalp.out")): - arr_sigp = open(workdir + "signalp.out").readlines() - sigp_genes = {} - for i in range(0, len(arr_sigp)): - row = arr_sigp[i].split() - sigp_genes[row[0]] = row[4] # previous one is row[2], use Y-score instead from suggestion of Dongyao Li - - # remove duplicates from input lists - if not tools[0]: - diamond_genes = [] - if not tools[1]: - hmmer_genes = [] - if not tools[2]: - dbsub_genes = [] - - if len(dbsub_genes) > 0: - if dbsub_genes[-1] is None: - dbsub_genes.pop() - dbsub_genes = unique(dbsub_genes) - if "hmmer_genes" in locals(): - hmmer_genes.pop() - hmmer_genes = unique(hmmer_genes) - if "diamond_genes" in locals(): - diamond_genes.pop() - diamond_genes = unique(diamond_genes) - - # parse input, stroe needed variables - if tools[0] and (len(arr_diamond) > 1): - diamond_fams = {} - for i in range(1, len(arr_diamond)): - row = arr_diamond[i].split("\t") - fam = row[1].strip("|").split("|") - diamond_fams[row[0]] = fam[1:] - - if tools[1] and (len(arr_hmmer) > 1): - hmmer_fams = {} - for i in range(1, len(arr_hmmer)): - row = arr_hmmer[i].split("\t") - fam = row[0].split(".") - fam = fam[0] + "(" + row[7] + "-" + row[8] + ")" - if row[2] not in hmmer_fams: - hmmer_fams[row[2]] = [] - hmmer_fams[row[2]].append(fam) - - if tools[2] and (len(arr_dbsub) > 1): - dbsub_fams = {} - for i in range(1, len(arr_dbsub)): - row_ori = arr_dbsub[i].split("\t") - fams_ID = row_ori[5] - if fams_ID not in dbsub_fams: - dbsub_fams[fams_ID] = {} - dbsub_fams[fams_ID]["fam_name"] = [] - dbsub_fams[fams_ID]["ec_num"] = [] - - dbsub_fams[fams_ID]["fam_name"].append(row_ori[0]) - dbsub_fams[fams_ID]["ec_num"].append(row_ori[2]) - - # overall table + arr_diamond = read_lines_if_file_exists(outPath + "diamond.out") + arr_hmmer = read_lines_if_file_exists(outPath + "hmmer.out") + arr_dbsub = read_lines_if_file_exists(outPath + "dbcan-sub.hmm.out") + + diamond_genes = unique([line.split()[0] for line in arr_diamond[1:]]) + hmmer_genes = unique([line.split()[2] for line in arr_hmmer[1:]]) + dbsub_genes = unique([line.split("\t")[5] for line in arr_dbsub[1:]]) + + sigp_genes = {} + if use_signalP and os.path.exists(outPath + "signalp.out"): + arr_sigp = read_lines_if_file_exists(outPath + "signalp.out") + for line in arr_sigp: + parts = line.split() + sigp_genes[parts[0]] = parts[4] + + diamond_fams, hmmer_fams, dbsub_fams = {}, {}, {} + + if tools[0]: # Diamond + diamond_fams = {row.split("\t")[0]: row.split("\t")[1].strip("|").split("|")[1:] for row in arr_diamond[1:]} + + if tools[1]: # Hmmer + for row in arr_hmmer[1:]: + parts = row.split("\t") + fam = parts[0].split(".")[0] + "(" + parts[7] + "-" + parts[8] + ")" + hmmer_fams.setdefault(parts[2], []).append(fam) + + if tools[2]: # dbCAN_sub + for row in arr_dbsub[1:]: + parts = row.split("\t") + gene_id = parts[5] + dbsub_fams.setdefault(gene_id, {"fam_name": [], "ec_num": []}) + dbsub_fams[gene_id]["fam_name"].append(parts[0]) + dbsub_fams[gene_id]["ec_num"].append(parts[2]) + # Create the overview table all_genes = unique(hmmer_genes + dbsub_genes + diamond_genes) - with open(workdir + "overview.txt", "w+") as fp: + with open(outPath + "overview.txt", "w+") as fp: + headers = ["Gene ID", "EC#", "HMMER", "dbCAN_sub", "DIAMOND", "#ofTools"] if use_signalP: - fp.write("Gene ID\tEC#\tHMMER\tdbCAN_sub\tDIAMOND\tSignalp\t#ofTools\n") - else: - fp.write("Gene ID\tEC#\tHMMER\tdbCAN_sub\tDIAMOND\t#ofTools\n") + headers.insert(5, "Signalp") + fp.write("\t".join(headers) + "\n") + for gene in all_genes: - csv = [gene] + row = [gene] num_tools = 0 - if tools[2] and arr_dbsub is not None and (gene in dbsub_genes): - if dbsub_fams[gene]["ec_num"] == []: - csv.append("-") - else: - csv.append("|".join(dbsub_fams[gene]["ec_num"])) - else: - csv.append("-") + # dbCAN_sub + row.append("|".join(dbsub_fams[gene]["ec_num"]) if gene in dbsub_fams else "-") - if tools[1] and arr_hmmer is not None and (gene in hmmer_genes): + # HMMER + if gene in hmmer_fams: num_tools += 1 - csv.append("+".join(hmmer_fams[gene])) + row.append("+".join(hmmer_fams[gene])) else: - csv.append("-") - - if tools[2] and arr_dbsub is not None and (gene in dbsub_genes): + row.append("-") + + # dbCAN_sub (fam_name) + if tools[2] and gene in dbsub_fams: + row.append("+".join(dbsub_fams[gene]["fam_name"])) num_tools += 1 - csv.append("+".join(dbsub_fams[gene]["fam_name"])) else: - csv.append("-") + row.append("-") - if tools[0] and arr_diamond is not None and (gene in diamond_genes): + # DIAMOND + if gene in diamond_fams: num_tools += 1 - csv.append("+".join(diamond_fams[gene])) + row.append("+".join(diamond_fams[gene])) else: - csv.append("-") + row.append("-") + + # SignalP if use_signalP: - if gene in sigp_genes: - csv.append("Y(1-" + sigp_genes[gene] + ")") - else: - csv.append("N") - csv.append(str(num_tools)) - temp = "\t".join(csv) + "\n" - fp.write(temp) - print("overview table complete. Saved as " + workdir + "overview.txt") + row.append("Y(1-" + sigp_genes[gene] + ")" if gene in sigp_genes else "N") + + row.append(str(num_tools)) + fp.write("\t".join(row) + "\n") + print(f"Overview table complete. Saved as {outPath}overview.txt") # End overview @@ -1052,7 +984,7 @@ def rundbCAN_parser(): default="all", help="Choose gram+(p) or gram-(n) for proteome/prokaryote nucleotide, which are params of SingalP, only if user use singalP", ) - parser.add_argument("-v", "--version", default="4.1.0", type=str) + parser.add_argument("-v", "--version", default="4.1.1", type=str) # dbCAN-sub dbCAN_sub_group = parser.add_argument_group("dbCAN-sub parameters") dbCAN_sub_group.add_argument("--dbcan_thread", "-dt", default=12, type=int) @@ -1087,7 +1019,7 @@ def rundbCAN_parser(): cgcsubstrate_group.add_argument('--only_sub',action='store_false',help="Only run substrate prediction for PUL. If this parameter is presented, dbcan will skip the CAZyme annotation and CGC prediction.") cgcsubstrate_group.add_argument("--cgc_substrate", action="store_true", help="run cgc substrate prediction?") cgcsubstrate_group.add_argument("--pul", help="dbCAN-PUL PUL.faa") - cgcsubstrate_group.add_argument("-o", "--out", default="sub.prediction.out") + cgcsubstrate_group.add_argument("-o", "--out", default="substrate.out") cgcsubstrate_group.add_argument("-w", "--workdir", type=str, default=".") cgcsubstrate_group.add_argument("-env", "--env", type=str, default="local") cgcsubstrate_group.add_argument( diff --git a/dbcan/utils/dbcan_build.py b/dbcan/utils/dbcan_build.py new file mode 100644 index 000000000..ef09f442c --- /dev/null +++ b/dbcan/utils/dbcan_build.py @@ -0,0 +1,123 @@ +import os +import argparse +import requests +from tqdm import tqdm +import shutil +from concurrent.futures import ThreadPoolExecutor +import subprocess + + +def download_file(url, filename, position): + """使用requests下载文件并用tqdm显示进度条""" + response = requests.get(url, stream=True) + total_size = int(response.headers.get('content-length', 0)) + chunk_size = 1024 + with open(filename, 'wb') as f, tqdm( + desc=filename, + total=total_size, + unit='iB', + unit_scale=True, + position=position, + leave=False # 设置为False,下载完成后隐藏进度条 + ) as bar: + for chunk in response.iter_content(chunk_size=chunk_size): + size = f.write(chunk) + if size is not None: + bar.update(int(size)) + +def parse_args(): + """解析命令行参数""" + parser = argparse.ArgumentParser(description='dbCAN Database Downloader') + parser.add_argument('--cpus', type=int, default=8, help='Number of CPUs for parallel downloads') + parser.add_argument('--db-dir', type=str, default='db', help='Database directory name') + parser.add_argument('--clean', action='store_true', help='Clean up temporary files after processing') + return parser.parse_args() +def clean_up(db_dir): + try: + shutil.rmtree(db_dir) + print(f"Folder '{db_dir}' and all its contents have been deleted.") + except OSError as error: + print(f"Error: {error}") + print(f"Failed to delete the folder '{db_dir}'.") +def get_remote_file_size(url): + """获取远程文件的大小""" + response = requests.head(url, allow_redirects=True) + if 'content-length' in response.headers: + return int(response.headers['content-length']) + else: + return 0 +def run_command(cmd): + """运行单个shell命令""" + subprocess.run(cmd, shell=True, check=True) + +def main(): + args = parse_args() + + if args.clean and os.path.exists(args.db_dir): + clean_up(args.db_dir) + + if not os.path.exists(args.db_dir): + os.makedirs(args.db_dir) + os.chdir(args.db_dir) + + download_urls = [ + "https://bcb.unl.edu/dbCAN2/download/Databases/fam-substrate-mapping-08012023.tsv", + "https://bcb.unl.edu/dbCAN2/download/Databases/PUL.faa", + "https://bcb.unl.edu/dbCAN2/download/Databases/dbCAN-PUL_12-12-2023.xlsx", + "https://bcb.unl.edu/dbCAN2/download/Databases/dbCAN-PUL.tar.gz", + "https://bcb.unl.edu/dbCAN2/download/Databases/dbCAN_sub.hmm", + "https://bcb.unl.edu/dbCAN2/download/Databases/V12/CAZyDB.07262023.fa", + "https://bcb.unl.edu/dbCAN2/download/Databases/V12/dbCAN-HMMdb-V12.txt", + "https://bcb.unl.edu/dbCAN2/download/Databases/V12/tcdb.fa", + "https://bcb.unl.edu/dbCAN2/download/Databases/V12/tf-1.hmm", + "https://bcb.unl.edu/dbCAN2/download/Databases/V12/tf-2.hmm", + "https://bcb.unl.edu/dbCAN2/download/Databases/V12/stp.hmm" + ] + + total_size = sum(get_remote_file_size(url) for url in download_urls) + + with ThreadPoolExecutor(max_workers=args.cpus) as executor: + futures = [] + for i, url in enumerate(download_urls): + filename = os.path.basename(url) + futures.append(executor.submit(download_file, url, filename, i)) + + # 显示总的进度条 + with tqdm(total=total_size, unit='iB', unit_scale=True, position=len(download_urls), leave=False) as bar: + for future in futures: + result = future.result() + if result is not None: + bar.update(int(result)) + + # 执行其他命令 + other_commands = [ + "mv fam-substrate-mapping-08012023.tsv fam-substrate-mapping.tsv", + "makeblastdb -in PUL.faa -dbtype prot", + "mv dbCAN-PUL_12-12-2023.xlsx dbCAN-PUL.xlsx", + "tar xzvf dbCAN-PUL.tar.gz", + "hmmpress -f dbCAN_sub.hmm", + "mv CAZyDB.07262023.fa CAZyDB.fa", + "diamond makedb --in CAZyDB.fa -d CAZy", + "mv dbCAN-HMMdb-V12.txt dbCAN.txt", + "hmmpress dbCAN.txt" + "diamond makedb --in tcdb.fa -d tcdb", + "hmmpress -f tf-1.hmm", + "hmmpress -f tf-2.hmm", + "hmmpress -f stp.hmm" + ] + for cmd in other_commands: + subprocess.run(cmd, shell=True) + + os.chdir('..') + # 下载样本文件 + sample_commands = [ + "wget http://bcb.unl.edu/dbCAN2/download/Samples/EscheriaColiK12MG1655.fna", + "wget http://bcb.unl.edu/dbCAN2/download/Samples/EscheriaColiK12MG1655.faa", + "wget http://bcb.unl.edu/dbCAN2/download/Samples/EscheriaColiK12MG1655.gff" + ] + + with ThreadPoolExecutor() as executor: + executor.map(run_command, sample_commands) + +if __name__ == "__main__": + main() diff --git a/dbcan/utils/plots.py b/dbcan/utils/plots.py index 422a512cf..11d52e9e0 100644 --- a/dbcan/utils/plots.py +++ b/dbcan/utils/plots.py @@ -15,10 +15,10 @@ from matplotlib.patches import Patch #plt.style.use('seaborn') from dbcan.utils.utils import cgc_standard_line -from dbcan_cli.syntenic_plot import syntenic_plot,read_blast_result_cgc,read_UHGG_CGC_stanrdard_out,read_PUL_cgcgff -from dbcan_cli.syntenic_plot import Get_parameters_for_plot,plot_Polygon_homologous,plot_syntenic_block -from dbcan_cli.syntenic_plot import Get_Position as synGet_Position -from dbcan_cli.syntenic_plot import plot_genome_line as synplot_genome_line +from dbcan.cli.syntenic_plot import syntenic_plot,read_blast_result_cgc,read_UHGG_CGC_stanrdard_out,read_PUL_cgcgff +from dbcan.cli.syntenic_plot import Get_parameters_for_plot,plot_Polygon_homologous,plot_syntenic_block +from dbcan.cli.syntenic_plot import Get_Position as synGet_Position +from dbcan.cli.syntenic_plot import plot_genome_line as synplot_genome_line import matplotlib as mpl mpl.rcParams['pdf.fonttype'] = 42 mpl.rcParams['ps.fonttype'] = 42 diff --git a/docker/cazyme_annotation/Dockerfile b/docker/cazyme_annotation/Dockerfile new file mode 100644 index 000000000..21510d658 --- /dev/null +++ b/docker/cazyme_annotation/Dockerfile @@ -0,0 +1,14 @@ +FROM continuumio/miniconda3 + +# set work dir +WORKDIR /app +COPY dbcan.yml . + +# install conda packages +RUN conda env create -f dbcan.yml && conda clean -ya + +# add run_dbcan environment to path +RUN echo "source activate CAZyme_annotation" > ~/.bashrc +ENV PATH /opt/conda/envs/CAZyme_annotation/bin:$PATH + +CMD [ "run_dbcan -h" ] diff --git a/docs/_static/img/Fig1.png b/docs/_static/img/Fig1.png new file mode 100644 index 0000000000000000000000000000000000000000..49196ab2443c825f24df3760b234dc4e3e65bcf0 GIT binary patch literal 177576 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�pSJPZ#zzRX@tldk3pZ!5 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 Ls;h!jvX1;eK-DjW literal 0 HcmV?d00001 diff --git a/docs/installation.rst b/docs/installation.rst index c0b0470d1..4fba40dd2 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -27,7 +27,7 @@ or `Miniconda `_. Then, you .. code-block:: shell - conda create --dbcan python=3.8 + conda create --name dbcan python=3.8 If you already have a ``conda`` environment, you can skip the step above. @@ -37,6 +37,26 @@ To install the `dbcan`_ package, use the ``conda install`` command: conda install dbcan -c conda-forge -c bioconda + +Build database +-------------- + +You can build database via this command: + +.. code-block:: shell + + dbcan_build --cpus 8 --db-dir db --clean + + +1. `--cpu` indicates count of cpu you can use. Try as many as possible for fast building. + +2. `--db-dir` indicates database folder path. Default is `db` on your current database + +3. `--clean` indicates clean the folder indicated by `--db-dir`. +You can remove this parameter if you don't want to clean, but we recommend you add this to keep +away from index contamination. + + Installing with PyPI -------------------- @@ -55,10 +75,12 @@ dependencies: Due to the specific licensing terms of `SignalP`, it is not included directly as a dependency in our package. This requires users to undertake a separate installation process. **Installing SignalP (Optional)**: + - `SignalP` is optional and not essential for the core functionality of our software. Users requiring its specific features can integrate it as follows: 1. Visit the `SignalP website `_. 2. Submit a download `request `_. 3. Post-download, add `SignalP` to your system's environmental variables to make it executable. + - For installation assistance, refer to the :doc:`faq/signalp_installation`. This approach ensures compliance with `SignalP`'s licensing while offering the tool's functionality to those who need it. diff --git a/docs/references.bib b/docs/references.bib index 8a8936742..b76464443 100644 --- a/docs/references.bib +++ b/docs/references.bib @@ -28,3 +28,43 @@ @article{2017:nielsen year={2017}, publisher={Springer} } + +@article{2021:Wastyk, + title={Gut-microbiota-targeted diets modulate human immune status}, + author={Wastyk, Hannah C and Fragiadakis, Gabriela K and Perelman, Dalia and Dahan, Dylan and Merrill, Bryan D and Feiqiao, B Yu and Topf, Madeline and Gonzalez, Carlos G and Van Treuren, William and Han, Shuo and others}, + journal={Cell}, + volume={184}, + number={16}, + pages={4137--4153}, + year={2021}, + publisher={Elsevier} +} + +@article{2023:Priest, + title={Carbohydrates and carbohydrate degradation gene abundance and transcription in Atlantic waters of the Arctic}, + author={Priest, Taylor and Vidal-Melgosa, Silvia and Hehemann, Jan-Hendrik and Amann, Rudolf and Fuchs, Bernhard M}, + journal={ISME communications}, + volume={3}, + number={1}, + pages={130}, + year={2023}, + publisher={Nature Publishing Group UK London} +} + +@article{2023:carter, + title={Ultra-deep sequencing of Hadza hunter-gatherers recovers vanishing gut microbes}, + author={Carter, Matthew M and Olm, Matthew R and Merrill, Bryan D and Dahan, Dylan and Tripathi, Surya and Spencer, Sean P and Feiqiao, B Yu and Jain, Sunit and Neff, Norma and Jha, Aashish R and others}, + journal={Cell}, + year={2023}, + publisher={Elsevier} +} + + +@article{2023:dbCAN3, + title={dbCAN3: automated carbohydrate-active enzyme and substrate annotation}, + author={Zheng, Jinfang and Ge, Qiwei and Yan, Yuchen and Zhang, Xinpeng and Huang, Le and Yin, Yanbin}, + journal={Nucleic Acids Research}, + pages={gkad328}, + year={2023}, + publisher={Oxford University Press} +} diff --git a/docs/user_guide/database_preparation.rst b/docs/user_guide/database_preparation.rst index 35775e4ed..368f123ac 100644 --- a/docs/user_guide/database_preparation.rst +++ b/docs/user_guide/database_preparation.rst @@ -1,16 +1,14 @@ -Database preparation -==================== - -Install different databases and make index for them. +Database Installation Command +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. code-block:: shell + :name: include-this-part test -d db || mkdir db cd db \ && wget http://bcb.unl.edu/dbCAN2/download/Databases/fam-substrate-mapping-08012023.tsv && mv fam-substrate-mapping-08012023.tsv fam-substrate-mapping.tsv \ - && wget http://bcb.unl.edu/dbCAN2/download/Databases/PUL_12112023.faa && mv PUL_12112023.faa PUL.faa && makeblastdb -in PUL.faa -dbtype prot \ + && wget http://bcb.unl.edu/dbCAN2/download/Databases/PUL.faa && makeblastdb -in PUL.faa -dbtype prot \ && wget http://bcb.unl.edu/dbCAN2/download/Databases/dbCAN-PUL_12-12-2023.xlsx && mv dbCAN-PUL_12-12-2023.xlsx dbCAN-PUL.xlsx \ - && wget http://bcb.unl.edu/dbCAN2/download/Databases/dbCAN-PUL_12-12-2023.txt && mv dbCAN-PUL_12-12-2023.txt dbCAN-PUL.txt \ && wget http://bcb.unl.edu/dbCAN2/download/Databases/dbCAN-PUL.tar.gz && tar xvf dbCAN-PUL.tar.gz && rm dbCAN-PUL.tar.gz \ && wget https://bcb.unl.edu/dbCAN2/download/Databases/dbCAN_sub.hmm && hmmpress dbCAN_sub.hmm \ && wget https://bcb.unl.edu/dbCAN2/download/Databases/V12/CAZyDB.07262023.fa && mv CAZyDB.07262023.fa CAZyDB.fa && diamond makedb --in CAZyDB.fa -d CAZy \ diff --git a/docs/user_guide/index.rst b/docs/user_guide/index.rst index d3e45c2ec..a7c5979e5 100644 --- a/docs/user_guide/index.rst +++ b/docs/user_guide/index.rst @@ -10,3 +10,5 @@ User Guide run_with_CGCFinder run_from_raw_reads run_from_DNA_sequence + run_from_raw_reads_ex + run_from_raw_reads_pr diff --git a/docs/user_guide/run_from_DNA_sequence.rst b/docs/user_guide/run_from_DNA_sequence.rst index 31438d08b..20ea72505 100644 --- a/docs/user_guide/run_from_DNA_sequence.rst +++ b/docs/user_guide/run_from_DNA_sequence.rst @@ -1,4 +1,4 @@ -Run from Protein Sequence +Run from DNA Sequence ========================= This section provides a quick guide to running the run_dbcan tool suite with example data and explains the output files generated. diff --git a/docs/user_guide/run_from_raw_reads.rst b/docs/user_guide/run_from_raw_reads.rst index 95d02f8a7..0d7d2ea66 100644 --- a/docs/user_guide/run_from_raw_reads.rst +++ b/docs/user_guide/run_from_raw_reads.rst @@ -1,64 +1,174 @@ -Run from Raw Reads -================== +Run from Raw Reads: Automated CAZyme and Glycan Substrate Annotation in Microbiomes: A Step-by-Step Protocol +============================================================================================================ Introduction ------------ -dbCAN and run_dbcan require assembled contigs for CAZyme annotation. -Typically, microbiome researchers begin with raw sequencing reads (metagenomic or metatranscriptomic) from various samples. -These reads must be pre-processed and assembled prior to annotation. -Additionally, there's often a need for CAZyme abundance comparison -and visualization across multiple samples. To address these requirements, -this protocol paper provides a comprehensive guide on CAZyme annotation. -It includes steps from initial sequencing reads to the visualization of CAZyme occurrence and abundance across samples. -Key topics covered are software setup, read pre-processing, metagenome assembly, gene prediction, -CAZyme and CGC prediction, glycan substrate prediction, and data visualization. +Overview +```````` -.. image:: ../_static/img/Picture1.png +In this tutorial, we present a comprehensive protocol to annotate CAZymes and glycan substrates in microbiome datasets. Using three real-world microbiome example datasets: + +1. :ref:`Carter2023 ` :cite:`2023:carter`, +2. :ref:`Wastyk2021 ` :cite:`2021:Wastyk` (See :doc:`run_from_raw_reads_ex`), and, +3. :ref:`Priest2023 ` :cite:`2023:Priest` (See :doc:`run_from_raw_reads_pr.rst`), + +this guide will walk you through each step of the computational workflow for analyzing occurrence and abundance. The workflow, depicted in Fig. 1, is designed to be user-friendly and does not require extensive programming knowledge. + +.. image:: ../_static/img/Fig1.png :alt: workflow figure - :width: 800px + :width: 700px :align: center +.. |centered-text| raw:: html -For this tutorial, we provide a comprehensive pipeline to teach users how to run CAZyme annotations from raw reads to generate abundance information. -We use Carter2023 and the individual sample assembly route of the figure above. The procedure has 4 modules and 16 steps (P1-P16). -First, we need to create the environment. +
Fig.1 Overview of the protocol
-Installation and Data Preparation ---------------------------------- +|centered-text| +Workflow Steps +`````````````` -1. Downloading Carter2023 (Table 2) Raw Reads +1. **Pre-Processing of Raw Sequencing Reads:** + Begin with the preprocessing of raw sequencing reads. This includes the removal of contaminants, adapter sequences, and trimming of low-quality reads. We'll use `trim_galore` and `Kraken2` for this purpose (Steps 1-2). +2. **Contig Assembly:** + The clean reads from each sample are then assembled into contigs using `MEGAHIT` (Step 3). -To download the required raw reads, use the following wget commands: +3. **Gene Model Annotation:** + These contigs are subsequently passed to `Prokka` for gene model annotation (Step 4). -.. code-block:: shell +4. **CAZyme and CGC Annotation:** + The next phase involves annotating the contigs for CAZymes and CGCs. This is achieved by `run_dbcan`, utilizing the protein sequence (faa) and gene annotation (gff) files produced by `Prokka` (Step 5). - wget https://bcb.unl.edu/dbCAN_toturial/raw_reads/Dry2014_1.fastq.gz - wget https://bcb.unl.edu/dbCAN_toturial/raw_reads/Dry2014_2.fastq.gz - wget https://bcb.unl.edu/dbCAN_toturial/raw_reads/Wet2014_1.fastq.gz - wget https://bcb.unl.edu/dbCAN_toturial/raw_reads/Wet2014_2.fastq.gz +5. **Location Mapping and Substrate Prediction:** + Step 6 involves mapping the location of annotated CAZymes and CGCs on the contigs. In Step 7, `run_dbcan`'s substrate prediction function infers glycan substrates for these CAZymes and CGCs. -2. Create Anaconda Environment +6. **Abundance Calculation:** + To quantify the abundance of CAZymes, substrates, and CGCs, clean reads from Step 2 are mapped to the nucleotide coding sequences (CDS) of proteins from Step 4 (Steps 8-14). +7. **Data Visualization:** + Finally, steps 15-20 focus on visualizing the occurrence and abundance results. We provide Python scripts for creating publication-quality plots in PDF format. -Create and activate a new Anaconda environment with the following steps: + +.. image:: ../_static/img/Picture1.png + :alt: workflow figure + :width: 800px + :align: center + +.. |centered-text2| raw:: html + +
Fig.2 Experimental design of CAZyme annotation in microbiomes
+ +|centered-text2| + +User Requirements +````````````````` + +This protocol is designed for users who are comfortable with the Linux command-line interface and can execute Python scripts in the terminal. While extensive programming experience is not necessary, users should be familiar with editing Linux commands and plain-text scripts within a command-line environment. + +Equipment +--------- + +Operating System +```````````````` + +All the modules of this protocol (Fig. 2) are designed to run on a command line (CLI) environment with a Linux OS (e.g., Ubuntu). +We recommend users install these modules and execute all commands on a high-performance Linux cluster or workstation with >32 CPUs +and 128GB of RAM instead of a laptop, as the assembly of raw reads has a high demand of CPU and RAM. + +Once users finish the data visualization module (Fig. 2), the resulting image files (PDF format) can be copied +to a desktop or laptop with GUI for data visualization. In practice, users can choose not to use our read processing +module and read mapping module. They may instead use their preferred tools for preparing input data for run_dbcan module +and for calculating abundance for CAZymes and substrates. In that case, they can skip the installation of our read processing +module and read mapping module in this protocol. + +Data Files +`````````` + +The example dataset (Carter2023) is described above and detailed in Table 2. +The raw read data, intermediate data from each analysis step, and final result +data and visualization files are organized in nested folders available on our +website https://bcb.unl.edu/dbCAN_tutorial/dataset1-Carter2023/, Fig. 5) and +https://dbcan.readthedocs.io. These websites also include data files and +protocols for two additional example datasets from :cite:`2021:Wastyk` and :cite:`2023:Priest`, +which are not included in this protocol paper. We will use the independent sample +assembly route for :cite:`2023:carter` in the main text to demonstrate all the commands. +Commands for the other routes are provided Supplementary Protocols. + +Software and versions +````````````````````` + +- **Anaconda** (`Anaconda `_, version 23.7.3) +- **MEGAHIT** (`MEGAHIT `_, version 1.2.9) +- **BWA** (`BWA `_, version 0.7.17-r1188) +- **HMMER** (`HMMER `_, version 3.3) +- **DIAMOND** (`DIAMOND `_, version 2.1.8) +- **BLAST** (`BLAST `_, version 2.14) +- **TrimGalore** (`TrimGalore `_, version 0.6.0) +- **Prokka** (`Prokka `_, version 1.4) +- **Samtools** (`Samtools `_, version 1.7) +- **Seqkit** (`Seqkit `_, version 2.5.1) +- **Bedtools** (`Bedtools `_, version 2.27.1) +- **Kraken2** (`Kraken2 `_, version 2.1.1) +- **run_dbcan** (`run_dbcan `_, version 4.0.0) +- **BBTools** (`BBTools `_, version 37.62) +- **Seqkt** (`Seqkt `_, version 1.2-r94) +- **Minimap2** (`Minimap2 `_, version 2.26-r1175) +- **Flye** (`Flye `_, version 2.9.3-b1797) +- **Mmseqs2** (`Mmseqs2 `_, release 15-6f452) + +Anaconda as the Software Management System +`````````````````````````````````````````` +Anaconda will be used as the software package management system for this +protocol. Anaconda uses the ``conda`` command to create a virtual +environment to facilitate the easy installation of software packages +and running command line jobs. With the conda environment, users do +not need to worry about the potential issues of package dependencies +and version conflicts. + +Like in all bioinformatics data analysis tasks, we recommend users organize +their data files by creating a dedicated folder for each data analysis +step. + +.. _cater_2023: + +Example 1: Carter2023 Dataset :cite:`2023:carter` +------------------------------------------------- + +S1. Download Carter2023 (Table 2) raw reads (~10min) +````````````````````````````````````````````````````` +To download the required raw reads, use the following wget commands: .. code-block:: shell - conda create -n CAZyme_annotation python=3.9 - conda activate CAZyme_annotation + wget https://bcb.unl.edu/dbCAN_tutorial/dataset1-Carter2023/individual_assembly/Dry2014_1.fastq.gz + wget https://bcb.unl.edu/dbCAN_tutorial/dataset1-Carter2023/individual_assembly/Dry2014_2.fastq.gz + wget https://bcb.unl.edu/dbCAN_tutorial/dataset1-Carter2023/individual_assembly/Wet2014_1.fastq.gz + wget https://bcb.unl.edu/dbCAN_tutorial/dataset1-Carter2023/individual_assembly/Wet2014_2.fastq.gz + +These raw data were originally downloaded from +https://www.ncbi.nlm.nih.gov/sra/?term=ERR7745896 +and https://www.ncbi.nlm.nih.gov/sra/?term=ERR7738162 +and renamed to indicate their collected seasons (Table 2). -3. Installing Bioinformatics Dependencies and dbCAN +S2. Install Anaconda (~3min) +```````````````````````````` -Install all necessary bioinformatics tools either with a single command or individually: +Download and install the latest version of Anaconda for Linux from +https://www.anaconda.com/download#downloads. Once Anaconda is +successfully installed, proceed to create a dedicated conda environment +named `CAZyme_annotation` and activate it. +Subsequently, all the required tools can be seamlessly installed within +this environment. .. code-block:: shell - conda install -f dbcan.configure + conda create -n CAZyme_annotation python=3.9 + conda activate CAZyme_annotation -Alternatively, install the tools one by one: +S3. Install all bioinformatics tools (~10min) +````````````````````````````````````````````` .. code-block:: shell @@ -73,47 +183,66 @@ Alternatively, install the tools one by one: conda install -c conda-forge -c bioconda mmseqs2 conda install dbcan -c conda-forge -c bioconda +Alternatively, users can run a single configuration file dbcan.yml +(replace S2 and S3) that streamlines the above +configuration of all the essential software required for this protocol. -4. Database Installation +.. code-block:: shell + + git clone https://github.com/linnabrown/run_dbcan.git + cd run_dbcan + conda env create -f dbcan.yml + conda activate CAZyme_annotation +S4. Configure databases required by run_dbcan (~2h) +```````````````````````````````````````````````````` To install the databases, execute the following commands: +.. include:: database_preparation.rst + +Download database required by Kraken2 (very slow; can be skipped +if users do not intend to run Kraken2): + .. code-block:: shell - test -d db || mkdir db - cd db \ - && wget http://bcb.unl.edu/dbCAN2/download/Databases/fam-substrate-mapping-08012023.tsv \ - && wget http://bcb.unl.edu/dbCAN2/download/Databases/PUL_12112023.faa && mv PUL_12112023.faa PUL.faa && makeblastdb -in PUL.faa -dbtype prot \ - && wget http://bcb.unl.edu/dbCAN2/download/Databases/dbCAN-PUL_12-12-2023.xlsx \ - && wget http://bcb.unl.edu/dbCAN2/download/Databases/dbCAN-PUL_12-12-2023.txt \ - && wget http://bcb.unl.edu/dbCAN2/download/Databases/dbCAN-PUL.tar.gz && tar xvf dbCAN-PUL.tar.gz \ - && wget https://bcb.unl.edu/dbCAN2/download/Databases/dbCAN_sub.hmm && hmmpress dbCAN_sub.hmm \ - && wget https://bcb.unl.edu/dbCAN2/download/Databases/V12/CAZyDB.07262023.fa && diamond makedb --in CAZyDB.07262023.fa -d CAZy \ - && wget https://bcb.unl.edu/dbCAN2/download/Databases/V12/dbCAN-HMMdb-V12.txt && mv dbCAN-HMMdb-V12.txt dbCAN.txt && hmmpress dbCAN.txt \ - && wget https://bcb.unl.edu/dbCAN2/download/Databases/V12/tcdb.fa && diamond makedb --in tcdb.fa -d tcdb \ - && wget http://bcb.unl.edu/dbCAN2/download/Databases/V12/tf-1.hmm && hmmpress tf-1.hmm \ - && wget http://bcb.unl.edu/dbCAN2/download/Databases/V12/tf-2.hmm && hmmpress tf-2.hmm \ - && wget https://bcb.unl.edu/dbCAN2/download/Databases/V12/stp.hmm && hmmpress stp.hmm \ - && kraken2-build --standard --db K2 - -The downloaded files must be all in the right location (the db folder). -The CAZyDB.08062022.fa file is needed for DIAMOND search (Table 1). -The dbCAN-HMMdb-V11.txt and dbCAN_sub.hmm files are for HMMER search. -The tcdb.fa, tf-1.hmm, tf-2.hmm, and stp.hmm files are for CGC prediction. -The PUL.faa file consists of protein sequences from experimentally validated PULs for BLAST search to predict substrates for CGCs. -The dbCAN-PUL_07-01-2022.txt and dbCAN-PUL_07-01-2022.xlsx files contain PUL-substrate mapping curated from literature. -Lastly, the fam-substrate-mapping-08252022.tsv file is the family-EC-substrate mapping table for the prediction of CAZyme substrates. + kraken2-build --standard --db K2 -.. warning:: - The conda installation and configuration step may experience prolonged time while resolving environment dependencies. Users should be patient during this process. Alternatively, users consider "mamba", - another Python package manager that offers similar functionality to Anaconda. - Information and access to mamba software can be found at https://github.com/mamba-org/mamba. +**CRITICAL STEP** + + The downloaded files must be all in the right location (the db folder). + + The CAZyDB.07262023.fa file is needed for DIAMOND search (Table 1). + + The dbCAN-HMMdb-V12.txt and dbCAN_sub.hmm files are for HMMER search. + + The tcdb.fa, tf-1.hmm, tf-2.hmm, and stp.hmm files are for CGC prediction. + The PUL.faa file consists of protein sequences from experimentally + validated PULs for BLAST search to predict substrates for CGCs. + The dbCAN-PUL_12-12-2023.txt and dbCAN-PUL_12-12-2023.xlsx files contain + PUL-substrate mapping curated from literature. -Module 1: Reads processing to obtain contigs + Lastly, the + fam-substrate-mapping-08012023.tsv file is the family-EC-substrate + mapping table for the prediction of CAZyme substrates. + +.. warning:: + + Users should use a clean version of Anaconda. If the above steps failed, we suggest users reinstall their Anaconda. + The Anaconda installation and configuration step may experience + prolonged time while resolving environment dependencies. + Users should be patient during this process. Alternatively, + users may consider "mamba", another Python package manager + that offers similar functionality to Anaconda. Information and + access to mamba software can be found at + https://github.com/mamba-org/mamba. + +Procedure -------------------------------------------- +Module 1: Reads processing (Fig. 2) to obtain contigs +````````````````````````````````````````````````````` P1. Contamination Check ^^^^^^^^^^^^^^^^^^^^^^^ @@ -127,8 +256,9 @@ Use `kraken2` to check for contaminated reads: Kraken2 found very little contamination in the Carter2023 data. Consequently, there was no need for the contamination removal step. -If contamination is identified, users can align the reads to the reference genomes of potential -contamination source organisms to remove the aligned reads (Box 1). The most common source in human microbiome studies is from human hosts. +If contamination is identified, users can align the reads to the reference genomes of potential contamination source organisms to remove +the aligned reads (Box 1). The most common source in human microbiome studies is from human hosts. + Box 1: Removing Contamination Reads from Humans ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -142,6 +272,7 @@ Box 1: Removing Contamination Reads from Humans -rw-rw-r-- 1 jinfang jinfang 5.1G Dec 12 09:47 Wet2014.kraken.output -rw-rw-r-- 1 jinfang jinfang 1.1M Dec 12 09:48 Wet2014.kreport + Suppose from these files, we have identified humans as the contamination source, we can use the following commands to remove the contamination reads by aligning reads to the human reference genome. .. code-block:: shell @@ -155,18 +286,17 @@ Box 1: Removing Contamination Reads from Humans samtools fastq -1 Wet2014_1.clean.fq.gz -2 Wet2014_2.clean.fq.gz Wet2014.hg38.unmap.bam samtools fastq -1 Dry2014_1.clean.fq.gz -2 Dry2014_2.clean.fq.gz Dry2014.hg38.unmap.bam -P2. Trimming Adapters and Low-Quality Reads -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +P2. Trim adapter and low-quality reads (TIMING ~20min) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. code-block:: shell trim_galore --paired Wet2014_1.fastq.gz Wet2014_2.fastq.gz --illumina -j 36 trim_galore --paired Dry2014_1.fastq.gz Dry2014_2.fastq.gz --illumina -j 36 - -Trim_galore is used to trim adapters and low-quality reads. -We specified `--illumina` to indicate that the reads were generated using the Illumina sequencing platform. Nonetheless, trim_galore possesses the ability to automatically detect the adapter, -providing flexibility in adapter handling for users who may know the specific sequencing platform. +We specified `--illumina` to indicate that the reads were generated using the Illumina sequencing platform. +Nonetheless, trim_galore can automatically detect adapters, providing flexibility for users who may know the specific sequencing platform. Details of trimming are available in the trimming report file (Box 2). Box 2: Example output of `trim_galore` @@ -189,8 +319,8 @@ Box 2: Example output of `trim_galore` .. warning:: During the trimming process, certain reads may be entirely removed due to low quality in its entirety. - Using the --retain_unpaired parameter in trim_galore allows for the preservation of single-end reads. - In this protocol, this option was not select, so that both reads of a forward-revise pair were removed. + Using the ``--retain_unpaired`` parameter in ``trim_galore`` allows for the preservation of single-end reads. + In this protocol, this option was not selected, so that both reads of a forward-revise pair were removed. P3. Assemble reads into contigs ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -203,11 +333,11 @@ Use Megahit for assembling reads into contigs: megahit -m 0.5 -t 32 -o megahit_ Dry2014 -1 Dry2014_1_val_1.fq.gz -2 Dry2014_2_val_2.fq.gz --out-prefix Dry2014 --min-contig-len 1000 -MEGAHIT generates two output folders. Each contains five files and one sub-folder (Box 3). -Wet2014.contigs.fa is the final contig sequence file. We set --min-contig-len 1000, +``MEGAHIT`` generates two output folders. Each contains five files and one sub-folder (Box 3). +``Wet2014.contigs.fa`` is the final contig sequence file. We set `--min-contig-len 1000`, a common practice to retain all contigs longer than 1,000 base pairs. -Box 3: Example output of `megahit` +Box 3: Example output of `MEGAHIT` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. code-block:: shell @@ -217,18 +347,29 @@ Box 3: Example output of `megahit` drwxrwxr-x 2 jinfang jinfang 4.0K Dec 13 04:19 intermediate_contigs -rw-rw-r-- 1 jinfang jinfang 1.1K Dec 13 02:22 options.json -rw-rw-r-- 1 jinfang jinfang 258M Dec 13 04:19 Wet2014.contigs.fa + -rw-rw-r-- 1 jinfang jinfang 208K Dec 13 04:19 Wet2014.log + +.. warning:: + + A common practice in metagenomics after assembly is to further bin contigs into metagenome-assembled genomes (MAGs). + However, in this protocol, we chose not to generate MAGs because not all contigs can be binned into MAGs, and those un-binned + contigs can also encode CAZymes. -P4. Predict Genes with Prokka -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +P4. Predict genes by `Prokka` (TIMING ~21h) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. code-block:: shell - prokka --kingdom Bacteria --cpus 36 --outdir prokka_Wet2014 --prefix Wet2014 --addgenes --addmrna --locustag Wet2014 megahit_Wet2014/Wet2014.contigs.fa - prokka --kingdom Bacteria --cpus 36 --outdir prokka_Dry2014 --prefix Dry2014 --addgenes --addmrna --locustag Dry2014 megahit_Dry2014/Dry2014.contigs.fa + prokka --kingdom Bacteria --cpus 32 --outdir prokka_ Wet2014 --prefix Wet2014 --addgenes --addmrna --locustag Wet2014 megahit_ Wet2014/Wet2014.contigs.fa + prokka --kingdom Bacteria --cpus 32 --outdir prokka_ Dry2014 --prefix Dry2014 --addgenes --addmrna --locustag Dry2014 megahit_ Dry2014/Dry2014.contigs.fa + + +The parameter ``--kingdom Bacteria`` is required for bacterial gene prediction. +To optimize performance, ``--CPU 32`` instructs the utilization of 32 CPUs. +Reduce this number if you do not have this many CPUs on your computer. +The output files comprise of both protein and CDS sequences in Fasta format (e.g., ``Wet2014.faa`` and ``Wet2014.ffn`` in Box 4). -The parameter --kingdom Bacteria is required for bacterial gene prediction. -To optimize performance, --CPU 36 instructs the utilization of 36 computer processors. -The output files comprise of both protein and CDS sequences in Fasta format (e.g., Wet2014.faa and Wet2014.ffn in Box 4). Box 4: Example output of `Prokka` @@ -249,103 +390,75 @@ Box 4: Example output of `Prokka` -rw-rw-r-- 1 jinfang jinfang 30M Dec 13 21:38 Wet2014.tsv -rw-rw-r-- 1 jinfang jinfang 152 Dec 13 21:38 Wet2014.txt -Module 2. run_dbcan annotation to obtain CAZymes, CGCs, and substrates ----------------------------------------------------------------------- -P5. CAZyme annotation at family level (TIMING ~10min) -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Module 2. run_dbcan annotation (Fig. 2) to obtain CAZymes, CGCs, and substrates +``````````````````````````````````````````````````````````````````````````````` + +**CRITICAL STEP** + +Users can skip P5 and P6, and directly run P7 (much slower though), if they want to predict not only CAZymes and CGCs, but also substrates. + +P5. CAZyme annotation at the CAZyme family level (TIMING ~10min) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. code-block:: shell run_dbcan prokka_Wet2014/Wet2014.faa protein --hmm_cpu 32 --out_dir Wet2014.CAZyme --tools hmmer --db_dir db run_dbcan prokka_Dry2014/Dry2014.faa protein --hmm_cpu 32 --out_dir Dry2014.CAZyme --tools hmmer --db_dir db -Two arguments are required for run_dbcan: the input sequence file (faa files) and the sequence type (protein). -By default, run_dbcan will use three methods (HMMER vs dbCAN HMMdb, DIAMOND vs CAZy, HMMER vs dbCAN-sub HMMdb) for CAZyme annotation (Table 1, Figure 2). -This default setting is equivalent to the use --tools all parameter (Box 5). -Here we only invoke the HMMER vs dbCAN HMMdb for CAZyme annotation at the family level. +Two arguments are required for ``run_dbcan``: the input sequence file (faa files) and the sequence type (protein). +By default, ``run_dbcan`` will use three methods (``HMMER`` vs ``dbCAN HMMdb``, ``DIAMOND`` vs ``CAZy``, ``HMMER`` vs ``dbCAN-sub HMMdb``) for +CAZyme annotation (see Table 1, Fig. 1). This default setting is equivalent to the use of the ``--tools all`` parameter (refer to Box 5). Here, +we only invoke the ``HMMER`` vs ``dbCAN HMMdb`` for CAZyme annotation at the family level. + Box 5: CAZyme annotation with default setting ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -If the --tools parameter is not set, it is the default setting, which is the same as --tools all. -This will take much longer time to finish (~5h) due to the large size of dbCAN-sub HMMdb (used for substrate prediction for CAZymes, see Table 1). +If the ``--tools`` parameter is not set, it defaults to the equivalent of ``--tools all``. +This setting will take a much longer time to finish (approximately 5 hours) due to the large size of ``dbCAN-sub HMMdb`` +(used for substrate prediction for CAZymes, see Table 1). + .. code-block:: shell run_dbcan prokka_Wet2014/Wet2014.faa protein --out_dir Wet2014.CAZyme --dia_cpu 32 --hmm_cpu 32 --dbcan_thread 32 --tools all run_dbcan prokka_Dry2014/Dry2014.faa protein --out_dir Dry2014.CAZyme --dia_cpu 32 --hmm_cpu 32 --dbcan_thread 32 --tools all + The sequence type can be `protein`, `prok`, `meta`. If the input sequence file contains metagenomic contig sequences (`fna` file), -the sequence type has to be meta, and prodigal will be called to predict genes. +the sequence type has to be `meta`, and `prodigal` will be called to predict genes. .. code-block:: shell run_dbcan prokka_Wet2014/Wet2014.fna meta --out_dir Wet2014.CAZyme --dia_cpu 32 --hmm_cpu 32 --dbcan_thread 32 run_dbcan prokka_Dry2014/Dry2014.fna meta --out_dir Dry2014.CAZyme --dia_cpu 32 --hmm_cpu 32 --dbcan_thread 32 -5.1. Combine proteins from multiple samples - -.. warning:: - As shown in Figure 3 (step3), proteins from multiple samples can be combined to generate a non-redundant set of proteins. - This will reduce the runtime for the run_dbcan step (step4), as only one faa file will be processed. - However, this does not work for the CGC prediction, as contigs (fna files) from each sample will be needed. - Therefore, this step (5.1) is recommended if users only want the CAZyme annotation, and not recommended if CGCs are also to be predicted. - - -This protein sequence clustering step will create a mapping table with sequence cluster ID and protein IDs from each sample. - -.. code-block:: shell - - mkdir mmseqs_cluster && cd mmseqs_cluster - ln -s ../db . - cat ../prokka_Wet2014/Wet2014.faa ../prokka_Dry2014/Dry2014.faa > Dry_Wet.faa - mmseqs easy-cluster --threads 32 -c 0.95 --min-seq-id 0.95 --cov-mode 2 Dry_Wet.faa Dry_Wet_cluster tmp - mv Dry_Wet_cluster_cluster_rep.fasta Dry_Wet.cluster.faa - -This `Dry_Wet.cluster.faa` file now contains the non-redundant set of proteins from the two samples. - -.. code-block:: shell - - grep "^>" Dry_Wet.cluster.faa | tr ">" " " |awk '{print $1}' > Dry_Wet.geneids - seqkit grep -f Dry_Wet.geneids ../prokka_Dry2014/Wet2014.ffn > Dry_Wet.ffn - seqkit grep -f Dry_Wet.geneids ../prokka_Dry2014/Dry2014.ffn >> Dry_Wet.ffn - -This `Dry_Wet.ffn file` now contains the CDS sequences of the non-redundant set of proteins from the two samples. - -.. code-block:: shell - - bwa index Dry_Wet.ffn - ln -s ../Dry2014_1_val_1.fq.gz . && ln -s ../Dry2014_2_val_2.fq.gz . && ln -s ../Wet2014_2_val_2.fq.gz . && ln -s ../Wet2014_1_val_1.fq.gz . - bwa mem -t 32 -o samfiles/Wet2014.CDS.sam Dry_Wet.ffn Wet2014_1_val_1.fq.gz Wet2014 _2_val_2.fq.gz - bwa mem -t 32 -o samfiles/Dry2014.CDS.sam Dry_Wet.ffn Dry2014_1_val_1.fq.gz Dry2014_2_val_2.fq.gz - -The two sam files now contain the read mapping result from each sample to the `Dry_Wet.ffn` file. - -P6. CGC prediction. -^^^^^^^^^^^^^^^^^^^ +P6. CGC prediction (TIMING ~15 min) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The following commands will re-run run_dbcan to not only predict CAZymes but also CGCs with protein `faa` and gene location `gff` files. .. code-block:: shell run_dbcan prokka_Wet2014/Wet2014.faa protein --tools hmmer --tf_cpu 32 --stp_cpu 32 -c prokka_Wet2014/Wet2014.gff --out_dir Wet2014.PUL --dia_cpu 32 --hmm_cpu 32 - run_dbcan prokka_Dry2014/Dry2014.faa protein --tools hmmer --tf_cpu 32 --stp_cpu 32 -c prokka_ Dry2014/Dry2014.gff --out_dir Dry2014.PUL --dia_cpu 32 --hmm_cpu 32 + run_dbcan prokka_Dry2014/Dry2014.faa protein --tools hmmer --tf_cpu 32 --stp_cpu 32 -c prokka_Dry2014/Dry2014.gff --out_dir Dry2014.PUL --dia_cpu 32 --hmm_cpu 32 + + +As mentioned above (see Table 1, Fig. 1), CGC prediction is a featured function added into dbCAN2 in 2018. +To identify CGCs with the protein sequence type, a gene location file (``gff``) must be provided together. If the input sequence type +is ``prok`` or ``meta``, meaning users only have contig ``fna`` files, the CGC prediction can be activated by setting the ``-c cluster`` parameter. -As mentioned above (Table 1, Figure 2), -CGC prediction is a featured function added into dbCAN2 in 2018. -To identify CGCs with the protein sequence type, -a gene location file (gff) must be provided together. -If the input sequence type is prok or meta, meaning users only have contig fna files, the CGC prediction can be activated by setting -c cluster. .. warning:: **Creating own gff file** - If the users would like to create their own gff file (instead of using Prokka or Prodigal), - it is important to make sure the value of ID attribute in the gff file matches the protein ID in the protein faa file. + If the users would like to create their own ``gff`` file (instead of using Prokka or Prodigal), + it is important to make sure the value of ID attribute in the ``gff`` file matches the protein ID in the protein ``faa`` file. - **CGC not found** - If no result is found in CGC output file, it is most likely because the sequence IDs in gff file and faa file do not match. Another less likely reason is that the contigs are too short and fragmented and not suitable for CGC prediction. + **[Troubleshooting]CGC not found** + If no result is found in CGC output file, it is most likely because the sequence IDs in ``gff`` file and ``faa`` file do not match. + Another less likely reason is that the contigs are too short and fragmented and not suitable for CGC prediction. P7. Substrate prediction for CAZymes and CGCs (TIMING ~5h) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -355,13 +468,13 @@ The following commands will re-run run_dbcan to predict CAZymes, CGCs, and their .. code-block:: shell run_dbcan prokka_Wet2014/Wet2014.faa protein --dbcan_thread 32 --tf_cpu 32 --stp_cpu 32 -c prokka_Wet2014/Wet2014.gff --cgc_substrate --hmm_cpu 32 --out_dir Wet2014.dbCAN --dia_cpu 32 - run_dbcan prokka_Dry2014/Dry2014.faa protein --dbcan_thread 32 --stp_cpu 32 -c prokka_Dry2014/Dry2014.gff --cgc_substrate --out_dir Dry2014.dbCAN --dia_cpu 32 --hmm_cpu 32 --tf_cpu 32 + run_dbcan prokka_Dry2014/Dry2014.faa protein --dbcan_thread 32 --tf_cpu 32 --stp_cpu 32 -c prokka_Dry2014/Dry2014.gff --cgc_substrate --hmm_cpu 32 --out_dir Dry2014.dbCAN --dia_cpu 32 .. warning:: - The above commands do not set the --tools parameter, + The above commands do not set the `--tools` parameter, which means all three methods for CAZyme annotation will be activated (Box 5). Because dbCAN-sub HMMdb (for CAZyme substrate prediction) is 200 times larger than dbCAN HMMdb, - the runtime will be much longer. Users can specify --tools hmmer, so that the HMMER search against dbCAN-sub will be disabled. + the runtime will be much longer. Users can specify `--tools hmmer`, so that the HMMER search against dbCAN-sub will be disabled. However, this will turn off the substrate prediction for CAZymes and CGCs based on CAZyme substrate majority voting. Consequently, the substrate prediction will be solely based on homology search against PULs in dbCAN-PUL @@ -370,70 +483,96 @@ The following commands will re-run run_dbcan to predict CAZymes, CGCs, and their run_dbcan prokka_Wet2014/Wet2014.faa protein --tools hmmer --stp_cpu 32 -c prokka_Wet2014/Wet2014.gff --cgc_substrate --out_dir Wet2014.PUL.Sub --dia_cpu 32 --hmm_cpu 32 --tf_cpu 32 run_dbcan prokka_Dry2014/Dry2014.faa protein --tools hmmer --stp_cpu 32 -c prokka_Dry2014/Dry2014.gff --cgc_substrate --out_dir Dry2014.PUL.Sub --dia_cpu 32 --hmm_cpu 32 --tf_cpu 32 -.. warning:: - The above commands do not set the --tools parameter, which means all three methods for CAZyme annotation will be activated (Box 5). - Because dbCAN-sub HMMdb (for CAZyme substrate prediction) is 200 times larger than dbCAN HMMdb, the runtime will be much longer. - Users can specify --tools hmmer, so that the HMMER search against dbCAN-sub will be disabled. - However, this will turn off the substrate prediction for CAZymes and CGCs based on CAZyme substrate majority voting. - Consequently, the substrate prediction will be solely based on homology search against PULs in dbCAN-PUL (Figure 1, Table 1). - - .. code-block:: shell - - run_dbcan prokka_Wet2014/Wet2014.faa protein --tools hmmer --stp_cpu 32 -c prokka_Wet2014/Wet2014.gff --cgc_substrate --out_dir Wet2014.PUL.Sub --dia_cpu 32 --hmm_cpu 32 --tf_cpu 32 - run_dbcan prokka_Dry2014/Dry2014.faa protein --tools hmmer --stp_cpu 32 -c prokka_Dry2014/Dry2014.gff --cgc_substrate --out_dir Dry2014.PUL.Sub --dia_cpu 32 --hmm_cpu 32 --tf_cpu 32 - - -Box 6. Example Output Folder Content of run_dbcan Substrate Prediction +Box 6. Example output folder content of run_dbcan substrate prediction ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - The output directory of run_dbcan substrate prediction typically contains 17 files and 1 folder: + In the output directory (`Output Directory `_), + a total of 17 files and 1 folder are generated: + .. code-block:: shell - -rw-rw-r-- 1 jinfang jinfang 33M Dec 17 09:36 blastp.out - -rw-rw-r-- 1 jinfang jinfang 3.3M Dec 17 09:35 CAZyme.pep + -rw-rw-r-- 1 jinfang jinfang 33M Dec 17 09:36 PUL_blast.out + -rw-rw-r-- 1 jinfang jinfang 3.3M Dec 17 09:35 CGC.faa -rw-rw-r-- 1 jinfang jinfang 18M Dec 17 09:35 cgc.gff -rw-rw-r-- 1 jinfang jinfang 836K Dec 17 09:35 cgc.out -rw-rw-r-- 1 jinfang jinfang 374K Dec 17 09:35 cgc_standard.out -rw-rw-r-- 1 jinfang jinfang 1.8M Dec 17 09:35 cgc_standard.out.json - -rw-rw-r-- 1 jinfang jinfang 785K Dec 17 09:31 dbsub.out + -rw-rw-r-- 1 jinfang jinfang 785K Dec 17 09:31 dbcan-sub.hmm.out -rw-rw-r-- 1 jinfang jinfang 511K Dec 17 09:31 diamond.out -rw-rw-r-- 1 jinfang jinfang 638K Dec 17 09:31 dtemp.out -rw-rw-r-- 1 jinfang jinfang 414K Dec 17 09:31 hmmer.out -rw-rw-r-- 1 jinfang jinfang 386K Dec 17 09:35 overview.txt -rw-rw-r-- 1 jinfang jinfang 2.8M Dec 17 09:35 stp.out - -rw-rw-r-- 1 jinfang jinfang 63K Dec 17 09:36 sub.prediction.out - drwxrwxr-x 2 jinfang jinfang 36K Dec 17 09:39 syntenic.svg + -rw-rw-r-- 1 jinfang jinfang 63K Dec 17 09:36 substrate.out + drwxrwxr-x 2 jinfang jinfang 36K Dec 17 09:39 synteny.pdf -rw-rw-r-- 1 jinfang jinfang 799K Dec 17 09:32 tf-1.out -rw-rw-r-- 1 jinfang jinfang 645K Dec 17 09:34 tf-2.out -rw-rw-r-- 1 jinfang jinfang 2.3M Dec 17 09:35 tp.out -rw-rw-r-- 1 jinfang jinfang 75M Dec 17 02:07 uniInput - Descriptions of Key Output Files: - - `blastp.out`: BLAST results between CGCs and PULs. - - `CAZyme.pep`: Fasta sequences of CAZymes. - - `cgc.gff`: Reformatted user input GFF file, marking CAZymes, TFs, TCs, and STPs. - - `cgc.out`: Raw output of CGC predictions. - - `cgc_standard.out`: Simplified version of `cgc.out` in TSV format for easy parsing (refer to Box 7 for columns). - - `cgc_standard.out.json`: JSON format of `cgc_standard.out`. - - `dbsub.out`: HMMER search result against dbCAN-sub HMMdb, with CAZyme substrates extracted from fam-substrate-mapping-08252022.tsv. - - `diamond.out`: DIAMOND search result against the CAZy annotated protein sequences (CAZyDB.08062022.fa). - - `dtemp.out`: Temporary file. - - `hmmer.out`: HMMER search result against dbCAN HMMdb. - - `overview.txt`: Summary of CAZyme annotation from three methods in TSV format (refer to Box 7 for columns). - - `stp.out`: HMMER search result against the MiST65 compiled signal transduction protein HMMs from Pfam. - - `tf-1.out` and `tf-2.out`: HMMER search results against transcription factor HMMs from Pfam and Superfamily databases. - - `tp.out`: DIAMOND search result against the TCDB annotated protein sequences. - - `sub.prediction.out`: Summary of substrate prediction results (refer to Box 7) for CGCs. - - `syntenic.svg`: Syntenic block alignment plots between all CGCs and PULs. - - `uniInput`: Renamed Fasta file from input protein sequence file. + Descriptions of Output Files: + In the output directory, a total of 17 files and 1 folder are generated: + + - ``PUL_blast.out``: BLAST results between CGCs and PULs. + - ``CGC.faa``: Protein Fasta sequences encoded in all CGCs. + - ``cgc.gff``: Reformatted from the user input gff file by marking CAZymes, TFs, TCs, and STPs. + - ``cgc.out``: Raw output of CGC predictions. + - ``cgc_standard.out``: Simplified version of cgc.out for easy parsing in TSV format. Example columns include: + + 1. ``CGC_id``: CGC1 + 2. ``type``: CAZyme + 3. ``contig_id``: k141_272079 + 4. ``gene_id``: Wet2014_00308 + 5. ``start``: 5827 + 6. ``end``: 7257 + 7. ``strand``: - + 8. ``annotation``: GH1 + + **Explanation**: The gene Wet2014_00308 encodes a GH1 CAZyme in CGC1 of contig k141_272079. CGC1 also contains other genes, detailed in other rows. Wet2014_00308 is located on the negative strand of k141_272079 from positions 5827 to 7257. The type can be one of four signature gene types (CAZymes, TCs, TFs, STPs) or null type (not annotated as one of the signature genes). + + - ``cgc_standard.out.json``: JSON format of cgc_standard.out. + - ``dbcan-sub.hmm.out``: HMMER search result against dbCAN-sub HMMdb, including a column with CAZyme substrates from fam-substrate-mapping-08012023.tsv. + - ``diamond.out``: DIAMOND search result against the CAZy annotated protein sequences (CAZyDB.07262023.fa). + - ``dtemp.out``: Temporary file. + - ``hmmer.out``: HMMER search result against dbCAN HMMdb. + - ``overview.txt``: Summary of CAZyme annotation from three methods in TSV format. Example columns include: + + 1. ``Gene_ID``: Wet2014_00076 + 2. ``EC#``: 3.2.1.99:3 + 3. ``dbCAN``: GH43_4(42-453) + 4. ``dbCAN_sub``: GH43_e149 + 5. ``DIAMOND``: GH43_4 + 6. ``#ofTools``: 3 + + **Explanation**: The protein Wet2014_000076 is annotated by three tools as a CAZyme: GH43_4 (CAZy defined subfamily 4 of GH43) by HMMER vs dbCAN HMMdb, GH43_e149 (eCAMI defined subfamily e149; 'e' indicates it is from eCAMI not CAZy) by HMMER vs dbCAN-sub HMMdb, and GH43_4 by DIAMOND vs CAZy annotated protein sequences. The EC number is extracted from eCAMI, indicating that the eCAMI subfamily GH43_e149 contains 3 member proteins with an EC 3.2.1.99 according to CAZy. The preference order for different assignments is dbCAN > eCAMI/dbCAN-sub > DIAMOND. Refer to dbCAN2 paper11, dbCAN3 paper12, and eCAMI41 for more details. + + **Note**: If the ``--use_signalP`` parameter was invoked when running run_dbcan, an additional column called ``signalP`` will be in overview.txt. + + - ``stp.out``: HMMER search result against the MiST70 compiled signal transduction protein HMMs from Pfam. + - ``tf-1.out``: HMMER search result against the DBD71 compiled transcription factor HMMs from Pfam72. + - ``tf-2.out``: HMMER search result against the DBD compiled transcription factor HMMs from Superfamily73. + - ``tp.out``: DIAMOND search result against the TCDB 74 annotated protein sequences. + - ``substrate.out``: Summary of substrate prediction results for CGCs in TSV format from two approaches12 (dbCAN-PUL blast search and dbCAN-sub majority voting). Example columns include: + + 1. ``CGC_ID``: k141_227425|CGC1 + 2. ``Best hit PUL_ID in dbCAN-PUL``: PUL0402 + 3. ``Substrate of the hit PUL``: xylan + 4. ``Sum of bitscores for homologous gene pairs between CGC and PUL``: 2134.0 + 5. ``Types of homologous gene pairs``: TC-TC;CAZyme-CAZyme + 6. ``Substrate predicted by majority voting of CAZymes in CGC``: xylan + 7. ``Voting score``: 2.0 + *Explanation*: The CGC1 of contig k141_227425 has its best hit PUL0402 (from PUL_blast.out) with xylan as substrate (from dbCAN-PUL_12-12-2023.xlsx). Two signature genes are matched between k141_227425|CGC1 and PUL0402: one is a CAZyme and the other is a TC. The sum of blast bit scores of the two homologous pairs (TC-TC and CAZyme-CAZyme) is 2134.0. Hence, the substrate of k141_227425|CGC1 is predicted to be xylan according to dbCAN-PUL blast search. The last two columns are based on the dbCAN-sub result (dbcan-sub.hmm.out), as the file indicates that two CAZymes in k141_227425|CGC1 are predicted to have xylan substrate. The voting score is 2.0, so according to the majority voting rule, k141_227425|CGC1 is predicted to have a xylan substrate. + *Note*: For many CGCs, only one of the two approaches produces substrate prediction. In some cases, the two approaches produce different substrate assignments. The recommended preference order is dbCAN-PUL blast search > dbCAN-sub majority voting. Refer to dbCAN3 paper12 for more details. -Module 3. Read mapping (Figure 3) to calculate abundance for CAZyme families, subfamilies, CGCs, and substrates ---------------------------------------------------------------------------------------------------------------- + - ``synteny.pdf``: A folder with syntenic block alignment plots between all CGCs and PULs. + - ``uniInput``: Renamed Fasta file from input protein sequence file. +Module 3. Read mapping (Fig. 2) to calculate abundance for CAZyme families, subfamilies, CGCs, and substrates +`````````````````````````````````````````````````````````````````````````````````````````````````````````````` P8. Read mapping to all CDS of each sample (TIMING ~20 min) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -442,10 +581,11 @@ P8. Read mapping to all CDS of each sample (TIMING ~20 min) bwa index prokka_Wet2014/Wet2014.ffn bwa index prokka_Dry2014/Dry2014.ffn mkdir samfiles - bwa mem -t 32 -o samfiles/Wet2014.CDS.sam prokka_Wet2014/Wet2014.ffn Wet2014_1_val_1.fq.gz Wet2014 _2_val_2.fq.gz + bwa mem -t 32 -o samfiles/Wet2014.CDS.sam prokka_Wet2014/Wet2014.ffn Wet2014_1_val_1.fq.gz Wet2014_2_val_2.fq.gz bwa mem -t 32 -o samfiles/Dry2014.CDS.sam prokka_Dry2014/Dry2014.ffn Dry2014_1_val_1.fq.gz Dry2014_2_val_2.fq.gz -Reads are mapped to the ffn files from Prokka. + +Reads are mapped to the ``ffn`` files from Prokka. P9. Read mapping to all contigs of each sample (TIMING ~20min) @@ -453,147 +593,202 @@ P9. Read mapping to all contigs of each sample (TIMING ~20min) .. code-block:: shell - $ bwa index megahit_Wet2014/Wet2014.contigs.fa - $ bwa index megahit_Dry2014/Dry2014.contigs.fa - $ bwa mem -t 32 -o samfiles/Wet2014.sam megahit_Wet2014/Wet2014.contigs.fa Wet2014_1_val_1.fq.gz Wet2014_2_val_2.fq.gz - $ bwa mem -t 32 -o samfiles/Dry2014.sam megahit_Dry2014/Dry2014.contigs.fa Dry2014_1_val_1.fq.gz Dry2014_2_val_2.fq.gz + bwa index megahit_Wet2014/Wet2014.contigs.fa + bwa index megahit_Dry2014/Dry2014.contigs.fa + bwa mem -t 32 -o samfiles/Wet2014.sam megahit_Wet2014/Wet2014.contigs.fa Wet2014_1_val_1.fq.gz Wet2014_2_val_2.fq.gz + bwa mem -t 32 -o samfiles/Dry2014.sam megahit_Dry2014/Dry2014.contigs.fa Dry2014_1_val_1.fq.gz Dry2014_2_val_2.fq.gz -Reads are mapped to the contig files from MEGAHIT. +Reads are mapped to the `contig` files from MEGAHIT. P10. Sort SAM files by coordinates (TIMING ~8min) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. code-block:: shell - $ cd samfiles - $ samtools sort -@ 32 -o Wet2014.CDS.bam Wet2014.CDS.sam - $ samtools sort -@ 32 -o Dry2014.CDS.bam Dry2014.CDS.sam - $ samtools sort -@ 32 -o Wet2014.bam Wet2014.sam - $ samtools sort -@ 32 -o Dry2014.bam Dry2014.sam - $ rm -rf *sam - $ cd .. + cd samfiles + samtools sort -@ 32 -o Wet2014.CDS.bam Wet2014.CDS.sam + samtools sort -@ 32 -o Dry2014.CDS.bam Dry2014.CDS.sam + samtools sort -@ 32 -o Wet2014.bam Wet2014.sam + samtools sort -@ 32 -o Dry2014.bam Dry2014.sam + rm -rf *sam + cd .. + P11. Read count calculation for all proteins of each sample using Bedtools (TIMING ~2min) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. code-block:: shell - $ mkdir Wet2014_abund && cd Wet2014_abund - $ seqkit fx2tab -l -n -i ../prokka_Wet2014/Wet2014.ffn | awk '{print $1"\t"$2}' > Wet2014.length - $ seqkit fx2tab -l -n -i ../prokka_Wet2014/Wet2014.ffn | awk '{print $1"\t"0"\t"$2}' > Wet2014.bed - $ bedtools coverage -g Wet2014.length -sorted -a Wet2014.bed -counts -b ../samfiles/Wet2014.CDS.bam > Wet2014.depth.txt + mkdir Wet2014_abund && cd Wet2014_abund + seqkit fx2tab -l -n -i ../prokka_Wet2014/Wet2014.ffn | awk '{print $1"\t"$2}' > Wet2014.length + seqkit fx2tab -l -n -i ../prokka_Wet2014/Wet2014.ffn | awk '{print $1"\t"0"\t"$2}' > Wet2014.bed + bedtools coverage -g Wet2014.length -sorted -a Wet2014.bed -counts -b ../samfiles/Wet2014.CDS.bam > Wet2014.depth.txt - $ cd .. && mkdir Dry2014_abund && cd Dry2014_abund - $ seqkit fx2tab -l -n -i ../prokka_Dry2014/Dry2014.ffn | awk '{print $1"\t"$2}' > Dry2014.length - $ seqkit fx2tab -l -n -i ../prokka_Dry2014/Dry2014.ffn | awk '{print $1"\t"0"\t"$2}' > Dry2014.bed - $ bedtools coverage -g Dry2014.length -sorted -a Dry2014.bed -counts -b ../samfiles/Dry2014.CDS.bam > Dry2014.depth.txt - $ cd .. + cd .. && mkdir Dry2014_abund && cd Dry2014_abund + seqkit fx2tab -l -n -i ../prokka_Dry2014/Dry2014.ffn | awk '{print $1"\t"$2}' > Dry2014.length + seqkit fx2tab -l -n -i ../prokka_Dry2014/Dry2014.ffn | awk '{print $1"\t"0"\t"$2}' > Dry2014.bed + bedtools coverage -g Dry2014.length -sorted -a Dry2014.bed -counts -b ../samfiles/Dry2014.CDS.bam > Dry2014.depth.txt + cd .. -Read counts are saved in depth.txt files of each sample. + +Read counts are saved in ``depth.txt`` files of each sample. P12. Read count calculation for a given region of contigs using Samtools (TIMING ~2min) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. code-block:: shell - $ cd Wet2014_abund - $ samtools index ../samfiles/Wet2014.bam - $ samtools depth -r k141_41392:152403-165349 ../samfiles/Wet2014.bam > Wet2014.cgc.depth.txt - $ cd .. - $ cd Dry2014_abund - $ samtools index ../samfiles/Dry2014.bam - $ samtools depth -r k141_41392:152403-165349 ../samfiles/Dry2014.bam > Dry2014.cgc.depth.txt + cd Wet2014_abund + samtools index ../samfiles/Wet2014.bam + samtools depth -r k141_41392:152403-165349 ../samfiles/Wet2014.bam > Wet2014.cgc.depth.txt + cd .. + -The parameter -r k141_41392:152403-165349 specifies a region in a contig. For any CGC, its positional range can be found in the file cgc_standard.out produced by run_dbcan (Box 6). The depth.txt files contain the raw read counts for the specified region. +The parameter ``-r k141_41392:152403-165349`` specifies a region in a contig. For any CGC, its positional range can be found in the file ``cgc_standard.out`` produced by ``run_dbcan`` (refer to Box 6). The ``depth.txt`` files contain the raw read counts for the specified region. + +.. warning:: + The contig IDs are automatically generated by MEGAHIT. There is a small chance that the same contig ID appears in both samples. However, the two contigs in the two samples do not match each other even if the ID is the same. For example, the contig ID ``k141_4139`` is most likely only found in the Wet2014 sample. Even if there is a ``k141_41392`` in Dry2014, the actual contigs in the two samples are different. P13. dbcan_utils to calculate the abundance of CAZyme families, subfamilies, CGCs, and substrates (TIMING ~1min) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. code-block:: shell - $ dbcan_utils CAZyme_abund -bt Wet2014.depth.txt -i ../Wet2014.dbCAN -a TPM - $ dbcan_utils CAZymeSub_abund -bt Wet2014.depth.txt -i ../Wet2014.dbCAN -a TPM - $ dbcan_utils PUL_abund -bt Wet2014.depth.txt -i ../Wet2014.dbCAN -a TPM - $ dbcan_utils PULSub_abund -bt Wet2014.depth.txt -i ../Wet2014.dbCAN -a TPM + dbcan_utils fam_abund -bt Wet2014.depth.txt -i ../Wet2014.dbCAN -a TPM + dbcan_utils fam_substrate_abund -bt Wet2014.depth.txt -i ../Wet2014.dbCAN -a TPM + dbcan_utils CGC_abund -bt Wet2014.depth.txt -i ../Wet2014.dbCAN -a TPM + dbcan_utils CGC_substrate_abund -bt Wet2014.depth.txt -i ../Wet2014.dbCAN -a TPM - $ cd .. && cd Dry2014_abund - $ dbcan_utils CAZyme_abund -bt Dry2014.depth.txt -i ../Dry2014.dbCAN -a TPM - $ dbcan_utils CAZymeSub_abund -bt Dry2014.depth.txt -i ../Dry2014.dbCAN -a TPM - $ dbcan_utils PUL_abund -bt Dry2014.depth.txt -i ../Dry2014.dbCAN -a TPM - $ dbcan_utils PULSub_abund -bt Dry2014.depth.txt -i ../Dry2014.dbCAN -a TPM + cd .. && cd Dry2014_abund + dbcan_utils fam_abundfam_substrate_abund -bt Dry2014.depth.txt -i ../Dry2014.dbCAN -a TPM + dbcan_utils fam_substrate_abund -bt Dry2014.depth.txt -i ../Dry2014.dbCAN -a TPM + dbcan_utils CGC_abund -bt Dry2014.depth.txt -i ../Dry2014.dbCAN -a TPM + dbcan_utils CGC_substrate_abund -bt Dry2014.depth.txt -i ../Dry2014.dbCAN -a TPM cd .. -We developed a set of Python scripts as dbcan_utils to take the raw read counts for all CDS as input and output the normalized abundances (Box 8) of CAZyme families, subfamilies, CGCs, and substrates (Figure 4). The parameter -a TPM can also be two other metrics: RPM, or FPKM. -Box 8. Example output of dbcan_utils -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +We developed a set of Python scripts as ``dbcan_utils`` (included in the ``run_dbcan`` package) to take the raw read counts for all genes as input and output the normalized abundances (refer to Box 7) of CAZyme families, subfamilies, CGCs, and substrates (see Fig. 4). The parameter ``-a TPM`` can also be set to two other metrics: RPM, or RPKM61. - Executing these commands will yield five distinct files for each sample: CAZyme_abund_output, - PUL_abund_output, CAZymeSub_abund_output, PULSub_abund_output.major_voting, and PULSub_abund_output.homo. - These files encompass the abundance of CAZyme, CGC, and substrates within the respective samples, - providing detailed information. Notably, users can conveniently trace back the abundance of these entities. - The abundance calculations adhere to the TPM definition. +- **RPKM** is calculated as the number of mapped reads to a gene G divided by [(total number of mapped reads to all genes / 10^6) x (gene G length / 1000)]. +- **RPM** is the number of mapped reads to a gene G divided by (total number of mapped reads to all genes / 10^6). +- **TPM** is calculated as [number of mapped reads to a gene G / (gene G length / 1000)] divided by the sum of [number of mapped reads to each gene / (the gene length / 1000)]. -Module 4: dbcan_plot for data visualization (Figure 3) of abundances of CAZymes, CGCs, and substrates (TIMING variable) ------------------------------------------------------------------------------------------------------------------------ -To visualize the CAZyme annotation result, we provide a set of Python scripts as dbcan_plot to make publication quality plots with the dbcan_utils results as the input. The dbcan_plot scripts can be installed with commands as follows: +Box 7. Example output of dbcan_utils +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +As an example, the Wet2014_abund folder (https://bcb.unl.edu/dbCAN_tutorial/dataset1-Carter2023/individual_assembly/Wet2014_abund/) has 7 TSV files: .. code-block:: shell - $ python3 setup.py install + -rw-rw-r-- 1 jinfang jinfang 201106 Dec 31 01:58 CGC_abund.out + -rw-rw-r-- 1 jinfang jinfang 2204 Dec 31 01:58 CGC_substrate_majority_voting.out + -rw-rw-r-- 1 jinfang jinfang 16282 Dec 31 01:58 CGC_substrate_PUL_homology.out + -rw-rw-r-- 1 jinfang jinfang 2695 Dec 31 01:58 EC_abund.out + -rw-rw-r-- 1 jinfang jinfang 3949 Dec 31 01:58 fam_abund.out + -rw-rw-r-- 1 jinfang jinfang 44138 Dec 31 01:58 fam_substrate_abund.out + -rw-rw-r-- 1 jinfang jinfang 27314 Dec 31 01:58 subfam_abund.out + -rw-rw-r-- 1 jinfang jinfang 270535 Dec 31 02:43 Wet2014.cgc.depth.txt + +Explanation of columns in these TSV files is as follows: + + - ``fam_abund.out``: CAZy family (from HMMER vs dbCAN HMMdb), sum of TPM, number of CAZymes in the family. + - ``subfam_abund.out``: eCAMI subfamily (from HMMER vs dbCAN-sub HMMdb), sum of TPM, number of CAZymes in the subfamily. + - ``EC_abund.out``: EC number (extracted from dbCAN-sub subfamily), sum of TPM, number of CAZymes with the EC. + - ``fam_substrate_abund.out``: Substrate (from HMMER vs dbCAN-sub HMMdb), sum of TPM (all CAZymes in this substrate group), GeneID (all CAZyme IDs in this substrate group). + - ``CGC_abund.out``: CGC_ID (e.g., k141_338400|CGC1), mean of TPM (all genes in the CGC), Seq_IDs (IDs of all genes in the CGC), TPM (of all genes in the CGC), Families (CAZyme family or other signature gene type of all genes in the CGC). + - ``CGC_substrate_PUL_homology.out``: Substrate (from dbCAN-PUL blast search), sum of TPM, CGC_IDs (all CGCs predicted to have the substrate from dbCAN-PUL blast search), TPM (of CGCs in this substrate group). + - ``CGC_substrate_majority_voting.out``: Substrate (from dbCAN-sub majority voting), sum of TPM, CGC_IDs (all CGCs predicted to have the substrate from dbCAN-sub majority voting), TPM (of CGCs in this substrate group). + +.. warning:: + As shown in Fig. 2 (step3), proteins from multiple samples can be combined to generate a non-redundant set of proteins (Box 8). This may reduce the runtime for the run_dbcan step (step4), as only one faa file will be processed. However, this does not work for the CGC prediction, as contigs (fna files) from each sample will be needed. Therefore, this step is recommended if users only want the CAZyme annotation, and not recommended if CGCs are also to be predicted. + +Module 4: dbcan_plot for data visualization (Fig. 2) of abundances of CAZymes, CGCs, and substrates (TIMING variable) +````````````````````````````````````````````````````````````````````````````````````````````````````````````````````` +**CRITICAL STEP** -In addition to the two abundance folders Wet2014_abund and Dry2014_abund, the two CAZyme annotation folders Wet2014.dbCAN and Dry2014.dbCAN, are also needed well as two abundance folders Wet2014_abund. +To visualize the CAZyme annotation result, we provide a set of Python scripts as ``dbcan_plot`` to make publication-quality plots with the ``dbcan_utils`` results as the input. The ``dbcan_plot`` scripts are included in the ``run_dbcan`` package. Once the plots are made in PDF format, they can be transferred to users' Windows or Mac computers for visualization. -P14. Heatmap for CAZyme substrate abundance across samples (Figure 6A) (TIMING ~xx) +Five data folders will be needed as the input for ``dbcan_plot``: + +1. Two abundance folders: ``Wet2014_abund`` and ``Dry2014_abund``. +2. Two CAZyme annotation folders: ``Wet2014.dbCAN`` and ``Dry2014.dbCAN``. +3. The ``dbCAN-PUL`` folder (located under the db folder, released from ``dbCAN-PUL.tar.gz``). + + + +P14. Heatmap for CAZyme substrate abundance across samples (Fig. 6A) (TIMING 1min) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. code-block:: shell - $ dbcan_plot heatmap_plot --samples Wet2014,Dry2014 -i Wet2014_abund/CAZymeSub_abund_output,Dry2014_abund/CAZymeSub_abund_output --show_abund --top 20 + dbcan_plot heatmap_plot --samples Wet2014,Dry2014 -i Wet2014_abund/fam_substrate_abund.out, Dry2014_abund/fam_substrate_abund.out --show_abund --top 20 -Here we plot the top 20 substrates in the two samples. -The input files are the two CAZyme substrate abundance files calculated based on dbCAN-sub result. -The default heatmap is ranked by substrate abundances. -To rank the heatmap according to abundance profile using the xxx clustering algorithm, -users can invoke the `--cluster_map` parameter. +Here we plot the top 20 substrates in the two samples (Fig. 6A). The input files are the two CAZyme substrate abundance files calculated based on +dbCAN-sub result. The default heatmap is ranked by substrate abundances. To rank the heatmap according to abundance profile using +the clustermap function of the seaborn package (https://github.com/mwaskom/seaborn), users can invoke the ``--cluster_map`` parameter. -P15. Barplot for CAZyme substrate abundance across samples (Figure 6B) (TIMING ~xx) -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +P15. Barplot for CAZyme family/subfamily/EC abundance across samples (Fig. 6B,C) (TIMING 1min) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. code-block:: shell - $ dbcan_plot bar_plot --samples Wet2014,Dry2014 --vertical_bar --top 20 -i Wet2014_abund/CAZyme_abund_output,Dry2014_abund/CAZyme_abund_output + dbcan_plot bar_plot --samples Wet2014,Dry2014 --vertical_bar --top 20 -i Wet2014_abund/fam_abund.out,Dry2014_abund/fam_abund.out + dbcan_plot bar_plot --samples Wet2014,Dry2014 --vertical_bar --top 20 -i Wet2014_abund/subfam_abund.out,Dry2014_abund/subfam_abund.out -Users can choose to generate a barplot instead of heatmap using the bar_plot method. +Users can choose to generate a barplot instead of heatmap using the bar_plot method. -P16. Synteny plot between a CGC and its best PUL hit with read mapping coverage to CGC (Figure 6C) (TIMING ~xx) +P16. Synteny plot between a CGC and its best PUL hit with read mapping coverage to CGC (Fig. 6D) (TIMING 1min) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. code-block:: shell - $ dbcan_plot CGC_syntenic_with_PUL_abund -i Wet2014.dbCAN --cgcid 'k141_41392|CGC3' --readscount Wet2014_abund/Wet2014.cgc.depth.txt + dbcan_plot CGC_synteny_coverage_plot -i Wet2014.dbCAN --cgcid 'k141_41392|CGC3' --readscount Wet2014_abund/Wet2014.cgc.depth.txt -The Wet2014.dbCAN folder contains the PUL.out file. Using this file, the cgc_standard.out file, and the best PUL’s gff file in dbCAN-PUL.tar.gz, the CGC_synteny_plot method will create the CGC-PUL synteny plot. The –cgcid parameter is required to specify which CGC to be plotted (‘k141_41392|CGC3' in this example). The Wet2014.cgc.depth.txt file is used to plot the read mapping coverage. +The Wet2014.dbCAN folder contains the PUL.out file. Using this file, the cgc_standard.out file, and the best PUL's gff file in dbCAN-PUL.tar.gz, the CGC_synteny_plot method will create the CGC-PUL synteny plot. The –cgcid parameter is required to specify which CGC to plot (k141_41392|CGC3 in this example). The Wet2014.cgc.depth.txt file is used to plot the read mapping coverage. If users only want to plot the CGC structure: .. code-block:: shell - $ dbcan_plot CGC -i Wet2014.dbCAN --cgcid 'k141_41392|CGC3' + dbcan_plot CGC_plot -i Wet2014.dbCAN --cgcid 'k141_41392|CGC3' If users only want to plot the CGC structure plus the read mapping coverage: .. code-block:: shell - $ dbcan_plot CGC_abund -i Wet2014.dbCAN --cgcid 'k141_41392|CGC3' --readscount Wet2014_abund/Wet2014.cgc.depth.txt + dbcan_plot CGC_coverage_plot -i Wet2014.dbCAN --cgcid 'k141_41392|CGC3' --readscount Wet2014_abund/Wet2014.cgc.depth.txt If users only want to plot the synteny between the CGC and PUL: .. code-block:: shell - $ dbcan_plot CGC_syntenic_with_PUL -i Wet2014.dbCAN --cgcid 'k141_41392|CGC3' + dbcan_plot CGC_synteny_plot -i Wet2014.dbCAN --cgcid 'k141_41392|CGC3' .. warning:: - The CGC IDs in different samples do not match each other. For example, specifying -i Wet2014.dbCAN is to plot the `k141_41392|CGC3`` in the Wet2014 sample. The `k141_41392|CGC3`` in the Dry2014 sample will be different. + The CGC IDs in different samples do not match each other. For example, specifying -i Wet2014.dbCAN is to plot the 'k141_41392|CGC3' in the Wet2014 sample. The 'k141_41392|CGC3' in the Dry2014 sample most likely does not exist, and even it does, the CGC has a different sequence even if the ID is the same. + + +Troubleshooting +--------------- + +We provide Table 3 to list possible issues and solutions. Users can also post issues on run_dbcan GitHub site. + +Procedure Timing +---------------- + +The estimated time for completing each step of the protocol on the Carter2023 dataset is as follows: + +- **Step P1. Contamination checking**: Approximately 10 minutes. +- **Step P2. Raw reads processing**: Approximately 20 minutes. +- **Step P3. Metagenome assembly**: Approximately 4 hours and 20 minutes. +- **Step P4. Gene models prediction**: Approximately 21 hours. +- **Step P5. CAZyme annotation**: Approximately 10 minutes. +- **Step P6. PUL prediction**: Approximately 15 minutes. +- **Step P7. Substrate prediction for CAZyme and PUL**: Approximately 5 hours. +- **Step P8-P12. Reads mapping**: Approximately 52 minutes. +- **Step P13. Abundance estimation**: Approximately 1 minute. +- **Step P14-P16. Data visualization**: Approximately 3 minutes. + +Running this protocol on a Linux computer with 40 CPUs and 128GB of RAM is estimated to take approximately 33 hours. The most time-consuming step is P4 (Prokka gene prediction), which can be replaced by Prodigal59 for protein prediction to save time. The second most time-consuming step is P7 (substrate prediction for CGCs and CAZymes). Omitting substrate prediction reduces this step's time to about 15 minutes. The highest RAM usage is likely during P3 (read assembly), although specific RAM usage was not monitored during the protocol execution. diff --git a/docs/user_guide/run_from_raw_reads_ex.rst b/docs/user_guide/run_from_raw_reads_ex.rst new file mode 100644 index 000000000..bec216f1b --- /dev/null +++ b/docs/user_guide/run_from_raw_reads_ex.rst @@ -0,0 +1,546 @@ +More examples: Run from Raw Reads +================================= + +.. _wastyk_2021: + +Example 2: Wastyk2021 Dataset :cite:`2021:Wastyk` +------------------------------------------------- + +The Wastyk2021 dataset :cite:`2021:Wastyk` was published in 20211 from a human dietary intervention study. In the published paper, researchers studied how high-fermented and high-fiber diets influence the human microbiome metabolism and modulate the human immune status. Among various data analyses conducted in the paper1, CAZymes were mined from shotgun metagenomic reads of 18 healthy human participants, and each participant had four time points of stool samples for metagenome sequencing. CAZyme abundance profiles were compared before and after the high-fiber intervention (baseline vs high-fiber). One of the main findings from their CAZyme analysis was that high-fiber consumption increased the CAZyme abundance. For this protocol, we will select two samples (paired-end 2x146bp reads) of two time points (day 2 before high-fiber diet as baseline, and 10 weeks after high-fiber diet as intervention) from one participant (Table S2). The protocol is for the individual sample route (Fig. 3). + +The raw read data, intermediate data from each analysis step, and final result data and visualization files are organized in nested folders available on our website https://bcb.unl.edu/dbCAN_tutorial/dataset2-Wastyk2021/, Fig. 5) and https://dbcan.readthedocs.io. + +Procedure +--------- + +Module 1: Reads processing (Fig. 3) to obtain contigs +````````````````````````````````````````````````````` + +P1. Contamination Check (TIMING ~10min) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Download the Wastyk2021 dataset: + +.. code-block:: shell + + wget https://bcb.unl.edu/dbCAN_tutorial/dataset2-Wastyk2021/fefifo_8022_1__shotgun_1.fastq.gz + wget https://bcb.unl.edu/dbCAN_tutorial/dataset2-Wastyk2021/fefifo_8022_1__shotgun_2.fastq.gz + wget https://bcb.unl.edu/dbCAN_tutorial/dataset2-Wastyk2021/fefifo_8022_7__shotgun_1.fastq.gz + wget https://bcb.unl.edu/dbCAN_tutorial/dataset2-Wastyk2021/fefifo_8022_7__shotgun_2.fastq.gz + +Use `kraken2` to check for contaminated reads: + +.. code-block:: shell + + kraken2 --threads 32 --quick --paired --db K2 --report fefifo_8022_1.kreport --output fefifo_8022_1.kraken.output fefifo_8022_1__shotgun_1.fastq.gz fefifo_8022_1__shotgun_2.fastq.gz + kraken2 --threads 32 --quick --paired --db K2 --report fefifo_8022_7.kreport --output fefifo_8022_7.kraken.output fefifo_8022_7__shotgun_1.fastq.gz fefifo_8022_7__shotgun_2.fastq.gz + +Kraken2 found very little contamination in the data. Consequently, there was no need for the contamination removal step. + +If contamination is identified, users can align the reads to the reference genomes of potential contamination source organisms to remove +the aligned reads (Box 1). The most common source in human microbiome studies is from human hosts. + +Box 1: Example to remove contamination reads from human +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Kraken2 will produce the following output files: + + .. code-block:: shell + + -rw-rw-r-- 1 jinfang jinfang 1.1G Sep 21 23:17 fefifo_8022_1.kraken.output + -rw-rw-r-- 1 jinfang jinfang 991K Sep 21 23:19 fefifo_8022_1.kreport + -rw-rw-r-- 1 jinfang jinfang 574M Sep 21 23:21 fefifo_8022_7.kraken.output + -rw-rw-r-- 1 jinfang jinfang 949K Sep 21 23:22 fefifo_8022_7.kreport + + + Suppose from these files, we have identified humans as the contamination source, we can use the following commands to remove the contamination reads by aligning reads to the human reference genome. + + .. code-block:: shell + + wget https://ftp.ensembl.org/pub/release-110/fasta/homo_sapiens/dna/Homo_sapiens.GRCh38.dna.primary_assembly.fa.gz + bwa index -p hg38 Homo_sapiens.GRCh38.dna.primary_assembly.fa.gz + bwa mem hg38 fefifo_8022_1__shotgun_1.fastq.gz fefifo_8022_1__shotgun_2.fastq.gz -t 32 -o fefifo_8022_1.hg38.sam + bwa mem hg38 fefifo_8022_7__shotgun_1.fastq.gz fefifo_8022_7__shotgun_2.fastq.gz -t 32 -o fefifo_8022_7.hg38.sam + samtools view -f 12 fefifo_8022_1.hg38.sam > fefifo_8022_1.hg38.unmap.bam + samtools view -f 12 fefifo_8022_7.hg38.sam > fefifo_8022_7.hg38.unmap.bam + samtools fastq -1 fefifo_8022_1_1.clean.fq.gz -2 fefifo_8022_1_2.clean.fq.gz fefifo_8022_1.hg38.unmap.bam + samtools fastq -1 fefifo_8022_7_1.clean.fq.gz -2 fefifo_8022_7_2.clean.fq.gz fefifo_8022_7.hg38.unmap.bam + +P2. Trim adapter and low-quality reads (TIMING ~20min) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: shell + + trim_galore --paired fefifo_8022_1__shotgun_1.fastq.gz fefifo_8022_1__shotgun_2.fastq.gz --illumina -j 36 + trim_galore --paired fefifo_8022_7__shotgun_1.fastq.gz fefifo_8022_7__shotgun_2.fastq.gz --illumina -j 36 + +We specified --illumina to indicate that the reads were generated using the Illumina sequencing platform. +Nonetheless, trim_galore can automatically detect adapters, providing flexibility for users who may know the specific sequencing platform. +Details of trimming are available in the trimming report file (Box 2). + +Box 2: Example output of `trim_galore` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + In addition to the trimmed read files, `Trim_galore`` also generates a trimming report file. + The trimming report contains details on read trimming, such as the number of trimmed reads. + + .. code-block:: shell + + -rw-rw-r-- 1 jinfang jinfang 429M Oct 30 22:44 fefifo_8022_1__shotgun_1.fastq.gz + -rw-rw-r-- 1 jinfang jinfang 4.1K Oct 31 05:15 fefifo_8022_1__shotgun_1.fastq.gz_trimming_report.txt + -rw-rw-r-- 1 jinfang jinfang 390M Oct 31 05:16 fefifo_8022_1__shotgun_1_val_1.fq.gz + -rw-rw-r-- 1 jinfang jinfang 540M Oct 30 22:44 fefifo_8022_1__shotgun_2.fastq.gz + -rw-rw-r-- 1 jinfang jinfang 4.2K Oct 31 05:16 fefifo_8022_1__shotgun_2.fastq.gz_trimming_report.txt + -rw-rw-r-- 1 jinfang jinfang 499M Oct 31 05:16 fefifo_8022_1__shotgun_2_val_2.fq.gz + -rw-rw-r-- 1 jinfang jinfang 931M Oct 30 22:34 fefifo_8022_7__shotgun_1.fastq.gz + -rw-rw-r-- 1 jinfang jinfang 4.2K Oct 31 05:17 fefifo_8022_7__shotgun_1.fastq.gz_trimming_report.txt + -rw-rw-r-- 1 jinfang jinfang 861M Oct 31 05:20 fefifo_8022_7__shotgun_1_val_1.fq.gz + -rw-rw-r-- 1 jinfang jinfang 1.1G Oct 30 22:34 fefifo_8022_7__shotgun_2.fastq.gz + -rw-rw-r-- 1 jinfang jinfang 4.4K Oct 31 05:20 fefifo_8022_7__shotgun_2.fastq.gz_trimming_report.txt + -rw-rw-r-- 1 jinfang jinfang 1003M Oct 31 05:20 fefifo_8022_7__shotgun_2_val_2.fq.gz + +.. warning:: + + During the trimming process, certain reads may be entirely removed due to low quality in its entirety. + Using the ``--retain_unpaired`` parameter in ``trim_galore`` allows for the preservation of single-end reads. + In this protocol, this option was not selected, so that both reads of a forward-revise pair were removed. + +P3. Assemble reads into contigs (TIMING ~84min) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Use Megahit for assembling reads into contigs: + +.. code-block:: shell + + megahit -m 0.5 -t 32 -o megahit_fefifo_8022_1 -1 fefifo_8022_1__shotgun_1_val_1.fq.gz -2 fefifo_8022_1__shotgun_2_val_2.fq.gz --out-prefix fefifo_8022_1 --min-contig-len 1000 + megahit -m 0.5 -t 32 -o megahit_fefifo_8022_7 -1 fefifo_8022_7__shotgun_1_val_1.fq.gz -2 fefifo_8022_7__shotgun_2_val_2.fq.gz --out-prefix fefifo_8022_7 --min-contig-len 1000 + + +`MEGAHIT` generates two output folders `megahit_fefifo_8022_1` and `megahit_fefifo_8022_7`. +Each contains five files and one sub-folder (Box 3). `fefifo_8022_1.contigs.fa` is the final contig sequence file. +We set `--min-contig-len 1000`, a common practice to retain all contigs longer than 1,000 base pairs. + +Box 3: Example output of `MEGAHIT` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. code-block:: shell + + -rw-rw-r-- 1 jinfang jinfang 262 Oct 31 05:49 checkpoints.txt + -rw-rw-r-- 1 jinfang jinfang 0 Oct 31 05:49 done + -rw-rw-r-- 1 jinfang jinfang 97M Oct 31 05:49 fefifo_8022_1.contigs.fa + -rw-rw-r-- 1 jinfang jinfang 149K Oct 31 05:49 fefifo_8022_1.log + drwxrwxr-x 2 jinfang jinfang 4.0K Oct 31 05:49 intermediate_contigs + -rw-rw-r-- 1 jinfang jinfang 1.1K Oct 31 05:27 options.json + + +P4. Predict genes by `Prokka` (TIMING ~40h) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: shell + + prokka --kingdom Bacteria --cpus 36 --outdir prokka_fefifo_8022_1 --prefix fefifo_8022_1 --addgenes --addmrna --locustag fefifo_8022_1 megahit_fefifo_8022_1/fefifo_8022_1.contigs.fa + prokka --kingdom Bacteria --cpus 36 --outdir prokka_fefifo_8022_7 --prefix fefifo_8022_7 --addgenes --addmrna --locustag fefifo_8022_7 megahit_fefifo_8022_7/fefifo_8022_7.contigs.fa + +The parameter `--kingdom Bacteria` is required for bacterial gene prediction. +To optimize performance, `--CPU 36` instructs the utilization of 36 computer processors. The output files comprise of both protein and CDS sequences in Fasta format (e.g., `fefifo_8022_1.faa` and `fefifo_8022_1.ffn` in Box 4). + +Box 4: Example output of `Prokka` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. code-block:: shell + + -rw-rw-r-- 1 jinfang jinfang 181 Oct 31 22:28 errorsummary.val + -rw-rw-r-- 1 jinfang jinfang 2.6M Oct 31 22:28 fefifo_8022_1.err + -rw-rw-r-- 1 jinfang jinfang 31M Oct 31 22:09 fefifo_8022_1.faa + -rw-rw-r-- 1 jinfang jinfang 83M Oct 31 22:09 fefifo_8022_1.ffn + -rw-rw-r-- 1 jinfang jinfang 22K Oct 31 22:21 fefifo_8022_1.fixedproducts + -rw-rw-r-- 1 jinfang jinfang 98M Oct 31 21:50 fefifo_8022_1.fna + -rw-rw-r-- 1 jinfang jinfang 99M Oct 31 22:09 fefifo_8022_1.fsa + -rw-rw-r-- 1 jinfang jinfang 222M Oct 31 22:24 fefifo_8022_1.gbf + -rw-rw-r-- 1 jinfang jinfang 142M Oct 31 22:09 fefifo_8022_1.gff + -rw-rw-r-- 1 jinfang jinfang 692K Oct 31 22:29 fefifo_8022_1.log + -rw-rw-r-- 1 jinfang jinfang 406M Oct 31 22:22 fefifo_8022_1.sqn + -rw-rw-r-- 1 jinfang jinfang 26M Oct 31 22:09 fefifo_8022_1.tbl + -rw-rw-r-- 1 jinfang jinfang 12M Oct 31 22:09 fefifo_8022_1.tsv + -rw-rw-r-- 1 jinfang jinfang 131 Oct 31 22:09 fefifo_8022_1.txt + -rw-rw-r-- 1 jinfang jinfang 145K Oct 31 22:24 fefifo_8022_1.val + +Module 2. run_dbcan annotation (Fig. 3) to obtain CAZymes, CGCs, and substrates +``````````````````````````````````````````````````````````````````````````````` + +**CRITICAL STEP** + +Users can skip P5 and P6, and directly run P7 (much slower though), if they want to predict not only CAZymes and CGCs, but also substrates. + +P5. CAZyme annotation at the CAZyme family level (TIMING ~10min) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: shell + + run_dbcan prokka_fefifo_8022_1/fefifo_8022_1.faa protein --hmm_cpu 32 --out_dir fefifo_8022_1.CAZyme --tools hmmer --db_dir db + run_dbcan prokka_fefifo_8022_7/fefifo_8022_7.faa protein --hmm_cpu 32 --out_dir fefifo_8022_7.CAZyme --tools hmmer --db_dir db + +Two arguments are required for ``run_dbcan``: the input sequence file (faa files) and the sequence type (protein). +By default, ``run_dbcan`` will use three methods (``HMMER`` vs ``dbCAN HMMdb``, ``DIAMOND`` vs ``CAZy``, ``HMMER`` vs ``dbCAN-sub HMMdb``) for +CAZyme annotation (Table 1, Fig. 2). This default setting is equivalent to the use ``--tools all`` parameter (Box 5). +Here we only invoke the ``HMMER`` vs ``dbCAN HMMdb`` for CAZyme annotation at the family level. + +Box 5: CAZyme annotation with default setting +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If the ``--tools`` parameter is not set, it defaults to the equivalent of ``--tools all``. +This setting will take a much longer time to finish (~5 hours) due to the large size of ``dbCAN-sub HMMdb`` +(used for substrate prediction for CAZymes, see Table 1). + +.. code-block:: shell + + run_dbcan prokka_fefifo_8022_1/fefifo_8022_1.faa protein --out_dir fefifo_8022_1.CAZyme --dia_cpu 32 --hmm_cpu 32 --dbcan_thread 32 [--tools all] + run_dbcan prokka_fefifo_8022_7/fefifo_8022_7.faa protein --out_dir fefifo_8022_7.CAZyme --dia_cpu 32 --hmm_cpu 32 --dbcan_thread 32 [--tools all] + + +The sequence type can be `protein`, `prok`, `meta`. If the input sequence file contains metagenomic contig sequences (`fna` file), +the sequence type has to be `meta`, and `prodigal` will be called to predict genes. + +.. code-block:: shell + + run_dbcan prokka_fefifo_8022_1/fefifo_8022_1.fna meta --out_dir fefifo_8022_1.CAZyme --dia_cpu 32 --hmm_cpu 32 --dbcan_thread 32 + run_dbcan prokka_fefifo_8022_7/fefifo_8022_7.fna meta --out_dir fefifo_8022_7.CAZyme --dia_cpu 32 --hmm_cpu 32 --dbcan_thread 32 + + +P6. CGC prediction (TIMING ~15 min) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The following commands will re-run run_dbcan to not only predict CAZymes but also CGCs with protein `faa` and gene location `gff` files. + +.. code-block:: shell + + run_dbcan prokka_fefifo_8022_1/fefifo_8022_1.faa protein --tools hmmer --tf_cpu 32 --stp_cpu 32 -c prokka_fefifo_8022_1/fefifo_8022_1.gff --out_dir fefifo_8022_1.PUL --dia_cpu 32 --hmm_cpu 32 + run_dbcan prokka_fefifo_8022_7/fefifo_8022_7.faa protein --tools hmmer --tf_cpu 32 --stp_cpu 32 -c prokka_fefifo_8022_7/fefifo_8022_7.gff --out_dir fefifo_8022_7.PUL --dia_cpu 32 --hmm_cpu 32 + +As mentioned above (see Table 1, Fig. 2), CGC prediction is a featured function added into dbCAN2 in 2018. +To identify CGCs with the protein sequence type, a gene location file (``gff``) must be provided together. If the input sequence type +is ``prok`` or ``meta``, meaning users only have contig ``fna`` files, the CGC prediction can be activated by setting the ``-c cluster`` parameter. + +.. warning:: + + **Creating own gff file** + If the users would like to create their own ``gff`` file (instead of using Prokka or Prodigal), + it is important to make sure the value of ID attribute in the ``gff`` file matches the protein ID in the protein ``faa`` file. + + **[Troubleshooting]CGC not found** + If no result is found in CGC output file, it is most likely because the sequence IDs in ``gff`` file and ``faa`` file do not match. + Another less likely reason is that the contigs are too short and fragmented and not suitable for CGC prediction. + + +P7. Substrate prediction for CAZymes and CGCs (TIMING ~5h) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The following commands will re-run run_dbcan to predict CAZymes, CGCs, and their substrates with the `--cgc_substrate` parameter. + +.. code-block:: shell + + run_dbcan prokka_fefifo_8022_1/fefifo_8022_1.faa protein --dbcan_thread 32 --tf_cpu 32 --stp_cpu 32 -c prokka_fefifo_8022_1/fefifo_8022_1.gff --cgc_substrate --hmm_cpu 32 --out_dir fefifo_8022_1.dbCAN --dia_cpu 32 + run_dbcan prokka_fefifo_8022_7/fefifo_8022_7.faa protein --dbcan_thread 32 --tf_cpu 32 --stp_cpu 32 -c prokka_fefifo_8022_7/fefifo_8022_7.gff --cgc_substrate --hmm_cpu 32 --out_dir fefifo_8022_7.dbCAN --dia_cpu 32 + +The above commands do not set the `--tools` parameter, which means all three methods for CAZyme annotation will be activated (Box 5). Because dbCAN-sub HMMdb (for CAZyme substrate prediction) is 200 times larger than dbCAN HMMdb, the runtime will be much longer. Users can specify `--tools hmmer`, so that the HMMER search against dbCAN-sub will be disabled. However, this will turn off the substrate prediction for CAZymes and CGCs based on CAZyme substrate majority voting. Consequently, the substrate prediction will be solely based on homology search against PULs in dbCAN-PUL (Fig. 1, Table 1). + +.. code-block:: shell + + run_dbcan prokka_fefifo_8022_1/fefifo_8022_1.faa protein --tools hmmer --stp_cpu 32 -c prokka_fefifo_8022_1/fefifo_8022_1.gff --cgc_substrate --out_dir fefifo_8022_1.PUL.Sub --dia_cpu 32 --hmm_cpu 32 --tf_cpu 32 + run_dbcan prokka_fefifo_8022_7/fefifo_8022_7.faa protein --tools hmmer --stp_cpu 32 -c prokka_fefifo_8022_7/fefifo_8022_7.gff --cgc_substrate --out_dir fefifo_8022_7.PUL.Sub --dia_cpu 32 --hmm_cpu 32 --tf_cpu 32 + + +Box 6. Example output folder content of run_dbcan substrate prediction +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + In the `fefifo_8022_1.dbCAN _` directory, a total of 17 files and 1 folder are generated: + + .. code-block:: shell + + -rw-rw-r-- 1 jinfang jinfang 39M Nov 1 22:18 PUL_blast.out + -rw-rw-r-- 1 jinfang jinfang 3.1M Nov 1 22:15 CGC.faa + -rw-rw-r-- 1 jinfang jinfang 6.9M Nov 1 22:15 cgc.gff + -rw-rw-r-- 1 jinfang jinfang 702K Nov 1 22:15 cgc.out + -rw-rw-r-- 1 jinfang jinfang 321K Nov 1 22:15 cgc_standard.out + -rw-rw-r-- 1 jinfang jinfang 1.5M Nov 1 22:15 cgc_standard.out.json + -rw-rw-r-- 1 jinfang jinfang 556K Nov 1 22:14 dbcan-sub.hmm.out + -rw-rw-r-- 1 jinfang jinfang 345K Nov 1 22:14 diamond.out + -rw-rw-r-- 1 jinfang jinfang 455K Nov 1 22:14 dtemp.out + -rw-rw-r-- 1 jinfang jinfang 298K Nov 1 22:14 hmmer.out + -rw-rw-r-- 1 jinfang jinfang 270K Nov 1 22:15 overview.txt + -rw-rw-r-- 1 jinfang jinfang 1.1M Nov 1 22:15 stp.out + -rw-rw-r-- 1 jinfang jinfang 54K Nov 1 22:18 substrate.out + drwxrwxr-x 2 jinfang jinfang 32K Nov 2 09:48 synteny.pdf + -rw-rw-r-- 1 jinfang jinfang 288K Nov 1 22:14 tf-1.out + -rw-rw-r-- 1 jinfang jinfang 237K Nov 1 22:14 tf-2.out + -rw-rw-r-- 1 jinfang jinfang 804K Nov 1 22:15 tp.out + -rw-rw-r-- 1 jinfang jinfang 31M Nov 1 21:07 uniInput + + + Descriptions of Output Files: + + - ``PUL_blast.out``: BLAST results between CGCs and PULs. + - ``CGC.faa``: CGC Fasta sequences. + - ``cgc.gff``: reformatted from the user input gff file by marking CAZymes, TFs, TCs, and STPs. + - ``cgc.out``: raw output of CGC predictions. + + 1. CGC_id: CGC1 + 2. type: CAZyme + 3. contig_id: k141_32617 + 4. gene_id: fefifo_8022_1_00137 + 5. start: 1755 + 6. end: 3332 + 7. strand: - + 8. annotation: GH13 + + **Explanation**: Explanation: the gene fefifo_8022_1_00137 encodes a GH13 CAZyme in the CGC1 of the contig k141_32617. CGC1 also has other genes, which are provided in other rows. fefifo_8022_1_00137 is on the negative strand of k141_32617 from 1755 to 3332. The type can be one of the four signature gene types (CAZymes, TCs, TFs, STPs) or the null type (not annotated as one of the four signature genes). + + - ``cgc_standard.out.json``: JSON format of cgc_standard.out. + - ``dbcan-sub.hmm.out``: HMMER search result against dbCAN-sub HMMdb, including a column with CAZyme substrates extracted from `fam-substrate-mapping-08012023.tsv`. + - ``diamond.out``: DIAMOND search result against the CAZy annotated protein sequences (`CAZyDB.07262023.fa`). + - ``dtemp.out``: temporary file. + - ``hmmer.out``: HMMER search result against dbCAN HMMdb. + - ``overview.txt``: summary of CAZyme annotation from three methods in TSV format. An example row has the following columns: + + 1. ``Gene_ID``: fefifo_8022_1_00719 + 2. ``EC#``: PL8_e13:2 + 3. ``dbCAN``: PL8_2(368-612) + 4. ``dbCAN_sub``: PL8_e13 + 5. ``DIAMOND``: PL8_2 + 6. ``#ofTools``: 3 + + **Explanation**: Explanation: the protein fefifo_8022_1_00719 is annotated by 3 tools to be a CAZyme: (1) PL8_2 (CAZy defined subfamily 2 of PL8) by HMMER vs dbCAN HMMdb with a domain range from aa position 368 to 612, (2) PL8_e13 (eCAMI defined subfamily e13; e indicates it is from eCAMI not CAZy) by HMMER vs dbCAN-sub HMMdb (derived from eCAMI subfamilies), and (3) PL8_2 by DIAMOND vs CAZy annotated protein sequences. The second column 4.2.2.20:2 is extracted from eCAMI, meaning that the eCAMI subfamily PL8_e13 contains two member proteins which have an EC 4.2.2.20 according to CAZy. In most cases, the 3 tools will have the same CAZyme family assignment. When they give different assignment. We recommend a preference order: dbCAN > eCAMI/dbCAN-sub > DIAMOND. See our dbCAN2 paper2, dbCAN3 paper3, and eCAMI4 for more details. + + **Note**: If users invoked the ``--use_signalP`` parameter when running run_dbcan, there will be an additional column called ``signalP`` in the overview.txt. + + - ``stp.out``: HMMER search result against the MiST5 compiled signal transduction protein HMMs from Pfam. + - ``tf-1.out``: HMMER search result against the DBD6 compiled transcription factor HMMs from Pfam 7. + - ``tf-2.out``: HMMER search result against the DBD compiled transcription factor HMMs from Superfamily 8. + - ``tp.out``: DIAMOND search result against the TCDB 9 annotated protein sequences. + - ``substrate.out``: summary of substrate prediction results for CGCs in TSV format from two approaches3 (dbCAN-PUL blast search and dbCAN-sub majority voting). An example row has the following columns: + + 1. ``CGC_ID``: k141_31366|CGC2 + 2. ``Best hit PUL_ID in dbCAN-PUL``: PUL0008 + 3. ``Substrate of the hit PUL``: fructan + 4. ``Sum of bitscores for homologous gene pairs between CGC and PUL``: 6132.0 + 5. ``Types of homologous gene pairs``: CAZyme-CAZyme;CAZyme-CAZyme;TC-TC;CAZyme-CAZyme;CAZyme-CAZyme;TC-TC + 6. ``Substrate predicted by majority voting of CAZymes in CGC``: fructan + 7. ``Voting score``: 2.0 + + **Explanation**: The CGC1 of contig ``k141_31366`` has its best hit ``PUL0008`` (from ``PUL_blast.out``) with fructan as substrate (from ``dbCAN-PUL_12-12-2023.xlsx``). Six signature genes are matched between ``k141_31366|CGC2 and PUL0008 (from PUL_blast.out)``: four are CAZymes and the other two are TCs. The sum of blast bitscores of the six homologous pairs (``CAZyme-CAZyme, CAZyme-CAZyme, TC-TC, CAZyme-CAZyme, CAZyme-CAZyme and TC-TC``) is 6132.0. Hence, the substrate of ``k141_31366|CGC2`` is predicted to be fructan according to dbCAN-PUL blast search. The last two columns are based on the dbCAN-sub result (``dbcan-sub.hmm.out``), according to which two CAZymes in ``k141_31366|CGC2`` are predicted to have fructan substrate. The voting score is thus 2.0, so that according to the majority voting rule, ``k141_31366|CGC2`` is predicted to have a fructan substrate. + + *Note*: : for many CGCs, only one of the two approaches produces substrate prediction. In some cases, the two approaches produce different substrate assignments. We recommend a preference order: ``dbCAN-PUL blast search > dbCAN-sub`` majority voting. See our `dbCAN3 _` :cite:`2023:dbCAN3` paper3 for more details. + + - ``synteny.pdf``: a folder with syntenic block alignment plots between all CGCs and PULs. + - ``uniInput``: renamed Fasta file from input protein sequence file. + + +Module 3. Read mapping (Fig. 3) to calculate abundance for CAZyme families, subfamilies, CGCs, and substrates +`````````````````````````````````````````````````````````````````````````````````````````````````````````````` + +P8. Read mapping to all CDS of each sample (TIMING ~10 min) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: shell + + bwa index prokka_fefifo_8022_1/fefifo_8022_1.ffn + bwa index prokka_fefifo_8022_7/fefifo_8022_7.ffn + mkdir samfiles + bwa mem -t 32 -o samfiles/fefifo_8022_1.CDS.sam prokka_fefifo_8022_1/fefifo_8022_1.ffn fefifo_8022_1__shotgun_1_val_1.fq.gz fefifo_8022_1__shotgun_2_val_2.fq.gz + bwa mem -t 32 -o samfiles/fefifo_8022_7.CDS.sam prokka_fefifo_8022_7/fefifo_8022_7.ffn fefifo_8022_7__shotgun_1_val_1.fq.gz fefifo_8022_7__shotgun_2_val_2.fq.gz + + +Reads are mapped to the ``ffn`` files from Prokka. + + +P9. Read mapping to all contigs of each sample (TIMING ~10min) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: shell + + bwa index megahit_fefifo_8022_1/fefifo_8022_1.contigs.fa + bwa index megahit_fefifo_8022_7/fefifo_8022_7.contigs.fa + bwa mem -t 32 -o samfiles/fefifo_8022_1.sam megahit_fefifo_8022_1/fefifo_8022_1.contigs.fa fefifo_8022_1__shotgun_1_val_1.fq.gz fefifo_8022_1__shotgun_2_val_2.fq.gz + bwa mem -t 32 -o samfiles/fefifo_8022_7.sam megahit_fefifo_8022_7/fefifo_8022_7.contigs.fa fefifo_8022_7__shotgun_1_val_1.fq.gz fefifo_8022_7__shotgun_2_val_2.fq.gz + + +Reads are mapped to the `contig` files from MEGAHIT. + +P10. Sort SAM files by coordinates (TIMING ~6min) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: shell + + cd samfiles + samtools sort -@ 32 -o fefifo_8022_1.CDS.bam fefifo_8022_1.CDS.sam + samtools sort -@ 32 -o fefifo_8022_7.CDS.bam fefifo_8022_7.CDS.sam + samtools sort -@ 32 -o fefifo_8022_1.bam fefifo_8022_1.sam + samtools sort -@ 32 -o fefifo_8022_7.bam fefifo_8022_7.sam + rm -rf *sam + cd .. + + +P11. Read count calculation for all proteins of each sample using Bedtools (TIMING ~1min) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: shell + + mkdir fefifo_8022_1_abund && cd fefifo_8022_1_abund + seqkit fx2tab -l -n -i ../prokka_fefifo_8022_1/fefifo_8022_1.ffn | awk '{print $1"\t"$2}' > fefifo_8022_1.length + seqkit fx2tab -l -n -i ../prokka_fefifo_8022_1/fefifo_8022_1.ffn | awk '{print $1"\t"0"\t"$2}' > fefifo_8022_1.bed + bedtools coverage -g fefifo_8022_1.length -sorted -a fefifo_8022_1.bed -counts -b ../samfiles/fefifo_8022_1.CDS.bam > fefifo_8022_1.depth.txt + + cd .. && mkdir fefifo_8022_7_abund && cd fefifo_8022_7_abund + seqkit fx2tab -l -n -i ../prokka_fefifo_8022_7/fefifo_8022_7.ffn | awk '{print $1"\t"$2}' > fefifo_8022_7.length + seqkit fx2tab -l -n -i ../prokka_fefifo_8022_7/fefifo_8022_7.ffn | awk '{print $1"\t"0"\t"$2}' > fefifo_8022_7.bed + bedtools coverage -g fefifo_8022_7.length -sorted -a fefifo_8022_7.bed -counts -b ../samfiles/fefifo_8022_7.CDS.bam > fefifo_8022_7.depth.txt + cd .. + + +Read counts are saved in ``depth.txt`` files of each sample. + + +P12. Read count calculation for a given region of contigs using Samtools (TIMING ~1min) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: shell + + cd fefifo_8022_1_abund + samtools index ../samfiles/fefifo_8022_1.bam + samtools depth -r k141_2168:4235-19858 ../samfiles/fefifo_8022_1.bam > fefifo_8022_1.cgc.depth.txt + cd .. + + +The parameter ``-r k141_2168:4235-19858`` specifies a region in a contig. For any CGC, its positional range can be found in the file ``cgc_standard.out`` produced by run_dbcan (Box 6). The ``depth.txt`` files contain the raw read counts for the specified region. + + +.. warning:: + + The contig IDs are automatically generated by MEGAHIT. There is a small chance that a same contig ID appears in both samples. However, the two contigs in the two samples do not match each other even the ID is the same. For example, the contig ID ``k141_2168`` is most likely only found in the ``fefifo_8022_1`` sample. Even if there is a ``k141_2168`` in ``fefifo_8022_7``, the actual contigs in two samples are different. + +P13. dbcan_utils to calculate the abundance of CAZyme families, subfamilies, CGCs, and substrates (TIMING ~1min) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: shell + + dbcan_utils fam_abund -bt fefifo_8022_1.depth.txt -i ../fefifo_8022_1.dbCAN -a TPM + dbcan_utils fam_substrate_abund -bt fefifo_8022_1.depth.txt -i ../fefifo_8022_1.dbCAN -a TPM + dbcan_utils CGC_abund -bt fefifo_8022_1.depth.txt -i ../fefifo_8022_1.dbCAN -a TPM + dbcan_utils CGC_substrate_abund -bt fefifo_8022_1.depth.txt -i ../fefifo_8022_1.dbCAN -a TPM + + cd .. && cd fefifo_8022_7_abund + dbcan_utils fam_abundfam_substrate_abund -bt fefifo_8022_7.depth.txt -i ../fefifo_8022_7.dbCAN -a TPM + dbcan_utils fam_substrate_abund -bt fefifo_8022_7.depth.txt -i ../fefifo_8022_7.dbCAN -a TPM + dbcan_utils CGC_abund -bt fefifo_8022_7.depth.txt -i ../fefifo_8022_7.dbCAN -a TPM + dbcan_utils CGC_substrate_abund -bt fefifo_8022_7.depth.txt -i ../fefifo_8022_7.dbCAN -a TPM + cd .. + + +We developed a set of Python scripts as ``dbcan_utils`` (included in the ``run_dbcan`` package) to take the raw read counts for all genes as input and output the normalized abundances (refer to Box 7) of CAZyme families, subfamilies, CGCs, and substrates (see Fig. 4). The parameter ``-a TPM`` can also be set to two other metrics: RPM, or RPKM61. + +- **RPKM** is calculated as the number of mapped reads to a gene G divided by [(total number of mapped reads to all genes / 10^6) x (gene G length / 1000)]. +- **RPM** is the number of mapped reads to a gene G divided by (total number of mapped reads to all genes / 10^6). +- **TPM** is calculated as [number of mapped reads to a gene G / (gene G length / 1000)] divided by the sum of [number of mapped reads to each gene / (the gene length / 1000)]. + + +Box 7. Example output of dbcan_utils +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +As an example, `fefifo_8022_1_abund _` folder has 7 TSV files: + +.. code-block:: shell + + -rw-rw-r-- 1 jinfang jinfang 178K Jan 2 04:08 CGC_abund.out + -rw-rw-r-- 1 jinfang jinfang 3.3K Jan 2 04:08 CGC_substrate_majority_voting.out + -rw-rw-r-- 1 jinfang jinfang 12K Jan 2 04:08 CGC_substrate_PUL_homology.out + -rw-rw-r-- 1 jinfang jinfang 2.5K Jan 2 04:08 EC_abund.out + -rw-rw-r-- 1 jinfang jinfang 4.1K Jan 2 04:08 fam_abund.out + -rw-rw-r-- 1 jinfang jinfang 42K Jan 2 04:08 fam_substrate_abund.out + -rw-rw-r-- 1 jinfang jinfang 26K Jan 2 04:08 subfam_abund.out + +Explanation of columns in these TSV files is as follows: + + - ``fam_abund.out``: CAZy family (from HMMER vs dbCAN HMMdb), sum of TPM, number of CAZymes in the family. + - ``subfam_abund.out``: eCAMI subfamily (from HMMER vs dbCAN-sub HMMdb), sum of TPM, number of CAZymes in the subfamily. + - ``EC_abund.out``: EC number (extracted from dbCAN-sub subfamily), sum of TPM, number of CAZymes with the EC. + - ``fam_substrate_abund.out``: Substrate (from HMMER vs dbCAN-sub HMMdb), sum of TPM (all CAZymes in this substrate group), GeneID (all CAZyme IDs in this substrate group). + - ``CGC_abund.out``: CGC_ID (e.g., k141_338400|CGC1), mean of TPM (all genes in the CGC), Seq_IDs (IDs of all genes in the CGC), TPM (of all genes in the CGC), Families (CAZyme family or other signature gene type of all genes in the CGC). + - ``CGC_substrate_PUL_homology.out``: Substrate (from dbCAN-PUL blast search), sum of TPM, CGC_IDs (all CGCs predicted to have the substrate from dbCAN-PUL blast search), TPM (of CGCs in this substrate group). + - ``CGC_substrate_majority_voting.out``: Substrate (from dbCAN-sub majority voting), sum of TPM, CGC_IDs (all CGCs predicted to have the substrate from dbCAN-sub majority voting), TPM (of CGCs in this substrate group). + + +Module 4: dbcan_plot for data visualization (Fig. 3) of abundances of CAZymes, CGCs, and substrates (TIMING variable) +````````````````````````````````````````````````````````````````````````````````````````````````````````````````````` + +**CRITICAL STEP** + +To visualize the CAZyme annotation result, we provide a set of Python scripts as dbcan_plot to make publication quality plots with the dbcan_utils results as the input. The dbcan_plot scripts are included in the run_dbcan package. Once the plots are made in PDF format, they can be transferred to users' Windows or Mac computers for visualization. + +Five data folders will be needed as the input for ``dbcan_plot``: + +1. two abundance folders ``fefifo_8022_1_abund`` and ``fefifo_8022_7_abund``, +2. two CAZyme annotation ``folders fefifo_8022_1.dbCAN`` and ``fefifo_8022_7.dbCAN``, and +3. the ``dbCAN-PUL folder`` (under the db folder, released from ``dbCAN-PUL.tar.gz``). + +P14. Heatmap for CAZyme substrate abundance across samples (Fig. S4B) (TIMING 1min) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: shell + + dbcan_plot heatmap_plot --samples fefifo_8022_1,fefifo_8022_7 -i fefifo_8022_1_abund/ fam_substrate_abund.out, fefifo_8022_7_abund/fam_substrate_abund.out --show_abund --top 20 + + +Here we plot the top 20 substrates in the two samples. The input files are the two CAZyme substrate abundance files calculated based on dbCAN-sub result. The default heatmap is ranked by substrate abundances. To rank the heatmap according to abundance profile using the function clustermap of seaborn package, users can invoke the ``--cluster_map`` parameter. + +P15. Barplot for CAZyme family/subfamily/EC abundance across samples (Fig. S4C) (TIMING 1min) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: shell + + dbcan_plot bar_plot --samples fefifo_8022_1,fefifo_8022_7 --vertical_bar --top 20 -i fefifo_8022_1_abund/fam_abund.out,fefifo_8022_7_abund/fam_abund.out + +Users can choose to generate a barplot instead of heatmap using the ``bar_plot`` method. + +P16. Synteny plot between a CGC and its best PUL hit with read mapping coverage to CGC (Fig. S4A) (TIMING 1min) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: shell + + dbcan_plot CGC_synteny_coverage_plot -i fefifo_8022_1.dbCAN --cgcid 'k141_2168|CGC1' --readscount fefifo_8022_1_abund/fefifo_8022_1.cgc.depth.txt + + +The ``fefifo_8022_1.dbCAN`` folder contains the ``PUL_blast.out`` file. Using this file, the ``cgc_standard.out`` file, +and the best PUL's ``gff`` file in ``dbCAN-PUL.tar.gz``, the CGC_synteny_plot method will create the ``CGC-PUL synteny plot``. +The ``-cgcid`` parameter is required to specify which CGC to be plotted (``'k141_2168|CGC1'`` in this example). +The ``fefifo_8022_1.cgc.depth.txt`` file is used to plot the read mapping coverage. + +If users only want to plot the CGC structure: + +.. code-block:: shell + + dbcan_plot CGC_plot -i fefifo_8022_1.dbCAN --cgcid 'k141_2168|CGC1' + +If users only want to plot the CGC structure plus the read mapping coverage: + +.. code-block:: shell + + dbcan_plot CGC_coverage_plot -i fefifo_8022_1.dbCAN --cgcid 'k141_2168|CGC1' --readscount fefifo_8022_1_abund/fefifo_8022_1.cgc.depth.txt + +If users only want to plot the synteny between the CGC and PUL: + +.. code-block:: shell + + dbcan_plot CGC_synteny_plot -i fefifo_8022_1.dbCAN --cgcid 'k141_2168|CGC1' + + +.. warning:: + + The CGC IDs in different samples do not match each other. For example, specifying ``-i fefifo_8022_1.dbCAN`` is to plot + the ``'k141_2168|CGC1'`` in the fefifo_8022_1 sample. The ``'k141_2168|CGC1'`` in the fefifo_8022_7 sample most likely does not exist, + and even it does, the CGC has a different sequence even if the ID is the same. + + +.. _priest_2023: + +Example 3: Priest2023 Dataset :cite:`2023:Priest` +------------------------------------------------- diff --git a/docs/user_guide/run_from_raw_reads_pr.rst b/docs/user_guide/run_from_raw_reads_pr.rst new file mode 100644 index 000000000..a3df25ef9 --- /dev/null +++ b/docs/user_guide/run_from_raw_reads_pr.rst @@ -0,0 +1,369 @@ +More examples: Run from Raw Reads +================================= + +.. _priest_2023: + +Example 3: Priest2023 Dataset :cite:`2023:Priest` +------------------------------------------------- + +The Wastyk2021 dataset :cite:`2023:Priest` was published in 2021 from a human dietary intervention study. In the published paper, researchers studied how high-fermented and high-fiber diets influence the human microbiome metabolism and modulate the human immune status. +Among various data analyses conducted in the paper, +CAZymes were mined from shotgun metagenomic reads of 18 healthy human participants, and each participant had four time points of stool samples for metagenome sequencing. +CAZyme abundance profiles were compared before and after the high-fiber intervention (baseline vs high-fiber). One of the main findings from their CAZyme analysis was that high-fiber consumption increased the CAZyme abundance. +For this protocol, we will select two samples (paired-end 2x146bp reads) of two time points (day 2 before high-fiber diet as baseline, and 10 weeks after high-fiber diet as intervention) from one participant +The protocol is for the individual sample route. + +============ =========== =========== +Header 1 Header 2 Header 3 +============ =========== =========== +row 1, col 1 row 1, col 2 row 1, col 3 +row 2, col 1 row 2, col 2 row 2, col 3 +============ =========== =========== + + +The Priest2023 dataset :cite:`2021:Wastyk` was published in 20211 from a human dietary intervention study. In the published paper, researchers studied how high-fermented and high-fiber diets influence the human microbiome metabolism and modulate the human immune status. Among various data analyses conducted in the paper1, CAZymes were mined from shotgun metagenomic reads of 18 healthy human participants, and each participant had four time points of stool samples for metagenome sequencing. CAZyme abundance profiles were compared before and after the high-fiber intervention (baseline vs high-fiber). One of the main findings from their CAZyme analysis was that high-fiber consumption increased the CAZyme abundance. For this protocol, we will select two samples (paired-end 2x146bp reads) of two time points (day 2 before high-fiber diet as baseline, and 10 weeks after high-fiber diet as intervention) from one participant (Table S2). The protocol is for the individual sample route (Fig. 3). + +Procedure +--------- + +Module 1: Reads processing (Fig. 3) to obtain contigs +````````````````````````````````````````````````````` + +P1. Contamination Check (TIMING ~10min) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Download the Priest2023 dataset: +.. code-block:: shell + + wget https://bcb.unl.edu/dbCAN_tutorial/dataset3-Priest2023/BML_MG.fastq.gz + wget https://bcb.unl.edu/dbCAN_tutorial/dataset3-Priest2023/SRF_MG.fastq.gz + wget https://bcb.unl.edu/dbCAN_tutorial/dataset3-Priest2023/BML_MT_1.fastq.gz + wget https://bcb.unl.edu/dbCAN_tutorial/dataset3-Priest2023/BML_MT_2.fastq.gz + wget https://bcb.unl.edu/dbCAN_tutorial/dataset3-Priest2023/SRF_MT_1.fastq.gz + wget https://bcb.unl.edu/dbCAN_tutorial/dataset3-Priest2023/SRF_MT_2.fastq.gz + +Use `kraken2` to check for contaminated reads: + + +.. code-block:: shell + + kraken2 --threads 32 --quick --paired --db K2 --report SRF_MT.kreport --output SRF_MT.kraken.output SRF_MT_1.fastq.gz SRF_MT_2.fastq.gz + kraken2 --threads 32 --quick --paired --db K2 --report BML_MT.kreport --output BML_MT.kraken.output BML_MT_1.fastq.gz BML_MT_2.fastq.gz + + kraken2 --threads 32 --quick --paired --db K2 --report SRF_MG.kreport --output SRF_MG.kraken.output SRF_MG_1.fastq.gz SRF_MG_2.fastq.gz + kraken2 --threads 32 --quick --paired --db K2 --report BML_MG.kreport --output BML_MG.kraken.output BML_MG_1.fastq.gz BML_MG_2.fastq.gz + +Kraken2 found much contamination (Box 1) from human in the Priest2023 data. Consequently, human reads need to be removed before assembly. + +Reads can be aligned to the reference genomes of potential contamination source organisms to remove the aligned reads. The most common source in microbiome studies is from human. + +Box 1: Example of Kraken2 output files +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + The `kreport` files can be examined to identify potential contamination source organisms. + + .. code-block:: shell + + -rw-rw-r-- 1 jinfang jinfang 54M Dec 27 07:42 BML_MG.kraken.output + -rw-rw-r-- 1 jinfang jinfang 1.2M Dec 27 07:42 BML_MG.kreport + -rw-rw-r-- 1 jinfang jinfang 3.4G Dec 27 08:01 BML_MT.kraken.output + -rw-rw-r-- 1 jinfang jinfang 1023K Dec 27 08:02 BML_MT.kreport + -rw-rw-r-- 1 jinfang jinfang 61M Dec 27 07:39 SRF_MG.kraken.output + -rw-rw-r-- 1 jinfang jinfang 1.2M Dec 27 07:39 SRF_MG.kreport + -rw-rw-r-- 1 jinfang jinfang 2.6G Dec 27 07:50 SRF_MT.kraken.output + -rw-rw-r-- 1 jinfang jinfang 1.1M Dec 27 07:51 SRF_MT.kreport + + +P2. Remove contamination reads from human (TIMING ~40min) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +From the Kraken2 output files, we identified humans as the contamination source, we can use the following commands to remove the contamination reads by aligning reads to the human reference genome. + +.. code-block:: shell + + mkdir hg38 && cd hg38 && wget https://ftp.ensembl.org/pub/release-110/fasta/homo_sapiens/dna/Homo_sapiens.GRCh38.dna.primary_assembly.fa.gz + cd .. && mkdir contamination && cd contamination + minimap2 -a -x map-hifi -MD -t 32 -o SRF_MG.hg38.sam ../hg38/Homo_sapiens.GRCh38.dna.primary_assembly.fa.gz ../SRF_MG.fastq.gz + minimap2 -a -x map-hifi -MD -t 32 -o BML_MG.hg38.sam ../hg38/Homo_sapiens.GRCh38.dna.primary_assembly.fa.gz ../BML_MG.fastq.gz + samtools fastq -f 4 -@ 32 -0 ../SRF_MG.clean.fq.gz SRF_MG.hg38.sam + samtools fastq -f 4 -@ 32 -0 ../BML_MG.clean.fq.gz BML_MG.hg38.sam + bwa mem ../hg38/hg38 ../SRF_MT_1.fastq.gz ../SRF_MT_2.fastq.gz -t 32 -o SRF_MT.hg38.sam + bwa mem ../hg38/hg38 ../BML_MT_1.fastq.gz ../BML_MT_2.fastq.gz -t 32 -o BML_MT.hg38.sam + samtools fastq -f 12 -@ 32 -1 ../SRF_MT_1.clean.fq.gz -2 ../SRF_MT_2.clean.fq.gz SRF_MT.hg38.sam + samtools fastq -f 12 -@ 32 -1 ../BML_MT_1.clean.fq.gz -2 ../BML_MT_2.clean.fq.gz BML_MT.hg38.sam + cd .. + +P3| Trim adapter and low-quality reads (TIMING ~20min) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + +.. code-block:: shell + + trim_galore --illumina -j 8 --paired BML_MT_1.clean.fastq.gz BML_MT_2.clean.fastq.gz + trim_galore --illumina -j 8 --paired SRF_MT_1.clean.fastq.gz SRF_MT_2.clean.fastq.gz + +The HiFi long reads do not need to be trimmed. Hence, this step only applies to MT illumina short read data. We specified --illumina to indicate that the reads were generated using the Illumina sequencing platform. Nonetheless, trim_galore possesses the ability to automatically detect the adapter, providing flexibility in adapter handling for users who may know the specific sequencing platform. Details of trimming are available in the trimming report file (Box 2). + +Box 2: Example output of trim_galore +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + In addition to the trimmed read files, Trim_galore also generates a trimming report file. The trimming report contains details on read trimming, such as the number of trimmed reads. + + .. code-block:: shell + + -rw-rw-r-- 1 jinfang jinfang 4.2K Dec 28 21:56 BML_MT_1.clean.fq.gz_trimming_report.txt + -rw-rw-r-- 1 jinfang jinfang 2.3G Dec 28 22:05 BML_MT_1.clean_val_1.fq.gz + -rw-rw-r-- 1 jinfang jinfang 4.7K Dec 28 22:05 BML_MT_2.clean.fq.gz_trimming_report.txt + -rw-rw-r-- 1 jinfang jinfang 3.0G Dec 28 22:05 BML_MT_2.clean_val_2.fq.gz + -rw-rw-r-- 1 jinfang jinfang 4.9K Dec 28 10:07 SRF_MT_1.clean.fq.gz_trimming_report.txt + -rw-rw-r-- 1 jinfang jinfang 2.7G Dec 28 10:19 SRF_MT_1.clean_val_1.fq.gz + -rw-rw-r-- 1 jinfang jinfang 5.1K Dec 28 10:19 SRF_MT_2.clean.fq.gz_trimming_report.txt + -rw-rw-r-- 1 jinfang jinfang 3.3G Dec 28 10:19 SRF_MT_2.clean_val_2.fq.gz + +.. warning:: + + During the trimming process, certain reads may be entirely removed due to low quality in its entirety. Using the `--retain_unpaired` parameter in trim_galore allows for the preservation of single-end reads. In this protocol, this option was not selected, so that both reads of a forward-revise pair were removed. + + + +P4. Assemble HiFi reads into metagenome (TIMING ~4h20min) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Flye was used to assemble the HiFi long reads into contigs. + +.. code-block:: shell + + flye --threads 32 --meta --pacbio-hifi BML_MG.clean.fq.gz --hifi-error 0.01 --keep-haplotypes --out-dir flye_BML_MG + flye --threads 32 --meta --pacbio-hifi SRF_MG.clean.fq.gz --hifi-error 0.01 --keep-haplotypes --out-dir flye_SRF_MG + +Flye generates two folders `flye_BML_MG` and `flye_SRF_MG`. Each folder +contains 6 files and 5 sub-folders (Box 3), among them `assembly.fasta` is the final contig sequence file. +We set `--hifi-error` 0.01, a generally accepted error rate of HiFi sequencing. +Parameter `--meta` is set to assemble reads into metagenomes. + +Box 3: Example output of Flye +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + .. code-block:: shell + + drwxrwxr-x 2 jinfang jinfang 4.0K Dec 27 20:15 00-assembly + drwxrwxr-x 2 jinfang jinfang 4.0K Dec 27 20:43 10-consensus + drwxrwxr-x 2 jinfang jinfang 4.0K Dec 27 21:14 20-repeat + drwxrwxr-x 2 jinfang jinfang 4.0K Dec 27 21:16 30-contigger + drwxrwxr-x 2 jinfang jinfang 4.0K Dec 27 22:06 40-polishing + -rw-rw-r-- 1 jinfang jinfang 314M Dec 27 22:06 assembly.fasta + -rw-rw-r-- 1 jinfang jinfang 311M Dec 27 22:06 assembly_graph.gfa + -rw-rw-r-- 1 jinfang jinfang 6.6M Dec 27 22:06 assembly_graph.gv + -rw-rw-r-- 1 jinfang jinfang 867K Dec 27 22:06 assembly_info.txt + -rw-rw-r-- 1 jinfang jinfang 61M Dec 27 22:06 flye.log + -rw-rw-r-- 1 jinfang jinfang 92 Dec 27 22:06 params.json + + +P5. Predict genes by Prokka (~21h) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: shell + + prokka --outdir prokka_BML_MG --prefix BML_MG --addgenes --addmrna --locustag BML_MG --kingdom Bacteria --cpus 36 flye_BML_MG/assembly.fasta + prokka --outdir prokka_SRF_MG --prefix SRF_MG --addgenes --addmrna --locustag SRF_MG --kingdom Bacteria --cpus 36 flye_SRF_MG/assembly.fasta + +The parameter `--kingdom` Bacteria is required for bacterial gene prediction. +To optimize performance, `--CPU` 36 instructs the utilization of 36 computer processors. +The output files comprise of both protein and CDS sequences in Fasta format (e.g., `BML_MG.faa` and `SRF_MG.ffn` in Box 4). + +Box 3: Example output of Prokka +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + .. code-block:: shell + + -rw-rw-r-- 1 jinfang jinfang 2.2M Dec 28 05:38 BML_MG.err + -rw-rw-r-- 1 jinfang jinfang 105M Dec 27 23:26 BML_MG.faa + -rw-rw-r-- 1 jinfang jinfang 288M Dec 27 23:26 BML_MG.ffn + -rw-rw-r-- 1 jinfang jinfang 314M Dec 27 22:06 BML_MG.fna + -rw-rw-r-- 1 jinfang jinfang 315M Dec 27 23:26 BML_MG.fsa + -rw-rw-r-- 1 jinfang jinfang 724M Dec 28 05:39 BML_MG.gbk + -rw-rw-r-- 1 jinfang jinfang 467M Dec 27 23:26 BML_MG.gff + -rw-rw-r-- 1 jinfang jinfang 1.9M Dec 28 05:39 BML_MG.log + -rw-rw-r-- 1 jinfang jinfang 1.5G Dec 28 05:39 BML_MG.sqn + -rw-rw-r-- 1 jinfang jinfang 89M Dec 27 23:26 BML_MG.tbl + -rw-rw-r-- 1 jinfang jinfang 40M Dec 27 23:26 BML_MG.tsv + -rw-rw-r-- 1 jinfang jinfang 152 Dec 27 23:26 BML_MG.txt + + +Module 1: run_dbcan annotation (Fig. 3) to obtain CAZymes, CGCs, and substrates +``````````````````````````````````````````````````````````````````````````````````````````````` + +Users can skip P6 and P7, and directly run P8 (much slower though), if they want to predict not only CAZymes and CGCs, but also substrates. + +P6. CAZyme annotation at family level (TIMING ~10min) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: shell + + run_dbcan prokka_BML_MG/BML_MG.faa protein --hmm_cpu 32 --out_dir BML_MG.CAZyme --tools hmmer --db_dir db + run_dbcan prokka_SRF_MG/SRF_MG.faa protein --hmm_cpu 32 --out_dir SRF_MG.CAZyme --tools hmmer --db_dir db + +Two arguments are required for run_dbcan: the input sequence file (faa) and the sequence type (protein). By default, run_dbcan will use three methods (HMMER vs dbCAN HMMdb, DIAMOND vs CAZy, HMMER vs dbCAN-sub HMMdb) for CAZyme annotation (Table 1, Fig. 2). This default setting is equivalent to the use --tools all parameter (Box 5). Here we only invoke the HMMER vs dbCAN HMMdb for CAZyme annotation at the family level. + + +Box 3: CAZyme annotation with default setting +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + If the `--tools` parameter is not set, it is the default setting, which is the same as `--tools` all. + This will take much longer time to finish (~5h) due to the large size of dbCAN-sub HMMdb (used for substrate prediction for CAZymes, see Table 1). + + .. code-block:: shell + + run_dbcan prokka_BML_MG/BML_MG.faa protein --out_dir BML_MG.CAZyme --dia_cpu 32 --hmm_cpu 32 --dbcan_thread 32 --tools all + run_dbcan prokka_SRF_MG/SRF_MG.faa protein --out_dir SRF_MG.CAZyme --dia_cpu 32 --hmm_cpu 32 --dbcan_thread 32 --tools all + + The sequence type can be protein, prok, meta. If the input sequence file contains metagenomic contig sequences (fna file), + the sequence type has to be meta, and prodigal will be called to predict genes. + + .. code-block:: shell + + run_dbcan prokka_BML_MG/BML_MG.fna meta --out_dir BML_MG.CAZyme --dia_cpu 32 --hmm_cpu 32 --dbcan_thread 32 + run_dbcan prokka_SRF_MG/SRF_MG.fna meta --out_dir SRF_MG.CAZyme --dia_cpu 32 --hmm_cpu 32 --dbcan_thread 32 + +P7. CGC prediction (TIMING ~15 min) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The following commands will re-run run_dbcan to not only predict CAZymes but also CGCs with protein faa and gene location gff files. + + .. code-block:: shell + + run_dbcan prokka_BML_MG/BML_MG.faa protein --tools hmmer --tf_cpu 32 --stp_cpu 32 -c prokka_BML_MG/BML_MG.gff --out_dir BML_MG.PUL --dia_cpu 32 --hmm_cpu 32 + run_dbcan prokka_SRF_MG/SRF_MG.faa protein --tools hmmer --tf_cpu 32 --stp_cpu 32 -c prokka_SRF_MG/SRF_MG.gff --out_dir SRF_MG.PUL --dia_cpu 32 --hmm_cpu 32 + +As mentioned above (Table 1, Fig. 2), CGC prediction is a featured function added into dbCAN2 in 2018. +To identify CGCs with the protein sequence type, a gene location file (gff) must be provided together. +If the input sequence type is prok or meta, meaning users only have contig fna files, +the CGC prediction can be activated by setting `-c cluster`. + +.. warning:: + + **CAUTION ** + + If the users would like to create their own gff file (instead of using Prokka or Prodigal), + it is important to make sure the value of ID attribute in the gff file matches the protein ID in the protein faa file. + + **Troubleshooting** + + If no result is found in CGC output file, it is most likely because the sequence IDs in gff file and faa file do not match. + Another less likely reason is that the contigs are too short and fragmented and not suitable for CGC prediction. + +P8. Substrate prediction for CAZymes and CGCs (TIMING ~5h) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The following commands will re-run run_dbcan to predict CAZymes, CGCs, +and their substrates with the `--cgc_substrate` parameter. + +.. code-block:: shell + run_dbcan prokka_BML_MG/BML_MG.faa protein --dbcan_thread 32 --tf_cpu 32 --stp_cpu 32 -c prokka_BML_MG/BML_MG.gff --cgc_substrate --hmm_cpu 32 --out_dir BML_MG.dbCAN --dia_cpu 32 + run_dbcan prokka_SRF_MG/SRF_MG.faa protein --dbcan_thread 32 --stp_cpu 32 -c prokka_SRF_MG/SRF_MG.gff --cgc_substrate --out_dir SRF_MG.dbCAN --dia_cpu 32 --hmm_cpu 32 --tf_cpu 32 + +.. warning:: + + The above commands do not set the `--tools` parameter, + which means all three methods for CAZyme annotation will be activated (Box 5). + Because dbCAN-sub HMMdb (for CAZyme substrate prediction) is 200 times larger than dbCAN HMMdb, + the runtime will be much longer. Users can specify `--tools` hmmer, + so that the HMMER search against dbCAN-sub will be disabled. + However, this will turn off the substrate prediction for CAZymes and CGCs based on CAZyme substrate majority voting. + Consequently, + the substrate prediction will be solely based on homology search against PULs in dbCAN-PUL (Fig. 1, Table 1). + +.. code-block:: shell + + run_dbcan prokka_BML_MG/BML_MG.faa protein --tools hmmer --stp_cpu 32 -c prokka_BML_MG/BML_MG.gff --cgc_substrate --out_dir BML_MG.PUL.Sub --dia_cpu 32 --hmm_cpu 32 --tf_cpu 32 + run_dbcan prokka_SRF_MG/SRF_MG.faa protein --tools hmmer --stp_cpu 32 -c prokka_SRF_MG/SRF_MG.gff --cgc_substrate --out_dir SRF_MG.PUL.Sub --dia_cpu 32 --hmm_cpu 32 --tf_cpu 32 + +Box 6: Example output folder content of run_dbcan substrate prediction +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + + In the output directory (https://bcb.unl.edu/dbCAN_tutorial/dataset3-Priest2023/BML_MG.dbCAN/), a total of 17 files and 1 folder are generated: + + .. code-block:: shell + + -rw-rw-r-- 1 jinfang jinfang 9.6M Dec 28 10:18 PUL_blast.out + -rw-rw-r-- 1 jinfang jinfang 1.8M Dec 28 10:18 CGC.faa + -rw-rw-r-- 1 jinfang jinfang 26M Dec 28 10:18 cgc.gff + -rw-rw-r-- 1 jinfang jinfang 450K Dec 28 10:18 cgc.out + -rw-rw-r-- 1 jinfang jinfang 212K Dec 28 10:18 cgc_standard.out + -rw-rw-r-- 1 jinfang jinfang 1005K Dec 28 10:18 cgc_standard.out.json + -rw-rw-r-- 1 jinfang jinfang 406K Dec 28 10:11 dbcan-sub.hmm.out + -rw-rw-r-- 1 jinfang jinfang 325K Dec 28 10:11 diamond.out + -rw-rw-r-- 1 jinfang jinfang 332K Dec 28 10:11 dtemp.out + -rw-rw-r-- 1 jinfang jinfang 220K Dec 28 10:11 hmmer.out + -rw-rw-r-- 1 jinfang jinfang 240K Dec 28 10:18 overview.txt + -rw-rw-r-- 1 jinfang jinfang 1.7M Dec 28 10:17 stp.out + -rw-rw-r-- 1 jinfang jinfang 17K Dec 28 10:18 substrate.out + drwxrwxr-x 2 jinfang jinfang 12K Dec 28 10:19 synteny.pdf + -rw-rw-r-- 1 jinfang jinfang 293K Dec 28 10:13 tf-1.out + -rw-rw-r-- 1 jinfang jinfang 222K Dec 28 10:15 tf-2.out + -rw-rw-r-- 1 jinfang jinfang 1.7M Dec 28 10:17 tp.out + -rw-rw-r-- 1 jinfang jinfang 105M Dec 28 05:57 uniInput + + +Descriptions of Output Files: + + - ``PUL_blast.out``: BLAST results between CGCs and PULs. + - ``CGC.faa``: CGC Fasta sequences. + - ``cgc.gff``: reformatted from the user input gff file by marking CAZymes, TFs, TCs, and STPs. + - ``cgc.out``: raw output of CGC predictions. +Each entry in cgc.out includes: + + + 1. CGC_id: CGC1 + 2. type: CAZyme + 3. contig_id: contig_10157 + 4. gene_id: BML_MG_01992 + 5. start: 33003 + 6. end: 36077 + 7. strand: + + 8. annotation: GH2 + +Explanation: the gene BML_MG_01992 encodes a GH2 CAZyme in the CGC1 of the contig contig_10157. CGC1 also has other genes, which are provided in other rows. BML_MG_01992 is on the positive strand of contig_10157 from 33003 to 36077. The type can be one of the four signature gene types (CAZymes, TCs, TFs, STPs) or the null type (not annotated as one of the four signature genes). + +`cgc_standard.out.json`: JSON format of cgc_standard.out. +`dbcan-sub.hmm.out`: HMMER search result against dbCAN-sub HMMdb, including a column with CAZyme substrates extracted from fam-substrate-mapping-08012023.tsv. +`diamond.out`: DIAMOND search result against the CAZy annotated protein sequences (CAZyDB.07262023.fa). +`dtemp.out`: temporary file. +`hmmer.out`: HMMER search result against dbCAN HMMdb. +`overview.txt`: summary of CAZyme annotation from three methods in TSV format. An example row has the following columns: + 1. Gene_ID: BML_MG_01761 + 2. EC#: 2.4.99.-:5 + 3. dbCAN: GT112(19-370) + 4. dbCAN_sub: GT112_e0 + 5. DIAMOND: GT112 + 6. #ofTools: 3 +Explanation: the protein BML_MG_01761 is annotated by 3 tools to be a CAZyme: (1) GT112 (CAZy defined family GT112) by HMMER vs dbCAN HMMdb with a domain range from aa position 19 to 370, (2) GT112_e0 (eCAMI defined subfamily e0; e indicates it is from eCAMI not CAZy) by HMMER vs dbCAN-sub HMMdb (derived from eCAMI subfamilies), and (3) GT112 by DIAMOND vs CAZy annotated protein sequences. The second column 2.4.99.-:5 is extracted from eCAMI, meaning that the eCAMI subfamily GT112_e0 contains 5 member proteins which have an EC 2.4.99.- according to CAZy. In most cases, the 3 tools will have the same CAZyme family assignment. When they give different assignment. We recommend a preference order: dbCAN > eCAMI/dbCAN-sub > DIAMOND. See our dbCAN2 paper2, dbCAN3 paper3, and eCAMI4 for more details. +Note: If users invoked the --use_signalP parameter when running run_dbcan, there will be an additional column called signal in the overview.txt. +stp.out: HMMER search result against the MiST5 compiled signal transduction protein HMMs from Pfam. +tf-1.out: HMMER search result against the DBD6 compiled transcription factor HMMs from Pfam 7. +tf-2.out: HMMER search result against the DBD compiled transcription factor HMMs from Superfamily 8. +tp.out: DIAMOND search result against the TCDB 9 annotated protein sequences. +substrate.out: summary of substrate prediction results for CGCs in TSV format from two approaches3 (dbCAN-PUL blast search and dbCAN-sub majority voting). An example row has the following columns: + 1. CGC_ID: contig_10778|CGC2 + 2. Best hit PUL_ID in dbCAN-PUL: PUL0400 + 3. Substrate of the hit PUL: alginate + 4. Sum of bitscores for homologous gene pairs between CGC and PUL: 851.0 + 5. Types of homologous gene pairs: CAZyme-CAZyme;CAZyme-CAZyme;CAZyme-CAZyme;CAZyme-CAZyme + 6. Substrate predicted by majority voting of CAZymes in CGC: alginate + 7. Voting score: 2.0 +Explanation: The CGC2 of contig_10778 has its best hit PUL0400 (from PUL_blast.out) with alginate as substrate (from dbCAN-PUL_12-12-2023.xlsx). Four signature genes are matched between contig_10778|CGC2 and PUL0400 (from PUL_blast.out): all the four are CAZymes. The sum of blast bitscores of the 4 homologous pairs (CAZyme-CAZyme;CAZyme-CAZyme;CAZyme-CAZyme;CAZyme-CAZyme) is 851.0. Hence, the substrate of contig_10778|CGC2 is predicted to be alginate according to dbCAN-PUL blast search. The last two columns are based on the dbCAN-sub result (dbcan-sub.hmm.out), according to which two CAZymes in contig_10778|CGC2 are predicted to have alginate substrate. The voting score is thus 2.0, so that according to the majority voting rule, contig_10778|CGC2 is predicted to have an alginate substrate. +Note: for many CGCs, only one of the two approaches produces substrate prediction. In some cases, the two approaches produce different substrate assignments. We recommend a preference order: dbCAN-PUL blast search > dbCAN-sub majority voting. See our dbCAN3 paper3 for more details. +synteny.pdf: a folder with syntenic block alignment plots between all CGCs and PULs. +uniInput: renamed Fasta file from input protein sequence file. + + + + + + + + + + + + + diff --git a/pyproject.toml b/pyproject.toml index 65993e880..202e18461 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ requires = ["hatchling"] [project] name = "dbcan" -version = "4.1.0" +version = "4.1.2" description = "Standalone version of dbCAN annotation tool for automated CAZyme annotation" readme = "README.md" requires-python = ">=3.6" @@ -25,6 +25,10 @@ dependencies = [ "scipy", "pandas", "biopython", + "tqdm", + "openpyxl", + "matplotlib", + "pyhmmer", # for debug logging (referenced from the issue template) "session-info" ] @@ -50,6 +54,7 @@ syntenic_plot = "dbcan.cli.syntenic_plot:main" dbcan_utils = "dbcan.utils.utils:main" dbcan_plot = "dbcan.utils.plots:main" dbcan_asmfree = "dbcan.utils.diamond_unassembly:main" +dbcan_build = "dbcan.utils.dbcan_build:main" [project.optional-dependencies] dev = [ @@ -131,7 +136,7 @@ ignore = [ # First line should be in imperative mood; try rephrasing "D401", ## Disable one in each pair of mutually incompatible rules - # We don’t want a blank line before a class docstring + # We don't want a blank line before a class docstring "D203", # We want docstrings to start immediately after the opening triple quote "D213",