From a9f649283e8341185612f982277e79fd97e6c825 Mon Sep 17 00:00:00 2001 From: Abhirupa Ghosh <100681585+AbhirupaGhosh@users.noreply.github.com> Date: Wed, 9 Sep 2026 11:10:02 -0600 Subject: [PATCH 1/4] Update feature_expr to replace '-' with '.' --- R/feature_to_head.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/feature_to_head.R b/R/feature_to_head.R index 17bead1..e0e8c12 100644 --- a/R/feature_to_head.R +++ b/R/feature_to_head.R @@ -411,7 +411,7 @@ buildDyadFeatureMap <- function( view_name = "v_pfam", parquet_dir = parquet_dir, dataset_name = "protein_Pfam", - feature_expr = "query_name" + feature_expr = "REPLACE(query_name, '-', '.')" ) } From 6c612c38743c2c399067d93cf0e87e06d9fae9d5 Mon Sep 17 00:00:00 2001 From: Abhirupa Ghosh <100681585+AbhirupaGhosh@users.noreply.github.com> Date: Wed, 9 Sep 2026 11:10:37 -0600 Subject: [PATCH 2/4] Delete R/feature_to_cluster.R --- R/feature_to_cluster.R | 171 ----------------------------------------- 1 file changed, 171 deletions(-) delete mode 100644 R/feature_to_cluster.R diff --git a/R/feature_to_cluster.R b/R/feature_to_cluster.R deleted file mode 100644 index 494f52e..0000000 --- a/R/feature_to_cluster.R +++ /dev/null @@ -1,171 +0,0 @@ -#' Build a protein cluster-to-feature mapping using DuckDB -#' -#' This function constructs a mapping between protein clusters and functional -#' features (e.g., gene families, domains, COGs, and ARGs) using a DuckDB-backed -#' workflow. The implementation is SQL-first and memory-efficient, leveraging -#' DuckDB views and Parquet output. -#' -#' @param duckdb_parquet_path Character. Path to the DuckDB database file with parquet file views -#' containing the input tables. -#' @param output_path Character or NULL. Directory where the output Parquet file -#' (\code{cluster_feature.parquet}) will be written. If NULL, the output is written -#' alongside the DuckDB database. -#' -#' @details -#' The function performs the following steps: -#' \itemize{ -#' \item Creates views for each feature type: -#' \itemize{ -#' \item Gene → protein features -#' \item Domain annotations -#' \item COG annotations -#' \item Antibiotic resistance gene (ARG) annotations -#' } -#' \item Combines all feature mappings into a unified protein–feature view -#' \item Joins protein–feature mappings to cluster membership -#' \item Writes the resulting cluster–feature mapping to a compressed Parquet file -#' } -#' -#' All joins and transformations are executed inside DuckDB, ensuring scalability -#' for large datasets without loading data into R memory. -#' -#' @return Invisibly returns the file path to the generated Parquet file. -#' -#' @examples -#' \dontrun{ -#' buildClusterFeatureMap( -#' duckdb_parquet_path = "data/Csp_parquet.duckdb", -#' output_path = NULL -#' ) -#' } -#' -#' @import DBI duckdb -#' @export -buildClusterFeatureMap <- function( - duckdb_parquet_path, - output_path = NULL -) { - con <- DBI::dbConnect( - duckdb::duckdb(), - normalizePath(duckdb_parquet_path) - ) - on.exit(DBI::dbDisconnect(con, shutdown = TRUE), add = TRUE) - - out_dir <- if (is.null(output_path)) { - dirname(duckdb_parquet_path) - } else { - normalizePath(output_path) - } - parquet_path <- file.path(out_dir, "cluster_feature.parquet") - - # ========================= - # Gene → protein features - # ========================= - DBI::dbExecute(con, " - CREATE OR REPLACE VIEW v_gene AS - SELECT DISTINCT - protein_ids AS protein_id, - REPLACE(Gene, '~', '.') AS feature - FROM genome_gene_protein - WHERE protein_ids IS NOT NULL - AND Gene IS NOT NULL - ") - - # ========================= - # Domain features - # ========================= - DBI::dbExecute(con, " - CREATE OR REPLACE VIEW v_domain AS - SELECT DISTINCT - AccNum AS protein_id, - \"DB.ID\" AS feature - FROM domain_names - WHERE AccNum IS NOT NULL - AND \"DB.ID\" IS NOT NULL - ") - - # ========================= - # Structural gene features - # (equivalent to separate_rows + inner_join(gp)) - # ========================= - # DBI::dbExecute(con, " - # CREATE OR REPLACE VIEW v_struct AS - # SELECT DISTINCT - # gp.protein_ids AS protein_id, - # s_gene AS feature - # FROM struct s - # JOIN genome_gene_protein gp - # ON gp.genome_ids = s.genome_id - # CROSS JOIN UNNEST(string_split(s.struct, '.')) AS t(s_gene) - # WHERE s.value = 1 - # ") - - # ========================= - # COG features - # ========================= - DBI::dbExecute(con, " - CREATE OR REPLACE VIEW v_cog AS - SELECT DISTINCT - query_name AS protein_id, - name AS feature - FROM protein_COG - WHERE query_name IS NOT NULL - AND name IS NOT NULL - ") - - # ========================= - # ARG features - # ========================= - DBI::dbExecute(con, " - CREATE OR REPLACE VIEW v_arg AS - SELECT DISTINCT - query_name AS protein_id, - REPLACE(REPLACE(name, '-NCBIFAM', ''), '-', '.') AS feature - FROM protein_ResFinder - WHERE query_name IS NOT NULL - AND name IS NOT NULL - ") - - # ========================= - # Union: protein → feature - # ========================= - DBI::dbExecute(con, " - CREATE OR REPLACE VIEW v_protein_feature AS - SELECT protein_id, feature FROM v_gene - UNION - SELECT protein_id, feature FROM v_domain - UNION - SELECT protein_id, feature FROM v_cog - UNION - SELECT protein_id, feature FROM v_arg - ") - - # ========================= - # Cluster → feature mapping - # ========================= - DBI::dbExecute(con, " - CREATE OR REPLACE VIEW cluster_feature AS - SELECT DISTINCT - cm.cluster, - pf.feature - FROM protein_members cm - JOIN v_protein_feature pf - ON pf.protein_id = cm.member - WHERE cm.cluster IS NOT NULL - AND pf.feature IS NOT NULL - ") - - # ========================= - # Write Parquet from DuckDB - # ========================= - DBI::dbExecute( - con, - sprintf( - "COPY cluster_feature TO '%s' - (FORMAT PARQUET, COMPRESSION ZSTD)", - parquet_path - ) - ) - - invisible(parquet_path) -} From 179781287822a2a1ac082b984c3e9b368f5f206d Mon Sep 17 00:00:00 2001 From: Abhirupa Ghosh <100681585+AbhirupaGhosh@users.noreply.github.com> Date: Wed, 9 Sep 2026 11:43:07 -0600 Subject: [PATCH 3/4] Update feature expression to replace '-' with '.' --- R/feature_to_head.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/feature_to_head.R b/R/feature_to_head.R index e0e8c12..9486096 100644 --- a/R/feature_to_head.R +++ b/R/feature_to_head.R @@ -444,7 +444,7 @@ buildDyadFeatureMap <- function( view_name = "v_defensecas", parquet_dir = parquet_dir, dataset_name = "protein_DefenseCas", - feature_expr = "query_name" + feature_expr = "REPLACE(query_name, '-', '.')" ) } From 1a199a4a7f9afb1c060fc5abded1ecf942cad919 Mon Sep 17 00:00:00 2001 From: Abhirupa Ghosh <100681585+AbhirupaGhosh@users.noreply.github.com> Date: Wed, 9 Sep 2026 12:25:32 -0600 Subject: [PATCH 4/4] Remove '_pseudo' and '_len' from protein_ids --- R/data_processing.R | 1 + 1 file changed, 1 insertion(+) diff --git a/R/data_processing.R b/R/data_processing.R index 4825c16..e9c8a6b 100644 --- a/R/data_processing.R +++ b/R/data_processing.R @@ -446,6 +446,7 @@ NULL tidyr::separate_rows(protein_ids, sep = ";") |> # dplyr::filter(!stringr::str_detect(protein_ids, "_pseudo")) |> dplyr::mutate(protein_ids = gsub("_pseudo", "", protein_ids)) |> + dplyr::mutate(protein_ids = gsub("_len", "", protein_ids)) |> DBI::dbWriteTable(conn = con, name = "genome_gene_protein", overwrite = TRUE) }