biopipen 0.32.1__py3-none-any.whl → 0.33.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of biopipen might be problematic. Click here for more details.

Files changed (134) hide show
  1. biopipen/__init__.py +1 -1
  2. biopipen/core/config.toml +6 -0
  3. biopipen/core/filters.py +77 -26
  4. biopipen/core/testing.py +6 -1
  5. biopipen/ns/bam.py +39 -0
  6. biopipen/ns/cellranger.py +5 -0
  7. biopipen/ns/cellranger_pipeline.py +2 -2
  8. biopipen/ns/cnvkit_pipeline.py +4 -1
  9. biopipen/ns/delim.py +33 -27
  10. biopipen/ns/protein.py +99 -0
  11. biopipen/ns/scrna.py +411 -250
  12. biopipen/ns/snp.py +16 -3
  13. biopipen/ns/tcr.py +125 -1
  14. biopipen/ns/vcf.py +34 -0
  15. biopipen/ns/web.py +5 -1
  16. biopipen/reports/scrna/SeuratClusterStats.svelte +1 -1
  17. biopipen/reports/scrna/SeuratMap2Ref.svelte +15 -2
  18. biopipen/reports/tcr/ClonalStats.svelte +15 -0
  19. biopipen/reports/utils/misc.liq +22 -7
  20. biopipen/scripts/bam/BamMerge.py +2 -2
  21. biopipen/scripts/bam/BamSampling.py +4 -4
  22. biopipen/scripts/bam/BamSort.py +141 -0
  23. biopipen/scripts/bam/BamSplitChroms.py +10 -10
  24. biopipen/scripts/bam/BamSubsetByBed.py +3 -3
  25. biopipen/scripts/bam/CNVpytor.py +10 -10
  26. biopipen/scripts/bam/ControlFREEC.py +11 -11
  27. biopipen/scripts/bed/Bed2Vcf.py +5 -5
  28. biopipen/scripts/bed/BedConsensus.py +5 -5
  29. biopipen/scripts/bed/BedLiftOver.sh +6 -4
  30. biopipen/scripts/bed/BedtoolsIntersect.py +4 -4
  31. biopipen/scripts/bed/BedtoolsMakeWindows.py +3 -3
  32. biopipen/scripts/bed/BedtoolsMerge.py +4 -4
  33. biopipen/scripts/cellranger/CellRangerCount.py +20 -9
  34. biopipen/scripts/cellranger/CellRangerSummary.R +20 -29
  35. biopipen/scripts/cellranger/CellRangerVdj.py +8 -8
  36. biopipen/scripts/cnvkit/CNVkitAccess.py +6 -6
  37. biopipen/scripts/cnvkit/CNVkitAutobin.py +25 -18
  38. biopipen/scripts/cnvkit/CNVkitBatch.py +5 -5
  39. biopipen/scripts/cnvkit/CNVkitCall.py +3 -3
  40. biopipen/scripts/cnvkit/CNVkitCoverage.py +2 -2
  41. biopipen/scripts/cnvkit/CNVkitDiagram.py +5 -5
  42. biopipen/scripts/cnvkit/CNVkitFix.py +3 -3
  43. biopipen/scripts/cnvkit/CNVkitGuessBaits.py +9 -5
  44. biopipen/scripts/cnvkit/CNVkitHeatmap.py +4 -4
  45. biopipen/scripts/cnvkit/CNVkitReference.py +2 -2
  46. biopipen/scripts/cnvkit/CNVkitScatter.py +5 -5
  47. biopipen/scripts/cnvkit/CNVkitSegment.py +5 -5
  48. biopipen/scripts/cnvkit/guess_baits.py +166 -93
  49. biopipen/scripts/delim/SampleInfo.R +85 -139
  50. biopipen/scripts/misc/Config2File.py +2 -2
  51. biopipen/scripts/misc/Str2File.py +2 -2
  52. biopipen/scripts/protein/MMCIF2PDB.py +33 -0
  53. biopipen/scripts/protein/PDB2Fasta.py +60 -0
  54. biopipen/scripts/protein/Prodigy.py +4 -4
  55. biopipen/scripts/protein/RMSD.py +178 -0
  56. biopipen/scripts/regulatory/MotifScan.py +8 -8
  57. biopipen/scripts/scrna/CellCellCommunication.py +59 -22
  58. biopipen/scripts/scrna/CellsDistribution.R +31 -6
  59. biopipen/scripts/scrna/MarkersFinder.R +272 -602
  60. biopipen/scripts/scrna/MetaMarkers.R +16 -7
  61. biopipen/scripts/scrna/RadarPlots.R +75 -35
  62. biopipen/scripts/scrna/SCP-plot.R +15202 -0
  63. biopipen/scripts/scrna/ScVelo.py +0 -0
  64. biopipen/scripts/scrna/SeuratClusterStats-clustree.R +23 -25
  65. biopipen/scripts/scrna/SeuratClusterStats-dimplots.R +26 -47
  66. biopipen/scripts/scrna/SeuratClusterStats-features.R +85 -385
  67. biopipen/scripts/scrna/SeuratClusterStats-ngenes.R +33 -13
  68. biopipen/scripts/scrna/SeuratClusterStats-stats.R +45 -228
  69. biopipen/scripts/scrna/SeuratClusterStats.R +13 -19
  70. biopipen/scripts/scrna/SeuratMap2Ref.R +16 -6
  71. biopipen/scripts/scrna/SeuratPreparing.R +138 -81
  72. biopipen/scripts/scrna/SlingShot.R +71 -0
  73. biopipen/scripts/scrna/TopExpressingGenes.R +9 -7
  74. biopipen/scripts/scrna/celltypist-wrapper.py +7 -6
  75. biopipen/scripts/snp/Plink2GTMat.py +26 -11
  76. biopipen/scripts/snp/PlinkFilter.py +7 -7
  77. biopipen/scripts/snp/PlinkFromVcf.py +8 -5
  78. biopipen/scripts/snp/PlinkSimulation.py +4 -4
  79. biopipen/scripts/snp/PlinkUpdateName.py +4 -4
  80. biopipen/scripts/stats/ChowTest.R +48 -22
  81. biopipen/scripts/tcgamaf/Maf2Vcf.py +2 -2
  82. biopipen/scripts/tcgamaf/MafAddChr.py +2 -2
  83. biopipen/scripts/tcr/CDR3AAPhyschem.R +12 -2
  84. biopipen/scripts/tcr/ClonalStats.R +484 -0
  85. biopipen/scripts/tcr/CloneResidency.R +23 -5
  86. biopipen/scripts/tcr/Immunarch-basic.R +8 -1
  87. biopipen/scripts/tcr/Immunarch-clonality.R +5 -0
  88. biopipen/scripts/tcr/Immunarch-diversity.R +25 -4
  89. biopipen/scripts/tcr/Immunarch-geneusage.R +15 -1
  90. biopipen/scripts/tcr/Immunarch-kmer.R +14 -1
  91. biopipen/scripts/tcr/Immunarch-overlap.R +15 -1
  92. biopipen/scripts/tcr/Immunarch-spectratyping.R +10 -1
  93. biopipen/scripts/tcr/Immunarch-tracking.R +6 -0
  94. biopipen/scripts/tcr/Immunarch-vjjunc.R +33 -0
  95. biopipen/scripts/tcr/ScRepLoading.R +127 -0
  96. biopipen/scripts/tcr/TCRClusterStats.R +24 -7
  97. biopipen/scripts/tcr/TCRDock.py +10 -6
  98. biopipen/scripts/tcr/TESSA.R +6 -1
  99. biopipen/scripts/tcr/vdjtools-patch.sh +1 -1
  100. biopipen/scripts/vcf/BcftoolsAnnotate.py +8 -8
  101. biopipen/scripts/vcf/BcftoolsFilter.py +3 -3
  102. biopipen/scripts/vcf/BcftoolsMerge.py +31 -0
  103. biopipen/scripts/vcf/BcftoolsSort.py +4 -4
  104. biopipen/scripts/vcf/BcftoolsView.py +5 -5
  105. biopipen/scripts/vcf/Vcf2Bed.py +2 -2
  106. biopipen/scripts/vcf/VcfAnno.py +11 -11
  107. biopipen/scripts/vcf/VcfDownSample.sh +22 -10
  108. biopipen/scripts/vcf/VcfFilter.py +5 -5
  109. biopipen/scripts/vcf/VcfFix.py +7 -7
  110. biopipen/scripts/vcf/VcfFix_utils.py +12 -3
  111. biopipen/scripts/vcf/VcfIndex.py +3 -3
  112. biopipen/scripts/vcf/VcfIntersect.py +3 -3
  113. biopipen/scripts/vcf/VcfLiftOver.sh +5 -0
  114. biopipen/scripts/vcf/VcfSplitSamples.py +4 -4
  115. biopipen/scripts/vcf/bcftools_utils.py +3 -3
  116. biopipen/scripts/web/Download.py +8 -4
  117. biopipen/scripts/web/DownloadList.py +5 -5
  118. biopipen/scripts/web/GCloudStorageDownloadBucket.py +5 -5
  119. biopipen/scripts/web/GCloudStorageDownloadFile.py +3 -3
  120. biopipen/scripts/web/gcloud_common.py +1 -1
  121. biopipen/utils/gsea.R +96 -42
  122. biopipen/utils/misc.R +205 -7
  123. biopipen/utils/misc.py +17 -8
  124. biopipen/utils/plot.R +53 -17
  125. biopipen/utils/reference.py +11 -11
  126. biopipen/utils/repr.R +146 -0
  127. biopipen/utils/vcf.py +1 -1
  128. {biopipen-0.32.1.dist-info → biopipen-0.33.0.dist-info}/METADATA +9 -9
  129. {biopipen-0.32.1.dist-info → biopipen-0.33.0.dist-info}/RECORD +131 -122
  130. {biopipen-0.32.1.dist-info → biopipen-0.33.0.dist-info}/WHEEL +1 -1
  131. biopipen/scripts/scrna/SeuratClusterStats-hists.R +0 -139
  132. biopipen/scripts/scrna/SeuratPreparing-common.R +0 -452
  133. biopipen/scripts/scrna/SeuratPreparing-doublet_detection.R +0 -201
  134. {biopipen-0.32.1.dist-info → biopipen-0.33.0.dist-info}/entry_points.txt +0 -0
@@ -1,23 +1,11 @@
1
- {{ biopipen_dir | joinpaths: "utils", "misc.R" | source_r }}
2
- {{ biopipen_dir | joinpaths: "utils", "caching.R" | source_r }}
3
- {{ biopipen_dir | joinpaths: "utils", "mutate_helpers.R" | source_r }}
4
-
5
1
  library(rlang)
6
2
  library(dplyr)
7
- library(tidyr)
8
- library(tibble)
9
3
  library(Seurat)
10
- library(enrichR)
11
- library(ggplot2)
12
- library(ggprism)
13
- library(ggrepel)
14
- library(future)
15
- library(tidyseurat)
16
- library(ggVennDiagram)
17
- library(UpSetR)
18
-
19
- log_info("Setting up EnrichR ...")
20
- setEnrichrSite("Enrichr")
4
+ library(plotthis)
5
+ library(biopipen.utils)
6
+
7
+ log <- get_logger()
8
+ reporter <- get_reporter()
21
9
 
22
10
  srtfile <- {{ in.srtobj | quote }}
23
11
  outdir <- {{ out.outdir | quote }}
@@ -30,58 +18,37 @@ group.by <- {{ envs["group-by"] | r }}
30
18
  each <- {{ envs.each | r }}
31
19
  prefix_each <- {{ envs.prefix_each | r }}
32
20
  prefix_group <- {{ envs.prefix_group | r }}
33
- section <- {{ envs.section | r }}
34
- dbs <- {{ envs.dbs | r }}
35
21
  assay <- {{ envs.assay | r }}
36
- sigmarkers <- {{ envs.sigmarkers | r }}
37
- volcano_genes <- {{ envs.volcano_genes | r }}
38
22
  subset <- {{ envs.subset | r }}
23
+ error <- {{ envs.error | r }}
24
+ site <- {{ envs.site | r }}
39
25
  rest <- {{ envs.rest | r: todot="-" }}
40
- dotplot <- {{ envs.dotplot | r: todot="-" }}
41
- cases <- {{ envs.cases | r: todot="-", skip=1 }}
42
- overlapping_defaults <- {{ envs.overlap_defaults | r }}
43
- overlapping <- {{ envs.overlap | r }}
26
+ dbs <- {{ envs.dbs | r }}
27
+ sigmarkers <- {{ envs.sigmarkers | r }}
44
28
  cache <- {{ envs.cache | r }}
29
+ allmarker_plots_defaults <- {{ envs.allmarker_plots_defaults | r }}
30
+ allmarker_plots <- {{ envs.allmarker_plots | r }}
31
+ marker_plots_defaults <- {{ envs.marker_plots_defaults | r }}
32
+ marker_plots <- {{ envs.marker_plots | r }}
33
+ enrich_plots_defaults <- {{ envs.enrich_plots_defaults | r }}
34
+ enrich_plots <- {{ envs.enrich_plots | r }}
35
+ cases <- {{ envs.cases | r: todot="-", skip=1 }}
36
+ overlaps_defaults <- {{ envs.overlaps_defaults | r }}
37
+ overlaps <- {{ envs.overlaps | r }}
45
38
 
46
39
  if (isTRUE(cache)) { cache <- joboutdir }
47
40
 
48
- # expand overlapping
49
- for (sec in names(overlapping)) {
50
- overlapping[[sec]] <- list_update(overlapping_defaults, overlapping[[sec]])
51
- }
52
- overlapping_sections <- names(overlapping)
53
-
54
- overlaps <- list()
55
- if (is.character(volcano_genes) && length(volcano_genes) == 1) {
56
- volcano_genes <- trimws(strsplit(volcano_genes, ",")[[1]])
57
- }
58
-
59
41
  set.seed(8525)
60
42
  if (ncores > 1) {
61
43
  options(future.globals.maxSize = 80000 * 1024^2)
62
44
  plan(strategy = "multicore", workers = ncores)
63
45
  }
64
46
 
65
- log_info("- Reading Seurat object ...")
47
+ log$info("Reading Seurat object ...")
66
48
  srtobj <- readRDS(srtfile)
67
- defassay <- DefaultAssay(srtobj)
68
- if (defassay == "SCT" && !"PrepSCTFindMarkers" %in% names(srtobj@commands)) {
69
- log_warn(" SCTransform used but PrepSCTFindMarkers not applied, running ...")
70
-
71
- srtobj <- PrepSCTFindMarkers(srtobj)
72
- # compose a new SeuratCommand to record it to srtobj@commands
73
- commands <- names(pbmc_small@commands)
74
- scommand <- pbmc_small@commands[[commands[length(commands)]]]
75
- scommand@name <- "PrepSCTFindMarkers"
76
- scommand@time.stamp <- Sys.time()
77
- scommand@assay.used <- "SCT"
78
- scommand@call.string <- "PrepSCTFindMarkers(object = srtobj)"
79
- scommand@params <- list()
80
- srtobj@commands$PrepSCTFindMarkers <- scommand
81
- }
82
49
 
83
50
  if (!is.null(mutaters) && length(mutaters) > 0) {
84
- log_info("- Mutating meta data ...")
51
+ log$info("Mutating meta data ...")
85
52
  srtobj@meta.data <- srtobj@meta.data %>%
86
53
  mutate(!!!lapply(mutaters, parse_expr))
87
54
  }
@@ -93,614 +60,317 @@ defaults <- list(
93
60
  each = each,
94
61
  prefix_each = prefix_each,
95
62
  prefix_group = prefix_group,
96
- section = section,
97
63
  dbs = dbs,
98
- assay = assay %||% defassay,
64
+ assay = assay %||% DefaultAssay(srtobj),
99
65
  subset = subset,
66
+ error = error,
67
+ site = site,
100
68
  sigmarkers = sigmarkers,
101
- volcano_genes = volcano_genes,
102
- dotplot = dotplot,
69
+ allmarker_plots = allmarker_plots,
70
+ marker_plots = marker_plots,
71
+ enrich_plots = enrich_plots,
72
+ cache = cache,
103
73
  rest = rest
104
74
  )
105
75
 
106
- expand_each <- function(name, case) {
76
+ log$info("Expanding cases ...")
77
+
78
+ post_casing <- function(name, case) {
107
79
  outcases <- list()
108
- no_each <- is.null(case$each) || nchar(case$each) == 0
109
- if (no_each && !is.null(case$ident.1)) {
80
+ no_each <- is.null(case$each) || is.na(case$each) || nchar(case$each) == 0
81
+
82
+ if (no_each) {
110
83
  # single cases, no need to expand
111
- if (is.null(case$section) || case$section == "DEFAULT") {
112
- outcases[[name]] <- case
84
+ case$allmarker_plots <- lapply(
85
+ case$allmarker_plots,
86
+ function(x) { list_update(allmarker_plots_defaults, x) }
87
+ )
88
+ case$marker_plots <- lapply(
89
+ case$marker_plots,
90
+ function(x) { list_update(marker_plots_defaults, x) }
91
+ )
92
+ case$enrich_plots <- lapply(
93
+ case$enrich_plots,
94
+ function(x) { list_update(enrich_plots_defaults, x) }
95
+ )
96
+ outcases[[name]] <- case
97
+ } else { # !no_each
98
+ if (!is.null(case$subset)) {
99
+ sobj <- srtobj %>% filter(!!parse_expr(case$subset))
113
100
  } else {
114
- outcases[[paste0(case$section, "::", name)]] <- case
115
- }
116
- } else { # !no_each || is.null(case$ident.1)
117
- if (!is.null(case$section) && case$section != "DEFAULT") {
118
- log_warn(" Ignoring `section` in case `{name}` that will be expanded (`each` is set or `ident-1` is not set).")
119
- case$section <- NULL
101
+ sobj <- srtobj
120
102
  }
121
- if (no_each) { # is.null(ident.1)
122
- # no each and no ident.1, use FindAllMarkers
123
- key <- paste0(name, "::", name)
124
- outcases[[key]] <- case
125
- outcases[[key]]$section <- name
126
- outcases[[key]]$findall <- TRUE
127
- } else if (!no_each) {
128
- # expand each
129
- if (is.null(case$subset)) {
130
- eachs <- srtobj@meta.data %>%
131
- pull(case$each) %>% na.omit() %>% unique() %>% as.vector()
103
+
104
+ eachs <- sobj@meta.data %>% pull(case$each) %>% na.omit() %>% unique() %>% as.vector()
105
+ case_1 <- case
106
+ for (each in eachs) {
107
+ each_name <- ifelse(case_1$prefix_each, paste0(case_1$each, " - ", each), each)
108
+ if (!is.null(case_1$ident.1)) {
109
+ # Make name a section
110
+ key <- paste0(name, "::", each_name)
132
111
  } else {
133
- eachs <- srtobj@meta.data %>% dplyr::filter(!!parse_expr(case$subset)) %>%
134
- pull(case$each) %>% na.omit() %>% unique() %>% as.vector()
112
+ key <- paste0(name, ": ", each_name)
135
113
  }
136
- for (each in eachs) {
137
- by <- make.names(paste0("..", name, "_", case$each,"_", each))
138
- srtobj@meta.data <<- srtobj@meta.data %>% mutate(
139
- !!sym(by) := if_else(
140
- !!sym(case$each) == each,
141
- !!sym(case$group.by),
142
- NA
143
- )
144
- )
145
- if (isTRUE(case$prefix_each)) {
146
- key <- paste0(name, "::", case$each, " - ", each)
147
- } else {
148
- key <- paste0(name, "::", each)
149
- }
150
- outcases[[key]] <- case
151
- outcases[[key]]$section <- name
152
- outcases[[key]]$group.by <- by
153
- if (is.null(case$ident.1)) {
154
- outcases[[key]]$findall <- TRUE
155
- }
114
+ if (!is.null(case$subset)) {
115
+ case_1$subset <- paste0(case$subset, " & `", case_1$each, "` == '", each, "'")
116
+ } else {
117
+ case_1$subset <- paste0("`", case_1$each, "` == '", each, "'")
156
118
  }
119
+ case_1$allmarker_plots <- lapply(
120
+ case_1$allmarker_plots,
121
+ function(x) { list_update(allmarker_plots_defaults, x) }
122
+ )
123
+ case_1$marker_plots <- lapply(
124
+ case_1$marker_plots,
125
+ function(x) { list_update(marker_plots_defaults, x) }
126
+ )
127
+ case_1$enrich_plots <- lapply(
128
+ case_1$enrich_plots,
129
+ function(x) { list_update(enrich_plots_defaults, x) }
130
+ )
131
+ outcases[[key]] <- case_1
157
132
  }
158
133
  }
159
134
  outcases
160
135
  }
161
-
162
- log_info("- Expanding cases ...")
163
- cases <- expand_cases(cases, defaults, expand_each)
164
-
165
- plot_volcano = function(markers, volfile, sig, volgenes) {
166
- # markers
167
- # gene p_val avg_log2FC pct.1 pct.2 p_val_adj
168
- # 1 CCL5 1.883596e-11 -4.8282535 0.359 0.927 4.332270e-09
169
- # 2 HLA-DQB1 3.667713e-09 6.1543174 0.718 0.098 8.435740e-07
170
- # 3 HLA-DRB5 1.242993e-07 3.9032231 0.744 0.195 2.858885e-05
171
- # 4 CD79B 2.036731e-07 4.2748835 0.692 0.146 4.684482e-05
172
- log_info(" Plotting volcano plot ...")
173
- markers = markers %>%
174
- mutate(
175
- Significant = if_else(
176
- !!parse_expr(sig),
177
- if_else(avg_log2FC > 0, "Up", "Down"),
178
- "No"
179
- ),
180
- Label = if_else(
181
- Significant != "No" & (isTRUE(volgenes) | (gene %in% volgenes)),
182
- gene,
183
- ""
184
- )
185
- )
186
-
187
- p_vol = ggplot(markers, aes(x = avg_log2FC, y = -log10(p_val_adj))) +
188
- geom_point(aes(color = Significant), alpha = 0.75) +
189
- scale_color_manual(
190
- values = c(Up = "#FF3333", Down = "#3333FF", No = "#AAAAAA"),
191
- labels = c(Up = "Up", Down = "Down", No = "Non-Significant")
192
- ) +
193
- geom_text_repel(
194
- aes(label = Label),
195
- size = 3,
196
- color = "#000000",
197
- box.padding = unit(0.35, "lines"),
198
- point.padding = unit(0.5, "lines"),
199
- segment.color = "#000000"
200
- ) +
201
- theme_prism() +
202
- theme(legend.title=element_blank(), plot.margin=unit(c(1,1,1,1), "cm")) +
203
- labs(
204
- x = "log2 Fold Change",
205
- y = "-log10 Adjusted P-value"
206
- )
207
-
208
- png(volfile, res = 100, height = 1200, width = 900)
209
- print(p_vol)
210
- dev.off()
211
- }
212
-
213
- # Do enrichment analysis for a case using Enrichr
214
- # Args:
215
- # case: case name
216
- # markers: markers dataframe
217
- # sig: The expression to filter significant markers
218
- do_enrich <- function(info, markers, sig, volgenes) {
219
- log_info(" Running enrichment for case: {info$casename}")
220
-
221
- if (nrow(markers) == 0) {
222
- log_warn(" No markers found for case: {info$casename}")
223
- return(NULL)
224
- }
225
-
226
- plot_volcano(markers, file.path(info$casedir, "volcano.png"), sig, volgenes)
227
-
228
- markers_sig <- markers %>% filter(!!parse_expr(sig)) %>% arrange(p_val_adj)
229
- if (nrow(markers_sig) == 0) {
230
- log_warn(" No significant markers found.")
231
- return(NULL)
232
- }
233
-
234
- write.table(
235
- markers_sig,
236
- file.path(info$casedir, "markers.txt"),
237
- sep = "\t",
238
- row.names = FALSE,
239
- col.names = TRUE,
240
- quote = FALSE
241
- )
242
- if (nrow(markers_sig) < 5) {
243
- log_warn(" Too few significant markers found for case: {info$casename}")
244
- } else {
245
- enriched <- enrichr(unique(markers_sig$gene), dbs)
246
- for (db in dbs) {
247
- write.table(
248
- enriched[[db]],
249
- file.path(info$casedir, paste0("Enrichr-", db, ".txt")),
250
- sep = "\t",
251
- row.names = FALSE,
252
- col.names = TRUE,
253
- quote = FALSE
254
- )
255
- if (nrow(enriched[[db]]) == 0) {
256
- log_warn(" No enrichment found for case: {info$casename} - {db}")
257
- next
136
+ cases <- expand_cases(cases, defaults, post_casing)
137
+
138
+ # Checking the overlapping cases
139
+ case_markers <- list()
140
+ if (length(overlaps) > 0) {
141
+ log$info("Checking overlapping cases ...")
142
+ overlaps <- expand_cases(overlaps, overlaps_defaults)
143
+ for (ovname in names(overlaps)) {
144
+ ov <- overlaps[[ovname]]
145
+ # check the existence of the cases
146
+ for (case in ov$cases) {
147
+ if (is.null(cases[[case]])) {
148
+ stop(paste0("Case '", case, "' not found in the cases for overlapping case '", ovname, "'"))
258
149
  }
259
- png(
260
- file.path(info$casedir, paste0("Enrichr-", db, ".png")),
261
- res = 100, height = 1000, width = 1000
262
- )
263
- print(
264
- plotEnrich(enriched[[db]], showTerms = 20, title = db) +
265
- theme_prism()
266
- )
267
- dev.off()
150
+ }
151
+ if (length(ov$cases) < 2) {
152
+ stop("Overlapping cases must have at least 2 cases for overlapping case '", ovname, "'")
153
+ }
154
+ for (case in ov$cases) {
155
+ case_markers[[case]] <- TRUE
156
+ }
157
+ if (identical(ov$venn$enabled, "auto")) {
158
+ overlaps[[ovname]]$venn$enabled <- length(ov$cases) <= 5
268
159
  }
269
160
  }
270
- unique(markers_sig$gene)
271
161
  }
272
162
 
273
- do_dotplot <- function(info, siggenes, dotplot, args) {
274
- max_dotplot_features <- dotplot$maxgenes %||% 20
275
- dotplot$maxgenes <- NULL
276
- if (length(siggenes) > max_dotplot_features) {
277
- log_debug(" Too many significant markers ({length(siggenes)}), using first {max_dotplot_features} for dotplot")
278
- siggenes <- siggenes[1:max_dotplot_features]
279
- }
280
- dotplot_devpars <- dotplot$devpars
281
- dotplot$devpars <- NULL
282
- dotplot$object <- args$object
283
- dotplot$features <- siggenes
284
- dotplot$group.by <- args$group.by
285
- dotplot_width <- dotplot_devpars$width %||%
286
- ifelse(length(siggenes) <= 20, length(siggenes) * 60, min(1000, length(siggenes)) * 30)
287
- dotplot_height <- dotplot_devpars$height %||% 600
288
- dotplot_res <- dotplot_devpars$res %||% 100
289
- dotplot_file <- file.path(info$casedir, "dotplot.png")
290
- png(dotplot_file, res = dotplot_res, width = dotplot_height, height = dotplot_width)
291
- # rotate x axis labels
292
- print(
293
- do_call(DotPlot, dotplot) +
294
- theme(axis.text.x = element_text(angle = 90, hjust = 1)) +
295
- coord_flip()
163
+ log$info("Running cases ...")
164
+
165
+ process_markers <- function(markers, info, case) {
166
+ # Save markers
167
+ write.table(markers, file.path(info$prefix, "markers.tsv"), sep = "\t", quote = FALSE, row.names = FALSE)
168
+ reporter$add2(
169
+ list(
170
+ name = "Table",
171
+ contents = list(list(kind = "table", src = file.path(info$prefix, "markers.tsv"), data = list(nrows = 100)))
172
+ ),
173
+ hs = c(info$section, info$name),
174
+ hs2 = "Markers",
175
+ ui = "tabs"
296
176
  )
297
- dev.off()
298
- }
299
177
 
300
- add_case_report <- function(info, sigmarkers, siggenes) {
301
- h1 = info$h1
302
- h2 = info$h2
303
- if (is.null(siggenes) || length(siggenes) == 0) {
304
- add_report(
178
+ for (plotname in names(case$marker_plots)) {
179
+ plotargs <- case$marker_plots[[plotname]]
180
+ plotargs$degs <- markers
181
+ plotargs$outprefix <- file.path(info$prefix, paste0("markers.", slugify(plotname)))
182
+ do_call(VizDEGs, plotargs)
183
+ reporter$add2(
305
184
  list(
306
- kind = "error",
307
- content = "No significant markers found."
308
- ),
309
- h1 = h1,
310
- h2 = ifelse(h2 == "#", "Markers", h2),
311
- h3 = ifelse(h2 == "#", "#", "Markers"),
312
- ui = "flat"
313
- )
314
- } else {
315
- add_report(
316
- list(
317
- title = "Significant Markers",
318
- ui = "flat",
319
- contents = list(
320
- list(
321
- kind = "descr",
322
- content = paste0(
323
- "The markers are found using Seurat's FindMarkers function, ",
324
- "and filtered by: ",
325
- html_escape(sigmarkers)
326
- )
327
- ),
328
- list(
329
- kind = "table",
330
- data = list(nrows = 100),
331
- src = file.path(info$casedir, "markers.txt")
332
- )
333
- )
334
- ),
335
- list(
336
- title = "Volcano Plot",
337
- ui = "flat",
338
- contents = list(
339
- list(
340
- kind = "img",
341
- src = file.path(info$casedir, "volcano.png")
342
- )
343
- )
344
- ),
345
- list(
346
- title = "Dot Plot",
347
- ui = "flat",
348
- contents = list(
349
- list(
350
- kind = "img",
351
- src = file.path(info$casedir, "dotplot.png")
352
- )
353
- )
354
- ),
355
- h1 = h1,
356
- h2 = ifelse(h2 == "#", "Markers", h2),
357
- h3 = ifelse(h2 == "#", "#", "Markers"),
185
+ name = plotname,
186
+ contents = list(reporter$image(plotargs$outprefix, plotargs$more_formats, plotargs$save_code))),
187
+ hs = c(info$section, info$name),
188
+ hs2 = "Markers",
358
189
  ui = "tabs"
359
190
  )
191
+ }
360
192
 
361
- add_report(
362
- list(
363
- kind = "descr",
364
- content = paste0(
365
- "The enrichment analysis is done using Enrichr. ",
366
- "The significant markers are used as input. "
367
- )
368
- ),
193
+ # Do enrichment analysis
194
+ tryCatch({
195
+ enrich <- RunEnrichment(
196
+ markers, deg = case$sigmarkers, dbs = case$dbs, cache = case$cache,
197
+ error = TRUE, site = case$site)
198
+
199
+ write.table(enrich, file.path(info$prefix, "enrich.tsv"), sep = "\t", quote = FALSE, row.names = FALSE)
200
+ reporter$add2(
369
201
  list(
370
- kind = "enrichr",
371
- dir = info$casedir
202
+ name = "Table",
203
+ contents = list(list(kind = "table", src = file.path(info$prefix, "enrich.tsv"), data = list(nrows = 100)))
372
204
  ),
373
- h1 = h1,
374
- h2 = ifelse(h2 == "#", "Enrichment Analysis", h2),
375
- h3 = ifelse(h2 == "#", "#", "Enrichment Analysis"),
376
- ui = "flat"
205
+ hs = c(info$section, info$name),
206
+ hs2 = "Enrichment Analysis",
207
+ ui = "tabs"
377
208
  )
378
- }
379
- }
380
-
381
- ensure_sobj <- function(expr, allow_empty) {
382
- tryCatch({ expr }, error = function(e) {
383
- if (allow_empty) {
384
- log_warn(" Ignoring this case: {e$message}")
385
- return(NULL)
386
- } else {
387
- stop(e)
388
- }
389
- })
390
- }
391
-
392
- do_case_findall <- function(casename) {
393
- # casename
394
- ## Cluster::Cluster
395
- info <- casename_info(casename, cases, outdir, create = FALSE)
396
- if (info$section %in% overlapping_sections) {
397
- stop(paste0(" Can't do overlapping analysis for case without `ident-1` set: ", casename))
398
- }
399
209
 
400
- case <- cases[[casename]]
401
- log_info(" Using FindAllMarkers for case: {casename}...")
402
- args <- case$rest
403
- args$assay <- case$assay
404
- args$group.by <- case$group.by
405
- # args$logfc.threshold <- args$logfc.threshold %||% 0
406
- # args$min.cells.group <- args$min.cells.group %||% 1
407
- # args$min.cells.feature <- args$min.cells.feature %||% 1
408
- # args$min.pct <- args$min.pct %||% 0
409
- allow_empty = startsWith(case$group.by, "..")
410
- if (!is.null(case$subset)) {
411
- args$object <- ensure_sobj({
412
- srtobj %>% filter(!!parse_expr(case$subset) & !is.na(!!sym(case$group.by)))
413
- }, allow_empty)
414
- if (is.null(args$object)) { return() }
415
- } else {
416
- args$object <- ensure_sobj({
417
- srtobj %>% filter(!is.na(!!sym(case$group.by)))
418
- }, allow_empty)
419
- if (is.null(args$object)) { return() }
420
- }
421
- Idents(args$object) <- case$group.by
422
-
423
- cached <- get_cached(args, "FindAllMarkers", cache)
424
- if (!is.null(cached$data)) {
425
- log_info(" Using cached markers ...")
426
- markers <- cached$data
427
- } else {
428
- markers <- find_markers(args, find_all = TRUE)
429
- cached$data <- markers
430
- save_to_cache(cached, "FindAllMarkers", cache)
431
- }
432
-
433
- if (is.null(case$dotplot$assay)) {
434
- case$dotplot$assay <- case$assay
435
- }
436
-
437
- if (nrow(markers) == 0) {
438
- idents <- unique(Idents(args$object))
439
- } else {
440
- idents <- unique(markers$cluster)
441
- }
442
- for (ident in idents) {
443
- log_debug(" * Dealing with ident: {ident}...")
444
- if (case$prefix_group) {
445
- key <- paste0(info$section, "::", case$group.by, " - ", ident)
446
- } else {
447
- key <- paste0(info$section, "::", ident)
448
- }
449
- info_ident <- casename_info(key, cases, outdir, create = TRUE)
450
- if (nrow(markers) > 0) {
451
- markers_ident <- markers %>% filter(cluster == ident)
452
- } else {
453
- markers_ident <- markers
454
- }
455
- siggenes <- do_enrich(info_ident, markers_ident, case$sigmarkers, case$volcano_genes)
210
+ # Visualize enriched terms
211
+ if (length(case$enrich_plots) > 0) {
212
+ for (db in case$dbs) {
213
+ plots <- list()
214
+ for (plotname in names(case$enrich_plots)) {
215
+ plotargs <- case$enrich_plots[[plotname]]
216
+ plotargs$enrich <- enrich[enrich$db == db, , drop = FALSE]
217
+ plotargs$outprefix <- file.path(info$prefix, paste0("enrich.", slugify(db), ".", slugify(plotname)))
456
218
 
457
- if (length(siggenes) > 0) {
458
- args$ident.1 <- as.character(ident)
459
- do_dotplot(info_ident, siggenes, case$dotplot, args)
460
- }
461
-
462
- add_case_report(info_ident, case$sigmarkers, siggenes)
463
- }
464
- }
465
-
466
- find_markers <- function(findmarkers_args, find_all = FALSE) {
467
- if (find_all) {
468
- fun <- FindAllMarkers
469
- empty <- data.frame(
470
- gene = character(),
471
- p_val = numeric(),
472
- avg_log2FC = numeric(),
473
- pct.1 = numeric(),
474
- pct.2 = numeric(),
475
- p_val_adj = numeric(),
476
- cluster = character()
477
- )
478
- } else {
479
- fun <- FindMarkers
480
- empty <- data.frame(
481
- gene = character(),
482
- p_val = numeric(),
483
- avg_log2FC = numeric(),
484
- pct.1 = numeric(),
485
- pct.2 = numeric(),
486
- p_val_adj = numeric()
487
- )
488
- }
219
+ do_call(VizEnrich, plotargs)
489
220
 
490
- call_findmarkers <- function(fn, args) {
491
- if (find_all) {
492
- do_call(fn, args)
493
- } else {
494
- do_call(fn, args) %>% rownames_to_column("gene")
221
+ plots[[length(plots) + 1]] <- reporter$image(plotargs$outprefix, plotargs$more_formats, plotargs$save_code)
222
+ }
223
+ reporter$add2(
224
+ list(name = db, contents = plots),
225
+ hs = c(info$section, info$name),
226
+ hs2 = "Enrichment Analysis",
227
+ ui = "tabs"
228
+ )
229
+ }
495
230
  }
496
- }
497
- markers <- tryCatch({
498
- call_findmarkers(fun, findmarkers_args)
499
231
  }, error = function(e) {
500
- if (!grepl("PrepSCTFindMarkers", e$message) && defassay == "SCT") {
501
- log_warn(paste0(" ! ", e$message))
232
+ if (case$error) {
233
+ stop("Error: ", e$message)
234
+ } else {
235
+ log$warn(" ! Error: {e$message}")
236
+ reporter$add2(
237
+ list(
238
+ name = "Warning",
239
+ contents = list(list(kind = "error", content = e$message, kind_ = "warning"))),
240
+ hs = c(info$section, info$name),
241
+ hs2 = "Enrichment Analysis",
242
+ ui = "tabs"
243
+ )
502
244
  }
503
- empty
504
245
  })
505
-
506
- if (nrow(markers) == 0 && defassay == "SCT") {
507
- log_warn(" ! No markers found from SCT assay, trying recorrect_umi = FALSE")
508
- findmarkers_args$recorrect_umi <- FALSE
509
- markers <- tryCatch({
510
- call_findmarkers(fun, findmarkers_args)
511
- }, error = function(e) {
512
- log_warn(paste0(" ! ", e$message))
513
- empty
514
- })
515
- }
516
-
517
- markers
518
246
  }
519
247
 
520
- sections <- c()
521
- do_case <- function(casename) {
522
- if (isTRUE(cases[[casename]]$findall)) {
523
- log_info("- Dealing with case: {casename} (all idents) ...")
524
- do_case_findall(casename)
525
- return()
526
- }
527
- log_info("- Dealing with case: {casename} ...")
528
-
529
- info <- casename_info(casename, cases, outdir, create = TRUE)
530
- case <- cases[[casename]]
531
- # ident1
532
- # ident2
533
- # groupby
534
- # each # expanded
535
- # prefix_each
536
- # dbs
537
- # sigmarkers
538
- # rest
539
- args <- case$rest
540
- allow_empty = startsWith(case$group.by, "..")
541
- if (!is.null(case$subset)) {
542
- args$object <- ensure_sobj({
543
- srtobj %>% filter(!!parse_expr(case$subset) & !is.na(!!sym(case$group.by)))
544
- }, allow_empty)
545
- if (is.null(args$object)) { return() }
546
- } else {
547
- args$object <- ensure_sobj({
548
- srtobj %>% filter(!is.na(!!sym(case$group.by)))
549
- }, allow_empty)
550
- if (is.null(args$object)) { return() }
551
- }
248
+ run_case <- function(name) {
249
+ case <- cases[[name]]
250
+ log$info("- Case: {name} ...")
552
251
 
553
- args$assay <- case$assay
252
+ args <- case$rest %||% list()
253
+ args$object <- srtobj
554
254
  args$group.by <- case$group.by
555
255
  args$ident.1 <- case$ident.1
556
256
  args$ident.2 <- case$ident.2
557
- if (is.null(args$ident.2)) {
558
- args$ident.2 <- ".rest"
559
- args$object <- args$object %>% mutate(
560
- !!sym(args$group.by) := if_else(
561
- !!sym(args$group.by) == args$ident.1,
562
- args$ident.1,
563
- args$ident.2
564
- )
565
- )
566
- } else {
567
- args$object <- args$object %>%
568
- filter(!!sym(args$group.by) %in% c(args$ident.1, args$ident.2))
569
- }
570
- # args$logfc.threshold <- args$logfc.threshold %||% 0
571
- # args$min.cells.group <- args$min.cells.group %||% 1
572
- # args$min.cells.feature <- args$min.cells.feature %||% 1
573
- # args$min.pct <- args$min.pct %||% 0
574
-
575
- markers <- find_markers(args)
576
- siggenes <- do_enrich(info, markers, case$sigmarkers, case$volcano_genes)
257
+ args$cache <- case$cache
258
+ args$assay <- case$assay
259
+ args$error <- case$error
260
+ args$subset <- case$subset
577
261
 
578
- if (length(siggenes) > 0) {
579
- case$dotplot$assay <- case$dotplot$assay %||% args$assay
580
- do_dotplot(info, siggenes, case$dotplot, args)
262
+ markers <- do_call(RunSeuratDEAnalysis, args)
263
+ if (isTRUE(case_markers[[name]])) {
264
+ case_markers[[name]] <<- markers
581
265
  }
266
+ if (is.null(case$ident.1)) {
267
+ if (!is.null(case_markers[[name]])) {
268
+ stop("Case '", name, "' for overlapping analysis must have 'ident.1' defined")
269
+ }
270
+ all_idents <- unique(markers[[case$group.by]])
271
+ # Visualize all markers
272
+ if (length(case$allmarker_plots) > 0) {
273
+ log$info(" Visualizing all markers ...")
274
+ casename <- paste0(name, "::", ifelse(case$prefix_group, paste0(case$group.by, " - All Markers"), "All Markers"))
275
+ info <- case_info(casename, outdir, create = TRUE)
276
+ for (plotname in names(case$allmarker_plots)) {
277
+ plotargs <- case$allmarker_plots[[plotname]]
278
+ plotargs$degs <- markers
279
+ plotargs$outprefix <- file.path(info$prefix, slugify(plotname))
280
+ do_call(VizDEGs, plotargs)
281
+ reporter$add2(
282
+ list(
283
+ name = plotname,
284
+ contents = list(reporter$image(plotargs$outprefix, plotargs$more_formats, plotargs$save_code))
285
+ ),
286
+ hs = c(info$section, info$name),
287
+ ui = "tabs"
288
+ )
289
+ }
290
+ }
291
+ for (ident in all_idents) {
292
+ log$info(" {case$group.by}: {ident} ...")
293
+ ident_markers <- markers[markers[[case$group.by]] == ident, , drop = TRUE]
294
+ casename <- paste0(name, "::", ifelse(case$prefix_group, paste0(case$group.by, " - ", ident), ident))
295
+ info <- case_info(casename, outdir, create = TRUE)
582
296
 
583
- sections <<- union(sections, info$section)
584
- if (info$section %in% overlapping_sections) {
585
- overlaps[[info$section]] <<- overlaps[[info$section]] %||% list()
586
- overlaps[[info$section]][[info$case]] <<- siggenes %||% character()
297
+ process_markers(ident_markers, info = info, case = case)
298
+ }
299
+ } else {
300
+ info <- case_info(name, outdir, create = TRUE)
301
+ process_markers(markers, info = info, case = case)
587
302
  }
588
-
589
- add_case_report(info, case$sigmarkers, siggenes)
590
303
  }
591
304
 
592
- do_overlap <- function(section) {
593
- log_info("- Dealing with overlapping: {section}...")
594
-
595
- ov_args <- overlapping[[section]]
596
- ov_dir <- file.path(outdir, "OVERLAPPING", section)
597
- dir.create(ov_dir, showWarnings = FALSE, recursive = TRUE)
598
-
599
- ov_cases <- overlaps[[section]]
600
- if (length(ov_cases) < 2) {
601
- stop(sprintf(" Not enough cases for overlap: %s", section))
602
- }
305
+ sapply(names(cases), run_case)
603
306
 
604
- if (is.list(ov_args$venn) && length(ov_cases) > 4) {
605
- stop(paste0(" Too many cases (", length(ov_cases)," > 4) for venn plot for section: ", section))
606
- }
607
- if (is.list(ov_args$venn)) {
608
- venn_plot <- file.path(ov_dir, "venn.png")
609
- venn_p <- ggVennDiagram(ov_cases, label_percent_digit = 1) +
610
- scale_fill_distiller(palette = "Reds", direction = 1) +
611
- scale_x_continuous(expand = expansion(mult = .2))
612
- ov_args$venn$devpars$file <- venn_plot
613
- do.call(png, ov_args$venn$devpars)
614
- print(venn_p)
615
- dev.off()
616
- }
307
+ if (length(overlaps) > 0) {
308
+ log$info("Running overlapping cases ...")
617
309
 
618
- df_markers <- fromList(ov_cases)
619
- # A B MARKERS
620
- # 1 0 G1
621
- # 1 0 G2
622
- # 0 1 G3
623
- # 0 1 G4
624
- # 1 1 G5
625
- df_markers$MARKERS = Reduce(union, ov_cases)
626
- df_markers = df_markers %>%
627
- group_by(across(-MARKERS)) %>%
628
- summarise(MARKERS = paste0(MARKERS, collapse = ","), .groups = "drop")
629
-
630
- write.table(
631
- df_markers,
632
- file.path(ov_dir, "markers.txt"),
633
- sep = "\t",
634
- row.names = FALSE,
635
- col.names = TRUE,
636
- quote = FALSE
637
- )
310
+ run_overlap <- function(ovname) {
311
+ ov <- overlaps[[ovname]]
312
+ ov$sigmarkers <- ov$sigmarkers %||% sigmarkers
313
+ log$info("- Overlapping case: {ovname} ...")
314
+ markers <- lapply(ov$cases, function(case) {
315
+ case_markers[[case]] %>% filter(!!parse_expr(ov$sigmarkers)) %>%
316
+ pull("gene") %>% unique()
317
+ })
318
+ names(markers) <- ov$cases
319
+ info <- case_info(paste0("OVERLAPPING::", ovname), outdir, create = TRUE)
320
+
321
+ if (ov$venn$enabled) {
322
+ venn <- extract_vars(ov$venn, "enabled", "more_formats", "save_code", "devpars")
323
+ venn$data <- markers
324
+ venn$in_form <- "list"
325
+ prefix <- file.path(info$prefix, "venn")
326
+ p <- do_call(gglogger::register(VennDiagram), venn)
327
+ save_plot(p, prefix, devpars, formats = c("png", more_formats))
328
+ if (save_code) {
329
+ save_plotcode(
330
+ p, prefix,
331
+ c("library(plotthis)", "load('data.RData')", "invisible(list2env(venn, .GlobalEnv))"),
332
+ "venn",
333
+ auto_data_setup = FALSE)
334
+ }
638
335
 
639
- if (is.list(ov_args$upset)) {
640
- upset_plot <- file.path(ov_dir, "upset.png")
641
- if (nrow(df_markers) == 0) {
642
- upset_p <- ggplot() +
643
- theme_void() +
644
- ggtitle("No overlapping markers found") +
645
- # center the title, and make it red
646
- theme(plot.title = element_text(hjust = 0.5, color = "red"))
647
- ov_args$upset$devpars <- list(
648
- res = 100, height = 42, width = 400
336
+ reporter$add2(
337
+ list(
338
+ name = "Venn Diagram",
339
+ contents = list(reporter$image(prefix, more_formats, save_code))
340
+ ),
341
+ hs = c(info$section, info$name),
342
+ ui = "tabs"
649
343
  )
650
- } else {
651
- upset_p <- upset(fromList(ov_cases))
652
344
  }
653
- ov_args$upset$devpars$file <- upset_plot
654
- do.call(png, ov_args$upset$devpars)
655
- print(upset_p)
656
- dev.off()
657
- }
658
345
 
659
- add_report(
660
- list(
661
- title = "Venn Diagram",
662
- ui = "flat",
663
- contents = list(
664
- list(
665
- kind = "img",
666
- src = file.path(ov_dir, "venn.png")
667
- )
668
- )
669
- ),
670
- list(
671
- title = "UpSet Plot",
672
- ui = "flat",
673
- contents = list(
674
- list(
675
- kind = "img",
676
- src = file.path(ov_dir, "upset.png")
677
- )
678
- )
679
- ),
680
- list(
681
- title = "Marker Table",
682
- ui = "flat",
683
- contents = list(
346
+ if (ov$upset$enabled) {
347
+ upset <- extract_vars(ov$upset, "enabled", "more_formats", "save_code", "devpars")
348
+ upset$data <- markers
349
+ upset$in_form <- "list"
350
+ prefix <- file.path(info$prefix, "upset")
351
+ p <- do_call(gglogger::register(UpsetPlot), upset)
352
+ save_plot(p, prefix, devpars, formats = c("png", more_formats))
353
+ if (save_code) {
354
+ save_plotcode(
355
+ p, prefix,
356
+ c("library(plotthis)", "load('data.RData')", "invisible(list2env(upset, .GlobalEnv))"),
357
+ "upset",
358
+ auto_data_setup = FALSE)
359
+ }
360
+
361
+ reporter$add2(
684
362
  list(
685
- kind = "table",
686
- data = list(nrows = 100),
687
- src = file.path(ov_dir, "markers.txt")
688
- )
363
+ name = "UpSet Plot",
364
+ contents = list(reporter$image(prefix, more_formats, save_code))
365
+ ),
366
+ hs = c(info$section, info$name),
367
+ ui = "tabs"
689
368
  )
690
- ),
691
- h1 = "Overlapping Markers",
692
- h2 = section,
693
- ui = "tabs"
694
- )
695
- }
369
+ }
696
370
 
697
- sapply(sort(names(cases)), do_case)
371
+ }
698
372
 
699
- unhit_overlaps <- setdiff(overlapping_sections, names(overlaps))
700
- if (length(unhit_overlaps) > 0) {
701
- log_warn(paste0("- No sections found for overlapping analysis: ", paste(unhit_overlaps, collapse = ", ")))
702
- log_warn(" Available sections: ", paste(sections, collapse = ", "))
373
+ sapply(names(overlaps), run_overlap)
703
374
  }
704
- sapply(sort(names(overlaps)), do_overlap)
705
375
 
706
- save_report(joboutdir)
376
+ reporter$save(joboutdir)