-
Notifications
You must be signed in to change notification settings - Fork 13
Expand file tree
/
Copy pathadd.R
More file actions
806 lines (780 loc) · 33.2 KB
/
Copy pathadd.R
File metadata and controls
806 lines (780 loc) · 33.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
#' Create a study
#'
#' Create a new OmicNavigator study.
#'
#' You can add metadata to describe your study by passing a named list to to the
#' argument \code{studyMeta}. The names of the list cannot contain spaces or
#' colons, and they can't start with \code{#} or \code{-}. The values of each
#' list should be a single value. Also, your metadata fields cannot use any of
#' the
#' \href{https://gist.github.com/jdblischak/f9d946327c9991fb57dde1e6f2bff1c2}{reserved
#' fields for R's DESCRIPTION file}.
#'
#' @param name Name of the study
#' @param description Description of the study
#' @param version (Optional) Include a version number to track the updates to
#' your study package. If you export the study to a package, the version is
#' used as the package version.
#' @param maintainer (Optional) Include the name of the study package's
#' maintainer
#' @param maintainerEmail (Optional) Include the email of the study package's
#' maintainer
#' @param studyMeta (Optional) Define metadata about your study. The input is a
#' list of key:value pairs. See below for more details.
#' @inheritParams addSamples
#' @inheritParams addFeatures
#' @inheritParams addModels
#' @inheritParams addAssays
#' @inheritParams addTests
#' @inheritParams addAnnotations
#' @inheritParams addResults
#' @inheritParams addEnrichments
#' @inheritParams addMetaFeatures
#' @inheritParams addPlots
#' @inheritParams addMapping
#' @inheritParams addBarcodes
#' @inheritParams addReports
#' @inheritParams addResultsLinkouts
#' @inheritParams addEnrichmentsLinkouts
#' @inheritParams addMetaFeaturesLinkouts
#' @inheritParams addMetaAssays
#' @inheritParams addObjects
#'
#' @return Returns a new OmicNavigator study object, which is a named nested
#' list with class \code{onStudy}
#'
#' @seealso
#' \code{\link{addSamples}},
#' \code{\link{addFeatures}},
#' \code{\link{addModels}},
#' \code{\link{addAssays}},
#' \code{\link{addTests}},
#' \code{\link{addAnnotations}},
#' \code{\link{addResults}},
#' \code{\link{addEnrichments}},
#' \code{\link{addMetaFeatures}},
#' \code{\link{addPlots}},
#' \code{\link{addMapping}},
#' \code{\link{addBarcodes}},
#' \code{\link{addReports}},
#' \code{\link{addResultsLinkouts}},
#' \code{\link{addEnrichmentsLinkouts}},
#' \code{\link{addMetaFeaturesLinkouts}},
#' \code{\link{addMetaAssays}},
#' \code{\link{addObjects}},
#' \code{\link{exportStudy}},
#' \code{\link{installStudy}}
#'
#' @examples
#'
#' study <- createStudy(name = "ABC",
#' description = "An analysis of ABC")
#'
#' # Define a version and study metadata
#' study <- createStudy(name = "ABC",
#' description = "An analysis of ABC",
#' version = "0.1.0",
#' maintainer = "My Name",
#' maintainerEmail = "me@email.com",
#' studyMeta = list(department = "immunology",
#' organism = "Mus musculus"))
#'
#' @export
createStudy <- function(name,
description = name,
samples = list(),
features = list(),
models = list(),
assays = list(),
tests = list(),
annotations = list(),
results = list(),
enrichments = list(),
metaFeatures = list(),
plots = list(),
mapping = list(),
barcodes = list(),
reports = list(),
resultsLinkouts = list(),
enrichmentsLinkouts = list(),
metaFeaturesLinkouts = list(),
metaAssays = list(),
objects = list(),
version = NULL,
maintainer = NULL,
maintainerEmail = NULL,
studyMeta = list())
{
checkName(name)
checkDescription(description)
checkVersion(version)
checkMaintainer(maintainer)
checkMaintainerEmail(maintainerEmail)
checkStudyMeta(studyMeta)
study <- list(name = name,
description = description,
samples = list(),
features = list(),
models = list(),
assays = list(),
tests = list(),
annotations = list(),
results = list(),
enrichments = list(),
metaFeatures = list(),
plots = list(),
mapping = list(),
barcodes = list(),
reports = list(),
resultsLinkouts = list(),
enrichmentsLinkouts = list(),
metaFeaturesLinkouts = list(),
metaAssays = list(),
objects = list(),
overlaps = list(),
version = version,
maintainer = maintainer,
maintainerEmail = maintainerEmail,
studyMeta = studyMeta)
class(study) <- "onStudy"
study <- addSamples(study, samples = samples)
study <- addFeatures(study, features = features)
study <- addModels(study, models = models)
study <- addAssays(study, assays = assays)
study <- addTests(study, tests = tests)
study <- addAnnotations(study, annotations = annotations)
study <- addResults(study, results = results)
study <- addEnrichments(study, enrichments = enrichments)
study <- addMetaFeatures(study, metaFeatures = metaFeatures)
study <- addPlots(study, plots = plots)
study <- addMapping(study, mapping = mapping)
study <- addBarcodes(study, barcodes = barcodes)
study <- addReports(study, reports = reports)
study <- addResultsLinkouts(study, resultsLinkouts = resultsLinkouts)
study <- addEnrichmentsLinkouts(study, enrichmentsLinkouts = enrichmentsLinkouts)
study <- addMetaFeaturesLinkouts(study, metaFeaturesLinkouts = metaFeaturesLinkouts)
suppressWarnings(study <- addMetaAssays(study, metaAssays = metaAssays))
suppressWarnings(study <- addObjects(study, objects = objects))
return(study)
}
#' Shared parameters for add functions
#'
#' @name shared-add
#'
#' @param study An OmicNavigator study created with \code{\link{createStudy}}
#' @param reset Reset the data prior to adding the new data (default:
#' \code{FALSE}). The default is to add to or modify any previously added data
#' (if it exists). Setting \code{reset = TRUE} enables you to remove existing
#' data you no longer want to include in the study.
#'
#' @return Returns the original \code{onStudy} object passed to the argument
#' \code{study}, but modified to include the newly added data
#'
#' @keywords internal
NULL
#' Add sample metadata
#'
#' @param samples The metadata variables that describe the samples in the study.
#' The input object is a named list of data frames (one per model). The first
#' column of each data frame is used as the sampleID, so it must contain
#' unique values. To share a data frame across multiple models, use the
#' modelID "default".
#' @inherit shared-add
#'
#' @seealso \code{\link{getSamples}}
#'
#' @export
addSamples <- function(study, samples, reset = FALSE) {
addElements(study, samples, reset)
}
#' Add feature metadata
#'
#' @param features The metadata variables that describe the features in the
#' study. The input object is a list of data frames (one per model). The first
#' column of each data frame is used as the featureID, so it must contain
#' unique values. To share a data frame across multiple models, use the
#' modelID "default". All columns will be coerced to character strings.
#' @inherit shared-add
#'
#' @seealso \code{\link{getFeatures}}
#'
#' @export
addFeatures <- function(study, features, reset = FALSE) {
addElements(study, features, reset)
}
#' Add models
#'
#' @param models The models analyzed in the study. The input is a named list.
#' The names correspond to the names of the models. The elements correspond to
#' the descriptions of the models. Alternatively, instead of a single
#' character string, you can provide a list of metadata fields about each
#' model. The field "description" will be used to derive the tooltip displayed
#' in the app.
#' @inherit shared-add
#'
#' @seealso \code{\link{getModels}}
#'
#' @examples
#' study <- createStudy("example")
#' models <- list(
#' model_01 = "Name of first model",
#' model_02 = "Name of second model"
#' )
#' study <- addModels(study, models)
#'
#' # Alternative: provide additional metadata about each model
#' models <- list(
#' model_01 = list(
#' description = "Name of first model",
#' data_type = "transcriptomics"
#' ),
#' model_02 = list(
#' description = "Name of second model",
#' data_type = "proteomics"
#' )
#' )
#'
#' @export
addModels <- function(study, models, reset = FALSE) {
addElements(study, models, reset)
}
#' Add assays
#'
#' Add assays to the models of an OmicNavigator study.
#'
#' If you want to add multiple transformations of your assays for a given
#' modelID, you can add another layer of nesting. Instead of passing a data
#' frame for that modelID, you can pass a named list of data frames. Each
#' transformation should have identical row and column names. If your data
#' doesn't fit this restriction, you should probably use multiple models
#' instead.
#'
#' @param assays The assays from the study. The input object is a list of data
#' frames (one per model). The row names should correspond to the featureIDs
#' (\code{\link{addFeatures}}). The column names should correspond to the
#' sampleIDs (\code{\link{addSamples}}). The data frame should only contain
#' numeric values. To share a data frame across multiple models, use the
#' modelID "default".
#' @inherit shared-add
#'
#' @seealso \code{\link{getAssays}}
#'
#' @export
addAssays <- function(study, assays, reset = FALSE) {
addElements(study, assays, reset)
}
#' Add tests
#'
#' @param tests The tests from the study. The input object is a list of lists.
#' Each element of the top-level list is a model. The names should be the
#' modelIDs. For each modelID, each element of the nested list is a test. The
#' names should be the testIDs. The value should be a single character string
#' describing the testID. To share tests across multiple models, use the
#' modelID "default". Instead of a single character string, you can provide a
#' list of metadata fields about each test. The field "description" will be
#' used to derive the tooltip displayed in the app. Furthermore, any fields
#' that match the column names in the results table (added via
#' \code{\link{addFeatures}} or \code{\link{addResults}}) will be used to
#' derive tooltips for those columns.
#' @inherit shared-add
#'
#' @seealso \code{\link{getTests}}
#'
#' @examples
#' study <- createStudy("example")
#' tests <- list(
#' default = list(
#' test_01 = "Name of first test",
#' test_02 = "Name of second test"
#' )
#' )
#' study <- addTests(study, tests)
#'
#' # Alternative: provide additional metadata about each test
#' tests <- list(
#' default = list(
#' test_01 = list(
#' description = "Name of first test",
#' comparison_type = "treatment vs control",
#' effect_size = "beta"
#' ),
#' test_02 = list(
#' description = "Name of second test",
#' comparison_type = "treatment vs control",
#' effect_size = "logFC"
#' )
#' )
#' )
#'
#' @export
addTests <- function(study, tests, reset = FALSE) {
addElements(study, tests, reset)
}
#' Add annotations
#'
#' @param annotations The annotations used for the enrichment analyses. The
#' input is a nested list. The top-level list contains one entry per
#' annotation database, e.g. reactome. The names correspond to the name of
#' each annotation database. Each of these elements should be a list that
#' contains more information about each annotation database. Specifically the
#' sublist should contain 1) \code{description}, a character vector that
#' describes the resource, 2) \code{featureID}, the name of the column in the
#' features table that was used for the enrichment analysis, and 3) \code{terms},
#' a list of annotation terms. The names of \code{terms} sublist correspond to
#' the name of the annotation terms. Each of the annotation terms should be a
#' character vector of featureIDs.
#' @inherit shared-add
#'
#' @seealso \code{\link{getAnnotations}}
#'
#' @export
addAnnotations <- function(study, annotations, reset = FALSE) {
addElements(study, annotations, reset)
}
#' Add inference results
#'
#' @param results The inference results from each model. The input is a
#' nested named list. The names of the list correspond to the model names.
#' Each element in the list should be a list of data frames with inference
#' results, one for each test. In each data frame, the featureID must be in
#' the first column, and all other columns must be numeric.
#' @inherit shared-add
#'
#' @seealso \code{\link{getResults}}
#'
#' @export
addResults <- function(study, results, reset = FALSE) {
addElements(study, results, reset)
}
#' Add enrichment results
#'
#' @param enrichments The enrichment results from each model. The input is a
#' nested named list. The names of the list correspond to the model names.
#' Each list element should be a list of the annotation databases tested
#' (\code{\link{addAnnotations}}). The names of the list correspond to the
#' annotation databases. Each list element should be another list of tests
#' (\code{\link{addTests}}). The names correspond to the tests performed. Each
#' of these elements should be a data frame with enrichment results. Each
#' table must contain the following columns: "termID", "description",
#' "nominal" (the nominal statistics), and "adjusted" (the statistics after
#' adjusting for multiple testing). Any additional columns are ignored and
#' removed. The first column should be "termID", and it should only contain
#' unique values.
#' @inherit shared-add
#'
#' @seealso \code{\link{getEnrichments}}
#'
#' @export
addEnrichments <- function(study, enrichments, reset = FALSE) {
addElements(study, enrichments, reset)
}
#' Add meta-feature metadata
#'
#' The meta-features table is useful anytime there are metadata variables that
#' cannot be mapped 1:1 to your features. For example, a peptide may be
#' associated with multiple proteins.
#'
#' @param metaFeatures The metadata variables that describe the meta-features in
#' the study. The input object is a list of data frames (one per model). The
#' first column of each data frame is used as the featureID, so it must
#' contain the same IDs as the corresponding features data frame
#' (\code{\link{addFeatures}}). The second column of each data frame is used
#' as the metaFeatureID, and thus should match the row names of any metaAssays
#' added via \code{\link{addMetaAssays}}. To share a data frame across
#' multiple models, use the modelID "default". All columns will be coerced to
#' character strings.
#' @inherit shared-add
#'
#' @seealso \code{\link{getMetaFeatures}}
#'
#' @export
addMetaFeatures <- function(study, metaFeatures, reset = FALSE) {
addElements(study, metaFeatures, reset)
}
#' Add custom plotting functions
#'
#' `addPlots()` adds custom plotting functions and plot metadata to an
#' OmicNavigator study.
#'
#' Custom plotting functions must be constructed to accept as the first argument
#' the value returned from `getPlottingData()`. Custom plotting functions can
#' have additional arguments, but these must be provided with default values.
#' The end-user should call `getPlottingData()` when testing their custom
#' plotting function. The end-user should consider the nature of the plot, i.e.
#' the `plotType` and (rarely) `models` values (see [getPlottingData()]). For
#' example, a custom plotting function meant to produce a `multiTest` plot
#' should accept the output of a `getPlottingData()` call with multiple
#' `testID`s assigned to the `testID` argument. See the details section of
#' [plotStudy()] for a description of how `plotType` dictates the way a custom
#' plotting function is invoked by the app.
#'
#' Note that any ggplot2 plots will require extra care. This is because the
#' plotting code will be inserted into a study package, and thus must follow the
#' \href{https://ggplot2.tidyverse.org/articles/ggplot2-in-packages.html#using-aes-and-vars-in-a-package-function-1}{best
#' practices for using ggplot2 within packages}. Specifically, when you refer to
#' columns of the data frame, e.g. \code{aes(x = group)}, you need to prefix it
#' with \code{.data$}, so that it becomes \code{aes(x = .data$group)}.
#' Fortunately this latter code will also run fine as you interactively develop
#' the function.
#'
#' Note that the plotting functions are written to the R package when the study
#' is exported via \code{\link{exportStudy}} or installed via
#' \code{\link{installStudy}}, not when \code{addPlots} is invoked. In other
#' words, if you add a custom plotting function to your study object via
#' \code{addPlots}, but then subsequently update the function in the global
#' environment prior to installing the study, this latest version will be saved
#' in the R package and executed when run in the app.
#'
#' @param plots A nested list containing custom plotting functions and plot
#' metadata. The input object is a 3-level nested list. The first, or
#' top-level list element name(s) must match the study `modelID`(s). The second,
#' or mid-level list element name(s) must match the names of the plotting
#' function(s) defined in the current R session (see Details below for
#' function construction requirements). The third, or bottom-level list
#' provides metadata to categorize, display, and support each plot. The
#' accepted fields are `displayName`, `description`, `plotType`, `models`, and
#' `packages.` `displayName` sets the plot name in the app and the `description`
#' field will display as a tool tip when hovering over plotting dropdown
#' menus. The `plotType` field is a character vector that categorizes the plot
#' by 1) the number of features it supports (“`singleFeature`” or
#' “`multiFeature`”), 2) the number of test results used by the plotting
#' function (“`singleTest`”, “`multiTest`”), 3) if data from one or more models is
#' used (add “`multiModel`” to specify that data from two or more models are
#' used in the plot; otherwise the plot is assumed to reference only data
#' within the model specified by the top-level list element name), and 4) if
#' the plot is interactive (add “`plotly`” to specify interactive plots built
#' using the plotly package; otherwise the plot is assumed to be static).
#' e.g., `plotType = c("multiFeature", "multiTest", "plotly")`. If you do not
#' specify the `plotType`, the plot will be designated as `plotType =
#' c("singleFeature", "singleTest")`. The `models` field is an optional
#' character vector that specifies the models that should be used by the app
#' when invoking your custom plotting function. This field is set to ‘all’ by
#' default and is only used when `plotType` includes “`multiModel`”. If this field
#' is not included the app will assume all models in the study should be used
#' with your plotting function. If the plotting function requires additional
#' packages beyond those attached by default to a fresh R session, these must
#' be defined in the element `packages`. To share a plotting functions across
#' multiple models, use the modelID "default". Alternatively, to share a plot
#' across a specific subset of models, you can explicitly add the same
#' plotting function to each model (option available as of OmicNavigator
#' 1.16.0).
#'
#' @inherit shared-add
#'
#' @seealso
#' \code{\link{getPlots}},
#' \code{\link{getPlottingData}},
#' \code{\link{plotStudy}}
#'
#' @export
addPlots <- function(study, plots, reset = FALSE) {
addElements(study, plots, reset)
}
#' Add mapping object
#'
#' @param mapping Feature IDs from models. The input object is a list of named
#' data frames. For each data frame, column names indicate model names while
#' rows indicate featureIDs per model. Features with same index position across
#' columns are treated as mapped across models. For each model, feature IDs must
#' match feature IDs available in the results object of the respective model.
#' 1:N relationships are allowed.
#'
#' Mapping list elements are required to be named as 'default' or after a model
#' name as provided in addModels(). If a single data frame is provided, this
#' list element is recommended to be named 'default'. For multiple list
#' elements, each with its own data frame, list elements should be named after
#' model name(s) (a single element may still be named 'default'). In that case,
#' when navigating in ON front-end (FE), mapping element related to the selected
#' model in the FE will be used in multimodel plots. If a selected model in FE
#' does not have a corresponding mapping list element, it may still use the
#' mapping list element called 'default' if this is available.
#'
#' E.g., if in a study there are models "transcriptomics" and "proteomics" and
#' the user wants to create a plot based on data from both, a mapping list
#' should be provided with addMapping(). In this case, the mapping list element
#' may be named 'default'. This should contain a data frame with column names
#' 'transcriptomics' and 'proteomics', where feature IDs that map across models
#' are found in the same row.
#' @inherit shared-add
#'
#' @seealso
#' \code{\link{getMapping}},
#' \code{\link{getPlottingData}},
#' \code{\link{plotStudy}}
#'
#' @export
addMapping <- function(study, mapping, reset = FALSE) {
addElements(study, mapping, reset)
}
#' Add barcode plot metadata
#'
#' The app can display a barcode plot of the enrichment results for a given
#' annotation term. The metadata in `barcodes` instructs the app how to create
#' and label the barcode plot.
#'
#' @param barcodes The metadata variables that describe the barcode plot.
#' The input object is a list of lists (one per model). Each sublist must
#' contain the element \code{statistic}, which is the column name in the
#' results table to use to construct the barcode plot. Each sublist may
#' additionally contain any of the following optional elements:
#' 1) \code{absolute} - Should the statistic be converted to its absolute
#' value (default is \code{TRUE}).
#' 2) \code{logFoldChange} - The column name in the results table that contains
#' the log fold change values.
#' 3) \code{labelStat} - The x-axis label to describe the statistic.
#' 4) \code{labelLow} - The left-side label to describe low values of the statistic.
#' 5) \code{labelHigh} - The right-side label to describe high values of the statistic.
#' 6) \code{featureDisplay} - The feature variable to use to label the barcode plot
#' on hover.
#' To share metadata across multiple models, use the modelID "default".
#' @inherit shared-add
#'
#' @seealso \code{\link{getBarcodes}}
#'
#' @export
addBarcodes <- function(study, barcodes, reset = FALSE) {
addElements(study, barcodes, reset)
}
#' Add reports
#'
#' You can include reports of the analyses you performed to generate the
#' results.
#'
#' @param reports The analysis report(s) that explain how the study results were
#' generated. The input object is a list of character vectors (one per model).
#' Each element should be either a URL or a path to a file on your computer.
#' If it is a path to a file, this file will be included in the exported study
#' package. To share a report across multiple models, use the modelID
#' "default".
#' @inherit shared-add
#'
#' @seealso \code{\link{getReports}}
#'
#' @export
addReports <- function(study, reports, reset = FALSE) {
addElements(study, reports, reset)
}
#' Add linkouts to external resources in the results table
#'
#' You can provide additional information on the features in your study by
#' providing linkouts to external resources. These will be embedded directly in
#' the results table.
#'
#' For each linkout, the URL pattern you provide will be concatenated with the
#' value of that column for each row. As an example, if your features table
#' included a column named \code{"ensembl"} that contained the Ensembl Gene ID
#' for each feature, you could create a linkout to Ensembl using the following
#' pattern:
#'
#' \preformatted{ensembl = "https://ensembl.org/Homo_sapiens/Gene/Summary?g="}
#'
#' As another example, if you had a column named \code{"entrez"} that contained
#' the Entrez Gene ID for each feature, you could create a linkout to Entrez
#' using the following pattern:
#'
#' \preformatted{entrez = "https://www.ncbi.nlm.nih.gov/gene/"}
#'
#' Note that you can provide more than one linkout per column.
#'
#' @param resultsLinkouts The URL patterns that describe linkouts to external
#' resources (see Details below). The input object is a nested named list. The
#' names of the list correspond to the model names. Each element of the list
#' is a named list of character vectors. The names of this nested list must
#' correspond to the column names of the matching features table. To share
#' linkouts across multiple models, use the modelID "default".
#' @inherit shared-add
#'
#' @examples
#' study <- createStudy("example")
#' resultsLinkouts <- list(
#' default = list(
#' ensembl = c("https://ensembl.org/Homo_sapiens/Gene/Summary?g=",
#' "https://www.genome.ucsc.edu/cgi-bin/hgGene?hgg_gene="),
#' entrez = "https://www.ncbi.nlm.nih.gov/gene/"
#' )
#' )
#' study <- addResultsLinkouts(study, resultsLinkouts)
#'
#' @seealso
#' \code{\link{getResultsLinkouts}},
#' \code{\link{addFeatures}}
#'
#' @export
addResultsLinkouts <- function(study, resultsLinkouts, reset = FALSE) {
addElements(study, resultsLinkouts, reset)
}
#' Add linkouts to external resources in the enrichments table
#'
#' You can provide additional information on the annotation terms in your study
#' by providing linkouts to external resources. These will be embedded directly
#' in the enrichments table.
#'
#' For each linkout, the URL pattern you provide will be concatenated with the
#' value of the termID column. As an example, if you used the annotation
#' database \href{https://amigo.geneontology.org/}{AmiGO 2} for your enrichments
#' analysis, you can provide a linkout for each termID using the following
#' pattern:
#'
#' \preformatted{go = "https://amigo.geneontology.org/amigo/term/"}
#'
#' As another example, if you used the annotation database
#' \href{https://reactome.org/}{Reactome} for your enrichments analysis, you can
#' provide a linkout for each termID using the following pattern:
#'
#' \preformatted{reactome = "https://reactome.org/content/detail/"}
#'
#' Note that you can provide more than one linkout per termID.
#'
#' @param enrichmentsLinkouts The URL patterns that describe linkouts to
#' external resources (see Details below). The input object is a named list.
#' The names of the list correspond to the annotation names. Each element of
#' the list is a character vector of linkouts for that annotationID.
#' @inherit shared-add
#'
#' @examples
#' study <- createStudy("example")
#' enrichmentsLinkouts <- list(
#' gobp = c("https://amigo.geneontology.org/amigo/term/",
#' "https://www.ebi.ac.uk/QuickGO/term/"),
#' reactome = "https://reactome.org/content/detail/"
#' )
#' study <- addEnrichmentsLinkouts(study, enrichmentsLinkouts)
#'
#' @seealso
#' \code{\link{getEnrichmentsLinkouts}},
#' \code{\link{addAnnotations}},
#' \code{\link{addEnrichments}}
#'
#' @export
addEnrichmentsLinkouts <- function(study, enrichmentsLinkouts, reset = FALSE) {
addElements(study, enrichmentsLinkouts)
}
#' Add linkouts to external resources in the metaFeatures table
#'
#' You can provide additional information on the metaFeatures in your study by
#' providing linkouts to external resources. These will be embedded directly in
#' the metaFeatures table.
#'
#' For each linkout, the URL pattern you provide will be concatenated with the
#' value of that column for each row. As an example, if your metaFeatures table
#' included a column named \code{"ensembl"} that contained the Ensembl Gene ID
#' for each feature, you could create a linkout to Ensembl using the following
#' pattern:
#'
#' \preformatted{ensembl = "https://ensembl.org/Homo_sapiens/Gene/Summary?g="}
#'
#' As another example, if you had a column named \code{"entrez"} that contained
#' the Entrez Gene ID for each feature, you could create a linkout to Entrez
#' using the following pattern:
#'
#' \preformatted{entrez = "https://www.ncbi.nlm.nih.gov/gene/"}
#'
#' Note that you can provide more than one linkout per column.
#'
#' @param metaFeaturesLinkouts The URL patterns that describe linkouts to external
#' resources (see Details below). The input object is a nested named list. The
#' names of the list correspond to the model names. Each element of the list
#' is a named list of character vectors. The names of this nested list must
#' correspond to the column names of the matching metaFeatures table (\code{\link{addMetaFeatures}}). To share
#' linkouts across multiple models, use the modelID "default".
#' @inherit shared-add
#'
#' @examples
#' study <- createStudy("example")
#' metaFeaturesLinkouts <- list(
#' default = list(
#' ensembl = c("https://ensembl.org/Homo_sapiens/Gene/Summary?g=",
#' "https://www.genome.ucsc.edu/cgi-bin/hgGene?hgg_gene="),
#' entrez = "https://www.ncbi.nlm.nih.gov/gene/"
#' )
#' )
#' study <- addMetaFeaturesLinkouts(study, metaFeaturesLinkouts)
#'
#' @seealso
#' \code{\link{getMetaFeaturesLinkouts}},
#' \code{\link{addMetaFeatures}}
#'
#' @export
addMetaFeaturesLinkouts <- function(study, metaFeaturesLinkouts, reset = FALSE) {
addElements(study, metaFeaturesLinkouts, reset)
}
#' Add metaAssays
#'
#' Experimental. Add metaAssay measurements that map to the metaFeatureIDs in
#' the metaFeatures table.
#'
#' If you want to add multiple transformations of your metaAssays for a given
#' modelID, you can add another layer of nesting. Instead of passing a data
#' frame for that modelID, you can pass a named list of data frames. Each
#' transformation should have identical row and column names. If your data
#' doesn't fit this restriction, you should probably use multiple models
#' instead.
#'
#' @param metaAssays The metaAssays from the study. The input object is a list
#' of data frames (one per model). The row names should correspond to the
#' metaFeatureIDs (second column of data frame added via
#' \code{\link{addMetaFeatures}}). The column names should correspond to the
#' sampleIDs (\code{\link{addSamples}}). The data frame should only contain
#' numeric values. To share a data frame across multiple models, use the
#' modelID "default".
#' @inheritParams shared-add
#'
#' @seealso
#' \code{\link{getMetaAssays}},
#' \code{\link{addAssays}},
#' \code{\link{addMetaFeatures}}
#'
#' @export
addMetaAssays <- function(study, metaAssays, reset = FALSE) {
warning("Support for metaAssays is highly experimental")
addElements(study, metaAssays, reset)
}
#' Add objects
#'
#' Experimental. Add arbitrary R objects to a study. These will be exported via
#' \code{\link[base]{saveRDS}} and imported via \code{\link[base]{readRDS}}.
#' This allows preserving the exact structure of complex R objects.
#'
#' The main purpose of adding a custom object to your study package is to use it
#' in custom plots in the app. If available, they will be returned by
#' \code{\link{getPlottingData}}. If the custom package requires additional R
#' packages to be available to use, make sure to list these packages in the
#' field \code{packages} when adding the custom plotting function via
#' \code{\link{addPlots}}.
#'
#' @param objects Any arbitrary R objects from the study. The input object is a
#' list of objects (one per model). To share an object across multiple models,
#' use the modelID "default".
#' @inheritParams shared-add
#'
#' @seealso
#' \code{\link{getObjects}},
#' \code{\link[base]{saveRDS}},
#' \code{\link[base]{readRDS}}
#'
#' @export
addObjects <- function(study, objects, reset = FALSE) {
warning("Support for objects is highly experimental")
addElements(study, objects, reset)
}
addElements <- function(study, elements, reset = FALSE) {
elementsName <- deparse(substitute(elements))
checkStudy(study)
# Note: I really don't like this strategy of obtaining functions dynamically
# via getFromNamespace(), but I'm not sure what the best strategy would be.
# I could create S3 generics for the check() and sanitize() functions, and
# then set the class of `elements` to `elementsName`. That is more idiomatic,
# but it also seems like a lot simply to internally dispatch these functions
# here and also in validateStudy().
checkFunctionName <- paste0("check", capitalize(elementsName))
checkFunction <- getFromNamespace(checkFunctionName, ns = "OmicNavigator")
checkFunction(elements)
sanitizeFunctionName <- paste0("sanitize", capitalize(elementsName))
sanitizeFunction <- getFromNamespace(sanitizeFunctionName, ns = "OmicNavigator")
elements <- sanitizeFunction(elements)
if (reset) {
study[[elementsName]] <- list()
}
study[[elementsName]] <- modifyList(study[[elementsName]], elements)
return(study)
}