--- title: "OmicsLake v2.0 Quick Start Guide" author: "OmicsLake Development Team" date: "`r Sys.Date()`" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{OmicsLake v2.0 Quick Start Guide} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r setup, include=FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>", eval = isTRUE(getOption("omicslake.vignette.eval", FALSE)) ) ``` # Introduction OmicsLake v2.0 is a modern, easy-to-use omics data management package with data lineage at its core. It integrates into existing analysis workflows with minimal changes and automatically tracks data dependencies. ## Before you run all chunks This vignette is built with non-evaluated chunks by default for stable package checks. If you want to execute every chunk locally, run: ```r options(omicslake.vignette.eval = TRUE) ``` Then render the vignette from a writable directory. ## Recommended Next Guides - Representative layer-by-layer use cases: `vignettes/omicslake_layer_use_cases_EN.Rmd` - Practical RNA-seq centered workflow: `vignettes/omicslake_practical_workflow_EN.Rmd` - Full API coverage: `vignettes/omicslake_comprehensive_guide_EN.Rmd` ## Key Features - **Simple API**: Basic operations with just `put()`, `get()`, `snap()`, `tree()` - **Automatic Lineage Tracking**: Dependencies detected through dplyr pipes - **No SQL Required**: Formula syntax and QueryBuilder for R-native queries - **Existing Code Support**: observe/wrap modes for non-invasive tracking # Installation ```{r install} # Install from GitHub # Installation command is documented in README.md ``` # Basic Usage ## Initializing a Lake ```{r init} library(OmicsLake) # Create/open a project lake <- Lake$new("my_analysis") # Or use global shortcuts use_lake("my_analysis") ``` ## Storing and Reading Data ```{r basic_io} # Store a data frame counts <- data.frame( gene_id = paste0("GENE", 1:100), sample_A = rpois(100, 50), sample_B = rpois(100, 60) ) lake$put("counts", counts) # R objects can also be stored params <- list( method = "TMM", log_transform = TRUE, threshold = 0.05 ) lake$put("analysis_params", params) # Read data data <- lake$get("counts") my_params <- lake$get("analysis_params") ``` ## Filtering with Formula Syntax ```{r formula_filter} # No SQL needed! Filter with formula syntax high_expr <- lake$get("counts", where = ~ sample_A > 50) # Custom operators are also available mito_genes <- lake$get("counts", where = ~ gene_id %like% "MT-%") # Compound conditions filtered <- lake$get("counts", where = ~ sample_A > 30 & sample_B %between% c(40, 80) ) # Select columns simultaneously subset <- lake$get("counts", where = ~ sample_A > 50, select = c("gene_id", "sample_A") ) ``` ## dplyr Integration (Automatic Lineage Tracking) ```{r dplyr_integration} # Get a lazy reference with lake$ref() # Dependencies in dplyr pipes are automatically tracked! library(dplyr) lake$ref("counts") |> filter(sample_A > 30) |> mutate( mean_expr = (sample_A + sample_B) / 2, log2_ratio = log2(sample_B / sample_A) ) |> arrange(desc(mean_expr)) |> save_as("processed_counts", lake) # Check lineage lake$tree("processed_counts") # counts -> processed_counts ``` ## Joining Multiple Tables ```{r join_example} # Add metadata metadata <- data.frame( gene_id = paste0("GENE", 1:100), gene_name = paste0("Gene_", LETTERS[1:4])[rep(1:4, 25)], biotype = sample(c("protein_coding", "lncRNA"), 100, replace = TRUE) ) lake$put("gene_metadata", metadata) # JOIN with dplyr lake$ref("counts") |> left_join(lake$ref("gene_metadata"), by = "gene_id") |> filter(biotype == "protein_coding") |> group_by(gene_name) |> summarize(total_A = sum(sample_A), total_B = sum(sample_B)) |> save_as("gene_summary", lake) # Dependencies are automatically tracked lake$tree("gene_summary") # counts -----> gene_summary # gene_metadata ↗ ``` # QueryBuilder Build complex queries without writing SQL. ```{r querybuilder} # Build queries with method chaining result <- lake$from("counts")$ join("gene_metadata", on = "gene_id")$ where(biotype == "protein_coding")$ where(sample_A > 40)$ select(gene_id, gene_name, sample_A, sample_B)$ order_by(desc(sample_A))$ top(20, by = sample_A)$ run() # Save results to Lake lake$from("counts")$ where(sample_A > 50)$ as("high_expression_genes") ``` # Version Control ## Snapshots and Tags ```{r versioning} # Snapshot current state lake$snap("v1.0_raw_data") # Update data normalized <- lake$get("counts") normalized$sample_A <- log2(normalized$sample_A + 1) normalized$sample_B <- log2(normalized$sample_B + 1) lake$put("counts", normalized) lake$snap("v1.1_normalized") # Tag individual data lake$tag("counts", "before_normalization") # Get past version original <- lake$get("counts", ref = "@tag(before_normalization)") # Restore to snapshot lake$restore("v1.0_raw_data") ``` ## Viewing History ```{r history} # Project history lake$log() # History of specific data lake$log("counts") # List snapshots lake$snaps() ``` # Lineage (Data Provenance) ## Checking Dependencies ```{r lineage} # Upstream dependencies (what was this data made from?) lake$deps("gene_summary", direction = "up") # Downstream dependencies (what uses this data?) lake$deps("counts", direction = "down") # Complete lineage tree lake$tree("gene_summary", direction = "up", depth = 10) # Impact analysis (what would be affected if this data changes?) lake$impact("counts") ``` ## Lineage Visualization ```{r plot_lineage} # Visualize as graph (requires igraph package) lake$plot("gene_summary", direction = "both") ``` # Lightweight Mode (Integrating with Existing Code) ## observe: Track without Code Changes ```{r observe_mode} # Run existing scripts in observation mode result <- observe({ data <- read.csv("input_data.csv") processed <- data[data$value > 0, ] write.csv(processed, "output_data.csv") }) # Files read and written are recorded print(result$reads) print(result$writes) print(result$lineage) ``` ## wrap: Wrap Functions for Tracking ```{r wrap_mode} # Wrap an existing function normalize_data <- function(x) { x$normalized <- scale(x$value) x } tracked_normalize <- wrap_fn(normalize_data, lake, "normalized_result") # Use the wrapped function - lineage is automatically recorded result <- tracked_normalize(my_data) ``` ## Defining Pipelines ```{r pipeline} pipeline <- create_pipeline(lake, "preprocessing") pipeline$ step("load", function() read.csv("data.csv"))$ step("clean", function(data) na.omit(data))$ step("normalize", function(data) { data$value <- scale(data$value) data })$ step("filter", function(data) data[data$quality > 0.8, ]) result <- pipeline$run() # Each step is recorded in the Lake lake$tree("preprocessing.filter") ``` # Custom Operators ```{r operators} # %like% - SQL LIKE pattern matching genes[genes %like% "MT-%"] # Genes starting with MT- genes[genes %like% "%kinase%"] # Contains "kinase" # %ilike% - Case-insensitive names[names %ilike% "john%"] # %between% - Range filter values[values %between% c(10, 100)] # %regex% - Regular expression matching ids[ids %regex% "^ENSG\\d{11}$"] # %!in% - NOT IN letters[letters %!in% c("a", "e", "i", "o", "u")] # is_null / is_not_null data[is_not_null(data$value), ] ``` # Bracket Notation ```{r bracket_notation} # Simple read/write lake["counts"] # Read all data lake["new_data"] <- df # Write # Read with filter lake["counts", sample_A > 50] # Filter + column selection lake["counts", sample_A > 50, .(gene_id, sample_A)] ``` # Import/Export ```{r import_export} # Parquet export lake$export("counts", "counts.parquet") # CSV export lake$export("counts", "counts.csv") # Import lake$import("external_data.parquet", "imported_data") lake$import("annotations.csv", "gene_annotations") ``` # Bioconductor Integration ```{r bioconductor} library(SummarizedExperiment) # Store SummarizedExperiment directly # assays, colData, rowData, metadata are all preserved lake$put("rna_experiment", se_object) # Restore completely se_restored <- lake$get("rna_experiment") ``` # Global Shortcuts ```{r shortcuts} # Set default Lake use_lake("my_project") # Operate without lake$ prefix put("data", df) data <- fetch("data") # fetch() instead of get() snap("checkpoint1") tree("data") tables() history() ``` # Migration from Legacy API The v1.0 `ol_*` functions continue to work, but migration to the new API is recommended: ```{r migration} # Show migration guide show_migration_guide() ``` | Legacy API | New API | |------------|---------| | `ol_init("proj")` | `Lake$new("proj")` | | `ol_write("t", df)` | `lake$put("t", df)` | | `ol_read("t")` | `lake$get("t")` | | `ol_label("v1")` | `lake$snap("v1")` | | `ol_tag("t", "v1")` | `lake$tag("t", "v1")` | | `ol_checkout("v1")` | `lake$restore("v1")` | | `ol_show_lineage("t")` | `lake$tree("t")` | | `ol_query("SQL")` | `lake$sql("SQL")` | # Summary Key features of OmicsLake v2.0: 1. **Lake R6 Class** - Simple and intuitive API 2. **Automatic Lineage Tracking** - Dependencies detected through dplyr pipes 3. **QueryBuilder** - Query construction without SQL 4. **Formula Syntax** - R-like filter notation 5. **Lightweight Mode** - Non-invasive integration with existing code 6. **Bioconductor Integration** - Full SE/MAE support For concrete layer-wise examples, see `vignettes/omicslake_layer_use_cases_EN.Rmd`. See individual function help for details: ```{r help} ?Lake ?QueryBuilder ?observe ?wrap_fn ``` ## Session Information ```{r session_info} sessionInfo() ```