@gmod/hic 2.0.0 → 2.2.0
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.
- package/dist/hicFile.d.ts +24 -2
- package/dist/hicFile.js +142 -48
- package/dist/hicFile.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/matrix.d.ts +2 -0
- package/dist/matrix.js +4 -0
- package/dist/matrix.js.map +1 -1
- package/dist/matrixZoomData.d.ts +3 -1
- package/dist/matrixZoomData.js +6 -3
- package/dist/matrixZoomData.js.map +1 -1
- package/dist/types.d.ts +16 -0
- package/esm/hicFile.d.ts +24 -2
- package/esm/hicFile.js +142 -48
- package/esm/hicFile.js.map +1 -1
- package/esm/index.d.ts +1 -1
- package/esm/matrix.d.ts +2 -0
- package/esm/matrix.js +4 -0
- package/esm/matrix.js.map +1 -1
- package/esm/matrixZoomData.d.ts +3 -1
- package/esm/matrixZoomData.js +6 -3
- package/esm/matrixZoomData.js.map +1 -1
- package/esm/types.d.ts +16 -0
- package/package.json +1 -1
- package/src/hicFile.ts +225 -57
- package/src/index.ts +1 -0
- package/src/matrix.ts +5 -0
- package/src/matrixZoomData.ts +6 -1
- package/src/types.ts +12 -0
package/src/hicFile.ts
CHANGED
|
@@ -15,6 +15,7 @@ import type {
|
|
|
15
15
|
BaseOpts,
|
|
16
16
|
BlockIndexEntry,
|
|
17
17
|
Chromosome,
|
|
18
|
+
ExpectedValues,
|
|
18
19
|
HicMetadata,
|
|
19
20
|
HicRegion,
|
|
20
21
|
ProgressOpts,
|
|
@@ -49,6 +50,36 @@ interface SignalOpts extends ProgressOpts {
|
|
|
49
50
|
signal: AbortSignal
|
|
50
51
|
}
|
|
51
52
|
|
|
53
|
+
/** One expected-value vector: its values on disk and its chromosome scale factors. */
|
|
54
|
+
interface ExpectedChunk {
|
|
55
|
+
vector: NormalizationVector
|
|
56
|
+
nValues: number
|
|
57
|
+
chrScaleFactors: Map<number, number>
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** A walked expected-value section, and where the next section starts. */
|
|
61
|
+
interface ExpectedSection {
|
|
62
|
+
chunks: Map<string, ExpectedChunk>
|
|
63
|
+
end: number
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function getExpectedKey(type: string, unit: string, binSize: number) {
|
|
67
|
+
return `${type}_${unit}_${binSize}`
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// The range of `|bin2 - bin1|` over two half-open bin windows.
|
|
71
|
+
function distanceRange(
|
|
72
|
+
[x1, x2]: readonly [number, number],
|
|
73
|
+
[y1, y2]: readonly [number, number],
|
|
74
|
+
) {
|
|
75
|
+
const overlap = x1 < y2 && y1 < x2
|
|
76
|
+
const nearest = overlap
|
|
77
|
+
? 0
|
|
78
|
+
: Math.min(Math.abs(y1 - (x2 - 1)), Math.abs(x1 - (y2 - 1)))
|
|
79
|
+
const farthest = Math.max(Math.abs(y2 - 1 - x1), Math.abs(x2 - 1 - y1))
|
|
80
|
+
return [nearest, farthest] as const
|
|
81
|
+
}
|
|
82
|
+
|
|
52
83
|
export interface HicConfig {
|
|
53
84
|
/** a `generic-filehandle2` handle, e.g. `RemoteFile` for a URL */
|
|
54
85
|
filehandle?: GenericFilehandle
|
|
@@ -180,6 +211,9 @@ export class HicFile {
|
|
|
180
211
|
string,
|
|
181
212
|
NormVectorIndex | undefined
|
|
182
213
|
>()
|
|
214
|
+
// 'raw' and 'normalized', each walked once: the sections carry no index, so
|
|
215
|
+
// a chunk's position is known only by walking every chunk before it.
|
|
216
|
+
private expectedSectionCache = new SharedReadCache<string, ExpectedSection>()
|
|
183
217
|
private normVectorCache = new SharedReadCache<
|
|
184
218
|
string,
|
|
185
219
|
NormalizationVector | undefined
|
|
@@ -196,6 +230,8 @@ export class HicFile {
|
|
|
196
230
|
private version = 0
|
|
197
231
|
private genomeId = ''
|
|
198
232
|
private footerPosition = 0
|
|
233
|
+
// Where the raw (NONE) expected values begin, right after the master index.
|
|
234
|
+
private expectedValuesPosition = 0
|
|
199
235
|
// Where the file's normalization data begins, and so also where a file
|
|
200
236
|
// carrying none of it ends. Public so a test can cut a real file there to
|
|
201
237
|
// make that second shape.
|
|
@@ -253,8 +289,11 @@ export class HicFile {
|
|
|
253
289
|
}
|
|
254
290
|
const footerPosition = binaryParser.getLong()
|
|
255
291
|
|
|
256
|
-
const {
|
|
257
|
-
|
|
292
|
+
const {
|
|
293
|
+
masterIndex,
|
|
294
|
+
expectedValuesPosition,
|
|
295
|
+
normExpectedValueVectorsPosition,
|
|
296
|
+
} = await this.readFooter(version, footerPosition, signal)
|
|
258
297
|
|
|
259
298
|
const bodyPosition = Object.values(masterIndex).reduce(
|
|
260
299
|
(min, entry) => Math.min(min, entry.start),
|
|
@@ -303,6 +342,7 @@ export class HicFile {
|
|
|
303
342
|
throwIfAborted(signal)
|
|
304
343
|
this.version = version
|
|
305
344
|
this.footerPosition = footerPosition
|
|
345
|
+
this.expectedValuesPosition = expectedValuesPosition
|
|
306
346
|
this.masterIndex = masterIndex
|
|
307
347
|
this.normExpectedValueVectorsPosition = normExpectedValueVectorsPosition
|
|
308
348
|
this.genomeId = genomeId
|
|
@@ -350,10 +390,15 @@ export class HicFile {
|
|
|
350
390
|
masterIndex[key] = { start: pos, size }
|
|
351
391
|
}
|
|
352
392
|
|
|
393
|
+
const expectedValuesPosition = footerPosition + skip + binaryParser.position
|
|
353
394
|
// Normalized expected values start after the expected values
|
|
354
395
|
const normExpectedValueVectorsPosition =
|
|
355
396
|
version > 5 ? footerPosition + (version < 9 ? 4 : 8) + nBytes : undefined
|
|
356
|
-
return {
|
|
397
|
+
return {
|
|
398
|
+
masterIndex,
|
|
399
|
+
expectedValuesPosition,
|
|
400
|
+
normExpectedValueVectorsPosition,
|
|
401
|
+
}
|
|
357
402
|
}
|
|
358
403
|
|
|
359
404
|
async getMatrix(chrIdx1: number, chrIdx2: number, opts?: BaseOpts) {
|
|
@@ -871,10 +916,7 @@ export class HicFile {
|
|
|
871
916
|
const { signal } = opts
|
|
872
917
|
let index: NormVectorIndex | undefined
|
|
873
918
|
if (this.normExpectedValueVectorsPosition !== undefined) {
|
|
874
|
-
const nviStart = await this.
|
|
875
|
-
this.normExpectedValueVectorsPosition,
|
|
876
|
-
opts,
|
|
877
|
-
)
|
|
919
|
+
const nviStart = (await this.getExpectedSection('normalized', opts)).end
|
|
878
920
|
const data = await this.file.read(nviStart, INT, { signal })
|
|
879
921
|
// Possible if there are no norm vectors. A legal v8 file, though uncommon.
|
|
880
922
|
if (data.byteLength !== 0) {
|
|
@@ -903,69 +945,195 @@ export class HicFile {
|
|
|
903
945
|
return index
|
|
904
946
|
}
|
|
905
947
|
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
948
|
+
/**
|
|
949
|
+
* The expected count for a region pair at `binsize`, the denominator of
|
|
950
|
+
* observed/expected, as straw computes it. `normalization` must be the one
|
|
951
|
+
* the pair's records carry (`getContactRecords`' `appliedNormalization`),
|
|
952
|
+
* since each normalization has its own vector. Undefined where the file has
|
|
953
|
+
* no expected value for it: no vector at this binsize, or a version 5 file
|
|
954
|
+
* asked for a normalized one.
|
|
955
|
+
*
|
|
956
|
+
* Within a chromosome the vector is read for only the distances the pair
|
|
957
|
+
* spans. Between chromosomes straw divides by the map's average contact, the
|
|
958
|
+
* raw `sumCounts` over its bins, whatever the normalization.
|
|
959
|
+
*/
|
|
960
|
+
async getExpectedValues(
|
|
961
|
+
normalization: string,
|
|
962
|
+
region1: HicRegion,
|
|
963
|
+
region2: HicRegion,
|
|
964
|
+
binsize: number,
|
|
965
|
+
opts?: ProgressOpts,
|
|
966
|
+
): Promise<ExpectedValues | undefined> {
|
|
967
|
+
await this.init(opts)
|
|
968
|
+
const idx1 = this.chromosomeIndexMap.get(region1.chr)
|
|
969
|
+
const idx2 = this.chromosomeIndexMap.get(region2.chr)
|
|
970
|
+
if (idx1 === undefined || idx2 === undefined) {
|
|
971
|
+
return undefined
|
|
972
|
+
}
|
|
973
|
+
if (idx1 !== idx2) {
|
|
974
|
+
const matrix = await this.getMatrix(idx1, idx2, opts)
|
|
975
|
+
const zd = matrix?.getZoomData(binsize)
|
|
976
|
+
if (!zd) {
|
|
977
|
+
return undefined
|
|
978
|
+
}
|
|
979
|
+
// straw's bin counts leave out a chromosome's partial last bin
|
|
980
|
+
const nBins1 = Math.max(
|
|
981
|
+
1,
|
|
982
|
+
Math.floor(this.chromosomes[idx1]!.size / binsize),
|
|
983
|
+
)
|
|
984
|
+
const nBins2 = Math.max(
|
|
985
|
+
1,
|
|
986
|
+
Math.floor(this.chromosomes[idx2]!.size / binsize),
|
|
987
|
+
)
|
|
988
|
+
return { kind: 'inter', average: zd.sumCounts / nBins1 / nBins2 }
|
|
989
|
+
}
|
|
990
|
+
const normalized = !!normalization && normalization !== 'NONE'
|
|
991
|
+
if (normalized && this.normExpectedValueVectorsPosition === undefined) {
|
|
992
|
+
return undefined
|
|
993
|
+
}
|
|
994
|
+
const section = await this.getExpectedSection(
|
|
995
|
+
normalized ? 'normalized' : 'raw',
|
|
996
|
+
opts ?? {},
|
|
997
|
+
)
|
|
998
|
+
const chunk = section.chunks.get(
|
|
999
|
+
getExpectedKey(normalized ? normalization : 'NONE', 'BP', binsize),
|
|
1000
|
+
)
|
|
1001
|
+
if (!chunk || chunk.nValues === 0) {
|
|
1002
|
+
return undefined
|
|
1003
|
+
}
|
|
1004
|
+
const [first, last] = distanceRange(
|
|
1005
|
+
binWindow(region1, binsize),
|
|
1006
|
+
binWindow(region2, binsize),
|
|
1007
|
+
)
|
|
1008
|
+
const signalOpts = { signal: opts?.signal }
|
|
1009
|
+
const stored = await chunk.vector.getValues(first, last + 1, signalOpts)
|
|
1010
|
+
const tail =
|
|
1011
|
+
stored.length < last + 1 - first
|
|
1012
|
+
? (
|
|
1013
|
+
await chunk.vector.getValues(
|
|
1014
|
+
chunk.nValues - 1,
|
|
1015
|
+
chunk.nValues,
|
|
1016
|
+
signalOpts,
|
|
1017
|
+
)
|
|
1018
|
+
)[0]!
|
|
1019
|
+
: 0
|
|
1020
|
+
// straw divides by 1 where the section names no factor for the chromosome
|
|
1021
|
+
const factor = chunk.chrScaleFactors.get(idx1) ?? 1
|
|
1022
|
+
const values = new Float64Array(last + 1 - first)
|
|
1023
|
+
for (let i = 0; i < values.length; i++) {
|
|
1024
|
+
values[i] = (i < stored.length ? stored[i]! : tail) / factor
|
|
1025
|
+
}
|
|
1026
|
+
return { kind: 'intra', firstDistance: first, values }
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
/**
|
|
1030
|
+
* The library's total contact count, the `ALL` whole-genome map's
|
|
1031
|
+
* `sumCounts`: what scales two libraries of different depth against each
|
|
1032
|
+
* other. Undefined for a file with no `ALL` map.
|
|
1033
|
+
*/
|
|
1034
|
+
async getTotalContacts(opts?: BaseOpts) {
|
|
1035
|
+
await this.init(opts)
|
|
1036
|
+
const all = this.chromosomes.find(chr => chr.name.toUpperCase() === 'ALL')
|
|
1037
|
+
const zd = all
|
|
1038
|
+
? (await this.getMatrix(all.index, all.index, opts))?.getZoomLevels()[0]
|
|
1039
|
+
: undefined
|
|
1040
|
+
return zd?.sumCounts
|
|
1041
|
+
}
|
|
1042
|
+
|
|
1043
|
+
private async getExpectedSection(
|
|
1044
|
+
section: 'raw' | 'normalized',
|
|
1045
|
+
opts: ProgressOpts,
|
|
1046
|
+
) {
|
|
1047
|
+
return this.expectedSectionCache.get(section, opts.signal, signal =>
|
|
1048
|
+
this.walkExpectedSection(
|
|
1049
|
+
section === 'raw'
|
|
1050
|
+
? this.expectedValuesPosition
|
|
1051
|
+
: this.normExpectedValueVectorsPosition!,
|
|
1052
|
+
section === 'normalized',
|
|
1053
|
+
{ signal, onProgress: opts.onProgress },
|
|
1054
|
+
),
|
|
1055
|
+
)
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1058
|
+
// Walk one expected-value section, recording where each chunk's values sit
|
|
1059
|
+
// and its chromosome scale factors. The normalized section's end is also
|
|
1060
|
+
// where a pre-v9 file's normalization vector index begins.
|
|
1061
|
+
//
|
|
1062
|
+
// A chunk's two reads land a whole expected-value vector apart — one per bin
|
|
1063
|
+
// of the genome's longest chromosome, so megabytes at a fine binsize — which
|
|
1064
|
+
// is further than the buffer reaches. On a remote file that is two round
|
|
1065
|
+
// trips per chunk that nothing can merge, and it is why this walk, not the
|
|
1066
|
+
// index it leads to, is the slow part of opening a pre-v9 file. It is also
|
|
1067
|
+
// why the chunk is the unit worth counting: known before the first read, each
|
|
1068
|
+
// costing about the same. Chunks are walked in order, since each one's size
|
|
1069
|
+
// is known only once the one before it has been parsed.
|
|
1070
|
+
private async walkExpectedSection(
|
|
1071
|
+
start: number,
|
|
1072
|
+
normalized: boolean,
|
|
1073
|
+
opts: SignalOpts,
|
|
1074
|
+
): Promise<ExpectedSection> {
|
|
909
1075
|
const { signal, onProgress } = opts
|
|
910
1076
|
const version = this.version
|
|
1077
|
+
const valueSize = version < 9 ? DOUBLE : FLOAT
|
|
911
1078
|
const file = new BufferedFile({ file: this.file, size: 256000 })
|
|
1079
|
+
const chunks = new Map<string, ExpectedChunk>()
|
|
912
1080
|
const data = await file.read(start, INT, { signal })
|
|
913
|
-
// A file with no normalization at all ends where
|
|
914
|
-
// so the count this is about to read is past EOF.
|
|
915
|
-
//
|
|
916
|
-
//
|
|
917
|
-
//
|
|
918
|
-
// discovery path, and that path starts by skipping a section that isn't
|
|
919
|
-
// there. Answering `start` leaves the caller's guard to do the rest.
|
|
1081
|
+
// A file with no normalization at all ends where the normalized section
|
|
1082
|
+
// would start, so the count this is about to read is past EOF. A v9 file
|
|
1083
|
+
// that records no norm-vector-index position takes the v8 discovery path,
|
|
1084
|
+
// which starts by walking a section that isn't there, so the empty answer
|
|
1085
|
+
// has to come from here.
|
|
920
1086
|
if (data.byteLength < INT) {
|
|
921
|
-
return start
|
|
1087
|
+
return { chunks, end: start }
|
|
922
1088
|
}
|
|
923
|
-
const
|
|
924
|
-
const nEntries = binaryParser.getInt() // Total # of expected value chunks
|
|
925
|
-
|
|
926
|
-
// Skip one chunk, answering where the next one starts.
|
|
927
|
-
//
|
|
928
|
-
// Its two reads land a whole expected-value vector apart — one per bin of
|
|
929
|
-
// the genome, so tens of MB at a fine binsize — which is further than the
|
|
930
|
-
// buffer reaches. On a remote file that is two round trips per chunk that
|
|
931
|
-
// nothing can merge, and it is why this walk, not the index it is looking
|
|
932
|
-
// for, is the slow part of opening a pre-v9 file. It is also why the chunk
|
|
933
|
-
// is the unit worth counting: `nEntries` of them, known before the first
|
|
934
|
-
// read, each costing about the same.
|
|
935
|
-
const skipChunk = async (chunkStart: number) => {
|
|
936
|
-
let chunkSize = 0
|
|
937
|
-
|
|
938
|
-
let buf = await file.read(chunkStart, 500, { signal })
|
|
939
|
-
let parser = new BinaryParser(new DataView(buf))
|
|
940
|
-
parser.getString() // type
|
|
941
|
-
parser.getString() // unit
|
|
942
|
-
parser.getInt() // binSize
|
|
943
|
-
const nValues = version < 9 ? parser.getInt() : parser.getLong()
|
|
944
|
-
chunkSize += parser.position + nValues * (version < 9 ? DOUBLE : FLOAT)
|
|
945
|
-
|
|
946
|
-
buf = await file.read(chunkStart + chunkSize, INT, { signal })
|
|
947
|
-
parser = new BinaryParser(new DataView(buf))
|
|
948
|
-
const nChrScaleFactors = parser.getInt()
|
|
949
|
-
chunkSize +=
|
|
950
|
-
INT + nChrScaleFactors * (INT + (version < 9 ? DOUBLE : FLOAT))
|
|
951
|
-
|
|
952
|
-
return chunkStart + chunkSize
|
|
953
|
-
}
|
|
954
|
-
|
|
955
|
-
// A loop rather than the tail recursion this was, because the position is
|
|
956
|
-
// the only thing carried between chunks and a counter now rides along with
|
|
957
|
-
// it. Chunks must be walked in order — each one's size is only known once
|
|
958
|
-
// the one before it has been parsed — so the awaits are sequential by
|
|
959
|
-
// nature, not by oversight.
|
|
1089
|
+
const nEntries = new BinaryParser(new DataView(data)).getInt()
|
|
960
1090
|
if (nEntries > 0) {
|
|
961
1091
|
onProgress?.(0, nEntries)
|
|
962
1092
|
}
|
|
963
1093
|
let position = start + INT
|
|
964
1094
|
for (let done = 0; done < nEntries; done++) {
|
|
965
|
-
|
|
1095
|
+
let parser = new BinaryParser(
|
|
1096
|
+
new DataView(await file.read(position, 500, { signal })),
|
|
1097
|
+
)
|
|
1098
|
+
const type = normalized ? parser.getString() : 'NONE'
|
|
1099
|
+
const unit = parser.getString()
|
|
1100
|
+
const binSize = parser.getInt()
|
|
1101
|
+
const nValues = version < 9 ? parser.getInt() : parser.getLong()
|
|
1102
|
+
const valuesPosition = position + parser.position
|
|
1103
|
+
const factorsPosition = valuesPosition + nValues * valueSize
|
|
1104
|
+
|
|
1105
|
+
parser = new BinaryParser(
|
|
1106
|
+
new DataView(await file.read(factorsPosition, INT, { signal })),
|
|
1107
|
+
)
|
|
1108
|
+
const nFactors = parser.getInt()
|
|
1109
|
+
const factorBytes = nFactors * (INT + valueSize)
|
|
1110
|
+
parser = new BinaryParser(
|
|
1111
|
+
new DataView(
|
|
1112
|
+
await file.read(factorsPosition + INT, factorBytes, { signal }),
|
|
1113
|
+
),
|
|
1114
|
+
)
|
|
1115
|
+
const chrScaleFactors = new Map<number, number>()
|
|
1116
|
+
for (let i = 0; i < nFactors; i++) {
|
|
1117
|
+
const chrIdx = parser.getInt()
|
|
1118
|
+
chrScaleFactors.set(
|
|
1119
|
+
chrIdx,
|
|
1120
|
+
version < 9 ? parser.getDouble() : parser.getFloat(),
|
|
1121
|
+
)
|
|
1122
|
+
}
|
|
1123
|
+
chunks.set(getExpectedKey(type, unit, binSize), {
|
|
1124
|
+
vector: new NormalizationVector(
|
|
1125
|
+
this.file,
|
|
1126
|
+
valuesPosition,
|
|
1127
|
+
nValues,
|
|
1128
|
+
valueSize,
|
|
1129
|
+
),
|
|
1130
|
+
nValues,
|
|
1131
|
+
chrScaleFactors,
|
|
1132
|
+
})
|
|
1133
|
+
position = factorsPosition + INT + factorBytes
|
|
966
1134
|
onProgress?.(done + 1, nEntries)
|
|
967
1135
|
}
|
|
968
|
-
return position
|
|
1136
|
+
return { chunks, end: position }
|
|
969
1137
|
}
|
|
970
1138
|
|
|
971
1139
|
private parseNormVectorEntry(
|
package/src/index.ts
CHANGED
package/src/matrix.ts
CHANGED
|
@@ -13,6 +13,11 @@ export default class Matrix {
|
|
|
13
13
|
this.bpZoomData = zoomDataList.filter(zd => zd.zoom.unit === 'BP')
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
+
/** The BP zoom levels this matrix holds, finest last as the file lists them. */
|
|
17
|
+
getZoomLevels(): readonly MatrixZoomData[] {
|
|
18
|
+
return this.bpZoomData
|
|
19
|
+
}
|
|
20
|
+
|
|
16
21
|
// Fetch zoom data by bin size. If no matching level exists return undefined.
|
|
17
22
|
getZoomData(binSize: number) {
|
|
18
23
|
return this.bpZoomData.find(zd => binSize === zd.zoom.binSize)
|
package/src/matrixZoomData.ts
CHANGED
|
@@ -7,6 +7,8 @@ export default class MatrixZoomData {
|
|
|
7
7
|
chr1: Chromosome
|
|
8
8
|
chr2: Chromosome
|
|
9
9
|
zoom: Zoom
|
|
10
|
+
/** the raw contacts summed over the whole map at this binsize */
|
|
11
|
+
sumCounts: number
|
|
10
12
|
blockBinCount: number
|
|
11
13
|
blockColumnCount: number
|
|
12
14
|
blockIndex: Record<number, BlockIndexEntry>
|
|
@@ -15,6 +17,7 @@ export default class MatrixZoomData {
|
|
|
15
17
|
chr1: Chromosome,
|
|
16
18
|
chr2: Chromosome,
|
|
17
19
|
zoom: Zoom,
|
|
20
|
+
sumCounts: number,
|
|
18
21
|
blockBinCount: number,
|
|
19
22
|
blockColumnCount: number,
|
|
20
23
|
blockIndex: Record<number, BlockIndexEntry>,
|
|
@@ -22,6 +25,7 @@ export default class MatrixZoomData {
|
|
|
22
25
|
this.chr1 = chr1
|
|
23
26
|
this.chr2 = chr2
|
|
24
27
|
this.zoom = zoom
|
|
28
|
+
this.sumCounts = sumCounts
|
|
25
29
|
this.blockBinCount = blockBinCount
|
|
26
30
|
this.blockColumnCount = blockColumnCount
|
|
27
31
|
this.blockIndex = blockIndex
|
|
@@ -104,7 +108,7 @@ export default class MatrixZoomData {
|
|
|
104
108
|
) {
|
|
105
109
|
const unit = dis.getString()
|
|
106
110
|
const zoomIndex = dis.getInt()
|
|
107
|
-
dis.getFloat()
|
|
111
|
+
const sumCounts = dis.getFloat()
|
|
108
112
|
dis.getFloat() // occupiedCellCount
|
|
109
113
|
dis.getFloat() // stdDev
|
|
110
114
|
dis.getFloat() // percent95
|
|
@@ -125,6 +129,7 @@ export default class MatrixZoomData {
|
|
|
125
129
|
chr1,
|
|
126
130
|
chr2,
|
|
127
131
|
{ index: zoomIndex, unit, binSize },
|
|
132
|
+
sumCounts,
|
|
128
133
|
blockBinCount,
|
|
129
134
|
blockColumnCount,
|
|
130
135
|
blockIndex,
|
package/src/types.ts
CHANGED
|
@@ -68,6 +68,18 @@ export interface BlockIndexEntry {
|
|
|
68
68
|
size: number
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
+
/**
|
|
72
|
+
* The expected contact count for one region pair, the denominator of
|
|
73
|
+
* observed/expected. Within a chromosome it depends only on the distance in
|
|
74
|
+
* bins, so it is the expected-value vector's entries over the distances the
|
|
75
|
+
* pair spans: `values[|bin2 - bin1| - firstDistance]`, already divided by the
|
|
76
|
+
* chromosome's scale factor and holding the vector's last value past its end.
|
|
77
|
+
* Between chromosomes it is one number, the map's average contact.
|
|
78
|
+
*/
|
|
79
|
+
export type ExpectedValues =
|
|
80
|
+
| { kind: 'intra'; firstDistance: number; values: Float64Array }
|
|
81
|
+
| { kind: 'inter'; average: number }
|
|
82
|
+
|
|
71
83
|
export interface HicMetadata {
|
|
72
84
|
version: number
|
|
73
85
|
genome: string
|