Skip to content

Commit 3f55fa2

Browse files
committed
docs(vignettes): switch Getting Started to general functionality
- switch all uses of methylation functions to the general ones - switch CpG to general loci - add note on tabix unresponsiveness
1 parent 074b008 commit 3f55fa2

2 files changed

Lines changed: 153 additions & 160 deletions

File tree

vignettes/iscream.Rmd

Lines changed: 103 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,9 @@ library(iscream)
2828

2929
### Input BED files
3030

31-
Running this vignette requires downloading 2GB of BED files and tabix indices
32-
from this Zenodo record: <https://zenodo.org/records/14733834>.
31+
Running this vignette requires downloading 2GB of single-cell whole genome
32+
bisulfite sequencing (WGBS) BED files and tabix indices from this Zenodo
33+
record: <https://zenodo.org/records/14733834>.
3334

3435

3536
``` r
@@ -87,22 +88,25 @@ head(regions)
8788

8889
### Make tabix queries
8990

90-
The `tabix()` function can be used to query regions from BED files much like the
91-
*tabix* shell command. It returns the queried lines from the BED files, parsed
92-
into columns, as a `data.table`. `tabix()` is a generic BED files query function
93-
and is not restricted to methylation BED files. It has built-in support for
94-
BISCUIT, Bismark, and BSBolt BED file column names, set with the `aligner`
95-
argument, but can take other column names with the `col.names` argument.
91+
The `tabix()` function can be used to query regions from BED files much like
92+
the *tabix* shell command. It returns the queried lines from the BED files,
93+
parsed into columns, as a `data.table`. `tabix()` is a generic BED files query
94+
function. It has support for the BISCUIT, Bismark, and BSBolt aligners, set
95+
with the `aligner` argument, to correctly set column names in the output.
9696

9797
If multiple input files are provided, they are queried in parallel. If `raw =
9898
TRUE`, `tabix()` will return the same data as `Rsamtools::scanTabix()` does - a
99-
named list of strings.
99+
named list of strings. For large queries, `tabix()` may currently seem
100+
unresponsive, but a progress bar is in development to show its progress.
100101

101102

102103
``` r
103104
system.time(tbx_query <- tabix(bedfiles, regions, col.names = c("beta", "coverage")))
104105
#> user system elapsed
105-
#> 32.184 5.368 11.000
106+
#> 29.272 7.398 10.178
107+
```
108+
109+
``` r
106110
tbx_query
107111
#> chr start end beta coverage file
108112
#> <char> <int> <int> <num> <int> <char>
@@ -121,105 +125,101 @@ tbx_query
121125

122126
### Get summary data
123127

124-
To get a summary of the methylation information of the gene bodies use
125-
`summarize_regions`, providing the gene name column as the feature column:
128+
To get a summary of the information of the gene bodies use `summarize_regions`,
129+
providing the gene name column as the feature column:
126130

127131

128132
``` r
129-
system.time(summary_query <- summarize_meth_regions(
133+
system.time(summary_query <- summarize_regions(
130134
bedfiles,
131135
regions,
136+
columns = 4,
137+
col_names = "beta",
132138
feature_col = "gene")
133139
)
134-
#> [11:20:22.814673] [iscream::summarize_regions] [info] Summarizing 5000 regions from 100 bedfiles
135-
#> [11:20:22.814996] [iscream::summarize_regions] [info] using sum, mean, median, stddev, variance, min, max, range, count
136-
#> [11:20:22.815005] [iscream::summarize_regions] [info] with columns 4, 5 as coverage, M
140+
#> [15:59:49.032602] [iscream::summarize_regions] [info] Summarizing 5000 regions from 100 bedfiles
141+
#> [15:59:49.032651] [iscream::summarize_regions] [info] using sum, mean, median, stddev, variance, min, max, range, count
142+
#> [15:59:49.032653] [iscream::summarize_regions] [info] with columns 4 as beta
137143
#> user system elapsed
138-
#> 24.616 0.618 4.913
144+
#> 27.525 0.536 5.107
145+
```
146+
147+
``` r
139148
head(summary_query)
140-
#> feature file coverage.sum M.sum coverage.mean M.mean
141-
#> 1 ATAD3B bisc_SRR6911624 109 95 1.101010 0.9595960
142-
#> 2 PRDM16 bisc_SRR6911624 1470 789 1.074561 0.5767544
143-
#> 3 PEX10 bisc_SRR6911624 62 15 1.000000 0.2419355
144-
#> 4 PEX14 bisc_SRR6911624 258 200 1.011765 0.7843137
145-
#> 5 PLCH2 bisc_SRR6911624 272 195 1.066667 0.7647059
146-
#> 6 SPSB1 bisc_SRR6911624 74 64 1.000000 0.8648649
147-
#> coverage.median M.median coverage.stddev M.stddev coverage.variance
148-
#> 1 1 1 0.3028757 0.4932026 0.09173366
149-
#> 2 1 1 0.2892802 0.5888135 0.08368306
150-
#> 3 1 0 0.0000000 0.4317514 0.00000000
151-
#> 4 1 1 0.1080374 0.4307897 0.01167207
152-
#> 5 1 1 0.2796698 0.5169655 0.07821522
153-
#> 6 1 1 0.0000000 0.3442015 0.00000000
154-
#> M.variance coverage.min M.min coverage.max M.max coverage.range M.range
155-
#> 1 0.2432488 1 0 2 2 1 2
156-
#> 2 0.3467014 1 0 3 3 2 3
157-
#> 3 0.1864093 1 0 1 1 0 1
158-
#> 4 0.1855797 1 0 2 2 1 2
159-
#> 5 0.2672534 1 0 3 3 2 3
160-
#> 6 0.1184746 1 0 1 1 0 1
161-
#> cpg_count
162-
#> 1 99
163-
#> 2 1368
164-
#> 3 62
165-
#> 4 255
166-
#> 5 255
167-
#> 6 74
149+
#> feature file beta.sum beta.mean beta.median beta.stddev
150+
#> 1 ATAD3B bisc_SRR6911624 85.000 0.8585859 1 0.3502215
151+
#> 2 PRDM16 bisc_SRR6911624 723.500 0.5288743 1 0.4976973
152+
#> 3 PEX10 bisc_SRR6911624 15.000 0.2419355 0 0.4317514
153+
#> 4 PEX14 bisc_SRR6911624 198.000 0.7764706 1 0.4174294
154+
#> 5 PLCH2 bisc_SRR6911624 184.333 0.7228745 1 0.4474832
155+
#> 6 SPSB1 bisc_SRR6911624 64.000 0.8648649 1 0.3442015
156+
#> beta.variance beta.min beta.max beta.range count
157+
#> 1 0.1226551 0 1 1 99
158+
#> 2 0.2477026 0 1 1 1368
159+
#> 3 0.1864093 0 1 1 62
160+
#> 4 0.1742473 0 1 1 255
161+
#> 5 0.2002412 0 1 1 255
162+
#> 6 0.1184746 0 1 1 74
168163
```
169164

170-
Alternatively to get just the beta column use the general `summarize_regions()`
171-
function, specifying the columns to summarize:
165+
Alternatively to use the methylation-specific `summarize_meth_regions()`
166+
function:
172167

173168

174169
``` r
175-
system.time(summary_query <- summarize_regions(
170+
system.time(summary_query <- summarize_meth_regions(
176171
bedfiles,
177172
regions,
178-
columns = 4,
179-
col_names = "beta",
180173
feature_col = "gene")
181174
)
182175
```
183176

184177
### Build matrices
185178

186-
The `make_bsseq_mat()` function queries and stores every CpG in the input
187-
regions. Unlike `summarize_regions()` the output matrix dimensions are unknown
188-
at runtime. Although usually quite fast, if the CpG count is very large and
189-
there are few overlaps in the CpGs between files, this can take a long time.
190-
Here, gene bodies are large and the final matrix can contain millions of CpGs.
191-
Further, with single-cell data, chances are new CpGs are found in every file.
179+
The `make_mat()` function queries and stores every locus within the input
180+
regions across input files. Unlike `summarize_regions()` the output matrix
181+
dimensions are unknown at runtime. Although usually quite fast, if the locus
182+
count is very large and there are few overlaps in the loci between files, this
183+
can take a long time. Here, gene bodies are large and the final matrix can
184+
contain millions of loci. Further, with sparse data, chances are new loci are
185+
found in every file.
192186

193187
Preallocating the number of rows, however, can drastically reduce runtime.
194-
Since we got 45 million CpGs from all the BED files with the tabix query above,
195-
we can expect approximately between 5 and 10 million unique CpGs as single-cell
196-
data has lower coverage than bulk. We already have the tabix query so we can get
197-
the unique CpG count here and use it to preallocate the matrix, reducing the
198-
number of matrix resizes. We'll add 100,000 extra on top of the existing count
199-
to be safe since every avoided resize cuts off at least a couple seconds from
200-
the runtime. Making tabix queries can be a relatively quick way to approximate
201-
the CpG count of a dataset. If you haven't done a tabix query of the full
202-
dataset, you can approximate how many CpGs to expect based on CpG counts in one
203-
file and the coverage of your WGBS method.
188+
Since we got 45 million loci/CpGs from all the BED files with the tabix query
189+
above, we can expect approximately between 5 and 10 million unique loci as
190+
single-cell data has lower coverage than bulk. We already have the tabix query
191+
so we can get the unique CpG count here and use it to preallocate the matrix,
192+
reducing the number of matrix resizes. We'll add 100,000 extra on top of the
193+
existing count to be safe since every avoided resize cuts off at least a couple
194+
seconds from the runtime. Making tabix queries can be a relatively quick way to
195+
approximate the CpG count of a dataset. If you haven't done a tabix query of
196+
the full dataset, you can approximate how many CpGs to expect based on CpG
197+
counts in one file and the coverage of your WGBS method. Here we make a matrix
198+
of the beta-values in the 4th column:
199+
204200

205201
``` r
206202
cpg.count <- tbx_query$start |> unique() |> length()
207-
system.time(meth_mat <- make_bsseq_mat(
203+
system.time(meth_mat <- make_mat(
208204
bedfiles,
209205
regions,
206+
column = 4,
210207
sparse = TRUE,
211208
prealloc = cpg.count + 1e5
212209
))
213-
#> [11:20:29.883091] [iscream::query_all] [info] Querying 5000 regions from 100 bedfiles
210+
#> [15:59:56.450308] [iscream::query_all] [info] Querying 5000 regions from 100 bedfiles
214211
#>
215-
#> [11:21:13.888292] [iscream::query_all] [info] Creating metadata vectors
216-
#> [11:21:14.365486] [iscream::query_all] [info] 7276107 loci found - 16250 extra rows allocated with 0 resizes
217-
#> [11:21:22.518141] [iscream::query_all] [info] Creating sparse matrix
212+
#> [16:00:40.571982] [iscream::query_all] [info] Creating metadata vectors
213+
#> [16:00:40.867558] [iscream::query_all] [info] 7276107 loci found - 16250 extra rows allocated with 0 resizes
214+
#> [16:00:44.217883] [iscream::query_all] [info] Creating sparse matrix
218215
#> user system elapsed
219-
#> 275.560 2.978 53.696
216+
#> 335.525 1.186 47.981
217+
```
218+
219+
``` r
220220
str(meth_mat)
221-
#> List of 5
222-
#> $ M :Formal class 'dgCMatrix' [package "Matrix"] with 6 slots
221+
#> List of 4
222+
#> $ value :Formal class 'dgCMatrix' [package "Matrix"] with 6 slots
223223
#> .. ..@ i : int [1:32627134] 9 11 12 13 14 15 16 17 18 19 ...
224224
#> .. ..@ p : int [1:101] 0 157256 362760 626888 904511 1158005 1437240 1729046 2014168 2231683 ...
225225
#> .. ..@ Dim : int [1:2] 7276107 100
@@ -228,73 +228,65 @@ str(meth_mat)
228228
#> .. .. ..$ : chr [1:100] "bisc_SRR6911624" "bisc_SRR6911625" "bisc_SRR6911626" "bisc_SRR6911627" ...
229229
#> .. ..@ x : num [1:32627134] 1 1 1 1 1 1 1 1 1 1 ...
230230
#> .. ..@ factors : list()
231-
#> $ Cov :Formal class 'dgCMatrix' [package "Matrix"] with 6 slots
232-
#> .. ..@ i : int [1:43227794] 0 1 2 3 4 5 6 7 8 9 ...
233-
#> .. ..@ p : int [1:101] 0 217582 488919 850016 1220035 1545163 1920047 2322291 2713873 3020522 ...
234-
#> .. ..@ Dim : int [1:2] 7276107 100
235-
#> .. ..@ Dimnames:List of 2
236-
#> .. .. ..$ : NULL
237-
#> .. .. ..$ : chr [1:100] "bisc_SRR6911624" "bisc_SRR6911625" "bisc_SRR6911626" "bisc_SRR6911627" ...
238-
#> .. ..@ x : num [1:43227794] 1 1 1 1 1 1 1 1 1 1 ...
239-
#> .. ..@ factors : list()
240231
#> $ pos : int [1:7276107] 1472309 1472386 1472390 1472394 1472407 1472414 1472439 1472489 1472503 1473922 ...
241232
#> $ chr : chr [1:7276107] "chr1" "chr1" "chr1" "chr1" ...
242233
#> $ sampleNames: chr [1:100] "bisc_SRR6911624" "bisc_SRR6911625" "bisc_SRR6911626" "bisc_SRR6911627" ...
243234
```
244235

245-
The output of `make_bsseq_mat()` is a named list containing matrices of coverage
246-
values and M values and vectors of the sample names, chromosome names and
247-
positions of the loci.
236+
The output of `make_mat()` is a named list containing a matrix of beta values
237+
and vectors of the sample names, chromosome names and positions of the loci.
248238

249-
This list can be used to produce a BSseq object. However since BSseq cannot work
250-
with sparse matrices, the two matrices would need to be converted to dense
251-
matrices first.
252-
253-
``` r
254-
bs <- do.call(BSseq, meth_mat)
255-
```
239+
If you want to make a BSseq object, you can use `make_bsseq_mat()` which makes
240+
both beta/M-value and coverage value matrices. Its output can be used to
241+
produce a BSseq object. However since BSseq cannot work with sparse matrices,
242+
the two matrices would need to be converted to dense matrices first.
256243

257-
If you want just one column from the BED file as a matrix instead of the two
258-
for BSseq, use `make_mat()`. For example, to get a matrix of beta values
259-
(column 4 in the BISCUIT BED file) run
260244

261245
``` r
262-
make_mat(bedfiles, regions, col = 4, mat_name = "beta")
246+
meth_mat <- make_bsseq_mat(
247+
bedfiles,
248+
regions,
249+
sparse = TRUE,
250+
prealloc = cpg.count + 1e5
251+
)
252+
bs <- do.call(BSseq, meth_mat)
263253
```
264254

265255
## Session info
266256

267257

268258
``` r
269259
sessionInfo()
270-
#> R version 4.4.2 (2024-10-31)
260+
#> R version 4.4.3 (2025-02-28)
271261
#> Platform: x86_64-pc-linux-gnu
272-
#> Running under: AlmaLinux 9.5 (Teal Serval)
262+
#> Running under: Ubuntu 24.04.2 LTS
273263
#>
274264
#> Matrix products: default
275-
#> BLAS/LAPACK: /usr/lib64/libopenblas-r0.3.26.so; LAPACK version 3.12.0
265+
#> BLAS/LAPACK: /nix/store/6kknwpcf8fl7ihkkxmdb6p764kdn443n-blas-3/lib/libblas.so.3; LAPACK version 3.12.0
276266
#>
277267
#> locale:
278-
#> [1] LC_CTYPE=C.utf8 LC_NUMERIC=C LC_TIME=C.UTF-8
279-
#> [4] LC_COLLATE=C.utf8 LC_MONETARY=C.UTF-8 LC_MESSAGES=C.utf8
280-
#> [7] LC_PAPER=C.UTF-8 LC_NAME=C LC_ADDRESS=C
281-
#> [10] LC_TELEPHONE=C LC_MEASUREMENT=C.UTF-8 LC_IDENTIFICATION=C
268+
#> [1] LC_CTYPE=en_US.UTF-8 LC_NUMERIC=C
269+
#> [3] LC_TIME=en_US.UTF-8 LC_COLLATE=en_US.UTF-8
270+
#> [5] LC_MONETARY=en_US.UTF-8 LC_MESSAGES=en_US.UTF-8
271+
#> [7] LC_PAPER=en_US.UTF-8 LC_NAME=C
272+
#> [9] LC_ADDRESS=C LC_TELEPHONE=C
273+
#> [11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C
282274
#>
283-
#> time zone: UTC
284-
#> tzcode source: internal
275+
#> time zone: America/Detroit
276+
#> tzcode source: system (glibc)
285277
#>
286278
#> attached base packages:
287279
#> [1] stats graphics grDevices utils datasets methods base
288280
#>
289281
#> other attached packages:
290-
#> [1] data.table_1.17.0 iscream_0.0.0.9000
282+
#> [1] data.table_1.17.0 iscream_0.1.0.9000
291283
#>
292284
#> loaded via a namespace (and not attached):
293-
#> [1] compiler_4.4.2 parallelly_1.43.0 Matrix_1.7-3
294-
#> [4] parallel_4.4.2 tools_4.4.2 Rcpp_1.0.14
295-
#> [7] grid_4.4.2 knitr_1.50 xfun_0.51
285+
#> [1] compiler_4.4.3 parallelly_1.42.0 Matrix_1.7-2
286+
#> [4] parallel_4.4.3 tools_4.4.3 Rcpp_1.0.14
287+
#> [7] grid_4.4.3 knitr_1.47 xfun_0.51
296288
#> [10] RcppParallel_5.1.10 stringfish_0.16.0 lattice_0.22-6
297-
#> [13] evaluate_1.0.3
289+
#> [13] evaluate_0.24.0
298290
```
299291

300292
<!-- vim: set filetype=rmd: -->

0 commit comments

Comments
 (0)