From 0784fc7bbab04e5165ef43729f889059e95ad3e0 Mon Sep 17 00:00:00 2001 From: phoman14 Date: Mon, 29 Jun 2026 17:35:59 -0400 Subject: [PATCH 01/15] Update count_type to list with raw, clean, filt, norm options (default: filt) --- .codeocean/app-panel.json | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/.codeocean/app-panel.json b/.codeocean/app-panel.json index 9939872..fdbde25 100644 --- a/.codeocean/app-panel.json +++ b/.codeocean/app-panel.json @@ -37,9 +37,15 @@ "name": "Count type", "param_name": "count_type", "description": "Type of counts to use (e.g., filt, norm)", - "type": "text", + "type": "list", "value_type": "string", - "default_value": "filt" + "default_value": "filt", + "extra_data": [ + "raw", + "clean", + "filt", + "norm" + ] }, { "id": "sub_count_type_id", From 2416cecb594a72d8d5f5183b475929ca6900d7d2 Mon Sep 17 00:00:00 2001 From: phoman14 Date: Mon, 29 Jun 2026 18:00:51 -0400 Subject: [PATCH 02/15] Move count_type to first position in Basic category --- .codeocean/app-panel.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.codeocean/app-panel.json b/.codeocean/app-panel.json index fdbde25..0b18072 100644 --- a/.codeocean/app-panel.json +++ b/.codeocean/app-panel.json @@ -16,24 +16,24 @@ "id": "7Rr6IxOMDucKMImp", "name": "Input Data Parameters", "description": "Options for defining input data", - "icon": "📁" + "icon": "\ud83d\udcc1" }, { "id": "EzTg1ivlFDHEy9PI", "name": "Basic", - "icon": "📂" + "icon": "\ud83d\udcc2" }, { "id": "FvI4Z2eb9sjL47Jt", "name": "Visualization", "description": "Visualization and plotting options", - "icon": "📊" + "icon": "\ud83d\udcca" } ], "parameters": [ { "id": "count_type_id", - "category": "FvI4Z2eb9sjL47Jt", + "category": "EzTg1ivlFDHEy9PI", "name": "Count type", "param_name": "count_type", "description": "Type of counts to use (e.g., filt, norm)", @@ -199,4 +199,4 @@ "file_name": "figures/pca/pca_2D.png" } ] -} \ No newline at end of file +} From e8e56c706d063d8417030ecaff7e66278a70644e Mon Sep 17 00:00:00 2001 From: phoman14 Date: Mon, 29 Jun 2026 18:20:54 -0400 Subject: [PATCH 03/15] Update legend_position parameter(s) to list with top, bottom, left, right options --- .codeocean/app-panel.json | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/.codeocean/app-panel.json b/.codeocean/app-panel.json index 0b18072..32ef49e 100644 --- a/.codeocean/app-panel.json +++ b/.codeocean/app-panel.json @@ -119,9 +119,15 @@ "name": "Legend position", "param_name": "legend_position", "description": "Position of the legend", - "type": "text", + "type": "list", "value_type": "string", - "default_value": "top" + "default_value": "top", + "extra_data": [ + "top", + "bottom", + "left", + "right" + ] }, { "id": "point_size_id", From 26626c22a640b3d1fe8b95b9615692de6f18a31d Mon Sep 17 00:00:00 2001 From: phoman14 Date: Tue, 30 Jun 2026 03:42:45 -0400 Subject: [PATCH 04/15] Convert PCA booleans to lists --- .codeocean/app-panel.json | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/.codeocean/app-panel.json b/.codeocean/app-panel.json index 32ef49e..c39e8b4 100644 --- a/.codeocean/app-panel.json +++ b/.codeocean/app-panel.json @@ -145,9 +145,13 @@ "name": "Add labels", "param_name": "add_label", "description": "Whether to add labels to points", - "type": "text", + "type": "list", "value_type": "string", - "default_value": "TRUE" + "default_value": "TRUE", + "extra_data": [ + "TRUE", + "FALSE" + ] }, { "id": "label_font_size_id", @@ -185,9 +189,13 @@ "name": "Interactive plots", "param_name": "interactive_plots", "description": "Whether to create interactive plots", - "type": "text", + "type": "list", "value_type": "string", - "default_value": "FALSE" + "default_value": "FALSE", + "extra_data": [ + "TRUE", + "FALSE" + ] }, { "id": "color_values_id", From 1d01fe308cb1b060f8cc4c930539dc0c7e8f9e61 Mon Sep 17 00:00:00 2001 From: phoman14 Date: Tue, 30 Jun 2026 03:49:33 -0400 Subject: [PATCH 05/15] Reorganize PCA panel categories --- .codeocean/app-panel.json | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/.codeocean/app-panel.json b/.codeocean/app-panel.json index c39e8b4..5ae5b18 100644 --- a/.codeocean/app-panel.json +++ b/.codeocean/app-panel.json @@ -12,12 +12,6 @@ } ], "categories": [ - { - "id": "7Rr6IxOMDucKMImp", - "name": "Input Data Parameters", - "description": "Options for defining input data", - "icon": "\ud83d\udcc1" - }, { "id": "EzTg1ivlFDHEy9PI", "name": "Basic", @@ -28,6 +22,12 @@ "name": "Visualization", "description": "Visualization and plotting options", "icon": "\ud83d\udcca" + }, + { + "id": "7Rr6IxOMDucKMImp", + "name": "Advanced", + "description": "Advanced input data options", + "icon": "\ud83d\udcc1" } ], "parameters": [ @@ -49,7 +49,7 @@ }, { "id": "sub_count_type_id", - "category": "FvI4Z2eb9sjL47Jt", + "category": "7Rr6IxOMDucKMImp", "name": "Sub count type", "param_name": "sub_count_type", "description": "Sub count type if count_type is a list", @@ -58,7 +58,7 @@ }, { "id": "feature_id_colname_id", - "category": "FvI4Z2eb9sjL47Jt", + "category": "EzTg1ivlFDHEy9PI", "name": "Feature ID column name", "param_name": "feature_id_colname", "description": "Column name for feature IDs", @@ -67,7 +67,7 @@ }, { "id": "sample_id_colname_id", - "category": "FvI4Z2eb9sjL47Jt", + "category": "EzTg1ivlFDHEy9PI", "name": "Sample ID column name", "param_name": "sample_id_colname", "description": "Column name for sample IDs", @@ -105,7 +105,7 @@ }, { "id": "principal_components_id", - "category": "EzTg1ivlFDHEy9PI", + "category": "7Rr6IxOMDucKMImp", "name": "Principal components", "param_name": "principal_components", "description": "Principal components to plot (comma-separated, e.g., 1,2)", From 1189bd448426eb62fe81717fb072968041dd2d71 Mon Sep 17 00:00:00 2001 From: phoman14 Date: Tue, 30 Jun 2026 03:52:49 -0400 Subject: [PATCH 06/15] Adjust PCA panel parameter order --- .codeocean/app-panel.json | 58 +++++++++++++++++++-------------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/.codeocean/app-panel.json b/.codeocean/app-panel.json index 5ae5b18..acc9601 100644 --- a/.codeocean/app-panel.json +++ b/.codeocean/app-panel.json @@ -47,6 +47,26 @@ "norm" ] }, + { + "id": "group_colname_id", + "category": "EzTg1ivlFDHEy9PI", + "name": "Group column name", + "param_name": "group_colname", + "description": "Column name for sample groups", + "type": "text", + "value_type": "string", + "default_value": "Group" + }, + { + "id": "label_colname_id", + "category": "EzTg1ivlFDHEy9PI", + "name": "Label column name", + "param_name": "label_colname", + "description": "Column name for sample labels", + "type": "text", + "value_type": "string", + "default_value": "Label" + }, { "id": "sub_count_type_id", "category": "7Rr6IxOMDucKMImp", @@ -56,15 +76,6 @@ "type": "text", "value_type": "string" }, - { - "id": "feature_id_colname_id", - "category": "EzTg1ivlFDHEy9PI", - "name": "Feature ID column name", - "param_name": "feature_id_colname", - "description": "Column name for feature IDs", - "type": "text", - "value_type": "string" - }, { "id": "sample_id_colname_id", "category": "EzTg1ivlFDHEy9PI", @@ -83,26 +94,6 @@ "type": "text", "value_type": "string" }, - { - "id": "group_colname_id", - "category": "7Rr6IxOMDucKMImp", - "name": "Group column name", - "param_name": "group_colname", - "description": "Column name for sample groups", - "type": "text", - "value_type": "string", - "default_value": "Group" - }, - { - "id": "label_colname_id", - "category": "7Rr6IxOMDucKMImp", - "name": "Label column name", - "param_name": "label_colname", - "description": "Column name for sample labels", - "type": "text", - "value_type": "string", - "default_value": "Label" - }, { "id": "principal_components_id", "category": "7Rr6IxOMDucKMImp", @@ -113,6 +104,15 @@ "value_type": "string", "default_value": "1,2" }, + { + "id": "feature_id_colname_id", + "category": "7Rr6IxOMDucKMImp", + "name": "Feature ID column name", + "param_name": "feature_id_colname", + "description": "Column name for feature IDs", + "type": "text", + "value_type": "string" + }, { "id": "legend_position_id", "category": "FvI4Z2eb9sjL47Jt", From df498706eedaf4eb5b8666e244c2a4f680191cd2 Mon Sep 17 00:00:00 2001 From: phoman14 Date: Tue, 30 Jun 2026 13:40:48 -0400 Subject: [PATCH 07/15] Update changelog for parameter UI changes --- CHANGELOG.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 033542a..67436fa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Code Ocean capsule - MOSuite - plot 2D PCA +## Development version + +- Improved the Code Ocean parameter UI for the plot pca 2D capsule (#1). + ## v2.0 - Use MOSuite v0.3.0 @@ -9,4 +13,4 @@ Initial release - `bd6ca75` \ No newline at end of file + `bd6ca75` From f24ad6b84cbf01522fd31cf5d98e596a20501be4 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 30 Jun 2026 17:40:55 +0000 Subject: [PATCH 08/15] `air format` (GitHub Actions) --- code/main.R | 143 ++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 110 insertions(+), 33 deletions(-) diff --git a/code/main.R b/code/main.R index 64d8eb1..1440fac 100644 --- a/code/main.R +++ b/code/main.R @@ -13,22 +13,97 @@ setup_capsule_environment() # parse CLI arguments parser <- ArgumentParser() -parser$add_argument("--count_type", type="character", default="filt") -parser$add_argument("--sub_count_type", type="character", default=NULL, help="Sub count type if count_type is a list") -parser$add_argument("--feature_id_colname", type="character", default=NULL, help="Column name for feature IDs") -parser$add_argument("--sample_id_colname", type="character", default=NULL, help="Column name for sample IDs") -parser$add_argument("--samples_to_rename", type="character", default="", help="Samples to rename in format old:new,old2:new2") -parser$add_argument("--group_colname", type="character", default="Group", help="Column name for sample groups") -parser$add_argument("--label_colname", type="character", default="Label", help="Column name for sample labels") -parser$add_argument("--principal_components", type="character", default="1,2", help="Principal components to plot (comma-separated)") -parser$add_argument("--legend_position", type="character", default="top", help="Position of the legend") -parser$add_argument("--point_size", type="double", default=1, help="Size of points in plot") -parser$add_argument("--add_label", type="logical", default=TRUE, help="Whether to add labels to points") -parser$add_argument("--label_font_size", type="double", default=3, help="Font size for labels") -parser$add_argument("--label_offset_x_", type="double", default=2, help="X-axis offset for labels") -parser$add_argument("--label_offset_y_", type="double", default=2, help="Y-axis offset for labels") -parser$add_argument("--interactive_plots", type="logical", default=FALSE, help="Whether to create interactive plots") -parser$add_argument("--color_values", type="character", default="#5954d6,#e1562c,#b80058,#00c6f8,#d163e6,#00a76c,#ff9287,#008cf9,#006e00,#796880,#FFA500,#878500", help="Comma-separated color values") +parser$add_argument("--count_type", type = "character", default = "filt") +parser$add_argument( + "--sub_count_type", + type = "character", + default = NULL, + help = "Sub count type if count_type is a list" +) +parser$add_argument( + "--feature_id_colname", + type = "character", + default = NULL, + help = "Column name for feature IDs" +) +parser$add_argument( + "--sample_id_colname", + type = "character", + default = NULL, + help = "Column name for sample IDs" +) +parser$add_argument( + "--samples_to_rename", + type = "character", + default = "", + help = "Samples to rename in format old:new,old2:new2" +) +parser$add_argument( + "--group_colname", + type = "character", + default = "Group", + help = "Column name for sample groups" +) +parser$add_argument( + "--label_colname", + type = "character", + default = "Label", + help = "Column name for sample labels" +) +parser$add_argument( + "--principal_components", + type = "character", + default = "1,2", + help = "Principal components to plot (comma-separated)" +) +parser$add_argument( + "--legend_position", + type = "character", + default = "top", + help = "Position of the legend" +) +parser$add_argument( + "--point_size", + type = "double", + default = 1, + help = "Size of points in plot" +) +parser$add_argument( + "--add_label", + type = "logical", + default = TRUE, + help = "Whether to add labels to points" +) +parser$add_argument( + "--label_font_size", + type = "double", + default = 3, + help = "Font size for labels" +) +parser$add_argument( + "--label_offset_x_", + type = "double", + default = 2, + help = "X-axis offset for labels" +) +parser$add_argument( + "--label_offset_y_", + type = "double", + default = 2, + help = "Y-axis offset for labels" +) +parser$add_argument( + "--interactive_plots", + type = "logical", + default = FALSE, + help = "Whether to create interactive plots" +) +parser$add_argument( + "--color_values", + type = "character", + default = "#5954d6,#e1562c,#b80058,#00c6f8,#d163e6,#00a76c,#ff9287,#008cf9,#006e00,#796880,#FFA500,#878500", + help = "Comma-separated color values" +) args <- parser$parse_args() @@ -37,21 +112,23 @@ moo <- load_moo_from_data_dir() # run MOSuite plot_pca_2d( - moo, - count_type = args$count_type, - sub_count_type = args$sub_count_type, - principal_components = as.integer(parse_optional_vector(args$principal_components)), - feature_id_colname = args$feature_id_colname, - sample_id_colname = args$sample_id_colname, - samples_to_rename = parse_samples_to_rename(args$samples_to_rename), - group_colname = args$group_colname, - label_colname = args$label_colname, - legend_position = args$legend_position, - point_size = args$point_size, - add_label = args$add_label, - label_font_size = args$label_font_size, - label_offset_x_ = args$label_offset_x_, - label_offset_y_ = args$label_offset_y_, - interactive_plots = args$interactive_plots, - color_values = parse_optional_vector(args$color_values) + moo, + count_type = args$count_type, + sub_count_type = args$sub_count_type, + principal_components = as.integer(parse_optional_vector( + args$principal_components + )), + feature_id_colname = args$feature_id_colname, + sample_id_colname = args$sample_id_colname, + samples_to_rename = parse_samples_to_rename(args$samples_to_rename), + group_colname = args$group_colname, + label_colname = args$label_colname, + legend_position = args$legend_position, + point_size = args$point_size, + add_label = args$add_label, + label_font_size = args$label_font_size, + label_offset_x_ = args$label_offset_x_, + label_offset_y_ = args$label_offset_y_, + interactive_plots = args$interactive_plots, + color_values = parse_optional_vector(args$color_values) ) From c38d0cfafb112164545adbfd450e0960bb0dd8a4 Mon Sep 17 00:00:00 2001 From: phoman14 Date: Tue, 30 Jun 2026 14:11:00 -0400 Subject: [PATCH 09/15] Add author handle to changelog entry --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 67436fa..08def5d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ ## Development version -- Improved the Code Ocean parameter UI for the plot pca 2D capsule (#1). +- Improved the Code Ocean parameter UI for the plot pca 2D capsule (#1, @phoman14). ## v2.0 From 7f75cbc63e7f4c8824a5d0cacc0df9ad33b84ae1 Mon Sep 17 00:00:00 2001 From: phoman14 Date: Tue, 30 Jun 2026 15:47:31 -0400 Subject: [PATCH 10/15] Add PCA 2D capsule tests --- tests/test-setup.R | 7 +++++ tests/testthat.R | 3 ++ tests/testthat/helper-panel.R | 54 ++++++++++++++++++++++++++++++++ tests/testthat/test-main.R | 59 +++++++++++++++++++++++++++++++++++ 4 files changed, 123 insertions(+) create mode 100644 tests/test-setup.R create mode 100644 tests/testthat.R create mode 100644 tests/testthat/helper-panel.R create mode 100644 tests/testthat/test-main.R diff --git a/tests/test-setup.R b/tests/test-setup.R new file mode 100644 index 0000000..c31f6b8 --- /dev/null +++ b/tests/test-setup.R @@ -0,0 +1,7 @@ +testthat::test_that("test setup has expected capsule files", { + repo_root <- normalizePath(file.path(testthat::test_path(), "..", "..")) + + testthat::expect_true(file.exists(file.path(repo_root, "code", "main.R"))) + testthat::expect_true(file.exists(file.path(repo_root, "code", "run"))) + testthat::expect_true(file.exists(file.path(repo_root, ".codeocean", "app-panel.json"))) +}) \ No newline at end of file diff --git a/tests/testthat.R b/tests/testthat.R new file mode 100644 index 0000000..aca735a --- /dev/null +++ b/tests/testthat.R @@ -0,0 +1,3 @@ +library(testthat) + +test_dir(file.path("tests", "testthat")) \ No newline at end of file diff --git a/tests/testthat/helper-panel.R b/tests/testthat/helper-panel.R new file mode 100644 index 0000000..2d8d52d --- /dev/null +++ b/tests/testthat/helper-panel.R @@ -0,0 +1,54 @@ +repo_path <- function(...) { + file.path(normalizePath(file.path(testthat::test_path(), "..", "..")), ...) +} + +read_repo_file <- function(...) { + readLines(repo_path(...), warn = FALSE) +} + +extract_main_arguments <- function(main_lines) { + main_text <- paste(main_lines, collapse = "\n") + matches <- regmatches( + main_text, + gregexpr( + 'parser\\$add_argument\\(\\s*"--([[:alnum:]_]+)"', + main_text, + perl = TRUE + ) + )[[1]] + + sub('.*"--([[:alnum:]_]+)".*', "\\1", matches) +} + +extract_panel_param_names <- function(panel_lines) { + matches <- regmatches( + panel_lines, + gregexpr('"param_name"[[:space:]]*:[[:space:]]*"([[:alnum:]_]+)"', panel_lines) + ) + matches <- unlist(matches, use.names = FALSE) + + sub('.*"param_name"[[:space:]]*:[[:space:]]*"([[:alnum:]_]+)".*', "\\1", matches) +} + +extract_panel_default <- function(panel_lines, param_name) { + param_line <- grep(sprintf('"param_name"[[:space:]]*:[[:space:]]*"%s"', param_name), panel_lines) + if (length(param_line) != 1) { + return(NA_character_) + } + + next_param <- grep('"param_name"[[:space:]]*:', panel_lines) + next_param <- next_param[next_param > param_line] + end_line <- if (length(next_param) > 0) next_param[[1]] - 1 else length(panel_lines) + block <- panel_lines[param_line:end_line] + default_line <- grep('"default_value"[[:space:]]*:', block, value = TRUE) + if (length(default_line) != 1) { + return(NA_character_) + } + + sub('.*"default_value"[[:space:]]*:[[:space:]]*"([^"]*)".*', "\\1", default_line) +} + +expect_same_values <- function(actual, expected, info = NULL) { + testthat::expect_setequal(actual, expected) + testthat::expect_equal(length(actual), length(unique(actual)), info = "Values should not be duplicated") +} \ No newline at end of file diff --git a/tests/testthat/test-main.R b/tests/testthat/test-main.R new file mode 100644 index 0000000..f4998cc --- /dev/null +++ b/tests/testthat/test-main.R @@ -0,0 +1,59 @@ +test_that("Code Ocean panel uses named parameters accepted by main.R", { + main_args <- extract_main_arguments(read_repo_file("code", "main.R")) + panel_lines <- read_repo_file(".codeocean", "app-panel.json") + panel_args <- extract_panel_param_names(panel_lines) + + expect_true( + any(grepl('"named_parameters"[[:space:]]*:[[:space:]]*true', panel_lines)), + info = "Code Ocean should pass parameters by name to main.R" + ) + expect_same_values( + panel_args, + main_args, + info = "Every app-panel param_name should match a main.R CLI argument" + ) +}) + +test_that("2D PCA capsule keeps expected PCA parameter contract", { + main_lines <- read_repo_file("code", "main.R") + panel_lines <- read_repo_file(".codeocean", "app-panel.json") + + shared_pca_args <- c( + "count_type", + "sub_count_type", + "feature_id_colname", + "sample_id_colname", + "samples_to_rename", + "group_colname", + "label_colname", + "principal_components", + "point_size", + "label_font_size", + "color_values" + ) + two_dimensional_args <- c( + "legend_position", + "add_label", + "label_offset_x_", + "label_offset_y_", + "interactive_plots" + ) + + expect_same_values( + extract_main_arguments(main_lines), + c(shared_pca_args, two_dimensional_args), + info = "2D PCA main.R should expose shared PCA args plus 2D-specific controls" + ) + expect_match(paste(main_lines, collapse = "\n"), "plot_pca_2d\\(") + expect_equal(extract_panel_default(panel_lines, "principal_components"), "1,2") + expect_equal(extract_panel_default(panel_lines, "add_label"), "TRUE") + expect_equal(extract_panel_default(panel_lines, "interactive_plots"), "FALSE") +}) + +test_that("run wrapper prepares result directories and forwards CLI arguments", { + run_lines <- read_repo_file("code", "run") + run_text <- paste(run_lines, collapse = "\n") + + expect_match(run_text, "mkdir -p \\.\\./results/figures \\.\\./results/moo") + expect_match(run_text, 'Rscript main\\.R "\\$@"') +}) \ No newline at end of file From 4bcd41e173d14232e6dfb2a798322dff81a5c7ca Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 30 Jun 2026 19:47:43 +0000 Subject: [PATCH 11/15] `air format` (GitHub Actions) --- tests/test-setup.R | 8 ++++++-- tests/testthat.R | 2 +- tests/testthat/helper-panel.R | 36 ++++++++++++++++++++++++++++------- tests/testthat/test-main.R | 7 +++++-- 4 files changed, 41 insertions(+), 12 deletions(-) diff --git a/tests/test-setup.R b/tests/test-setup.R index c31f6b8..dc1ce41 100644 --- a/tests/test-setup.R +++ b/tests/test-setup.R @@ -3,5 +3,9 @@ testthat::test_that("test setup has expected capsule files", { testthat::expect_true(file.exists(file.path(repo_root, "code", "main.R"))) testthat::expect_true(file.exists(file.path(repo_root, "code", "run"))) - testthat::expect_true(file.exists(file.path(repo_root, ".codeocean", "app-panel.json"))) -}) \ No newline at end of file + testthat::expect_true(file.exists(file.path( + repo_root, + ".codeocean", + "app-panel.json" + ))) +}) diff --git a/tests/testthat.R b/tests/testthat.R index aca735a..fa13c48 100644 --- a/tests/testthat.R +++ b/tests/testthat.R @@ -1,3 +1,3 @@ library(testthat) -test_dir(file.path("tests", "testthat")) \ No newline at end of file +test_dir(file.path("tests", "testthat")) diff --git a/tests/testthat/helper-panel.R b/tests/testthat/helper-panel.R index 2d8d52d..fbf5a2d 100644 --- a/tests/testthat/helper-panel.R +++ b/tests/testthat/helper-panel.R @@ -23,32 +23,54 @@ extract_main_arguments <- function(main_lines) { extract_panel_param_names <- function(panel_lines) { matches <- regmatches( panel_lines, - gregexpr('"param_name"[[:space:]]*:[[:space:]]*"([[:alnum:]_]+)"', panel_lines) + gregexpr( + '"param_name"[[:space:]]*:[[:space:]]*"([[:alnum:]_]+)"', + panel_lines + ) ) matches <- unlist(matches, use.names = FALSE) - sub('.*"param_name"[[:space:]]*:[[:space:]]*"([[:alnum:]_]+)".*', "\\1", matches) + sub( + '.*"param_name"[[:space:]]*:[[:space:]]*"([[:alnum:]_]+)".*', + "\\1", + matches + ) } extract_panel_default <- function(panel_lines, param_name) { - param_line <- grep(sprintf('"param_name"[[:space:]]*:[[:space:]]*"%s"', param_name), panel_lines) + param_line <- grep( + sprintf('"param_name"[[:space:]]*:[[:space:]]*"%s"', param_name), + panel_lines + ) if (length(param_line) != 1) { return(NA_character_) } next_param <- grep('"param_name"[[:space:]]*:', panel_lines) next_param <- next_param[next_param > param_line] - end_line <- if (length(next_param) > 0) next_param[[1]] - 1 else length(panel_lines) + end_line <- if (length(next_param) > 0) { + next_param[[1]] - 1 + } else { + length(panel_lines) + } block <- panel_lines[param_line:end_line] default_line <- grep('"default_value"[[:space:]]*:', block, value = TRUE) if (length(default_line) != 1) { return(NA_character_) } - sub('.*"default_value"[[:space:]]*:[[:space:]]*"([^"]*)".*', "\\1", default_line) + sub( + '.*"default_value"[[:space:]]*:[[:space:]]*"([^"]*)".*', + "\\1", + default_line + ) } expect_same_values <- function(actual, expected, info = NULL) { testthat::expect_setequal(actual, expected) - testthat::expect_equal(length(actual), length(unique(actual)), info = "Values should not be duplicated") -} \ No newline at end of file + testthat::expect_equal( + length(actual), + length(unique(actual)), + info = "Values should not be duplicated" + ) +} diff --git a/tests/testthat/test-main.R b/tests/testthat/test-main.R index f4998cc..b0c0746 100644 --- a/tests/testthat/test-main.R +++ b/tests/testthat/test-main.R @@ -45,7 +45,10 @@ test_that("2D PCA capsule keeps expected PCA parameter contract", { info = "2D PCA main.R should expose shared PCA args plus 2D-specific controls" ) expect_match(paste(main_lines, collapse = "\n"), "plot_pca_2d\\(") - expect_equal(extract_panel_default(panel_lines, "principal_components"), "1,2") + expect_equal( + extract_panel_default(panel_lines, "principal_components"), + "1,2" + ) expect_equal(extract_panel_default(panel_lines, "add_label"), "TRUE") expect_equal(extract_panel_default(panel_lines, "interactive_plots"), "FALSE") }) @@ -56,4 +59,4 @@ test_that("run wrapper prepares result directories and forwards CLI arguments", expect_match(run_text, "mkdir -p \\.\\./results/figures \\.\\./results/moo") expect_match(run_text, 'Rscript main\\.R "\\$@"') -}) \ No newline at end of file +}) From 9bf00a7fc7fee66866b91227b8dd665d2e921c66 Mon Sep 17 00:00:00 2001 From: phoman14 Date: Tue, 30 Jun 2026 15:50:21 -0400 Subject: [PATCH 12/15] Update changelog for PCA 2D tests --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 08def5d..bd63b2e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## Development version +- Added tests for the plot pca 2D capsule Code Ocean panel and CLI contract (#1, @phoman14). - Improved the Code Ocean parameter UI for the plot pca 2D capsule (#1, @phoman14). ## v2.0 From 9143df54cab556bb39fb4bf29a4abee75d409947 Mon Sep 17 00:00:00 2001 From: phoman14 Date: Thu, 2 Jul 2026 13:23:10 -0400 Subject: [PATCH 13/15] Document PCA 2D color fallback behavior Update color_values help text to describe the MOSuite default palette, supplied-color precedence, generated extra colors, and random fallback behavior. --- .codeocean/app-panel.json | 3 ++- code/main.R | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.codeocean/app-panel.json b/.codeocean/app-panel.json index acc9601..5e28204 100644 --- a/.codeocean/app-panel.json +++ b/.codeocean/app-panel.json @@ -202,7 +202,8 @@ "category": "FvI4Z2eb9sjL47Jt", "name": "Color values", "param_name": "color_values", - "description": "Comma-separated color values for groups", + "description": "Comma-separated group colors. Defaults to the MOSuite palette.", + "help_text": "Use color names or hex codes. Supplied colors are used first; if there are more groups than colors, additional colors are generated from the MOSuite palette, with random colors only if that palette is too short.", "type": "text", "value_type": "string", "default_value": "#5954d6,#e1562c,#b80058,#00c6f8,#d163e6,#00a76c,#ff9287,#008cf9,#006e00,#796880,#FFA500,#878500" diff --git a/code/main.R b/code/main.R index 1440fac..0dc8452 100644 --- a/code/main.R +++ b/code/main.R @@ -102,7 +102,7 @@ parser$add_argument( "--color_values", type = "character", default = "#5954d6,#e1562c,#b80058,#00c6f8,#d163e6,#00a76c,#ff9287,#008cf9,#006e00,#796880,#FFA500,#878500", - help = "Comma-separated color values" + help = "Comma-separated group colors. Defaults to the MOSuite palette; supplied colors are used first and extra group colors are generated when needed." ) args <- parser$parse_args() From 54491b4ff5d045b7e4ed9f1023d8442265e38f88 Mon Sep 17 00:00:00 2001 From: phoman14 Date: Thu, 2 Jul 2026 14:52:12 -0400 Subject: [PATCH 14/15] Align PCA color defaults --- .codeocean/app-panel.json | 2 +- code/main.R | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.codeocean/app-panel.json b/.codeocean/app-panel.json index 5e28204..097ca34 100644 --- a/.codeocean/app-panel.json +++ b/.codeocean/app-panel.json @@ -137,7 +137,7 @@ "description": "Size of points in plot", "type": "text", "value_type": "string", - "default_value": "1" + "default_value": "3" }, { "id": "add_label_id", diff --git a/code/main.R b/code/main.R index 0dc8452..89642f2 100644 --- a/code/main.R +++ b/code/main.R @@ -65,7 +65,7 @@ parser$add_argument( parser$add_argument( "--point_size", type = "double", - default = 1, + default = 3, help = "Size of points in plot" ) parser$add_argument( @@ -102,7 +102,7 @@ parser$add_argument( "--color_values", type = "character", default = "#5954d6,#e1562c,#b80058,#00c6f8,#d163e6,#00a76c,#ff9287,#008cf9,#006e00,#796880,#FFA500,#878500", - help = "Comma-separated group colors. Defaults to the MOSuite palette; supplied colors are used first and extra group colors are generated when needed." + help = "Comma-separated group colors. Defaults to the MOSuite palette. Extra group colors are generated when needed." ) args <- parser$parse_args() From 244b7f0d9ffb57025debf886a729f98f0442f6de Mon Sep 17 00:00:00 2001 From: phoman14 Date: Thu, 2 Jul 2026 15:49:31 -0400 Subject: [PATCH 15/15] docs: update PCA default changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index bd63b2e..d008cad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Development version +- Align the PCA color defaults with MOSuite package defaults. +- Document that color palettes fall back to random colors only when too few colors are provided. - Added tests for the plot pca 2D capsule Code Ocean panel and CLI contract (#1, @phoman14). - Improved the Code Ocean parameter UI for the plot pca 2D capsule (#1, @phoman14).