File: IRanges-utils.R

package info (click to toggle)
r-bioc-iranges 2.24.1-1
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 1,804 kB
  • sloc: ansic: 4,980; makefile: 2; sh: 1
file content (182 lines) | stat: -rw-r--r-- 6,581 bytes parent folder | download | duplicates (4)
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
### =========================================================================
### Utility functions for creating or modifying IRanges objects
### -------------------------------------------------------------------------
###


### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
### The "successiveIRanges" function.
###
### Note that the returned IRanges object is guaranteed to be normal in the
### following cases:
###   (a) when length(width) == 0
###   (b) when length(width) == 1 and width > 0
###   (c) when length(width) >= 2 and all(width > 0) and all(gapwidth > 0)
### However, the function doesn't try to turn the result into a NormalIRanges
### object.
###

successiveIRanges <- function(width, gapwidth=0, from=1)
{
    if (!is.numeric(width))
        stop("'width' must be an integer vector")
    if (length(width) == 0L)
        return(IRanges())
    if (!is.integer(width))
        width <- as.integer(width)  # this drops the names
    else if (!is.null(names(width)))
        names(width) <- NULL  # unname() used to be broken on 0-length vectors
    if (S4Vectors:::anyMissingOrOutside(width, 0L))
        stop("'width' cannot contain NAs or negative values")
    if (!is.numeric(gapwidth))
        stop("'gapwidth' must be an integer vector")
    if (!is.integer(gapwidth))
        gapwidth <- as.integer(gapwidth)
    if (S4Vectors:::anyMissing(gapwidth))
        stop("'gapwidth' cannot contain NAs")
    if (length(gapwidth) != length(width) - 1L) {
        if (length(gapwidth) != 1L)
            stop("'gapwidth' must a single integer or an integer vector ",
                 "with one less element than the 'width' vector")
        gapwidth <- rep.int(gapwidth, length(width) - 1L)
    }
    if (!isSingleNumber(from))
        stop("'from' must be a single integer")
    if (!is.integer(from))
        from <- as.integer(from)
    ans_start <- cumsum(width[-length(width)] + gapwidth)
    ans_start <- from + c(0L, ans_start)
    ## 'ans_start' could contain NAs in case of an integer overflow in
    ## cumsum(), hence the use of 'check=TRUE' here:
    new2("IRanges", start=ans_start, width=width, check=TRUE)
}

### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
### slidingIRanges()
###

slidingIRanges <- function(len, width, shift = 1L) {
    start <- seq(1L, len-width, by=shift)
    end <- seq(width, len, by=shift)
    IRanges(start, end)
}

### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
### breakInChunks()
###
### TODO: Should not be in IRanges-utils.R because it returns a
### PartitioningByEnd object, not an IRanges object. So move it to another
### file, e.g. to Partitioning-class.R. breakInChunks() is actually a
### specialized PartitioningByEnd constructor.
###

.normarg_totalsize <- function(totalsize)
{
    if (!isSingleNumber(totalsize))
        stop("'totalsize' must be a single integer")
    if (!is.integer(totalsize))
        totalsize <- as.integer(totalsize)
    if (totalsize < 0L)
        stop("'totalsize' cannot be negative")
    totalsize
}

.normarg_nchunk_or_chunksize <- function(nchunk, totalsize, what)
{
    if (!isSingleNumber(nchunk))
        stop("'", what, "' must be a single integer")
    if (!is.integer(nchunk))
        nchunk <- as.integer(nchunk)
    if (nchunk < 0L)
        stop("'", what, "' cannot be negative")
    if (nchunk == 0L && totalsize != 0L)
        stop("'", what, "' can be 0 only if 'totalsize' is 0")
    nchunk
}

breakInChunks <- function(totalsize, nchunk, chunksize)
{
    totalsize <- .normarg_totalsize(totalsize)
    if (!missing(nchunk)) {
        if (!missing(chunksize))
            stop("only one of 'nchunk' and 'chunksize' can be specified")
        ## All chunks will have more or less the same size, with the difference
        ## between smallest and biggest chunks guaranteed to be <= 1.
        nchunk <- .normarg_nchunk_or_chunksize(nchunk, totalsize,
                                               "nchunk")
        if (nchunk == 0L)
            return(PartitioningByEnd())
        chunksize <- totalsize / nchunk  # floating point division
        breakpoints <- as.integer(cumsum(rep.int(chunksize, nchunk)))
        ## The last value in 'breakpoints' *should* be 'totalsize' but there is
        ## always some uncertainty about what coercing the result of a floating
        ## point operation to integer will produce. So we set this value
        ## manually to 'totalsize' just in case.
        breakpoints[[nchunk]] <- totalsize
    } else {
        if (missing(chunksize))
            stop("one of 'nchunk' and 'chunksize' must be specified")
        ## All chunks will have the requested size, except maybe the last one.
        chunksize <- .normarg_nchunk_or_chunksize(chunksize, totalsize,
                                                  "chunksize")
        if (totalsize == 0L)
            return(PartitioningByEnd())
        quot <- totalsize %/% chunksize  # integer division
        breakpoints <- cumsum(rep.int(chunksize, quot))
        if (quot == 0L || breakpoints[[quot]] != totalsize)
            breakpoints <- c(breakpoints, totalsize)
    }
    PartitioningByEnd(breakpoints)
}


### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
### The "centeredIRanges" function.
###

centeredIRanges <- function(center, flank)
{
    if (!is.numeric(center))
        stop("'center' must be a numeric vector")
    if (!is.numeric(flank))
        stop("'flank' must be a numeric vector")
    IRanges(start=center-flank, end=center+flank)
}


### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
### The "whichAsIRanges" function.
###
### Note that unlike the standard which() function, whichAsIRanges() drops
### the names of 'x'.
###

whichAsIRanges <- function(x)
{
    if (!is.logical(x))
        stop("'x' must be a logical vector")
    as(x, "NormalIRanges")
}


### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
### Coercing an IRanges object to a NormalIRanges object.
###

asNormalIRanges <- function(x, force=TRUE)
{
    if (!is(x, "IntegerRanges"))
        stop("'x' must be an IntegerRanges object")
    else if (!is(x, "IRanges"))
        x <- as(x, "IRanges")
    if (!isTRUEorFALSE(force))
        stop("'force' must be TRUE or FALSE")
    if (force)
        x <- reduce(x, drop.empty.ranges=TRUE)
    newNormalIRangesFromIRanges(x, check=!force)
}

.asNormalIRanges <- function(from) asNormalIRanges(from, force=TRUE)

setAs("IRanges", "NormalIRanges", .asNormalIRanges)