///|
/// SingleCellExperiment Demo.
fn main {
println("=== SingleCellExperiment Demo ===")
// 1. Create example SCE
println("\n1. Create example SCE:")
let sce = @src.sce_create_example()
println(sce.to_string())
println(" n_genes = " + @src.sce_get_n_genes(sce).to_string())
println(" n_cells = " + @src.sce_get_n_cells(sce).to_string())
// 2. Demonstrate Builder pattern
println("\n2. Builder pattern:")
let counts = @src.sce_create_example_counts()
let built_sce = @src.SCEBuilder::new()
|> @src.SCEBuilder::add_assay("counts", counts)
|> @src.SCEBuilder::add_row_data("gene_type", [
"TF", "Kinase", "Receptor", "Enzyme", "Other",
])
|> @src.SCEBuilder::add_col_data("batch", ["b1", "b1", "b2", "b2"])
|> @src.SCEBuilder::add_reduced_dim("PCA", [
[0.1, 0.2],
[0.3, 0.4],
[0.5, 0.6],
[0.7, 0.8],
])
|> @src.SCEBuilder::build
println(
" Built SCE n_genes = " + @src.sce_get_n_genes(built_sce).to_string(),
)
println(
" Built SCE n_cells = " + @src.sce_get_n_cells(built_sce).to_string(),
)
// 3. Demonstrate assay access and setting
println("\n3. Assay access and set:")
let counts_assay = @src.sce_get_assay(sce, "counts")
println(
" counts assay: " +
counts_assay.length().to_string() +
" genes x " +
(if counts_assay.length() > 0 {
counts_assay[0].length().to_string()
} else {
"0".to_string()
}) +
" cells",
)
let logcounts_assay = @src.sce_get_assay(sce, "logcounts")
println(" logcounts assay length: " + logcounts_assay.length().to_string())
let updated_sce = @src.sce_set_assay(sce, "custom", [[1.0, 2.0], [3.0, 4.0]])
let custom = @src.sce_get_assay(updated_sce, "custom")
println(" custom assay length: " + custom.length().to_string())
// 4. Demonstrate counts and logcounts conversion
println("\n4. Counts and logcounts conversion:")
let raw_counts = @src.sce_get_counts(sce)
let logcounts = @src.sce_get_logcounts(sce)
println(" raw counts genes: " + raw_counts.length().to_string())
println(" logcounts genes: " + logcounts.length().to_string())
let computed_logcounts = @src.sce_compute_logcounts(raw_counts, [
1.0, 1.0, 1.0, 1.0,
])
let sce_with_log = @src.sce_set_logcounts(sce, computed_logcounts)
println(
" set logcounts: " +
@src.sce_get_logcounts(sce_with_log).length().to_string() +
" genes",
)
// 5. Demonstrate PCA dimensionality reduction
// Note: sce_compute_pca uses a square-matrix multiplication path; we pass a
// square (4x4) logcounts matrix so the source implementation runs cleanly.
println("\n5. PCA:")
let square_logcounts : Array[Array[Double]] = [
[100.0, 200.0, 50.0, 150.0],
[120.0, 180.0, 60.0, 140.0],
[80.0, 220.0, 40.0, 160.0],
[90.0, 210.0, 45.0, 155.0],
]
let pca_result = @src.sce_compute_pca(square_logcounts, 2)
println(pca_result.to_string())
// 6. Demonstrate t-SNE dimensionality reduction
println("\n6. t-SNE:")
let tsne_result = @src.sce_compute_tsne(square_logcounts, 3)
println(tsne_result.to_string())
// 7. Demonstrate UMAP dimensionality reduction
println("\n7. UMAP:")
let umap_result = @src.sce_compute_umap(square_logcounts, 2)
println(umap_result.to_string())
// 8. Demonstrate size factors computation
println("\n8. Size factors:")
let lib_sf = @src.sce_compute_library_size_factors(raw_counts)
println(" library size factors: " + lib_sf.length().to_string())
let mut i = 0
while i < lib_sf.length() {
println(" cell " + (i + 1).to_string() + ": " + lib_sf[i].to_string())
i = i + 1
}
let deconv_sf = @src.sce_compute_deconv_size_factors(raw_counts)
println(" deconv size factors: " + deconv_sf.length().to_string())
let sf_result = @src.sce_compute_size_factors(raw_counts, "library")
println(" size factor method: " + sf_result.method_)
// 9. Demonstrate normalization
println("\n9. Normalize:")
let norm_library = @src.sce_normalize(sce, "library")
let norm_logcounts = @src.sce_get_logcounts(norm_library)
println(
" library-normalized logcounts: " +
norm_logcounts.length().to_string() +
" genes",
)
let norm_deconv = @src.sce_normalize(sce, "deconv")
println(
" deconv-normalized logcounts: " +
@src.sce_get_logcounts(norm_deconv).length().to_string() +
" genes",
)
// 10. Demonstrate gene filtering
println("\n10. Filter genes (min_cells=2):")
let filtered_genes = @src.sce_filter_genes(sce, 2)
println(
" genes before: " +
@src.sce_get_n_genes(sce).to_string() +
", after: " +
@src.sce_get_n_genes(filtered_genes).to_string(),
)
// 11. Demonstrate cell filtering
println("\n11. Filter cells (min_genes=2):")
let filtered_cells = @src.sce_filter_cells(sce, 2)
println(
" cells before: " +
@src.sce_get_n_cells(sce).to_string() +
", after: " +
@src.sce_get_n_cells(filtered_cells).to_string(),
)
// 12. Demonstrate subset operations
println("\n12. Subset operations:")
let gene_subset = @src.sce_subset_genes(sce, [0, 2, 4])
println(
" subset genes [0, 2, 4] -> n_genes=" +
@src.sce_get_n_genes(gene_subset).to_string(),
)
let cell_subset = @src.sce_subset_cells(sce, [0, 1])
println(
" subset cells [0, 1] -> n_cells=" +
@src.sce_get_n_cells(cell_subset).to_string(),
)
let row_data = @src.sce_get_row_data(built_sce, "gene_type")
println(" row_data 'gene_type' length: " + row_data.length().to_string())
let mut g = 0
while g < row_data.length() {
println(" gene " + (g + 1).to_string() + ": " + row_data[g])
g = g + 1
}
let col_data = @src.sce_get_col_data(built_sce, "batch")
println(" col_data 'batch' length: " + col_data.length().to_string())
let mut c = 0
while c < col_data.length() {
println(" cell " + (c + 1).to_string() + ": " + col_data[c])
c = c + 1
}
let pca_dim = @src.sce_get_reduced_dim(built_sce, "PCA")
println(" PCA reduced dim length: " + pca_dim.length().to_string())
let sce_with_set_dim = @src.sce_set_reduced_dim(sce, "custom_dim", [
[0.5, 0.5],
[0.6, 0.6],
])
println(
" set custom_dim: " +
@src.sce_get_reduced_dim(sce_with_set_dim, "custom_dim")
.length()
.to_string() +
" rows",
)
// 13. Demonstrate merging multiple SCE
println("\n13. Merge multiple SCE:")
let sce1 = @src.sce_create_example()
let sce2 = @src.sce_create_example()
let merged = @src.sce_merge([sce1, sce2])
println(
" merged n_genes=" +
@src.sce_get_n_genes(merged).to_string() +
", n_cells=" +
@src.sce_get_n_cells(merged).to_string(),
)
// 14. Demonstrate setting reduced dims on an SCE
// Note: sce_create_example_with_reduced_dims() internally calls
// sce_compute_pca on the (5x4) example matrix which hits the source-side
// square-matrix assumption shown above. We instead demonstrate the
// sce_set_reduced_dim / sce_get_reduced_dim accessors directly, attaching
// the reduced dims computed in sections 5-7 to a fresh SCE.
println("\n14. SCE with reduced dims (manual):")
let sce_rd = @src.sce_set_reduced_dim(sce, "PCA", pca_result.coordinates)
|> @src.sce_set_reduced_dim("tSNE", tsne_result.coordinates)
|> @src.sce_set_reduced_dim("UMAP", umap_result.coordinates)
let pca_coords = @src.sce_get_reduced_dim(sce_rd, "PCA")
let tsne_coords = @src.sce_get_reduced_dim(sce_rd, "tSNE")
let umap_coords = @src.sce_get_reduced_dim(sce_rd, "UMAP")
println(" PCA coords: " + pca_coords.length().to_string() + " rows")
println(" tSNE coords: " + tsne_coords.length().to_string() + " rows")
println(" UMAP coords: " + umap_coords.length().to_string() + " rows")
// 15. Demonstrate data summary
println("\n15. SCE Summary:")
println(@src.sce_summary(sce))
println("\nSingleCellExperiment demo completed!")
}