Skip to content

Commit 2a23f49

Browse files
phoman14github-actions[bot]kelly-sovacool
authored
feat(app-panel): improve parameter UI (#1)
* Update count_type to list with raw, clean, filt, norm options (default: filt) * Move count_type to first position in Basic category * Reorganize PCA 3D panel categories * Update changelog for parameter UI changes * `air format` (GitHub Actions) * Add author handle to changelog entry * Add PCA 3D capsule tests * `air format` (GitHub Actions) * Align PCA 3D group colors with 2D * Revert "Align PCA 3D group colors with 2D" This reverts commit 5a35adf. * Update CHANGELOG.md Co-authored-by: Kelly Sovacool, PhD <kelly-sovacool@users.noreply.github.com> --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Kelly Sovacool, PhD <kelly-sovacool@users.noreply.github.com>
1 parent 65761f2 commit 2a23f49

7 files changed

Lines changed: 283 additions & 69 deletions

File tree

‎.codeocean/app-panel.json‎

Lines changed: 49 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -12,56 +12,73 @@
1212
}
1313
],
1414
"categories": [
15-
{
16-
"id": "7Rr6IxOMDucKMImp",
17-
"name": "Input Data Parameters",
18-
"description": "Options for defining input data",
19-
"icon": "📁"
20-
},
2115
{
2216
"id": "EzTg1ivlFDHEy9PI",
2317
"name": "Basic",
24-
"icon": "📂"
18+
"icon": "\ud83d\udcc2"
2519
},
2620
{
2721
"id": "FvI4Z2eb9sjL47Jt",
2822
"name": "Visualization",
2923
"description": "Visualization and plotting options",
30-
"icon": "📊"
24+
"icon": "\ud83d\udcca"
25+
},
26+
{
27+
"id": "7Rr6IxOMDucKMImp",
28+
"name": "Advanced",
29+
"description": "Advanced input data options",
30+
"icon": "\ud83d\udcc1"
3131
}
3232
],
3333
"parameters": [
3434
{
3535
"id": "count_type_id",
36-
"category": "FvI4Z2eb9sjL47Jt",
36+
"category": "EzTg1ivlFDHEy9PI",
3737
"name": "Count type",
3838
"param_name": "count_type",
3939
"description": "Type of counts to use (e.g., filt, norm)",
40+
"type": "list",
41+
"value_type": "string",
42+
"default_value": "filt",
43+
"extra_data": [
44+
"raw",
45+
"clean",
46+
"filt",
47+
"norm"
48+
]
49+
},
50+
{
51+
"id": "group_colname_id",
52+
"category": "EzTg1ivlFDHEy9PI",
53+
"name": "Group column name",
54+
"param_name": "group_colname",
55+
"description": "Column name for sample groups",
56+
"type": "text",
57+
"value_type": "string",
58+
"default_value": "Group"
59+
},
60+
{
61+
"id": "label_colname_id",
62+
"category": "EzTg1ivlFDHEy9PI",
63+
"name": "Label column name",
64+
"param_name": "label_colname",
65+
"description": "Column name for sample labels",
4066
"type": "text",
4167
"value_type": "string",
42-
"default_value": "filt"
68+
"default_value": "Label"
4369
},
4470
{
4571
"id": "sub_count_type_id",
46-
"category": "FvI4Z2eb9sjL47Jt",
72+
"category": "7Rr6IxOMDucKMImp",
4773
"name": "Sub count type",
4874
"param_name": "sub_count_type",
4975
"description": "Sub count type if count_type is a list",
5076
"type": "text",
5177
"value_type": "string"
5278
},
53-
{
54-
"id": "feature_id_colname_id",
55-
"category": "FvI4Z2eb9sjL47Jt",
56-
"name": "Feature ID column name",
57-
"param_name": "feature_id_colname",
58-
"description": "Column name for feature IDs",
59-
"type": "text",
60-
"value_type": "string"
61-
},
6279
{
6380
"id": "sample_id_colname_id",
64-
"category": "FvI4Z2eb9sjL47Jt",
81+
"category": "EzTg1ivlFDHEy9PI",
6582
"name": "Sample ID column name",
6683
"param_name": "sample_id_colname",
6784
"description": "Column name for sample IDs",
@@ -77,36 +94,25 @@
7794
"type": "text",
7895
"value_type": "string"
7996
},
80-
{
81-
"id": "group_colname_id",
82-
"category": "7Rr6IxOMDucKMImp",
83-
"name": "Group column name",
84-
"param_name": "group_colname",
85-
"description": "Column name for sample groups",
86-
"type": "text",
87-
"value_type": "string",
88-
"default_value": "Group"
89-
},
90-
{
91-
"id": "label_colname_id",
92-
"category": "7Rr6IxOMDucKMImp",
93-
"name": "Label column name",
94-
"param_name": "label_colname",
95-
"description": "Column name for sample labels",
96-
"type": "text",
97-
"value_type": "string",
98-
"default_value": "Label"
99-
},
10097
{
10198
"id": "principal_components_id",
102-
"category": "EzTg1ivlFDHEy9PI",
99+
"category": "7Rr6IxOMDucKMImp",
103100
"name": "Principal components",
104101
"param_name": "principal_components",
105102
"description": "Principal components to plot (comma-separated, e.g., 1,2,3)",
106103
"type": "text",
107104
"value_type": "string",
108105
"default_value": "1,2,3"
109106
},
107+
{
108+
"id": "feature_id_colname_id",
109+
"category": "7Rr6IxOMDucKMImp",
110+
"name": "Feature ID column name",
111+
"param_name": "feature_id_colname",
112+
"description": "Column name for feature IDs",
113+
"type": "text",
114+
"value_type": "string"
115+
},
110116
{
111117
"id": "point_size_id",
112118
"category": "FvI4Z2eb9sjL47Jt",
@@ -153,4 +159,4 @@
153159
"file_name": "figures/pca/pca_3D.html"
154160
}
155161
]
156-
}
162+
}

‎CHANGELOG.md‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Code Ocean capsule - MOSuite - plot 3D PCA
22

3+
## Development version
4+
5+
- Improved the Code Ocean parameter UI for the plot pca 3D capsule (#1, @phoman14).
6+
37
## v2.0
48

59
- Use MOSuite v0.3.0.
@@ -9,4 +13,4 @@
913

1014
Initial release
1115

12-
<https://poc-nci.codeocean.io/capsule/3313117/tree/v1>
16+
<https://poc-nci.codeocean.io/capsule/3313117/tree/v1>

‎code/main.R‎

Lines changed: 82 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,73 @@ setup_capsule_environment()
1313
# parse CLI arguments
1414
parser <- ArgumentParser()
1515

16-
parser$add_argument("--count_type", type="character", default="filt")
17-
parser$add_argument("--sub_count_type", type="character", default=NULL, help="Sub count type if count_type is a list")
18-
parser$add_argument("--feature_id_colname", type="character", default=NULL, help="Column name for feature IDs")
19-
parser$add_argument("--sample_id_colname", type="character", default=NULL, help="Column name for sample IDs")
20-
parser$add_argument("--samples_to_rename", type="character", default="", help="Samples to rename in format old:new,old2:new2")
21-
parser$add_argument("--group_colname", type="character", default="Group", help="Column name for sample groups")
22-
parser$add_argument("--label_colname", type="character", default="Label", help="Column name for sample labels")
23-
parser$add_argument("--principal_components", type="character", default="1,2,3", help="Principal components to plot (comma-separated)")
24-
parser$add_argument("--point_size", type="integer", default=8, help="Size of points in plot")
25-
parser$add_argument("--label_font_size", type="integer", default=24, help="Font size for labels")
26-
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")
27-
parser$add_argument("--plot_title", type="character", default="PCA 3D", help="Title for the plot")
16+
parser$add_argument("--count_type", type = "character", default = "filt")
17+
parser$add_argument(
18+
"--sub_count_type",
19+
type = "character",
20+
default = NULL,
21+
help = "Sub count type if count_type is a list"
22+
)
23+
parser$add_argument(
24+
"--feature_id_colname",
25+
type = "character",
26+
default = NULL,
27+
help = "Column name for feature IDs"
28+
)
29+
parser$add_argument(
30+
"--sample_id_colname",
31+
type = "character",
32+
default = NULL,
33+
help = "Column name for sample IDs"
34+
)
35+
parser$add_argument(
36+
"--samples_to_rename",
37+
type = "character",
38+
default = "",
39+
help = "Samples to rename in format old:new,old2:new2"
40+
)
41+
parser$add_argument(
42+
"--group_colname",
43+
type = "character",
44+
default = "Group",
45+
help = "Column name for sample groups"
46+
)
47+
parser$add_argument(
48+
"--label_colname",
49+
type = "character",
50+
default = "Label",
51+
help = "Column name for sample labels"
52+
)
53+
parser$add_argument(
54+
"--principal_components",
55+
type = "character",
56+
default = "1,2,3",
57+
help = "Principal components to plot (comma-separated)"
58+
)
59+
parser$add_argument(
60+
"--point_size",
61+
type = "integer",
62+
default = 8,
63+
help = "Size of points in plot"
64+
)
65+
parser$add_argument(
66+
"--label_font_size",
67+
type = "integer",
68+
default = 24,
69+
help = "Font size for labels"
70+
)
71+
parser$add_argument(
72+
"--color_values",
73+
type = "character",
74+
default = "#5954d6,#e1562c,#b80058,#00c6f8,#d163e6,#00a76c,#ff9287,#008cf9,#006e00,#796880,#FFA500,#878500",
75+
help = "Comma-separated color values"
76+
)
77+
parser$add_argument(
78+
"--plot_title",
79+
type = "character",
80+
default = "PCA 3D",
81+
help = "Title for the plot"
82+
)
2883

2984
args <- parser$parse_args()
3085

@@ -33,17 +88,19 @@ moo <- load_moo_from_data_dir()
3388

3489
# run MOSuite
3590
plot_pca(
36-
moo,
37-
count_type = args$count_type,
38-
sub_count_type = args$sub_count_type,
39-
principal_components = as.integer(parse_optional_vector(args$principal_components)),
40-
feature_id_colname = args$feature_id_colname,
41-
sample_id_colname = args$sample_id_colname,
42-
samples_to_rename = parse_samples_to_rename(args$samples_to_rename),
43-
group_colname = args$group_colname,
44-
label_colname = args$label_colname,
45-
point_size = args$point_size,
46-
label_font_size = args$label_font_size,
47-
color_values = parse_optional_vector(args$color_values),
48-
plot_title = args$plot_title
91+
moo,
92+
count_type = args$count_type,
93+
sub_count_type = args$sub_count_type,
94+
principal_components = as.integer(parse_optional_vector(
95+
args$principal_components
96+
)),
97+
feature_id_colname = args$feature_id_colname,
98+
sample_id_colname = args$sample_id_colname,
99+
samples_to_rename = parse_samples_to_rename(args$samples_to_rename),
100+
group_colname = args$group_colname,
101+
label_colname = args$label_colname,
102+
point_size = args$point_size,
103+
label_font_size = args$label_font_size,
104+
color_values = parse_optional_vector(args$color_values),
105+
plot_title = args$plot_title
49106
)

‎tests/test-setup.R‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
testthat::test_that("test setup has expected capsule files", {
2+
repo_root <- normalizePath(file.path(testthat::test_path(), "..", ".."))
3+
4+
testthat::expect_true(file.exists(file.path(repo_root, "code", "main.R")))
5+
testthat::expect_true(file.exists(file.path(repo_root, "code", "run")))
6+
testthat::expect_true(file.exists(file.path(
7+
repo_root,
8+
".codeocean",
9+
"app-panel.json"
10+
)))
11+
})

‎tests/testthat.R‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
library(testthat)
2+
3+
test_dir(file.path("tests", "testthat"))

‎tests/testthat/helper-panel.R‎

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
repo_path <- function(...) {
2+
file.path(normalizePath(file.path(testthat::test_path(), "..", "..")), ...)
3+
}
4+
5+
read_repo_file <- function(...) {
6+
readLines(repo_path(...), warn = FALSE)
7+
}
8+
9+
extract_main_arguments <- function(main_lines) {
10+
main_text <- paste(main_lines, collapse = "\n")
11+
matches <- regmatches(
12+
main_text,
13+
gregexpr(
14+
'parser\\$add_argument\\(\\s*"--([[:alnum:]_]+)"',
15+
main_text,
16+
perl = TRUE
17+
)
18+
)[[1]]
19+
20+
sub('.*"--([[:alnum:]_]+)".*', "\\1", matches)
21+
}
22+
23+
extract_panel_param_names <- function(panel_lines) {
24+
matches <- regmatches(
25+
panel_lines,
26+
gregexpr(
27+
'"param_name"[[:space:]]*:[[:space:]]*"([[:alnum:]_]+)"',
28+
panel_lines
29+
)
30+
)
31+
matches <- unlist(matches, use.names = FALSE)
32+
33+
sub(
34+
'.*"param_name"[[:space:]]*:[[:space:]]*"([[:alnum:]_]+)".*',
35+
"\\1",
36+
matches
37+
)
38+
}
39+
40+
extract_panel_default <- function(panel_lines, param_name) {
41+
param_line <- grep(
42+
sprintf('"param_name"[[:space:]]*:[[:space:]]*"%s"', param_name),
43+
panel_lines
44+
)
45+
if (length(param_line) != 1) {
46+
return(NA_character_)
47+
}
48+
49+
next_param <- grep('"param_name"[[:space:]]*:', panel_lines)
50+
next_param <- next_param[next_param > param_line]
51+
end_line <- if (length(next_param) > 0) {
52+
next_param[[1]] - 1
53+
} else {
54+
length(panel_lines)
55+
}
56+
block <- panel_lines[param_line:end_line]
57+
default_line <- grep('"default_value"[[:space:]]*:', block, value = TRUE)
58+
if (length(default_line) != 1) {
59+
return(NA_character_)
60+
}
61+
62+
sub(
63+
'.*"default_value"[[:space:]]*:[[:space:]]*"([^"]*)".*',
64+
"\\1",
65+
default_line
66+
)
67+
}
68+
69+
expect_same_values <- function(actual, expected, info = NULL) {
70+
testthat::expect_setequal(actual, expected)
71+
testthat::expect_equal(
72+
length(actual),
73+
length(unique(actual)),
74+
info = "Values should not be duplicated"
75+
)
76+
}

0 commit comments

Comments
 (0)