# NCBI Dataset and Dataformat programs to download metadata of genomes https://www.ncbi.nlm.nih.gov/datasets/docs/v2/download-and-install/ ## Installation First, create a conda environment: `conda create -n ncbi_datasets` Then, activate your new environment: `conda activate ncbi_datasets` Finally, install the datasets conda package: `conda install -c conda-forge ncbi-datasets-cli` ## Download genomes using GCA accesions **For just one genome** `datasets download genome accession GCF_XXXXXXXXX.XX --filename genomes_dataset.zip` **For multiple genomes** Crear un archivo de texto con los accession numbers **(accessions.txt)**: ``` GCF_XXXXXXXXX.X1 GCF_XXXXXXXXX.X2 GCF_XXXXXXXXX.X3 GCF_XXXXXXXXX.X4 GCF_XXXXXXXXX.X5 ``` Correr el comando: ```datasets download genome accession --inputfile accessions.txt --filename genomes.zip``` ## dataset: Print a data report containing genome metadata Utilizar el siguiente comando agregando los accession GCA o GCF. Para un solo genoma: `datasets summary genome accession GCA_XXXXXXXX --as-json-lines` Para un multiples genoma: `datasets summary genome accession GCA_XXXXXXXX GCA_YYYYYYYY GCA_ZZZZZZZZZZ --as-json-lines` **Sin embargo, hay que crear el archivo de salida utilizando el siguiente, porque, de lo contrario los metadatos solo se mostraran en la terminal:** `datasets summary genome accession GCA_XXXXXXXX GCA_YYYYYYYY GCA_ZZZZZZZZZZ --as-json-lines > assembly_data_report.jsonl` ## dataformat: convert metadata from JSON Lines format to other formats. Esto va a crear un .json file, por lo que necesitaremos del programa dataformat para convertirlo a formato excel: ``` dataformat excel genome --inputfile assembly_data_report.jsonl --outputfile NOMBRE.xlsx dataformat excel genome --package NOMBRE.zip --outputfile NOMBRE.xlsx ``` Lo que se puede hacer y es mejor, es que el archivo que se descargo del NCBI junto con los genomas .fna, el archivo assembly_data_report.jsonl sea utilizado para esto. Por lo que, no se tendria que usar dataset para obtener los metadatos, si no solo convertir el jsonl que se descargo inicialmente. # ncbi-genome-download https://github.com/kblin/ncbi-genome-download Download fasta genomes directly ## Installation `pip install ncbi-genome-download` ## Download fasta genomes using accesions Crear un archivo de texto con los accession numbers **(accessions.txt)**: ``` GCF_XXXXXXXXX.X1 GCF_XXXXXXXXX.X2 GCF_XXXXXXXXX.X3 GCF_XXXXXXXXX.X4 GCF_XXXXXXXXX.X5 ``` Corre el comando: `ncbi-genome-download bacteria -A accessions.txt --formats fasta --section genbank --output-folder genomes_fna -v ` # CheckM2 **Rapid assessment of genome bin quality using machine learning.** https://github.com/chklovski/CheckM2 --- ## **Installation** The easiest way to install is using Conda in a new environment: `conda create -n checkm2 -c bioconda -c conda-forge checkm2` However, conda can be very slow when processing requirements for the environment. A much faster and better way to install CheckM2 is to install using mamba and creating a new environment: `mamba create -n checkm2 -c bioconda -c conda-forge checkm2` --- ## **Bin quality prediction** The main use of CheckM2 is to predict the completeness and contamination of metagenome-assembled genomes (MAGs) and single-amplified genomes (SAGs), although it can also be applied to isolate genomes. You can give it a folder with FASTA files using --input and direct its output with --output-directory: ``` checkm2 predict --threads 30 --input <folder_with_bins> --output-directory <output_folder> ``` --- ## Quality prediction for multiple genomes (Script bash) ``` #!/bin/bash # Directorios de entrada y salida INPUT_DIR="ruta/a/los/archivos/fna" OUTPUT_DIR="ruta/a/donde/se/generaran/los/archivos/checkm2" # Recorre cada archivo .fna en el directorio for FILE in "$INPUT_DIR"/*.fna; do # Extrae el nombre del archivo sin la extensión BASENAME=$(basename "$FILE" .fna) # Ejecuta CheckM2 y guarda los resultados en un subdirectorio específico checkm2 predict --threads 20 --input "$FILE" --output-directory "$OUTPUT_DIR/${BASENAME}_checkm2" & # Controla el número de procesos en paralelo (ajusta según tu capacidad) while [ "$(jobs -r | wc -l)" -ge 10 ]; do sleep 5 done done # Espera a que terminen todos los procesos wait echo "CheckM2 ha finalizado en todos los archivos." ``` **Merge quality_report.tsv files** This guide demonstrates how to merge all the quality_report.tsv files located in different folders within the directory ***/ruta/hacia/el/directorio/que/contiene/las/carpetas/generadas/por/checkm2*** into a single file called **merged_quality_report.tsv**. The final file will include the header (the first line) only once, avoiding any duplicates. Execute the following script directly in the terminal: ``` first=1 for file in */quality_report.tsv; do if [ $first -eq 1 ]; then cat "$file" > merged_quality_report.tsv first=0 else tail -n +2 "$file" >> merged_quality_report.tsv fi done ``` **Explanation:** For the first file, the entire content (including the header) is copied into the output file. For subsequent files, tail -n +2 skips the first line (the header) and appends the remaining lines. **Filtration of genome dataset** A common standard for "near complete" assembly is **>90% completeness** and **<5% contamination**. For this go to the merge tsv and discard los genomas segun el standard o segun las necesidades de cada taxon. Crear un directorio donde esten todos los genomas fna que se utilizaron: `mkdir fna_filtered | cp ./fna_coded/*.fna fna_filtered` Contar el numero de genomas pre-filtracion: `ls | wc -l` Eliminar los genomas que no cumplan con el standard establecido: `rm genome1.fna genome1.fna genome1.fna genome1.fna genome1.fna ` Contar el numero de genomas pos-filtracion: `ls | wc -l` # Prokka ## **Installation** The easiest way to install is using Bioconda in a new environment: `conda install -c conda-forge -c bioconda -c defaults prokka` ## **Anotacion de multiples genomas (Script sh)** Crear un nuevo archivo usando nano: `nano prokka_multiple_anot.sh` Copiar y pegar el script: ``` #!/bin/bash outputdir="PROKKA" fnadir="/directorio/de/los/fna/filtrados" extension=".fna" cpus=20 # Create output directory if it doesn't exist if [ ! -d "$outputdir" ]; then mkdir "$outputdir" fi allfna=("${fnadir}"/*"${extension}") for file in "${allfna[@]}" do bname=$(basename "$file" "${extension}") prokka --cpus "$cpus" --kingdom Bacteria --locustag "$bname" \ --addgenes --outdir "${outputdir}/${bname}" --prefix "$bname" "$file" done ``` Cambiar los permisos para que sea ejecutable: `chmod +777 prokka_multiple_anot.sh` Correr el script: `./prokka_multiple_anot.sh` Si todo esta bien se observara algo asi en el bash: ![image](https://hackmd.io/_uploads/BJseQfp5kl.png) **Output files** ![image](https://hackmd.io/_uploads/S1uqWMpckl.png) # Roary https://github.com/sanger-pathogens/Roary ## Installation ## Analysis To run the analysis using gff files from PROKKA annotation: `roary -f ./roary_output -e -r -n -v -p 7 *.gff` ## Plots **Script para generar curva de rarefaccion ** ``` library(ggplot2) # Archivos de datos archivo_conserved = "number_of_conserved_genes.Rtab" archivo_total = "number_of_genes_in_pan_genome.Rtab" # Leer datos y calcular medias conserved = colMeans(read.table(archivo_conserved)) total = colMeans(read.table(archivo_total)) # Crear un dataframe combinado datos = data.frame( Genes = c(conserved, total), Genomas = c(1:length(conserved), 1:length(total)), Tipo = c(rep("Genes Conservados", length(conserved)), rep("Genes Totales", length(total))) ) # Crear la gráfica p <- ggplot(data = datos, aes(x = Genomas, y = Genes, color = Tipo)) + geom_line(size = 1.2) + theme_classic() + xlab("Number of genomes") + ylab("Number of genomes") + theme_bw(base_size = 16) + theme(legend.position = "right") # Guardar la gráfica en formato PNG ggsave(filename = "pangenoma_unico.png", plot = p, width = 10, height = 10) # Guardar la gráfica en formato SVG ggsave(filename = "pangenoma_unico.svg", plot = p, width = 10, height = 10) ``` **Script para generar curva de rarefaccion con multiples especies o genomas** ``` library(ggplot2) # Lista de especies y sus archivos correspondientes especies = c("all", "G1", "G2") archivos_conserved = c("number_of_conserved_genes_ALL.Rtab", "number_of_conserved_genes_G1.Rtab", "number_of_conserved_genes_G2.Rtab") archivos_total = c("number_of_genes_in_pan_genome_ALL.Rtab", "number_of_genes_in_pan_genome_G1.Rtab", "number_of_genes_in_pan_genome_G2.Rtab") # Leer datos y combinarlos en un dataframe datos_combinados = data.frame() for (i in 1:length(especies)) { conserved = colMeans(read.table(archivos_conserved[i])) total = colMeans(read.table(archivos_total[i])) datos_especie = data.frame( Genes = c(conserved, total), Genomas = c(1:length(conserved), 1:length(total)), Tipo = c(rep("Genes Conservados", length(conserved)), rep("Genes Totales", length(total))), Especie = rep(especies[i], 2 * length(conserved)) ) datos_combinados = rbind(datos_combinados, datos_especie) } # Crear la gráfica p <- ggplot(data = datos_combinados, aes(x = Genomas, y = Genes, color = Tipo)) + geom_line(aes(linetype = Especie)) + scale_linetype_manual(values = c("solid", "dotted", "dashed")) + theme_classic() + xlab("Número de Genomas") + ylab("Número de Genes") + theme_bw(base_size = 16) + theme(legend.position = "right") # Guardar la gráfica en formato PNG ggsave(filename = "comparacion_pangenomas.png", plot = p, width = 10, height = 10) # Guardar la gráfica en formato SVG ggsave(filename = "comparacion_pangenomas.svg", plot = p, width = 10, height = 10) ``` ### Script para generara graficos: modificacion del py ``` #!/usr/bin/env python # Copyright (C) <2015> EMBL-European Bioinformatics Institute # Modified for enhanced aesthetics and SVG output by Gemini. # Este script es una versión modificada de roary_plots.py para generar # gráficos de mayor calidad visual, listos para una publicación. # Para usarlo, ejecuta en la terminal: # python roary_plots_custom.py [tu_arbol.newick] [tu_matriz.csv] __author__ = "Marco Galardini & Gemini" __version__ = '1.0.0' def get_options(): """Configura y parsea los argumentos de la línea de comandos.""" import argparse description = "Create enhanced plots from Roary outputs." parser = argparse.ArgumentParser(description=description, prog='roary_plots_custom.py') parser.add_argument('tree', action='store', help='Newick Tree file (e.g., accessory_binary_genes.fa.newick)') parser.add_argument('spreadsheet', action='store', help='Roary gene presence/absence spreadsheet (e.g., gene_presence_absence.csv)') parser.add_argument('--labels', action='store_true', default=False, help='Add node labels to the tree (up to 10 chars)') # El formato por defecto ahora es SVG parser.add_argument('--format', choices=('png', 'tiff', 'pdf', 'svg'), default='svg', help='Output format [Default: svg]') parser.add_argument('-N', '--skipped-columns', action='store', type=int, default=14, help='First N columns of Roary\'s output to exclude [Default: 14]') parser.add_argument('--version', action='version', version='%(prog)s ' + __version__) return parser.parse_args() if __name__ == "__main__": options = get_options() import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt import seaborn as sns import pandas as pd import numpy as np from Bio import Phylo # Importamos una función para crear mapas de color personalizados from matplotlib.colors import ListedColormap # --- Configuración de Estilo Global --- # Usamos el estilo 'ticks' para un look limpio sin cuadrícula de fondo. sns.set_theme(style="ticks") # Aseguramos que todo el texto sea negro por defecto para máxima legibilidad. plt.rc('text', color='black') plt.rc('axes', labelcolor='black', edgecolor='black') plt.rc('xtick', color='black') plt.rc('ytick', color='black') plt.rc('figure', dpi=300) # --- Carga y Preparación de Datos --- print("-> Loading tree and Roary spreadsheet...") t = Phylo.read(options.tree, 'newick') roary = pd.read_csv(options.spreadsheet, low_memory=False) roary.set_index('Gene', inplace=True) roary.drop(list(roary.columns[:options.skipped_columns-1]), axis=1, inplace=True) roary.replace('.{2,100}', 1, regex=True, inplace=True) roary.replace(np.nan, 0, regex=True, inplace=True) print("-> Data loaded successfully.") # --- Cálculo de Categorías del Pangenoma --- num_genomes = roary.shape[1] core_threshold = num_genomes * 0.99 soft_core_threshold = num_genomes * 0.95 shell_threshold = num_genomes * 0.15 gene_sums = roary.sum(axis=1) # --- Gráfico 1: Histograma de Frecuencia del Pangenoma --- print("-> Generating pangenome frequency plot...") freq_df = pd.DataFrame({'frequency': gene_sums}) def assign_category_hist(freq): if freq >= core_threshold: return 'Core genes' elif freq >= soft_core_threshold: return 'Soft-core genes' elif freq >= shell_threshold: return 'Shell genes' else: return 'Cloud genes' freq_df['Category'] = freq_df['frequency'].apply(assign_category_hist) # Definimos la paleta de colores "Pastel1" que se usará en los gráficos de composición comp_palette = sns.color_palette("Pastel1", 4) color_map = { 'Cloud genes': comp_palette[0], 'Shell genes': comp_palette[1], 'Soft-core genes': comp_palette[2], 'Core genes': comp_palette[3] } plt.figure(figsize=(10, 6)) sns.histplot(data=freq_df, x='frequency', hue='Category', multiple="stack", bins=num_genomes, palette=color_map, edgecolor="white", linewidth=0.5, hue_order=['Cloud genes', 'Shell genes', 'Soft-core genes', 'Core genes']) plt.xlim(-0.5, num_genomes + 0.5) # Ajuste para centrar las barras plt.title('Pangenome Gene Frequency', fontsize=16, fontweight='bold') plt.xlabel('Number of Genomes', fontsize=12, fontweight='bold') plt.ylabel('Number of Genes', fontsize=12, fontweight='bold') sns.despine() # Elimina las líneas del recuadro superior y derecho plt.tight_layout() plt.savefig(f'pangenome_frequency.{options.format}') plt.clf() # --- Gráfico 2: Árbol Filogenético y Matriz --- print("-> Generating tree and presence/absence matrix plot...") roary_sorted = roary.loc[roary.sum(axis=1).sort_values(ascending=False).index] roary_sorted = roary_sorted[[x.name for x in t.get_terminals()]] fig = plt.figure(figsize=(17, 10)) gs = fig.add_gridspec(1, 40, wspace=0) ax_tree = fig.add_subplot(gs[0, 0:10]) with plt.rc_context({'lines.linewidth': 0.5}): Phylo.draw(t, axes=ax_tree, show_confidence=Fal ``` # Panaroo ## Installation Although Panaroo supports the latest version of python, currently Bioconda does not support versions >= 3.10 for all packages. An older version of python can be installed by creating an environment as ``` conda create -n panaroo python=3.9 conda activate panaroo ``` Panaroo can then be installed by running the following within a conda environment `conda install -c conda-forge -c bioconda -c defaults 'panaroo>=1.3'` ## Analysis ### Input format Panaroo now supports multiple input formats. To use non-standard **GFF3** files you must profile the input file as a list in a text file (one per line). Separate **GFF** and **FASTA** files can be provided per isolate by providing each file delimited by a space or a tab. Genbank file formats are also supported with extensions `'.gbk', '.gb' or '.gbff'`. These must compliant with Genbank/ENA/DDJB. This can be forced in Prokka by specifying the `--compliance` parameter. **NOTE:** Some annotations file such as those from RefSeq include annotations that break some of the assumptions of Panaroo. These include gene annotations of unusual length or that with premature stop codons (pseudogenes). By default Panaroo will throw an error if it encounters these annotations. You can automatically filter out such annotations by calling panaroo with the `--remove-invalid-genes` flag. ### Clean mode: strict By default Panaroo runs in its strictest (most conservative) mode. We have found that for most use cases this removes potential sources of contamination and error whilst retaining the majority of genes researchers are interested in. `panaroo -i *.gff -o results --clean-mode strict` ### Clean mode: sensitive Very rare plasmids are difficult to distinguish from contamination. Thus, if you are interested in retaining such plasmids at the expense of added contamination we recommend running panaroo using its most sensitive mode. `panaroo -i *.gff -o results --clean-mode sensitive` ### Exportar grafico para # Bacta https://github.com/oschwengers/bakta ### Installation ``` conda create -n bakta conda activate bakta conda install -c conda-forge -c bioconda bakta ``` # Anvio ## Installation **FASTA reformat** **PROGRAM: *anvi-script-reformat-fasta*** Asegúrate de tener un archivo llamado **genomes.txt** que contenga los nombres de los genomas que deseas procesar. Puedes crear este archivo de la siguiente manera: `ls *.fna | sed 's/.fna$//' > genomes.txt` Esto generará un archivo **genomes.txt** que contiene los nombres de los archivos FASTA sin la extensión ".fna". Crear un archivo .sh con el nombre que se desee usando nano para el script: `nano reformat_fasta.sh` Copiar y pegar el script en el archivo nano: ``` #Script for g in $(cat genomes.txt); do echo echo "Working on $g ..." echo # Obtener el nombre base del archivo base_name=$(basename "$g" .fna) # Obtener el nombre sin extensión del archivo file_name=$(basename "$g") name_without_ext="${file_name%.*}" # Reformatear el archivo fasta anvi-script-reformat-fasta "${base_name}.fna" \ --min-len 1000 \ --simplify-names \ --prefix "$name_without_ext" \ --seq-type NT \ -o "${base_name}_r.fna" done ``` Control X, Y, para guardar y salvar el archivo. Cambiar el archivo a executable: `chmod +777 reformat_fasta.sh` Ejecutar el script: `./reformat_fasta.sh` **Create contigs databases** **PROGRAM: *Anvio-gen-contigs-database*** The first thing we need to do is to generate an anvi’o contigs database for each one of them. Run the following script in directly in the terminal: ``` for i in `ls *fna | awk 'BEGIN{FS=".fna"}{print $1}'` do anvi-gen-contigs-database -f $i.fna -o $i.db -T 6 anvi-run-hmms -c $i.db -T 6 done ``` At the end of this, for each fna file you should have a file with the same name that ends with ‘**.db**’. The next step is to define all the contigs databases of interest, and give them a name to introduce them to anvi’o. Let’s call this file ‘**external-genomes.txt**’: **Contigs database annotation and HMMs SEARCHING?** Para anotar los db **PENDIENTE** ``` echo -e "name\tcontigs_db_path" > external-genomes.txt ls *.db | sed 's/\.db$//' | awk '{print $0 "\t" $0 ".db"}' >> external-genomes.txt ``` **Contigs database KEGG, COGs and tRNAs** Para anotar los db **PENDIENTE** ``` for g in *.db do anvi-run-kegg-kofams -c $g --num-threads 4 anvi-run-ncbi-cogs -c $g --num-threads 4 anvi-scan-trnas -c $g --num-threads 4 done ``` Antes de crear el -GENOMES.db file se debe **verificar que los `db files` hayan sido anotados correctamente y que realmente contengan las anotaciones funcionales como KEGGs, COGs, HMMs y RNAs**. Si se quiere verificar genoma por genoma utilizar el siguiente: `anvi-db-info genomaX.db` Se obtendra un output como el siguiente: ``` DB Info (no touch) =============================================== Database Path ................................: genomaX.db description ..................................: [Not found, but it's OK] db_type ......................................: contigs (variant: unknown) version ......................................: 21 DB Info (no touch also) =============================================== project_name .................................: genomaX contigs_db_hash ..............................: hash2900ccfd split_length .................................: 20000 kmer_size ....................................: 4 num_contigs ..................................: 39 total_length .................................: 4007300 num_splits ...................................: 198 gene_level_taxonomy_source ...................: None genes_are_called .............................: 1 external_gene_calls ..........................: 0 external_gene_amino_acid_seqs ................: 0 skip_predict_frame ...........................: 0 splits_consider_gene_calls ...................: 1 scg_taxonomy_was_run .........................: 0 scg_taxonomy_database_version ................: None trna_taxonomy_was_run ........................: 0 trna_taxonomy_database_version ...............: None creation_date ................................: 1736701872.34964 modules_db_hash ..............................: a2b5bde358bb gene_function_sources ........................: KEGG_BRITE,COG20_PATHWAY,Transfer_RNAs,COG20_FUNCTION,KEGG_Module,COG20_CATEGORY,KOfam,KEGG_Class * Please remember that it is never a good idea to change these values. But in some cases it may be absolutely necessary to update something here, and a programmer may ask you to run this program and do it. But even then, you should be extremely careful. AVAILABLE GENE CALLERS =============================================== * 'prodigal' (3,661 gene calls) * 'Transfer_RNAs' (58 gene calls) * 'Ribosomal_RNA_23S' (2 gene calls) * 'Ribosomal_RNA_16S' (1 gene calls) AVAILABLE FUNCTIONAL ANNOTATION SOURCES =============================================== * COG20_CATEGORY (3,243 annotations) * COG20_FUNCTION (3,243 annotations) * COG20_PATHWAY (828 annotations) * KEGG_BRITE (2,744 annotations) * KEGG_Class (600 annotations) * KEGG_Module (600 annotations) * KOfam (2,746 annotations) * Transfer_RNAs (58 annotations) AVAILABLE HMM SOURCES =============================================== * 'Archaea_76' (76 models with 35 hits) * 'Bacteria_71' (71 models with 74 hits) * 'Protista_83' (83 models with 6 hits) * 'Ribosomal_RNA_12S' (1 model with 0 hits) * 'Ribosomal_RNA_16S' (3 models with 1 hit) * 'Ribosomal_RNA_18S' (1 model with 0 hits) * 'Ribosomal_RNA_23S' (2 models with 2 hits) * 'Ribosomal_RNA_28S' (1 model with 0 hits) * 'Ribosomal_RNA_5S' (5 models with 0 hits) * 'Transfer_RNAs' (61 models with 58 hits) ``` **Para obtener un archivo multiple con la informacion de las anotaciones si hay o no anotacion tanto de KEGGs como de COGs:** ``` import os import subprocess def tiene_anotacion(linea, tipo): if tipo == "COG": return any(cog in linea for cog in [ "COG20_CATEGORY", "COG20_FUNCTION", "COG20_PATHWAY" ]) if tipo == "KEGG": return any(kegg in linea for kegg in [ "KEGG_BRITE", "KEGG_Class", "KEGG_Module", "KOfam" ]) return False with open("anotaciones_funcionales.tsv", "w") as salida: salida.write("archivo\tCOG\tKEGG\n") # encabezado for archivo in os.listdir(): if archivo.endswith(".db"): proceso = subprocess.run(["anvi-db-info", archivo], capture_output=True, text=True) salida_texto = proceso.stdout + proceso.stderr tiene_cog = tiene_kegg = False for linea in salida_texto.splitlines(): if "*" in linea: if tiene_anotacion(linea, "COG"): tiene_cog = True if tiene_anotacion(linea, "KEGG"): tiene_kegg = True cog_str = "sí" if tiene_cog else "no" kegg_str = "sí" if tiene_kegg else "no" salida.write(f"{archivo}\t{cog_str}\t{kegg_str}\n") print("✅ Archivo 'anotaciones_funcionales.tsv' generado con éxito.") ``` Correr este script de python en la terminal directamente y en el directorio que contiene los `db files`. El output `anotaciones_funcionales.tsv` debe ser algo asi: ``` archivo COG KEGG Aquamarina_558.db no no Aquamarina_DS40M3.db no no Neptunia_CECT5815.db no no Neptunia_DSM15720.db no no Populi_PA5.db no no Alkaliphila_2B2203Z.db sí sí Alkaliphila_BAA953.db sí sí Alkaliphila_DSM16354.db sí sí Alkaliphila_LS44.db sí sí Alkaliphila_WN018.db sí sí Alkaliphila_X3.db sí sí ``` Si representa que si hay anotacion para ese tipo de funcion y no para cuando no existe anotacion en el db para esa funcion. Para asegurarse que estos resultados estan correctos **verificar siempre de forma aleatorio y representativa** esto de forma manual. **anvi-gen-genomes-storage** Create genome storage db: anvi-gen-genomes-storage -e external-genomes.txt -o Met_genus-GENOMES.db **anvi-pan-genome** Start pangenome analysis: anvi-pan-genome -g Met_genus-GENOMES.db --project-name Methanobrevibacter_genus --num-threads 12 **anvi-display-pan** Display the pangenome: anvi-display-pan -g Met_genus-GENOMES.db -p Met_genus-PAN.db Extract bacteria 71 genes for phylogenomics # Anvio metabolism prediction `anvi-estimate-metabolism -e external-genomes.txt -O Enterococcus --matrix-format` `anvi-matrix-to-newick Enterococcus-completeness-MATRIX.txt` ### dry run to get the profile db: ``` anvi-interactive -d Enterococcus-completeness-MATRIX.txt -p Enterococcus_metabolism_PROFILE.db --manual-mode --dry-run ``` ### run for reals: ``` anvi-interactive --manual-mode -d Enterococcus-completeness-MATRIX.txt -t Enterococcus-completeness-MATRIX.txt.newick -p Enterococcus_metabolism_PROFILE.db --title "Enterococcus Metabolism Heatmap" ``` ### dry run to get the profile db: ``` anvi-interactive -d Enterococcus-completeness-MATRIX.txt \ -p Enterococcus_metabolism_PROFILE.db \ --manual-mode \ --dry-run ``` ### run for reals: ``` anvi-interactive --manual-mode \ -d Enterococcus-completeness-MATRIX.txt \ -t Enterococcus-completeness-MATRIX.txt.newick \ -p Enterococcus_metabolism_PROFILE.db \ --title "Enterococcus Metabolism Heatmap" ``` ### learn where the MODULES.db is: ``` export ANVIO_MODULES_DB=$(python -c "import anvio; import os; print(os.path.join(os.path.dirname(anvio.__file__), 'data/misc/KEGG/MODULES.db'))") ``` ### start an empty file: ``` echo -e "module\tclass\tcategory\tsubcategory\tname" > modules_info.txt ``` ### get module classes: ``` sqlite3 $ANVIO_MODULES_DB "select module, data_value from modules where data_name='CLASS'" | sed 's/; /|/g' | tr '|' '\t' >> module_class.txt ``` ### get module names: ``` sqlite3 $ANVIO_MODULES_DB "select module, data_value from modules where data_name='NAME'" | tr '|' '\t' > module_names.txt ``` **COMENTARIO:** en estos casos lo que ha cambiado es que no se llama kegg_modules si no modules, como se observó al revisar los archivos con la ayuda del comando: `sqlite3 $ANVIO_MODULES_DB ".tables"` en este comando nos dimos cuenta que en realidad era la tabla modules y lo comprobamos: ``` sqlite3 $ANVIO_MODULES_DB SELECT * FROM modules; ``` ### Unir todo `paste module_class.txt module_names.txt >> modules_info.txt` Se debe eliminar manualmente la segunda columna de modulos porque si no anvio no deja correrlo, ya que hay 5 columnas con nombres y 6 filas. **VERIFICAR PENDIENTE PARA EXPLICAR MEJOR.** A partir de aqui, el archivo que se anexara en el `PROFILE.db` va a depender del interes. Dado el caso sean todos, se utiliza el archivo creado `modules_info.txt` pero for prefiltered modules of interest hay que hacer un proceso de filtrado de los datos antes. #### Para extraer los modulos y poder posteriormente solo crear un archivo con los modulos de interes crear un archivo extract_modules_info.py con el script: Copiar los modulos que estan en el archivo de stepwise o pathwise completeness, dependiendo de cual enfoque se utilice y utilizarlos para obtener la informacion de los modulos a partir del archivo `modules_info.txt` que contiene toda la info de todos los modulos del keggs. Esto se hace de tal forma, al hacer la importacion solo aparezca en el filograma los modulos de interes, en este caso, los que se estan extrayendo, pero posterior a su filtrado, y no como cuando se importa directamente el `modules_info.txt` en el cual aparece en el filograma todos los modulos, incluyendo lo de interes y no intres, completos e incompletos. Crear un archivo python con el siguiente script: ``` def cargar_modulos(archivo_modulos): """Carga los módulos de un archivo de texto.""" with open(archivo_modulos, "r") as f: return {line.strip() for line in f if line.strip() and not line.startswith("module")} def extraer_info_modulos(archivo_info, modulos_interes): """Extrae la información de los módulos del archivo modules_info.txt""" info_modulos = {} with open(archivo_info, "r") as f: for line in f: parts = line.strip().split("\t") # Separar por tabulaciones if parts[0] in modulos_interes: info_modulos[parts[0]] = { "class": parts[1], "category": parts[2], "subcategory": parts[3], "name": parts[4] } return info_modulos # Archivos de entrada archivo_modulos = "lista_modulos.txt" # Reemplaza con la ruta de tu archivo de módulos archivo_info = "modules_info.txt" # Archivo con la información de los módulos # Cargar lista de módulos de interés modulos_interes = cargar_modulos(archivo_modulos) # Extraer información resultados = extraer_info_modulos(archivo_info, modulos_interes) # Guardar resultados en un archivo with open("modulos_extraidos.txt", "w") as f_out: f_out.write("module\tclass\tcategory\tsubcategory\tname\n") for modulo, info in resultados.items(): f_out.write(f"{modulo}\t{info['class']}\t{info['category']}\t{info['subcategory']}\t{info['name']}\n") print("Extracción completada. Revisa el archivo 'modulos_extraidos.txt'.") ``` Por otra parte, se debe crear un archivo `lista_modulos.txt` que contenga los modulos. En el siguiente formato: ``` M00001 M00002 M00003 M00004 M00005 M00006 M00007 M00008 M00009 M00010 M00011 ``` Revisar el documento y dejar solos los modulos de interes. Posteriormente, correr todo el analisis pero solo con los de interes. El archivo que debe ser modificado, es el que se importara, ya que el **generado por el script solo es para obtener los nombres de los modulos que estan presentes en este** y poder buscar, filtrar y dejar los de interes. ### Importar metabolism Independiente de las dos variantes, si es especifico o general, se sigue el siguiente proceso pero teniendo en cuenta que archivo es, si es `modules_info.txt` para general: ``` anvi-import-misc-data specific_modules.txt -p Enterococcus_metabolism_PROFILE.db -t items ``` O `modulos_extraidos.txt` para modulos de interes: ``` anvi-import-misc-data modulos_extraidos.txt -p Enterococcus_metabolism_PROFILE.db -t items ``` Finalmente, para la visualizacion del filograma del metabolismo: ``` anvi-interactive --manual-mode -d Enterococcus-completeness-MATRIX.txt -t Enterococcus-completeness-MATRIX.txt.newick -p Enterococcus_metabolism_PROFILE.db --title "Enterococcus Metabolism Heatmap" --manual ``` # ABRicate Mass screening of contigs for antimicrobial resistance or virulence genes. It comes bundled with multiple databases: NCBI, CARD, ARG-ANNOT, Resfinder, MEGARES, EcOH, PlasmidFinder, Ecoli_VF and VFDB. https://github.com/tseemann/abricate ## Installation ``` conda install -c conda-forge -c bioconda -c defaults abricate abricate --check abricate --list ``` Run the analysis for one genome: `abricate ARCHIVO.fna` También se puede correr en varios: `abricate *.fna` ABRicate tiene diferentes bases de datos que pueden ser utilizadas. Se pueve verificar las bases de datos con el comando: `abricate --list` Se vera un resultado como el siguiente: ``` DATABASE SEQUENCES DBTYPE DATE card 2631 nucl 2023-Nov-4 ecoli_vf 2701 nucl 2023-Nov-4 plasmidfinder 460 nucl 2023-Nov-4 ecoh 597 nucl 2023-Nov-4 ncbi 5386 nucl 2023-Nov-4 resfinder 3077 nucl 2023-Nov-4 vfdb 2597 nucl 2023-Nov-4 megares 6635 nucl 2023-Nov-4 argannot 2223 nucl 2023-Nov-4 ``` Para correr el analisis con una base de datos en especifico y generar un output en csv: `abricate *.fna --db DBname --csv > card.csv` Por ejemplo para correrla con la DB card: `abricate *.fna --db card --csv > card.csv` # AMRFinder ## Installation ### **Set up bioconda as the default channel** ``` conda config --add channels defaults conda config --add channels bioconda conda config --add channels conda-forge ``` ### **Create a conda enviroment and install all dependencies:** ``` conda create -n amrfinder conda activate amrfinder conda create -y -c conda-forge -c bioconda -n amrfinder --strict-channel-priority ncbi-amrfinderplus ``` ## Running the analysis ### **To run the analysis in a single genome:** `amrfinder -n GENOME.fna` **To run the analysis in multiple fna files create a amrfinder_multiple.sh using nano and the following script: ``` #!/bin/bash # Vacía o crea el archivo de salida > amrfinder_results.txt # Recorre todos los archivos .fna en el directorio actual for file in *.fna; do echo "Procesando $file" >> amrfinder_results.txt amrfinder -n "$file" >> amrfinder_results.txt echo "" >> amrfinder_results.txt # Línea en blanco para separar resultados done ``` Cambiar los permisos para que sea ejecutable: `chmod 777 amrfinder_multiple_anot.sh` Correr el script: `./amrfinder_multiple_anot.sh` # Gene extraction using PROKKA outputs **To extract genes from **gbk** files use the following script:** ``` from Bio import SeqIO import os # Lista de genes de interés genes_of_interest = [ "vioA", "vioB", "vioC", "vioD" ] # Ruta de los archivos .gbk input_folder = "/Users/abraham/Documents/Pangenomics/Violacein/Chromobacterium/gbk" output_folder = os.path.join(input_folder, "OUTPUT_DIRECTORY_NAME") # Crear la carpeta de salida si no existe if not os.path.exists(output_folder): os.makedirs(output_folder) # Detectar automáticamente archivos .gbk en la carpeta de entrada gbk_files = [f for f in os.listdir(input_folder) if f.endswith(".gbk")] if not gbk_files: print("No se encontraron archivos .gbk en la carpeta especificada.") exit() print(f"Se encontraron {len(gbk_files)} archivos .gbk.") # Función para extraer genes de interés y sus bloques completos def extract_genes(input_folder, gbk_files, genes_of_interest, output_folder): for gbk_file in gbk_files: file_path = os.path.join(input_folder, gbk_file) output_file = os.path.join(output_folder, f"genes_{gbk_file}") # Crear un archivo por genoma with open(output_file, "w") as out_handle: for record in SeqIO.parse(file_path, "genbank"): new_record = record[:] new_record.features = [] for feature in record.features: if feature.type == "gene" and "gene" in feature.qualifiers: gene_name = feature.qualifiers["gene"][0] if gene_name in genes_of_interest: # Agregar la característica 'gene' new_record.features.append(feature) # Buscar y agregar características relacionadas (CDS, mRNA, etc.) for related_feature in record.features: if ( related_feature.location == feature.location and related_feature.type in {"CDS", "mRNA"} ): new_record.features.append(related_feature) # Escribir el nuevo registro si tiene características if new_record.features: SeqIO.write(new_record, out_handle, "genbank") print(f"Genes extraídos de {gbk_file} y guardados en {output_file}") # Llamar a la función para extraer los genes extract_genes(input_folder, gbk_files, genes_of_interest, output_folder) print("Proceso completado. Todos los genes extraídos fueron guardados en:", output_folder) ``` ### Create a table with presence/absence from gbk files Puedes automatizar la construcción de tu tabla a partir de archivos GBK usando Python y Biopython. En este ejemplo se usa un script que extrae la presencia de los genes vioA, vioB, vioC, vioD y vioE de múltiples archivos GenBank y genera una tabla en formato CSV. Sin embargo, los nombres de los genes pueden modificar segun sea la necesidad. Asegúrate de tener Biopython instalado: `pip install biopython` Usa el siguiente script en Python: ``` import os import csv from Bio import SeqIO # Directorio donde están los archivos GBK gbk_dir = "ruta/a/tus/archivos" # Lista de genes a buscar vio_genes = ["vioA", "vioB", "vioC", "vioD", "vioE"] # Inicializar lista para la tabla table_data = [["Genome"] + vio_genes] # Recorrer cada archivo GBK en el directorio for filename in os.listdir(gbk_dir): if filename.endswith(".gbk") or filename.endswith(".gb"): genome_name = filename.replace(".gbk", "").replace(".gb", "") # Nombre base del genoma gene_presence = {gene: "No" for gene in vio_genes} # Inicializar como 'No' gbk_path = os.path.join(gbk_dir, filename) with open(gbk_path, "r") as gbk_file: for record in SeqIO.parse(gbk_file, "genbank"): for feature in record.features: if feature.type == "gene" and "gene" in feature.qualifiers: gene_name = feature.qualifiers["gene"][0] if gene_name in vio_genes: gene_presence[gene_name] = "Sí" # Marcar como encontrado # Agregar fila con la información table_data.append([genome_name] + [gene_presence[gene] for gene in vio_genes]) # Guardar la tabla en un archivo CSV output_csv = "vio_genes_table.csv" with open(output_csv, "w", newline="") as csvfile: writer = csv.writer(csvfile) writer.writerows(table_data) print(f"Tabla guardada en {output_csv}") ``` **To extract genes from **gff** files use the following script:** ``` import os import pandas as pd # Lista de genes de interés genes_of_interest = {"vioA", "vioB", "vioC", "vioD"} # Directorios de entrada y salida input_folder = "/Users/abraham/Documents/Pangenomics/Violacein/Chromobacterium/gff" output_folder = os.path.join(input_folder, "genes_extracted") # Crear carpeta de salida si no existe if not os.path.exists(output_folder): os.makedirs(output_folder) # Detectar archivos GFF en la carpeta de entrada gff_files = [f for f in os.listdir(input_folder) if f.endswith(".gff")] if not gff_files: print("No se encontraron archivos .gff en la carpeta especificada.") exit() print(f"Se encontraron {len(gff_files)} archivos .gff.") # Función para extraer genes de interés def extract_genes_from_gff(input_folder, gff_files, genes_of_interest, output_folder): for gff_file in gff_files: file_path = os.path.join(input_folder, gff_file) output_file = os.path.join(output_folder, f"genes_{gff_file}") # Leer el archivo GFF en un DataFrame, ignorando comentarios df = pd.read_csv(file_path, sep="\t", comment="#", header=None, names=[ "seqid", "source", "type", "start", "end", "score", "strand", "phase", "attributes" ]) # Filtrar solo las líneas que corresponden a genes y contienen nuestros genes de interés df_filtered = df[df["type"] == "gene"].copy() # Extraer el nombre del gen desde la columna "attributes" df_filtered["gene_name"] = df_filtered["attributes"].str.extract(r"Name=([^;]+)") # Filtrar los genes de interés df_filtered = df_filtered[df_filtered["gene_name"].isin(genes_of_interest)] # Guardar los genes extraídos en un nuevo archivo GFF if not df_filtered.empty: df_filtered.to_csv(output_file, sep="\t", index=False, header=False) print(f"Genes extraídos de {gff_file} y guardados en {output_file}") else: print(f"No se encontraron genes de interés en {gff_file}") # Ejecutar la función para extraer genes extract_genes_from_gff(input_folder, gff_files, genes_of_interest, output_folder) print("Proceso completado. Todos los genes extraídos fueron guardados en:", output_folder) ``` ### Create a table with presence/absence from gff files Puedes automatizar la construcción de tu tabla a partir de archivos GBK usando Python y Biopython. En este ejemplo se usa un script que extrae la presencia de los genes vioA, vioB, vioC, vioD y vioE de múltiples archivos GenBank y genera una tabla en formato CSV. Sin embargo, los nombres de los genes pueden modificar segun sea la necesidad. Asegúrate de tener Biopython instalado: `pip install biopython` Usa el siguiente script en Python: ``` import os import csv import pandas as pd # Directorio donde están los archivos GFF gff_dir = "/Users/abraham/Documents/Pangenomics/Violacein/Chromobacterium/gff" # Lista de genes a buscar vio_genes = ["vioA", "vioB", "vioC", "vioD", "vioE"] # Inicializar lista para la tabla table_data = [["Genome"] + vio_genes] # Recorrer cada archivo GFF en el directorio for filename in os.listdir(gff_dir): if filename.endswith(".gff"): genome_name = filename.replace(".gff", "") # Nombre base del genoma gene_presence = {gene: "No" for gene in vio_genes} # Inicializar como 'No' gff_path = os.path.join(gff_dir, filename) # Cargar el GFF como DataFrame (ignorando comentarios) df = pd.read_csv(gff_path, sep="\t", comment="#", header=None, names=[ "seqid", "source", "type", "start", "end", "score", "strand", "phase", "attributes" ]) # Filtrar solo las líneas de genes df_genes = df[df["type"] == "gene"].copy() # Extraer el nombre del gen desde la columna "attributes" df_genes["gene_name"] = df_genes["attributes"].str.extract(r"Name=([^;]+)") # Marcar los genes presentes for gene in vio_genes: if gene in df_genes["gene_name"].values: gene_presence[gene] = "Sí" # Agregar fila con la información table_data.append([genome_name] + [gene_presence[gene] for gene in vio_genes]) # Guardar la tabla en un archivo CSV output_csv = os.path.join(gff_dir, "vio_genes_presence_absence.csv") with open(output_csv, "w", newline="") as csvfile: writer = csv.writer(csvfile) writer.writerows(table_data) print(f"Tabla guardada en {output_csv}") ``` # Phylogenomics --- # MAFFT: Multiple alignment program for amino acid or nucleotide sequences **Installation** sudo apt install mafft - **--op # :** Gap opening penalty, default: 1.53 - **--ep # :** Offset (works like gap extension penalty), default: 0.0 - **--maxiterate # :** Maximum number of iterative refinement, default: 0 - **--clustalout :** Output: clustal format, default: fasta - **--reorder :** Outorder: aligned, default: input order - **--quiet :** Do not report progress - **--thread # :** Number of threads (if unsure, --thread -1) - **--dash :** Add structural information (Rozewicki et al, submitted) **If unsure which option to use:** % `mafft --auto in > out` **To run standard aligment:** `mafft --reorder --adjustdirection --auto input.fasta > output.fas` - **--reorder**: Outorder: aligned, default: input order - **--adjustdirection:** organize the direction of the sequences based on the first sequence - **--auto:** selection of auto model for the aligment - **in > out:** input.fas and output.fas --- --- # IQ-Tree: Efficient and versatile phylogenomic software by maximum likelihood **Installation** **Create a enviroment for IQ-Tree using conda:** `conda create -n iqtree` **Activate the enviroment:** `conda activate iqtree` **Install the packages using bioconda:** `conda install -c bioconda iqtree` **General ML tree analysis** Combine ModelFinder, tree search, SH-aLRT test and ultrafast bootstrap with 1000 replicates: `iqtree -s example.phy -B 1000 -alrt 1000` **Partitioned analysis with mixed data** http://www.iqtree.org/doc/Advanced-Tutorial To analyze different genes aligned in different files to create a phylogenomic tree using ML **Script:** ``` #nexus begin sets; charset part1 = rps16_alig.nex; charset part2 = ITS_alig.nex; charset part3 = rbcl_alig.nex; end;* ``` Note: each **part*** represent each of the aligned files that are going to be included in the ML tree analysis. It is **important** that in case .nex file is used, the *match=.* needs to be removed because it will not run the script as it wilk detect the *match=.* as an error # Species/genus delimitation standard ## Pyani: Average Nucleotide Identity https://github.com/widdowquinn/pyani ### Installation conda create --name pyani_env python=3.8 -y conda activate pyani_env conda install mummer blast legacy-blast -y conda install pyani Para correr el analisis: `average_nucleotide_identity.py -i . -o ANIb_output -m ANIb -g -v --write_excel --gformat svg` INFORMACION: https://gensoft.pasteur.fr/docs/pyani/0.2.10/ **PARA RETOMAR UN ANALISIS DE PYANI QUE QUEDO EN LA GENERACION DE LOS ARCHIVOS .BLAST**. Correr este comando en la carpeta fna donde se genero la carpeta ANIb_output y donde dentro de esa estan los otros archivos: `average_nucleotide_identity.py -i . -o ANIb_output -m ANIb -v --skip_blastn --noclobber --nocompress --force --write_excel` ``` INFO: Carrying out ANIb analysis INFO: Running ANIb INFO: Writing BLAST output to ANIb_output/blastn_output WARNING: Skipping BLASTN runs (as instructed)! INFO: Processing pairwise ANIb BLAST output. INFO: Writing ANIb results to ANIb_output INFO: ANIb_alignment_lengths INFO: ANIb_percentage_identity INFO: ANIb_alignment_coverage INFO: ANIb_similarity_errors INFO: ANIb_hadamard INFO: Done: Tue May 14 11:42:36 2024. INFO: Time taken: 890.59s ``` Debe verse al final algo como lo anterior Para hacer un clustering basado en el umbral del 0,95: Crear un archivo .py con el siguiente script: ``` import pandas as pd import networkx as nx def check_file(file_path): """Verifica si el archivo se puede abrir correctamente y muestra las primeras filas.""" try: # Intentamos leer el archivo y mostramos las primeras filas ani_matrix = pd.read_csv(file_path, sep='\t', index_col=0) print("Archivo cargado correctamente.") print(ani_matrix.head()) # Muestra las primeras filas para verificar return ani_matrix except Exception as e: print(f"Error al leer el archivo: {e}") return None def cluster_species(ani_matrix, threshold=0.95): G = nx.Graph() # Añadir nodos for genome in ani_matrix.index: G.add_node(genome) # Añadir aristas según el umbral de ANI for i, genome1 in enumerate(ani_matrix.index): for j, genome2 in enumerate(ani_matrix.columns): if i < j: # Evitar comparar duplicados y la diagonal ani_value = ani_matrix.loc[genome1, genome2] if ani_value >= threshold: G.add_edge(genome1, genome2) # Encontrar componentes conectados (grupos de especies) species_clusters = list(nx.connected_components(G)) return species_clusters def save_results(species_clusters, output_file): """Guarda los resultados en un archivo de texto o CSV.""" with open(output_file, 'w') as f: f.write(f"Se encontraron {len(species_clusters)} especies:\n") for i, cluster in enumerate(species_clusters, 1): f.write(f"Especie {i}:\n") for genome in sorted(cluster): f.write(f" {genome}\n") f.write("\n") def main(file_path, output_file): ani_matrix = check_file(file_path) if ani_matrix is not None: species_clusters = cluster_species(ani_matrix) save_results(species_clusters, output_file) print(f"Los resultados se guardaron en {output_file}") # Uso: # Asegúrate de pasar la ruta completa del archivo a 'main' y la ruta de salida donde deseas guardar el archivo main('ruta/a/tu/ANIb_percentage_identity.tab', 'ruta/al/output/resultados_ani_clusters.txt') ``` Solo se debe modificar la ruta al archivo.tab y la donde se quiere que se genere el output ## CompareM: Amino Acid Identity (AAI) Workflow *DID NOT WORK* https://github.com/donovan-h-parks/CompareM ### Installation ``` conda create -n comparem conda activate comparem conda install -c bioconda comparem ``` ### Analysis The most common task performed with CompareM is the calculation of pairwise amino acid identity (AAI) values between a set of genomes. This can be performed using the **`aai_wf`** command: `comparem aai_wf <input_files> <output_dir>` The `<input_file>` argument indicates the set of genomes to compare and can either i) a text file where each line indicating the location of a genome, or ii) a directory containing all genomes to be compared. The genomic nucleotide sequences of genomes must be in FASTA format. The `<output_dir>` indicates the desired directory for all output files. A typical use of this command would be: `comparem --cpus 20 aai_wf my_genomes aai_output` Where the directory `my_genomes` contains a set of genomes in FASTA format, the results are to be written to a directory called `aai_output`, and 20 processors should be used to calculate the results. A number of optional arguments can also be specified. This includes the **sequence similarity parameters** used to define reciprocal best hits between genomes(i.e., homologs). By default the e-value (`--evalue`), percent sequence identity (`--per_identity`), and percent alignment length (`--per_aln_len`) parameters are set to **1e-5**, **30%**, and **70%**. **When specifying a directory of genomes to process, CompareM only processes files with a fna extension.** This can be changes with the `--file_ext` argument. In addition, if genomes are already represented by amino acid protein sequences (as opposed to genomic nucleotide sequences), this must be specified with the `--proteins` flag. Otherwise, genes will be identified de novo using the Prodigal gene caller. The time to compute all pairwise AAI values can be substantially reduced by using multiple processors as specified with the `--cpus` argument. Other arguments are for specialized uses and are discussed in the User's Guide. Pairwise AAI statistics are provided in the output file **./<output_dir>/aai/aai_summary.tsv**. This file consists of 8 columns indicating: * Identifier of the first genome * Number of genes in the first genome * Identifier of the second genome * Number of genes in the second genome * Number of orthologous genes identified between the two genomes * The mean amino acid identity (AAI) of orthologous genes * The standard deviation of the AAI across orthologous genes * The orthologous fraction (OF) between the two genomes defined as the number of orthologous genes divided the minimum number of genes in either genome * Other output files produced by this command are described below. Debido al **error que muestra se deben hacer algunas modificaciones (https://hackmd.io/L2llRUU_SrWfI4OYN-uozQ?view)** pero como es para linux (servidor) se debe hacer de la siguiente forma: **Localiza tu instalación de CompareM** Activa el ambiente de conda de comparem: `conda activate comparem` En tu ambiente donde corre comparem, lanza: ``` python3 - <<'PY' import comparem, os print(os.path.dirname(comparem.__file__)) PY ``` Eso te imprimirá la ubicacion de la carpeta de comparem: `/home/aguerra/.conda/envs/comparem/lib/python3.13/site-packages/comparem` **Edita el archivo similarity_search.py** `cd /home/aguerra/.conda/envs/comparem/lib/python3.13/site-packages/comparem` Abre `similarity_search.py` en tu editor favorito y busca las líneas que contienen algo así: `nano similarity_search.py` **Las lineas que se deben buscar:** ``` if platform.system() == 'Darwin': os.system("LC_ALL=C sed -i '' 's/~/\t/g' %s" % input_hit_table) os.system("LC_ALL=C gsort --parallel=8 -o %s -k1,1 -k3,3 %s" % (input_hit_table, input_hit_table)) else: os.system("LC_ALL=C sed -i 's/~/\t/g' %s" % input_hit_table) os.system("LC_ALL=C sort --parallel=8 -o %s -k1,1 -k3,3 %s" % (input_hit_table, input_hit_table)) ``` Remplazar todo eso por lo siguiente: ``` def _some_method(self, input_hit_table, output_hit_table): # <-- el nombre depende del método original self.logger.info('Sorting table with hits (be patient!).') # Fix simplificado para Linux: usar GNU sed y sort os.system(f"LC_ALL=C sed -i 's/~/\t/g' {input_hit_table}") os.system(f"LC_ALL=C sort --parallel=8 -o {input_hit_table} -k1,1 -k3,3 {input_hit_table}") # Mover el fichero ya procesado a la salida os.system('mv %s %s' % (input_hit_table, output_hit_table)) ``` ## EzAAI: High Throughput Prokaryotic Average Amino acid Identity Calculator http://leb.snu.ac.kr/ezaai ### Installation ``` conda create -n EzAAI conda activate EzAAI conda install -y -c bioconda ezaai ezaai -h ``` ### Analysis #### EzAAI extract - Extract profile DB from sequences Creá un archivo de script llamado `create_AAI_db.sh`: `nano create_AAI_db.sh` Pegá este contenido dentro del archivo (ajustando las rutas si es necesario): ``` #!/bin/bash mkdir -p db # crea la carpeta db si no existe for file in /ruta/completa/a/los/fna/*.fna; do base=$(basename "$file" .fna) echo "Procesando $base..." ezaai extract -i "$file" -o db/"$base".db -l "$base" done ``` Reemplazá **/ruta/completa/a/los/fna/** por la ruta real donde están tus archivos .fna. Guardá y cerrá el archivo (en nano, presionás Ctrl+O para guardar y Ctrl+X para salir). Dale permisos de ejecución: `chmod +x create_AAI_db.sh` Ejecutá el script: `./create_AAI_db.sh` EzAAI will automatically produce a CDS profile DB of the genome with Prodigal with following prompt. ``` EzAAI |: Running prodigal on genome fasta/Cn.fasta... EzAAI |: Converting given CDS file into profile database... (fasta/Cn.fasta.faa -> db/Cn.db) EzAAI |: Task finished. ``` #### EzAAI calculate - calculate AAI value from profile DBs **Run EzAAI calculate module** Simply enter the following one-liner to perform all-by-all pairwise AAI calculation on the extracted profiles from above. `ezaai calculate -i db/ -j db/ -o out/aai.tsv` The pipeline will automatically detect .db files from the directory and calculate AAI values across the entire set of pairs using MMSeqs2. ``` EzAAI |: Calculating AAI... [Task 1/36] EzAAI |: Calculating AAI... [Task 2/36] ... EzAAI |: Calculating AAI... [Task 36/36] EzAAI |: Task finished. ``` **Check results** Run following to peek the contents of the result file. `head -7 out/aai.tsv` You migth see something like the following: ``` ID1 ID2 Label1 Label2 AAI 786958951 786958951 Leucobacter muris Leucobacter muris 100.000000 786958951 199206886 Leucobacter muris Clavibacter nebraskensis 61.609688 786958951 334056981 Leucobacter muris Microbacterium hominis 61.465138 786958951 204122518 Leucobacter muris Microbacterium aurum 61.842079 786958951 1073644442 Leucobacter muris Clavibacter insidiosus 61.453637 786958951 727401181 Leucobacter muris Leucobacter chironomi 88.755422 ``` You can see the result in glance of which the pair from same genus reports relatively high AAI value than the others. #### EzAAI cluster - hierarchical clustering of taxa with AAI values Run following to perform hierarchical clustering on the matrix provided from the previous step. `ezaai cluster -i out/aai.tsv -o out/sample.nwk` You migth see something like the following: ``` EzAAI |: AAI matrix identified. Running hierarchical clustering with UPGMA method... EzAAI |: Task finished. Resulting file is in a Newick format, which you can either look at it as a text, ``` `cat out/sample.nwk` You migth see something like the following: ``` (((Microbacterium hominis:9.325725,Microbacterium aurum:9.325725):9.500001, (Clavibacter nebraskensis:2.373246,Clavibacter insidiosus:2.373246):16.452480):0.335034, (Leucobacter muris:5.622289,Leucobacter chironomi:5.622289):13.538471); ``` or as a tree visualized with different external programs such as MEGA. ![image](https://hackmd.io/_uploads/B1V25TAA1l.png) ## POC https://github.com/2015qyliang/POCP?tab=readme-ov-file ### Installation ## core-proteome average amino acid identity (pAAI) https://github.com/flass/cpAAI_Rhizobiaceae?tab=readme-ov-file#cpaai_rhizobiaceae # POCP-VS-AAI: https://github.com/RiescoR/POCP-VS-AAI Evaluation of POCP VS AAI: This is a R script to parse all the results from EzAAI and Bio-PI POCP matrix into summary tables, analyze them and create some plots. # PPanGGOLiN: Depicting microbial species diversity via a Partitioned PanGenome Graph Of Linked Neighbors https://github.com/labgem/PPanGGOLiN ## Installation Install PPanGGOLiN into a new conda environment `conda create -n ppanggolin -c defaults -c conda-forge -c bioconda ppanggolin` Check PPanGGOLiN install ``` conda activate ppanggolin ppanggolin --version ``` ## Analysis: to run a complete pangenome analysis A complete pangenomic analysis with PPanGGOLiN can be performed using the all subcommand. This workflow runs a series of PPanGGOLiN commands to generate a partitioned pangenome graph with predicted RGPs (Regions of Genomic Plasticity), spots of insertion and modules. Execute the following command to run the all workflow: `ppanggolin all --fasta GENOMES_FASTA_LIST` By default, it uses parameters that we have found to be generally the best for working with species pangenomes. For further customization, you can adjust some parameters directly on the command line. Alternatively, you can use a configuration file to fine-tune the parameters of each subcommand used by the workflow (see here for more details). If you want to generate a rarefaction curve use: `ppanggolin all --fasta GENOME_LIST.txt -c 6 --rarefaction` The meaning of the added parameters: ``` --rarefaction Use to compute the rarefaction curves (WARNING: can be time consuming) --c CPU, --cpu CPU Number of available cpus ``` ### Input files The file GENOMES_FASTA_LIST is a tsv-separated file with the following organization: * The first column contains a unique genome name (without space) * The second column contains the path to the associated FASTA file * Circular contig identifiers are indicated in the following columns * Each line represents a genome Example of tsv GENOMES_FASTA_LIST: ``` alkanivorans_IITR_71 /Volumes/TOSHIBA EXT/Violacein/Chromobacterium/fna_coded/alkanivorans_IITR_71.fna alkanivorans_S00115 /Volumes/TOSHIBA EXT/Violacein/Chromobacterium/fna_coded/alkanivorans_S00115.fna alkanivorans_S00172 /Volumes/TOSHIBA EXT/Violacein/Chromobacterium/fna_coded/alkanivorans_S00172.fna alkanivorans_S00296 /Volumes/TOSHIBA EXT/Violacein/Chromobacterium/fna_coded/alkanivorans_S00296.fna alticapitis_MWU14_2602 /Volumes/TOSHIBA EXT/Violacein/Chromobacterium/fna_coded/alticapitis_MWU14_2602.fna amazonense_001855565_1 /Volumes/TOSHIBA EXT/Violacein/Chromobacterium/fna_coded/amazonense_001855565_1.fna ``` ### Results files Upon executing the all command, multiple output files and graphics are generated (more information here). Most notably, it writes an HDF-5 file (pangenome.h5). This file can be used as input to any of the subcommands to rerun parts of the analysis with different parameters, write and draw different representations of the pangenome, or perform additional analyses with PPanGGOLiN. ## Gephi setup to analyze pangenome graph https://gephi.org/ Steps to see the graph in gephi 1) Go to File/Open/and select the file pangenomeGraph.gexf. 2) Click OK in the window that appears. 3) Scroll out with your mouse. 4) Go to the Layout section on the left and in the selection bar choose ForceAtlas2. 5) In the Tuning section change the Scaling value to 4000 and check the Stronger Gravity box. 6) Click on the Run button and then click it again to stop. # pyGenomeViz https://github.com/moshi4/pyGenomeViz ## Installation `conda install -c conda-forge pygenomeviz` Additional installation of progressiveMauve is required. `conda install -c conda-forge -c bioconda pygenomeviz progressivemauve` **EN MACOS NO ESTA FUNCIONANDO, UTILIZAR EL DEL SERVIDOR O UN LINUX** ## Usage `pgv-pmauve seq1.gbk seq2.gbk seq3.gbk seq4.gbk -o pmauve_example` ***Options*** ``` General Options: --seq_files IN [IN ...] Input genome sequence files (Genbank or Fasta format) -o OUT, --outdir OUT Output directory --refid Reference genome index (Default: 0) --format [ ...] Output image format ('png'[*]|'jpg'|'svg'|'pdf'|`html`[*]) --reuse Reuse previous result if available -v, --version Print version information -h, --help Show this help message and exit Figure Appearence options: --fig_width Figure width (Default: 15) --fig_track_height Figure track height (Default: 1.0) --feature_track_ratio Feature track ratio (Default: 1.0) --link_track_ratio Link track ratio (Default: 5.0) --tick_track_ratio Tick track ratio (Default: 1.0) --track_labelsize Track label size (Default: 20) --tick_labelsize Tick label size (Default: 15) --normal_link_color Normal link color (Default: 'grey') --inverted_link_color Inverted link color (Default: 'tomato') --align_type Figure tracks align type ('left'|'center'[*]|'right') --tick_style Tick style ('bar'|'axis'|None[*]) --plotstyle Block box plot style ('box'[*]|'bigbox') --cmap Block box colormap (Default: 'hsv') --curve Plot curved style link (Default: OFF) --dpi Figure DPI (Default: 300) [*] marker means the default value. ``` Example 1 Download example dataset, four E.coli genbank files: `pgv-download-dataset -n escherichia_coli` Run CLI workflow: `pgv-pmauve --seq_files NC_000913.gbk NC_002695.gbk NC_011751.gbk NC_011750.gbk -o pmauve_example1 --tick_style bar --block_cmap Pastel2` ![image](https://hackmd.io/_uploads/ry3oaTrEle.png) # Panstripe https://github.com/gtonkinhill/panstripe ## Installation Instalar el gestor de paquetes de Bioconductor (BiocManager). Este comando instala BiocManager, que es la herramienta oficial para descargar paquetes de Bioconductor. Es seguro ejecutarlo incluso si ya lo tienes. ``` if (!require("BiocManager", quietly = TRUE)) install.packages("BiocManager") ``` Usar BiocManager para instalar ggtree. Ahora que tienes el instalador correcto, úsalo para instalar el paquete que falta. `BiocManager::install("ggtree")` Para instalar ahora si el panstripe: ``` install.packages("remotes") remotes::install_github("gtonkinhill/panstripe") ``` If you would like to also build the vignette with your installation run: `remotes::install_github("gtonkinhill/panstripe", build_vignettes = TRUE)` ## Analysis Panstripe takes as input a phylogeny and gene presence/absence matrix in Rtab format as is produced by Panaroo, Roary, PIRATE and other prokaryotic pangenome tools. Como tenemos un dataset particular, los comandos van a cambiar porque no estaremos usando el dataset del programa si no uno particular. ### Siempre cargar las librerias necesarias: ``` library(panstripe) library(ape) library(patchwork) set.seed(1234) ``` ### Siempre definir las rutas a tus archivos ``` my_tree_path <- "/path/to/newick/file/tree.newick" my_rtab_path <- "/path/to/Rtab/file/gene_presence_absence.Rtab" ``` ### Load files ``` pa <- read_rtab(my_rtab_path) tree <- read.tree(my_tree_path) ``` Apartir de aqui algunas cosas cambian dependiendo del dataset. En algunas ocasiones surge un error y hay que recurrrir a otros modelos para correr el analis. En la forma regular: ### Run panstripe (Option A = regular) ``` fit <- panstripe(pa, tree) fit$summary ``` Deberias de ver un **output una table** asi como esta: ``` #> # A tibble: 6 × 7 #> term estimate std.error statistic p.value `bootstrap CI …` `bootstrap CI …` #> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> #> 1 istip 1.49 0.282 5.29 8.03e- 7 0.978 1.99 #> 2 core 2.97 0.247 12.0 9.69e-21 2.54 3.54 #> 3 depth 0.0572 0.0619 0.923 3.58e- 1 -0.0859 0.162 #> 4 isti… -1.93 0.431 -4.48 2.10e- 5 -2.82 -1.18 #> 5 p 1.25 NA NA NA 1.11 1.36 #> 6 phi 2.58 NA NA NA 1.92 3.28 ``` Si con esto se obtiene un **mensaje de error** como el siguiente: ``` Error in value[[3L]](cond) : Panstripe model fit failed! This can sometime be caused by unusual branch lengths. Setting fit_method='glmmTMB' or family='quasipoisson' or 'gaussian' often provides a more stable fit to difficult datasets In addition: There were 50 or more warnings (use warnings() to see the first 50) Error in value[[3L]](cond) : Panstripe model fit failed! This can sometime be caused by unusual branch lengths. Setting fit_method='glmmTMB' or family='quasipoisson' or 'gaussian' often provides a more stable fit to difficult datasets In addition: Warning messages: 1: glm.fit: algorithm did not converge 2: glm.fit: algorithm did not converge 3: step size truncated due to divergence Error in value[[3L]](cond) : Panstripe model fit failed! This can sometime be caused by unusual branch lengths. Setting fit_method='glmmTMB' or family='quasipoisson' or 'gaussian' often provides a more stable fit to difficult datasets In addition: Warning messages: 1: glm.fit: algorithm did not converge 2: glm.fit: algorithm did not converge 3: step size truncated due to divergence Error in value[[3L]](cond) : Panstripe model fit failed! This can sometime be caused by unusual branch lengths. Setting fit_method='glmmTMB' or family='quasipoisson' or 'gaussian' often provides a more stable fit to difficult datasets In addition: Warning messages: 1: glm.fit: algorithm did not converge 2: glm.fit: algorithm did not converge 3: step size truncated due to divergence Error in value[[3L]](cond) : Panstripe model fit failed! This can sometime be caused by unusual branch lengths. Setting fit_method='glmmTMB' or family='quasipoisson' or 'gaussian' often provides a more stable fit to difficult datasets In addition: Warning messages: 1: glm.fit: algorithm did not converge 2: glm.fit: algorithm did not converge 3: step size truncated due to divergence Error in value[[3L]](cond) : Panstripe model fit failed! This can sometime be caused by unusual branch lengths. Setting fit_method='glmmTMB' or family='quasipoisson' or 'gaussian' often provides a more stable fit to difficult datasets In addition: Warning messages: 1: glm.fit: algorithm did not converge 2: glm.fit: algorithm did not converge 3: step size truncated due to divergence Error in statistic(data, i[r, ], ...) : Model fitting failed to converge in bootstrap replicate! ``` Proceder con la opcion b que utiliza la familia quasipoisson. ### Run panstripe (Option B = quasipoisson family) ``` fit_gaussian <- panstripe(pa, tree, family = "gaussian") fit$summary ``` En el dataset que se utilizo para ejemplificar este tipo de casos, se obtuvo un output como el siguiente: ``` # A tibble: 6 × 7 term estimate std.error statistic p.value `bootstrap CI 2.5%` `bootstrap CI 97.5%` <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> 1 istip 2.52 0.268 9.39 9.42e-19 2.03 2.91 2 core 81554. 22512. 3.62 3.37e- 4 53970 132420 3 depth 2417. 4326. 0.559 5.77e- 1 -5688 10188 4 istip:core -79323. 22557. -3.52 4.97e- 4 -129180 -51864 5 p NA NA NA NA NA NA 6 phi NA NA NA NA NA NA ``` Notese de los valores de phi, core y tip ya que de esos valores dependeran los resultados de algunas graficas. Independiemente de la opcion A o B los siguientes plots deben correrse de la misma forma. ## Plot results ### Pangenome params `plot_pangenome_params(fit)` Un output se deberia ver como los siguientes: ##### Option A (Regular; tomado del github) ![image](https://hackmd.io/_uploads/rkBk196Vlx.png) ##### Option B (Quasipoisson family) ![image](https://hackmd.io/_uploads/rJ5Nkq6Vgx.png) Note: Los dos output provienen de dos datasets diferentes, por lo que no son comparables. Pero si muestran dos casos a los cuales nos podriamos estar enfrentando. #### How to interpret params figures * **Core**: indicates whether the branch lengths in the phylogeny are associated with gene gain and loss. * **Depth:** indicates whether the rate of gene gain and loss changes significantly with the depth of a branch. * **Istip:** indicates associations with genes observed on the tips of the phylogeny. * **p:** the inferred index parameter of the underlying Tweedie distribution. * **Phi:** the inferred dispersion parameter. A significant p-value for the tip term indicates that there is a different rate of gene exchange at the tips of the phylogeny compared with the internal branches. This is usually driven by annotation errors or highly mobile elements that do not persist long enough to be observed in multiple genomes. A significant p-value for the core term indicates that there is a significant association between the core genome branch length and the number of gene exchange events. The depth term is less interesting but indicates when there is a difference in our ability to detect older gene exchange events. #### Script para refinar pangenome params ``` # Cargar los paquetes necesarios library(ggplot2) library(dplyr) library(gridExtra) library(grid) # 1. Extraer y limpiar datos del objeto 'fit' summary_data <- fit$summary summary_data_clean <- summary_data %>% rename( lower_ci = 6, upper_ci = 7 ) %>% filter(term %in% c("core", "istip")) # 2. Crear el gráfico para el parámetro 'core' plot_core <- summary_data_clean %>% filter(term == "core") %>% ggplot(aes(x = term, y = estimate)) + geom_errorbar(aes(ymin = lower_ci, ymax = upper_ci), width = 0.25, linewidth = 0.8) + geom_point(size = 4, shape = 21, fill = "dodgerblue") + labs( title = NULL, x = NULL, y = "Gene count estimate" ) + theme_bw(base_size = 14) + theme( axis.title.y = element_text(face = "bold") ) # 3. Crear el gráfico para el parámetro 'tip' plot_tip <- summary_data_clean %>% filter(term == "istip") %>% ggplot(aes(x = term, y = estimate)) + geom_errorbar(aes(ymin = lower_ci, ymax = upper_ci), width = 0.25, linewidth = 0.8) + geom_point(size = 4, shape = 21, fill = "coral") + labs( title = NULL, x = NULL, y = NULL ) + theme_bw(base_size = 14) # 4. Organizar los gráficos y añadir el eje X compartido grid.arrange( plot_core, plot_tip, ncol = 2, # Añade el texto en la parte inferior, centrado entre ambos gráficos bottom = textGrob("Parameter", gp = gpar(fontface = "bold", fontsize = 14)) ) ``` ### Pangenome cumulative plot We also suggest plotting the cumulative number of gene gain and loss events against the core branch length. As Panstripe models each branch individually and accounts for the depth of the branch it is not possible to add the Panstripe model fit to this plot. `plot_pangenome_cumulative(fit)` Un output se deberia ver como los siguientes: ##### Option A (Regular; tomado del github) ![image](https://hackmd.io/_uploads/SyixhhpVgl.png) ##### Option B (Quasipoisson family) ![M_Smithii_cumulative](https://hackmd.io/_uploads/BJMb32aVxl.png) #### Script para refinar pangenome params ``` # Cargar los paquetes necesarios library(ggplot2) library(ggtext) # --- Define la ruta de la carpeta de salida --- output_directory <- "/path/to/output/directory/" # --- Crea la carpeta si no existe --- if (!dir.exists(output_directory)) { dir.create(output_directory, recursive = TRUE) } # 1. ASIGNAR EL GRÁFICO A UNA VARIABLE my_cumulative_plot <- plot_pangenome_cumulative(fit) + theme_bw(base_size = 14) + # --- ETIQUETAS (LABELS) --- labs( title = NULL, y = "**cumulative gene gain & loss events**", x = "**cumulative core branch distance**", shape = "**branch**", color = "**branch**" ) + # --- GEOMETRÍA DE PUNTOS --- geom_point(aes(shape = branch, color = branch), size = 2.5) + # --- ESCALAS MANUALES (CONTROL TOTAL) --- scale_shape_manual(name = "**branch**", values = c("internal" = 16, "terminal" = 17)) + scale_color_manual(name = "**branch**", values = c("internal" = "#e78ac3", "terminal" = "#7fb1d3")) + # --- TEMA Y ESTILO --- theme( axis.title.y = element_markdown(), axis.title.x = element_markdown(), legend.title = element_markdown(), legend.position = "right" ) + # Unimos las leyendas de color y forma en una sola guides(color = guide_legend(), shape = guide_legend()) # 2. GUARDAR LA VARIABLE COMO UN ARCHIVO SVG EN LA RUTA ESPECIFICADA ggsave( filename = file.path(output_directory, "pangenome_cumulative_plot.svg"), plot = my_cumulative_plot, width = 8, height = 6 ) ``` These two plots can easily be combined using the patchwork R package as: `plot_pangenome_params(fit) + plot_pangenome_cumulative(fit) + plot_layout(nrow = 1)` Un output se deberia ver como los siguientes: ##### Option A (Regular; tomado del github) ![image](https://hackmd.io/_uploads/BJRw3npNxl.png) ##### Option B (Quasipoisson family) ![M_Smithii_params_vs_cumulative](https://hackmd.io/_uploads/S1FY3264eg.png) ### Pangenome residuals of regression A plot of the residuals of the regression can also be generated using `plot_residuals(fit)` Un output se deberia ver como los siguientes: ##### Option A (Regular; tomado del github) ![image](https://hackmd.io/_uploads/Sk81p3pEee.png) ##### Option B (Quasipoisson family) ![M_smithii_residual](https://hackmd.io/_uploads/SJP03h6Neg.png) #### Script para refinar pangenome residuals of regression ``` # Cargar los paquetes necesarios library(ggplot2) library(ggtext) # --- Define la ruta de la carpeta de salida --- output_directory <- "path/to/the/output/directory" # --- Crea la carpeta si no existe --- if (!dir.exists(output_directory)) { dir.create(output_directory, recursive = TRUE) } # 1. ASIGNAR EL GRÁFICO DE RESIDUOS A UNA VARIABLE my_residuals_plot <- plot_residuals(fit) + # --- GEOMETRÍA DE PUNTOS --- # Se actualiza el color al código hexadecimal que pediste geom_point(shape = 16, colour = "#99df8a", alpha = 0.5) + theme_bw(base_size = 14) + # --- ETIQUETAS (LABELS) --- labs( title = NULL, y = "**Randomized quantile residuals**", x = "**Core distance**" ) + # --- TEMA Y ESTILO --- theme( axis.title.y = element_markdown(), axis.title.x = element_markdown() ) # 2. GUARDAR LA VARIABLE COMO UN ARCHIVO SVG EN LA RUTA ESPECIFICADA ggsave( filename = file.path(output_directory, "residuals_plot.svg"), plot = my_residuals_plot, width = 7, height = 6 ) # 3. MOSTRAR EL GRÁFICO EN R print(my_residuals_plot) ``` ### Tree with presence/absence A plot of the phylogeny and the corresponding gene presence/absence matrix can be made using the plot_tree_pa function. This function also takes an optional vector of gene names to include in the plot. ``` # look at only those genes that vary variable_genes <- colnames(pa)[apply(pa, 2, sd) > 0] plot_tree_pa(tree = tree, pa = pa, genes = variable_genes, label_genes = FALSE, cols = "black") ``` Un output se deberia ver como los siguientes: ##### Option A (Regular; tomado del github) ![image](https://hackmd.io/_uploads/r1tLp3T4ge.png) ##### Option B (Quasipoisson family) ![M_smithii_presence_abs](https://hackmd.io/_uploads/Bkqr6hTNle.png) ### Inferred ancestral states The plot_gain_loss function allows for the visualisation of the fitted gene gain and loss events on the given phylogeny. The enrichment for events at the tips of a tree is often driven by a combination of highly mobile elements and annotation errors. `plot_gain_loss(fit)` Un output se deberia ver como los siguientes: ##### Option A (Regular; tomado del github) ![image](https://hackmd.io/_uploads/B11oahpNll.png) ##### Option B (Quasipoisson family) ![M_smithii_gain_loss_plot](https://hackmd.io/_uploads/SJuia3aVel.png) #### Script para refinar pangenome gene gain/loss tree plot ``` # Cargar los paquetes necesarios, si no estan instalados proceder con la instalación library(ggplot2) library(ggtree) library(dplyr) library(rlang) # Para .data # ============================================================================== # 1. DEFINICIÓN DE LA NUEVA FUNCIÓN PERSONALIZADA # ============================================================================== # Hemos creado una nueva función para no modificar la original del paquete. # Añadimos argumentos para controlar el grosor del árbol y el tamaño de las etiquetas. my_plot_gain_loss <- function(fit, tree_linewidth = 0.5, # Controla el grosor de las ramas tip_label = TRUE, tip_label_size = 2.5) { # Controla el tamaño de las etiquetas # (Esta parte de preparación de datos es la misma que la original) gt <- dplyr::full_join( ggtree::fortify(fit$tree), data.frame(node = fit$tree$edge[, 2], trait = fit$data$acc), by = 'node' ) # --- Construcción del Gráfico con MODIFICACIONES --- gg <- ggtree::ggtree(gt, ggplot2::aes(color = .data$trait), linewidth = tree_linewidth) + # <-- Usamos nuestro argumento para líneas más finas ggplot2::labs(colour = 'Total genes\ngained & lost') + ggplot2::scale_color_binned(type = 'viridis') + ggtree::theme_tree2() if (tip_label) { # --- MODIFICACIONES CLAVE AQUÍ --- gg <- gg + ggtree::geom_tiplab( align = FALSE, # <-- Se pone en FALSE para eliminar las líneas del medio size = tip_label_size, # <-- Usamos nuestro argumento para etiquetas más pequeñas colour = 'black' ) } return(gg) } # ============================================================================== # 2. USO DE LA NUEVA FUNCIÓN PARA CREAR Y GUARDAR EL GRÁFICO # ============================================================================== # --- Define la ruta de la carpeta de salida --- output_directory <- "/path/to/output/directory/" # --- Crea la carpeta si no existe --- if (!dir.exists(output_directory)) { dir.create(output_directory, recursive = TRUE) } # Ahora llamamos a nuestra nueva función con los valores que queramos final_plot <- my_plot_gain_loss( fit, tree_linewidth = 0.4, # Ramas más finas tip_label_size = 2 # Etiquetas mucho más pequeñas ) + # Podemos añadir más personalizaciones aquí theme(legend.position = "right") # Guardamos el gráfico mejorado ggsave( filename = file.path(output_directory, "gain_loss_refined_plot.svg"), plot = final_plot, width = 8, height = 10 ) # Mostramos el gráfico final en R print(final_plot) ``` ### tSNE The tSNE dimension reduction technique can be used to investigate evidence for clusters within the pangenome. `plot_tsne(pa)` Un output se deberia ver como los siguientes: ##### Option A (Regular; tomado del github) ![image](https://hackmd.io/_uploads/Sk0rR3T4gg.png) ##### Option B (Quasipoisson family) ![M_smithii_tSNE](https://hackmd.io/_uploads/BkqNAnaNxx.png) #### Script para refinar tSNE ``` # Cargar los paquetes necesarios library(ggplot2) library(ggtext) # --- Define la ruta de la carpeta de salida --- output_directory <- "/path/to/output/directory/" # --- Crea la carpeta si no existe --- if (!dir.exists(output_directory)) { dir.create(output_directory, recursive = TRUE) } # --- 1. Fijar la semilla aleatoria para reproducibilidad --- # Esto garantiza que el resultado del t-SNE sea siempre el mismo. set.seed(123) # --- 2. Ejecutar t-SNE una vez y obtener solo los datos --- tsne_data <- plot_tsne(pa, plot = FALSE) # --- 3. Construir el gráfico personalizado con las coordenadas fijas --- final_tsne_plot <- ggplot(tsne_data, aes(x = dim1, y = dim2)) + # Geometría de los puntos (sólidos y de color) geom_point(shape = 16, colour = "#1f77b4", alpha = 0.8, size = 2.5) + # Tema y etiquetas theme_bw(base_size = 14) + labs( title = NULL, x = "**dim1**", y = "**dim2**" ) + theme( axis.title.x = element_markdown(), axis.title.y = element_markdown() ) # --- 4. Guardar el gráfico final como SVG --- ggsave( filename = file.path(output_directory, "tsne_plot_final.svg"), plot = final_tsne_plot, width = 7, height = 7 ) # --- 5. Mostrar el gráfico en R --- print(final_tsne_plot) ``` ## Run the analysis for multiple pangenomes ### Siempre cargar las librerias necesarias: ``` library(panstripe) library(ape) library(patchwork) set.seed(1234) ``` ### Siempre definir las rutas a tus archivos ``` base_path <- "/path/to/directory/with/files" ``` **Rutas para pangenome1** ``` pangenome1_tree_path <- file.path(base_path, "tree_p1.newick") pangenome1_rtab_path <- file.path(base_path, "gene_presence_absence_p1.Rtab") ``` **Rutas para pangenome2** ``` pangenome2_tree_path <- file.path(base_path, "tree_p2.newick") pangenome2_rtab_path <- file.path(base_path, "gene_presence_absence_p2.Rtab") ``` ### Cargar los datos del pangenoma1 ``` pa_p1 <- read_rtab(pangenome1_rtab_path) tree_p1 <- read.tree(pangenome1_tree_path) ``` ### Correr panstripe en pangenoma1. Usamos family='quasipoisson' para mayor estabilidad. `fit_p1 <- panstripe(pa_p1, tree_p1, family = 'quasipoisson')` ### Cargar los datos del pangenoma2 ``` pa_p2 <- read_rtab(pangenome2_rtab_path) tree_p2 <- read.tree(pangenome2_tree_path) ``` ### Correr panstripe en pangenoma1. Usamos family='quasipoisson' para mayor estabilidad. `fit_p2 <- panstripe(pa_p2, tree_p2, family = 'quasipoisson')` ### Correr la función de comparación `result_comparacion <- compare_pangenomes(fit_p1, fit_p2)` ### Imprimir el resumen de la comparación print(result_comparacion$summary) ### Para graficar params vs cumulative Cargar la librería patchwork si no está cargada `library(patchwork)` Utilizar el siguiente comando para generar los dos gráficos juntos: ``` plot_pangenome_params(list(P1 = fit_p1, P2 = fit_p2), legend = FALSE) + plot_pangenome_cumulative(list(P1 = fit_p1, P2 = fit_p2)) + plot_layout(nrow = 1) ``` El output se deberia ver como los siguientes: ##### Option A (Regular; tomado del github) ![image](https://hackmd.io/_uploads/HycE-6pNex.png) ##### Option B (Quasipoisson family) ![Rplot04](https://hackmd.io/_uploads/HJ50WTaNgx.png) # EggNOG-mapper https://github.com/eggnogdb/eggnog-mapper ## Website analysis Debido al gran espacio (80GB) que ocupa el programa se puede correr el analisis en la pagina directamente: http://eggnog-mapper.embl.de/ Upload the `pan_genome_reference.fa` generado por roary o panaroo y seleccion la opcion ***CDS*** para que se corra correctamente el analisis. Ademas, ingresa un correo donde se envia el link del analisis: ![image](https://hackmd.io/_uploads/HkLMa-vSll.png) Modificar los parametros segun sea necesario y luego click en **Submit**: ![image](https://hackmd.io/_uploads/HyySpWDSee.png) Al click en **Submit** se debe ver algo asi en la pagina: ![image](https://hackmd.io/_uploads/HJRt6Zvrxx.png) Revisar el correo y entrar al link dando click en ***Click to manage your job***: ![image](https://hackmd.io/_uploads/HJ436Wwree.png) Al entrar al link darle click en ***Star job*** para comenzar el analisis: ![image](https://hackmd.io/_uploads/r1KgAbDBxx.png) Se recibira un correo donde el analisis ha finalizado: ![image](https://hackmd.io/_uploads/rJCNC-wSgl.png) entrar al link dando click en ***Click to manage your job*** y en ***Explore annotation*** para ver las anotaciones online: ![image](https://hackmd.io/_uploads/HJN20WDBlg.png) Ademas, click en el formato en el cual se requiere el archivo, asi como los archivos necesarios. Para el caso de los analisis subsequentes necesitaremos el `.emapper.annotations` file en el ejemplo llamado de `MM_rqbj1453.emapper.annotations.tsv` y en formato csv. ## Analisis de categorias COGs general de todo el pangenoma based on EggNOG-mapper output Este script de Python realiza un análisis de frecuencia de las categorías funcionales COG a partir de un archivo de resultados de eggNOG-mapper. Su propósito es cuantificar y visualizar la distribución de funciones en un conjunto de genes anotados. ### Entradas (Inputs): Archivo de anotaciones de eggNOG: Un archivo de salida estándar de eggnog-mapper con formato TSV (ej. `MM_rqbj1453.emapper.annotations.ts`v). El script asume que este archivo se encuentra en el mismo directorio. ### Explicacion del analisis: * **Carga de Datos:** Lee el archivo de anotaciones, identificando automáticamente la fila del encabezado para ignorar los metadatos. * **Extracción y Limpieza:** Extrae la columna COG_category, elimina las entradas sin anotación y procesa las categorías múltiples (ej. "C,G") para quedarse únicamente con la primera letra. * **Cuantificación:** Realiza un conteo de la frecuencia absoluta de cada categoría COG. * **Normalización:** Calcula la frecuencia relativa de cada categoría como un porcentaje del total de anotaciones válidas. * **Visualización:** Genera una gráfica de barras que representa la frecuencia relativa de cada categoría COG. ### Salidas (Outputs): **Tabla de datos (`tabla_frecuencia_cog.csv`):** Un archivo CSV con tres columnas: Categoria_COG, Conteo y Frecuencia_Porcentaje. **Gráfica de resultados (`grafica_frecuencia_cog.png`):** Una imagen en alta resolución (300 dpi) del gráfico de barras, ideal para reportes y publicaciones. ## Horizontal barplot de la frecuencia relativa de COGs based on EggNOG-MAPPER tsv (.emapper.annotations.tsv) #### Script `plot_pangenome_cogs.py`: Importante, verificar que el **EGGNOG_FILE** en el script conincida con el nombre del archivo **`.emapper.annotations.tsv`**. Correr el script despues de haber creado el archivo usando python `plot_pangenome_cogs.py`: #### Script: ``` import pandas as pd import matplotlib.pyplot as plt import seaborn as sns # --- CONFIGURACIÓN --- # El nombre exacto de tu archivo de resultados de eggNOG. # Asegúrate de que este archivo esté en la misma carpeta que el script. EGGNOG_FILE = 'MM_rqbj1453.emapper.annotations.tsv' # Nombres de los archivos que se van a crear. OUTPUT_PLOT_FILE = 'grafica_frecuencia_cog.png' OUTPUT_DATA_FILE = 'tabla_frecuencia_cog.csv' # --- SCRIPT PRINCIPAL --- print(f"Paso 1: Cargando el archivo de anotaciones '{EGGNOG_FILE}'...") try: # Lógica robusta para encontrar la fila del encabezado (la que empieza con '#query'). header_row = 0 with open(EGGNOG_FILE, 'r') as f: for i, line in enumerate(f): if line.startswith('#query'): header_row = i break # Cargar el archivo usando el número de fila correcto para el encabezado. df = pd.read_csv(EGGNOG_FILE, sep='\t', header=header_row) except FileNotFoundError: print(f"\nERROR: No se encontró el archivo '{EGGNOG_FILE}'.") print("Asegúrate de que el script y el archivo de datos estén en la misma carpeta.") exit() print("Paso 2: Extrayendo y limpiando las categorías COG...") # Verificar si la columna 'COG_category' existe. if 'COG_category' not in df.columns: print("\nERROR: No se encontró la columna 'COG_category' en tu archivo.") print("Verifica el formato del archivo de eggNOG.") exit() # Eliminar filas que no tienen una categoría COG asignada. cog_categories = df['COG_category'].dropna() # Procesar categorías: Ignorar las que son '-' y tomar solo la primera letra si hay varias (ej. "C,G"). cleaned_cogs = [str(cog)[0] for cog in cog_categories if str(cog) != '-'] if not cleaned_cogs: print("\nERROR: No se encontraron anotaciones COG válidas en el archivo.") exit() print(f"Se encontraron {len(cleaned_cogs)} anotaciones COG válidas.") print("Paso 3: Contando frecuencias y calculando porcentajes...") # Contar la frecuencia de cada categoría COG. cog_counts = pd.Series(cleaned_cogs).value_counts().reset_index() cog_counts.columns = ['Categoria_COG', 'Conteo'] # Calcular la frecuencia relativa en porcentaje. total_annotations = cog_counts['Conteo'].sum() cog_counts['Frecuencia_Porcentaje'] = (cog_counts['Conteo'] / total_annotations) * 100 # Guardar la tabla de datos en un archivo CSV. cog_counts.to_csv(OUTPUT_DATA_FILE, index=False) print(f"Tabla de datos guardada como '{OUTPUT_DATA_FILE}'") print("Paso 4: Generando la gráfica...") # --- VISUALIZACIÓN --- plt.figure(figsize=(12, 8)) splot = sns.barplot(data=cog_counts, x='Categoria_COG', y='Frecuencia_Porcentaje', palette='viridis', order=sorted(cog_counts['Categoria_COG'])) # Añadir los porcentajes encima de cada barra. for p in splot.patches: splot.annotate(format(p.get_height(), '.1f') + '%', (p.get_x() + p.get_width() / 2., p.get_height()), ha = 'center', va = 'center', xytext = (0, 9), textcoords = 'offset points') plt.title('Frecuencia Relativa de Categorías COG', fontsize=16) plt.xlabel('Categoría COG', fontsize=12) plt.ylabel('Frecuencia Relativa (%)', fontsize=12) plt.ylim(0, max(cog_counts['Frecuencia_Porcentaje']) * 1.1) # Ajustar límite del eje Y plt.tight_layout() # Guardar la gráfica en un archivo. plt.savefig(OUTPUT_PLOT_FILE, dpi=300) print(f"¡Éxito! Gráfica guardada como '{OUTPUT_PLOT_FILE}'") plt.show() ``` Se debe de generar un output svg y png como el siguiente: ![grafica_frecuencia_cog](https://hackmd.io/_uploads/H1ZchYvSel.png) Realizar las modificaciones especificas para las necesidades de los datos. Se puede modificar la paleta, entre otros detalles visuales de la figura. # eggnogCOGextractor https://github.com/vsmicrogenomics/eggnogCOGextractor/tree/main ## Instalation Solo es descargar el archivo `eggnogCOGextractor.py` para correr el programa ## Analysis Crear una carpeta llama input y otra output. En la input debe estar el`MM_rqbj1453.emapper.annotations.tsv`, sin embargo, es importante que este no tenga la extension tsv si no que termine en **`.emapper.annotations`** Para correr el analisis correr el siguiente comando: `python eggnogCOGextractor.py ` Se generara un archivo tsv en el directorio output/ de la siguiente forma: ![image](https://hackmd.io/_uploads/SkkuYPwHeg.png) **Este archivo es importante para hacer algunos analisis como barplot**, entre otros. ## Vertical barplot de la frecuencia relativa de COGs based on eggnogCOGextractor output tsv (.emapper.cog.tsv) #### Script: ``` import pandas as pd import matplotlib.pyplot as plt import seaborn as sns # --- CONFIGURACIÓN --- INPUT_FILE = '/Users/abraham/Downloads/eggNOG_mapper_analysis_CLAS/eggnogCOGextractor/output/MM_rqbj1453.emapper.cog.tsv' # Nombres para los archivos de salida OUTPUT_PLOT_PNG = 'cog_bar_chart_final.png' OUTPUT_PLOT_SVG = 'cog_bar_chart_final.svg' # --- SCRIPT PRINCIPAL --- print(f"Paso 1: Cargando datos desde '{INPUT_FILE}'...") try: df = pd.read_csv(INPUT_FILE, sep='\t') except FileNotFoundError: print(f"\nERROR: No se encontró el archivo '{INPUT_FILE}'.") exit() except pd.errors.EmptyDataError: print(f"\nERROR: El archivo '{INPUT_FILE}' está vacío.") exit() df = df[df['COGCount'] > 0] df = df.sort_values('COGCount', ascending=False) print("Paso 2: Generando la gráfica de barras...") # Crear la figura (fig) y los ejes (ax) fig, ax = plt.subplots(figsize=(12, 8)) # Crear la gráfica de barras horizontales sns.barplot(data=df, x='COGCount', y='COGDescription', hue='COGDescription', palette='tab20', orient='h', legend=False, ax=ax) # Añadir el número exacto al final de cada barra. for index, value in enumerate(df['COGCount']): ax.text(value, index, f' {value}', va='center', ha='left') # Añadir la letra de la categoría (COGID) en el lado derecho. ax.spines['right'].set_visible(False) ax.spines['top'].set_visible(False) ax2 = ax.twinx() ax2.spines['right'].set_visible(False) ax2.set_ylim(ax.get_ylim()) ax2.set_yticks(ax.get_yticks()) ax2.set_yticklabels(df['COGID'], fontsize=10, weight='bold') ax.set_title('Número de Genes por Categoría Funcional COG', fontsize=16, weight='bold') ax.set_xlabel('Número de Genes', fontsize=12) ax.set_ylabel('Categoría COG', fontsize=12) plt.tight_layout() # --- MODIFICACIÓN FINAL: Guardar en ambos formatos --- plt.savefig(OUTPUT_PLOT_PNG, dpi=300, bbox_inches='tight') plt.savefig(OUTPUT_PLOT_SVG, bbox_inches='tight') # SVG es un vector, no necesita dpi print(f"¡Éxito! Gráficas guardadas como '{OUTPUT_PLOT_PNG}' y '{OUTPUT_PLOT_SVG}'") plt.show() ``` Se debe de generar un output svg y png como el siguiente: ![cog_bar_chart_final](https://hackmd.io/_uploads/HyhmhFwrll.png) Realizar las modificaciones especificas para las necesidades de los datos. Se puede modificar la paleta, entre otros detalles visuales de la figura. ## Vertical barplot de los genes especificos de algun COGs category (Ej: V and Q) based on eggnogCOGextractor output tsv (.emapper.cog.tsv) #### Script ``` import pandas as pd import matplotlib.pyplot as plt import seaborn as sns # --- CONFIGURATION --- EGGNOG_ANNOTATIONS_FILE = 'MM_rqbj1453.emapper.annotations.tsv' # Color map for categories of interest COLOR_MAP = { 'Q': '#2eabb8ff', # Color for 'Secondary metabolites' 'V': '#d1d197ff' # Color for 'Defense mechanisms' } CATEGORIES_TO_PLOT = list(COLOR_MAP.keys()) # --- PLOTTING FUNCTION --- def generate_detailed_plot(df, cog_letter, plot_color): """ Filters the dataframe by a COG category and generates a bar plot using a specific color. """ print(f"\n--- Processing Category: {cog_letter} with color {plot_color} ---") category_df = df[df['Cleaned_COG'] == cog_letter].copy() if category_df.empty: print(f"No genes found for category '{cog_letter}'.") return plot_data = category_df.loc[category_df.groupby('Description')['score'].idxmax()] plot_data = plot_data.sort_values('score', ascending=False).head(25) print(f"Found {len(plot_data)} unique functions to plot.") plt.figure(figsize=(12, 10)) sns.barplot(data=plot_data, x='score', y='Description', color=plot_color, orient='h') # --- Plot labels in English --- plt.title(f'Detailed Functions for COG Category: "{cog_letter}"', fontsize=16, weight='bold') plt.xlabel('Annotation Score (Bit-score)', fontsize=12) plt.ylabel('Function Description', fontsize=12) plt.tight_layout() output_filename_svg = f'detailed_plot_category_{cog_letter}.svg' plt.savefig(output_filename_svg, bbox_inches='tight') print(f"Plot saved as '{output_filename_svg}'") plt.close() # --- MAIN SCRIPT --- print(f"Step 1: Loading data from '{EGGNOG_ANNOTATIONS_FILE}'...") try: header_row = 0 with open(EGGNOG_ANNOTATIONS_FILE, 'r') as f: for i, line in enumerate(f): if line.startswith('#query'): header_row = i break main_df = pd.read_csv(EGGNOG_ANNOTATIONS_FILE, sep='\t', header=header_row) except FileNotFoundError: print(f"\nERROR: File not found '{EGGNOG_ANNOTATIONS_FILE}'.") exit() print("Step 2: Cleaning COG categories...") main_df.dropna(subset=['COG_category'], inplace=True) main_df['Cleaned_COG'] = main_df['COG_category'].apply(lambda x: str(x)[0] if str(x) != '-' else None) # Generate a plot for each category of interest for category, color in COLOR_MAP.items(): generate_detailed_plot(main_df, category, color) print("\nAnalysis complete.") ``` Se debe de generar un output svg y png como el siguiente: ![final_cohesive_plot](https://hackmd.io/_uploads/rkAFgRnBee.png) # KEGGaNOG: visualize KEGG Pathways using output results from EggNOG-mapper https://github.com/iliapopov17/KEGGaNOG ## Installation ``` # Linux / WSL / macOS conda create -n kegganog pip -y conda activate kegganog pip install kegganog ``` ## Analysis ### Single mode plot for KEGGs completeness: `KEGGaNOG -i MM_rqbj1453.emapper.annotations.tsv -o output_dir` By the key -i the input (eggNOG-mapper output file) must be provided By the key -o the path to output directory (it will be created if it does not exist) must be provided ### Barplot for KEGGs completeness: **PENDIENTE MODIFICAR EL SCRIPT PARA QUE GENERE EL SVG. ASI COMO LA PALETA** Cambiar la ubicacion del archivo **`SAMPLE_pathways.tsv`** generado por el programa. ``` import kegganog as kgn import pandas as pd # Cargar los datos df = pd.read_csv("/Users/abraham/Downloads/eggNOG_mapper_analysis_CLAS/grouped_clas/SAMPLE_pathways.tsv", sep="\t") # Preparar el objeto de la gráfica kgnbar = kgn.barplot(df, figsize = (8, 10), sort_order="descending", yticks_fontsize = 8, cmap = "Blues", ) # ---- CORRECCIÓN FINAL ---- # 1. Generar la figura y guardarla en una variable 'fig' fig = kgnbar.plotfig() # 2. Usar el método savefig() de la figura para guardarla en un archivo fig.savefig("KEGG_barplot.png", # Nombre del archivo de salida dpi=300, # Para alta resolución bbox_inches='tight') # Asegura que las etiquetas no se corten print("¡Éxito! Gráfica guardada como KEGG_barplot.png") ``` Para analisis subsequentes explorar: https://github.com/iliapopov17/KEGGaNOG?tab=readme-ov-file https://github.com/raymondkiu/eggnog-mapper_COGextraction/tree/master https://github.com/lillycummins/IdentifierToGroupName https://docs.omicsbox.biobam.com/latest/Functional-Annotation-with-EggNOG-Mapper/