@weng-lab/genomebrowser-ui 0.1.9 → 0.1.11
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/TrackSelect/Data/{modifiedHumanTracks.json.d.ts → humanBiosamples.json.d.ts} +40705 -20804
- package/dist/TrackSelect/Data/mouseBiosamples.json.d.ts +10346 -0
- package/dist/TrackSelect/DataGrid/GroupingCell.d.ts +2 -0
- package/dist/TrackSelect/DataGrid/dataGridHelpers.d.ts +25 -6
- package/dist/TrackSelect/TrackSelect.d.ts +4 -1
- package/dist/TrackSelect/TreeView/treeViewHelpers.d.ts +1 -1
- package/dist/TrackSelect/consts.d.ts +6 -17
- package/dist/TrackSelect/store.d.ts +2 -1
- package/dist/TrackSelect/types.d.ts +5 -0
- package/dist/genomebrowser-ui.es.js +1173 -951
- package/dist/genomebrowser-ui.es.js.map +1 -1
- package/dist/lib.d.ts +0 -2
- package/package.json +2 -2
- package/src/TrackSelect/Data/formatBiosamples.go +254 -0
- package/src/TrackSelect/Data/{modifiedHumanTracks.json → humanBiosamples.json} +40704 -20804
- package/src/TrackSelect/Data/mouseBiosamples.json +10343 -0
- package/src/TrackSelect/DataGrid/DataGridWrapper.tsx +13 -6
- package/src/TrackSelect/DataGrid/GroupingCell.tsx +144 -0
- package/src/TrackSelect/DataGrid/columns.tsx +7 -0
- package/src/TrackSelect/DataGrid/dataGridHelpers.tsx +64 -19
- package/src/TrackSelect/TrackSelect.tsx +86 -27
- package/src/TrackSelect/TreeView/TreeViewWrapper.tsx +1 -1
- package/src/TrackSelect/TreeView/treeViewHelpers.tsx +65 -17
- package/src/TrackSelect/consts.ts +30 -30
- package/src/TrackSelect/issues.md +404 -0
- package/src/TrackSelect/store.ts +16 -6
- package/src/TrackSelect/types.ts +8 -0
- package/src/lib.ts +0 -3
- package/test/main.tsx +399 -17
- package/dist/TrackSelect/treeViewHelpers.d.ts +0 -1
- package/src/TrackSelect/.claude/settings.local.json +0 -7
- package/src/TrackSelect/Data/humanTracks.json +0 -35711
- package/src/TrackSelect/Data/human_chromhmm_biosamples_with_all_urls.json +0 -35716
- package/src/TrackSelect/bug.md +0 -4
- package/src/TrackSelect/treeViewHelpers.tsx +0 -0
package/src/lib.ts
CHANGED
package/test/main.tsx
CHANGED
|
@@ -1,9 +1,84 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
3
|
-
import TrackSelect from "../src/TrackSelect/TrackSelect";
|
|
1
|
+
// react
|
|
2
|
+
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
4
3
|
import { createRoot } from "react-dom/client";
|
|
5
4
|
|
|
6
|
-
|
|
5
|
+
// mui
|
|
6
|
+
import EditIcon from "@mui/icons-material/Edit";
|
|
7
|
+
import CloseIcon from "@mui/icons-material/Close";
|
|
8
|
+
import {
|
|
9
|
+
Box,
|
|
10
|
+
Button,
|
|
11
|
+
Dialog,
|
|
12
|
+
DialogContent,
|
|
13
|
+
DialogTitle,
|
|
14
|
+
IconButton,
|
|
15
|
+
Typography,
|
|
16
|
+
} from "@mui/material";
|
|
17
|
+
|
|
18
|
+
// weng lab
|
|
19
|
+
import {
|
|
20
|
+
BigBedConfig,
|
|
21
|
+
BigWigConfig,
|
|
22
|
+
Browser,
|
|
23
|
+
createBrowserStoreMemo,
|
|
24
|
+
createTrackStoreMemo,
|
|
25
|
+
DisplayMode,
|
|
26
|
+
Domain,
|
|
27
|
+
GQLWrapper,
|
|
28
|
+
Rect,
|
|
29
|
+
Track,
|
|
30
|
+
TrackType,
|
|
31
|
+
TranscriptConfig,
|
|
32
|
+
} from "@weng-lab/genomebrowser";
|
|
33
|
+
|
|
34
|
+
// local
|
|
35
|
+
import { createSelectionStore, TrackSelect, RowInfo } from "../src/lib";
|
|
36
|
+
import { Exon } from "@weng-lab/genomebrowser/dist/components/tracks/transcript/types";
|
|
37
|
+
|
|
38
|
+
interface Transcript {
|
|
39
|
+
id: string;
|
|
40
|
+
name: string;
|
|
41
|
+
coordinates: Domain;
|
|
42
|
+
strand: string;
|
|
43
|
+
exons?: Exon[];
|
|
44
|
+
color?: string;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const enum Assembly {
|
|
48
|
+
human = "GRCh38",
|
|
49
|
+
mouse = "mm10",
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Callback types for track interactions (using any to avoid type conflicts with library types)
|
|
53
|
+
interface TrackCallbacks {
|
|
54
|
+
onHover: (item: any) => void;
|
|
55
|
+
onLeave: () => void;
|
|
56
|
+
onCCREClick: (item: any) => void;
|
|
57
|
+
onGeneClick: (item: any) => void;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Helper to inject callbacks based on track type
|
|
61
|
+
function injectCallbacks(track: Track, callbacks: TrackCallbacks): Track {
|
|
62
|
+
if (track.trackType === TrackType.Transcript) {
|
|
63
|
+
return {
|
|
64
|
+
...track,
|
|
65
|
+
onHover: callbacks.onHover,
|
|
66
|
+
onLeave: callbacks.onLeave,
|
|
67
|
+
onClick: callbacks.onGeneClick,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
if (track.trackType === TrackType.BigBed) {
|
|
71
|
+
return {
|
|
72
|
+
...track,
|
|
73
|
+
onHover: callbacks.onHover,
|
|
74
|
+
onLeave: callbacks.onLeave,
|
|
75
|
+
onClick: callbacks.onCCREClick,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
return track;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function getLocalStorage(assembly: Assembly): Set<string> | null {
|
|
7
82
|
if (typeof window === "undefined" || !window.sessionStorage) return null;
|
|
8
83
|
|
|
9
84
|
const selectedIds = sessionStorage.getItem(assembly + "-selected-tracks");
|
|
@@ -12,32 +87,339 @@ function getLocalStorage(assembly: string): Set<string> | null {
|
|
|
12
87
|
return new Set(idsArray);
|
|
13
88
|
}
|
|
14
89
|
|
|
15
|
-
function setLocalStorage(trackIds: Set<string>, assembly:
|
|
90
|
+
function setLocalStorage(trackIds: Set<string>, assembly: Assembly) {
|
|
16
91
|
sessionStorage.setItem(
|
|
17
92
|
assembly + "-selected-tracks",
|
|
18
93
|
JSON.stringify([...trackIds]),
|
|
19
94
|
);
|
|
20
95
|
}
|
|
21
96
|
|
|
22
|
-
const assembly = "grch38";
|
|
23
97
|
function Main() {
|
|
98
|
+
const [open, setOpen] = useState(false);
|
|
99
|
+
const currentAssembly = Assembly.mouse;
|
|
100
|
+
|
|
101
|
+
const browserStore = createBrowserStoreMemo({
|
|
102
|
+
// chr12:53,380,176-53,416,446
|
|
103
|
+
domain: { chromosome: "chr12", start: 53380176, end: 53416446 },
|
|
104
|
+
marginWidth: 100,
|
|
105
|
+
trackWidth: 1400,
|
|
106
|
+
multiplier: 3,
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
const addHighlight = browserStore((s) => s.addHighlight);
|
|
110
|
+
const removeHighlight = browserStore((s) => s.removeHighlight);
|
|
111
|
+
const onHover = useCallback(
|
|
112
|
+
(item: Rect | Transcript) => {
|
|
113
|
+
const domain =
|
|
114
|
+
"start" in item
|
|
115
|
+
? { start: item.start, end: item.end }
|
|
116
|
+
: { start: item.coordinates.start, end: item.coordinates.end };
|
|
117
|
+
|
|
118
|
+
addHighlight({
|
|
119
|
+
id: "hover-highlight",
|
|
120
|
+
domain,
|
|
121
|
+
color: item.color || "blue",
|
|
122
|
+
});
|
|
123
|
+
},
|
|
124
|
+
[addHighlight],
|
|
125
|
+
);
|
|
126
|
+
const onLeave = useCallback(() => {
|
|
127
|
+
removeHighlight("hover-highlight");
|
|
128
|
+
}, [removeHighlight]);
|
|
129
|
+
|
|
130
|
+
const onCCREClick = useCallback((item: Rect) => {
|
|
131
|
+
console.log(item);
|
|
132
|
+
}, []);
|
|
133
|
+
const onGeneClick = useCallback((item: Transcript) => {
|
|
134
|
+
console.log(item);
|
|
135
|
+
}, []);
|
|
136
|
+
|
|
137
|
+
// Bundle callbacks for track injection
|
|
138
|
+
const callbacks = useMemo<TrackCallbacks>(
|
|
139
|
+
() => ({
|
|
140
|
+
onHover,
|
|
141
|
+
onLeave,
|
|
142
|
+
onCCREClick,
|
|
143
|
+
onGeneClick,
|
|
144
|
+
}),
|
|
145
|
+
[onHover, onLeave, onCCREClick, onGeneClick],
|
|
146
|
+
);
|
|
147
|
+
|
|
148
|
+
const trackStore = useLocalTracks(currentAssembly, callbacks);
|
|
149
|
+
|
|
150
|
+
const tracks = trackStore((s) => s.tracks);
|
|
151
|
+
const insertTrack = trackStore((s) => s.insertTrack);
|
|
152
|
+
const removeTrack = trackStore((s) => s.removeTrack);
|
|
153
|
+
|
|
24
154
|
const selectionStore = useMemo(() => {
|
|
25
|
-
const localIds = getLocalStorage(
|
|
155
|
+
const localIds = getLocalStorage(currentAssembly);
|
|
26
156
|
const ids = localIds != null ? localIds : new Set<string>();
|
|
27
|
-
return createSelectionStore(ids);
|
|
28
|
-
}, [
|
|
157
|
+
return createSelectionStore(currentAssembly, ids);
|
|
158
|
+
}, [currentAssembly]);
|
|
29
159
|
|
|
30
|
-
const
|
|
31
|
-
const getTrackIds = selectionStore((s) => s.getTrackIds);
|
|
160
|
+
const rowById = selectionStore((s) => s.rowById);
|
|
32
161
|
|
|
33
|
-
//
|
|
34
|
-
const
|
|
162
|
+
// Handle submit: sync tracks to browser and save to localStorage
|
|
163
|
+
const handleSubmit = useCallback(
|
|
164
|
+
(newTrackIds: Set<string>) => {
|
|
165
|
+
const currentIds = new Set(tracks.map((t) => t.id));
|
|
35
166
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
167
|
+
// Build tracks to add from newTrackIds + rowById lookup
|
|
168
|
+
const tracksToAdd = Array.from(newTrackIds)
|
|
169
|
+
.filter((id) => !currentIds.has(id)) // not in current track list
|
|
170
|
+
.map((id) => rowById.get(id)) // get RowInfo object
|
|
171
|
+
.filter((track): track is RowInfo => track !== undefined); // filter out undefined
|
|
172
|
+
|
|
173
|
+
const tracksToRemove = tracks.filter((t) => {
|
|
174
|
+
return !t.id.includes("ignore") && !newTrackIds.has(t.id);
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
console.log("removing", tracksToRemove);
|
|
178
|
+
for (const t of tracksToRemove) {
|
|
179
|
+
removeTrack(t.id);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
for (const s of tracksToAdd) {
|
|
183
|
+
const track = generateTrack(s, callbacks);
|
|
184
|
+
if (track === null) continue;
|
|
185
|
+
insertTrack(track);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Save the track IDs (not the auto-generated group IDs)
|
|
189
|
+
setLocalStorage(newTrackIds, currentAssembly);
|
|
190
|
+
// Close the dialog
|
|
191
|
+
setOpen(false);
|
|
192
|
+
},
|
|
193
|
+
[tracks, removeTrack, insertTrack, callbacks],
|
|
194
|
+
);
|
|
195
|
+
|
|
196
|
+
const handleCancel = () => {
|
|
197
|
+
setOpen(false);
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
// Handle reset: clear selections and remove non-default tracks
|
|
201
|
+
const handleReset = () => {
|
|
202
|
+
// Clear the selection store
|
|
203
|
+
selectionStore.getState().clear();
|
|
39
204
|
|
|
40
|
-
|
|
205
|
+
// Remove all non-default tracks from the browser
|
|
206
|
+
const tracksToRemove = tracks.filter((t) => !t.id.includes("ignore"));
|
|
207
|
+
for (const t of tracksToRemove) {
|
|
208
|
+
removeTrack(t.id);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Clear localStorage for selected tracks
|
|
212
|
+
setLocalStorage(new Set(), currentAssembly);
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
return (
|
|
216
|
+
<>
|
|
217
|
+
<Button
|
|
218
|
+
variant="contained"
|
|
219
|
+
startIcon={<EditIcon />}
|
|
220
|
+
size="small"
|
|
221
|
+
onClick={() => setOpen(true)}
|
|
222
|
+
>
|
|
223
|
+
Select Tracks
|
|
224
|
+
</Button>
|
|
225
|
+
<Dialog
|
|
226
|
+
open={open}
|
|
227
|
+
onClose={() => setOpen(false)}
|
|
228
|
+
maxWidth="lg"
|
|
229
|
+
fullWidth
|
|
230
|
+
>
|
|
231
|
+
<DialogTitle
|
|
232
|
+
bgcolor="#0c184a"
|
|
233
|
+
color="white"
|
|
234
|
+
display={"flex"}
|
|
235
|
+
justifyContent={"space-between"}
|
|
236
|
+
alignItems={"center"}
|
|
237
|
+
fontWeight={"bold"}
|
|
238
|
+
>
|
|
239
|
+
Biosample Tracks
|
|
240
|
+
<IconButton
|
|
241
|
+
size="large"
|
|
242
|
+
onClick={() => setOpen(false)}
|
|
243
|
+
sx={{ color: "white", padding: 0 }}
|
|
244
|
+
>
|
|
245
|
+
<CloseIcon fontSize="large" />
|
|
246
|
+
</IconButton>
|
|
247
|
+
</DialogTitle>
|
|
248
|
+
<DialogContent sx={{ marginTop: "5px" }}>
|
|
249
|
+
<TrackSelect
|
|
250
|
+
store={selectionStore}
|
|
251
|
+
onSubmit={handleSubmit}
|
|
252
|
+
onCancel={handleCancel}
|
|
253
|
+
onReset={handleReset}
|
|
254
|
+
/>
|
|
255
|
+
</DialogContent>
|
|
256
|
+
</Dialog>
|
|
257
|
+
<GQLWrapper>
|
|
258
|
+
<Browser browserStore={browserStore} trackStore={trackStore} />
|
|
259
|
+
</GQLWrapper>
|
|
260
|
+
</>
|
|
261
|
+
);
|
|
41
262
|
}
|
|
42
263
|
|
|
43
264
|
createRoot(document.getElementById("root")!).render(<Main />);
|
|
265
|
+
|
|
266
|
+
const ASSAY_COLORS: Record<string, string> = {
|
|
267
|
+
dnase: "#06da93",
|
|
268
|
+
h3k4me3: "#ff0000",
|
|
269
|
+
h3k27ac: "#ffcd00",
|
|
270
|
+
ctcf: "#00b0d0",
|
|
271
|
+
atac: "#02c7b9",
|
|
272
|
+
rnaseq: "#00aa00",
|
|
273
|
+
chromhmm: "#00ff00",
|
|
274
|
+
ccre: "#0c184a",
|
|
275
|
+
};
|
|
276
|
+
|
|
277
|
+
function generateTrack(sel: RowInfo, callbacks?: TrackCallbacks): Track {
|
|
278
|
+
const color = ASSAY_COLORS[sel.assay.toLowerCase()] || "#000000";
|
|
279
|
+
let track: Track;
|
|
280
|
+
|
|
281
|
+
switch (sel.assay.toLowerCase()) {
|
|
282
|
+
case "chromhmm":
|
|
283
|
+
track = {
|
|
284
|
+
...defaultBigBed,
|
|
285
|
+
id: sel.id,
|
|
286
|
+
url: sel.url,
|
|
287
|
+
title: sel.displayname,
|
|
288
|
+
color,
|
|
289
|
+
};
|
|
290
|
+
break;
|
|
291
|
+
case "ccre":
|
|
292
|
+
track = {
|
|
293
|
+
...defaultBigBed,
|
|
294
|
+
id: sel.id,
|
|
295
|
+
url: sel.url,
|
|
296
|
+
title: sel.displayname,
|
|
297
|
+
color,
|
|
298
|
+
};
|
|
299
|
+
break;
|
|
300
|
+
default:
|
|
301
|
+
track = {
|
|
302
|
+
...defaultBigWig,
|
|
303
|
+
id: sel.id,
|
|
304
|
+
url: sel.url,
|
|
305
|
+
title: sel.displayname,
|
|
306
|
+
color,
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
return callbacks ? injectCallbacks(track, callbacks) : track;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
export const defaultBigWig: Omit<BigWigConfig, "id" | "title" | "url"> = {
|
|
314
|
+
trackType: TrackType.BigWig,
|
|
315
|
+
height: 50,
|
|
316
|
+
displayMode: DisplayMode.Full,
|
|
317
|
+
titleSize: 12,
|
|
318
|
+
};
|
|
319
|
+
|
|
320
|
+
export const defaultBigBed: Omit<BigBedConfig, "id" | "title" | "url"> = {
|
|
321
|
+
trackType: TrackType.BigBed,
|
|
322
|
+
height: 20,
|
|
323
|
+
displayMode: DisplayMode.Dense,
|
|
324
|
+
titleSize: 12,
|
|
325
|
+
};
|
|
326
|
+
|
|
327
|
+
export const defaultTranscript: Omit<
|
|
328
|
+
TranscriptConfig,
|
|
329
|
+
"id" | "assembly" | "version"
|
|
330
|
+
> = {
|
|
331
|
+
title: "GENCODE Genes",
|
|
332
|
+
trackType: TrackType.Transcript,
|
|
333
|
+
displayMode: DisplayMode.Squish,
|
|
334
|
+
height: 100,
|
|
335
|
+
color: "#0c184a", // screen theme default
|
|
336
|
+
canonicalColor: "#100e98", // screen theme light
|
|
337
|
+
highlightColor: "#3c69e8", // bright blue
|
|
338
|
+
titleSize: 12,
|
|
339
|
+
};
|
|
340
|
+
|
|
341
|
+
export function useLocalTracks(assembly: string, callbacks?: TrackCallbacks) {
|
|
342
|
+
const localTracks = getLocalTracks(assembly);
|
|
343
|
+
|
|
344
|
+
const defaultTracks =
|
|
345
|
+
assembly === "GRCh38" ? defaultHumanTracks : defaultMouseTracks;
|
|
346
|
+
|
|
347
|
+
// Get base tracks (from storage or defaults)
|
|
348
|
+
let initialTracks = localTracks || defaultTracks;
|
|
349
|
+
|
|
350
|
+
// Inject callbacks if provided (callbacks are lost on JSON serialization)
|
|
351
|
+
if (callbacks) {
|
|
352
|
+
initialTracks = initialTracks.map((t) => injectCallbacks(t, callbacks));
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
const trackStore = createTrackStoreMemo(initialTracks, []);
|
|
356
|
+
const tracks = trackStore((state) => state.tracks);
|
|
357
|
+
|
|
358
|
+
// any time the track list changes, update local storage
|
|
359
|
+
useEffect(() => {
|
|
360
|
+
setLocalTracks(tracks, assembly);
|
|
361
|
+
}, [tracks, assembly]);
|
|
362
|
+
|
|
363
|
+
return trackStore;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
export function getLocalTracks(assembly: string): Track[] | null {
|
|
367
|
+
if (typeof window === "undefined" || !window.sessionStorage) return null;
|
|
368
|
+
|
|
369
|
+
const localTracks = sessionStorage.getItem(assembly + "-" + "tracks");
|
|
370
|
+
if (!localTracks) return null;
|
|
371
|
+
const localTracksJson = JSON.parse(localTracks) as Track[];
|
|
372
|
+
return localTracksJson;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
export function setLocalTracks(tracks: Track[], assembly: string) {
|
|
376
|
+
sessionStorage.setItem(assembly + "-tracks", JSON.stringify(tracks));
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
const defaultHumanTracks = [
|
|
380
|
+
{
|
|
381
|
+
...defaultTranscript,
|
|
382
|
+
color: ASSAY_COLORS.ccre,
|
|
383
|
+
id: "human-genes-ignore",
|
|
384
|
+
assembly: "GRCh38",
|
|
385
|
+
version: 40,
|
|
386
|
+
},
|
|
387
|
+
{
|
|
388
|
+
...defaultBigBed,
|
|
389
|
+
color: ASSAY_COLORS.ccre,
|
|
390
|
+
id: "human-ccre-ignore",
|
|
391
|
+
title: "All cCREs colored by group",
|
|
392
|
+
url: "https://downloads.wenglab.org/GRCh38-cCREs.DCC.bigBed",
|
|
393
|
+
},
|
|
394
|
+
{
|
|
395
|
+
...defaultBigWig,
|
|
396
|
+
color: ASSAY_COLORS.dnase,
|
|
397
|
+
id: "human-dnase-aggregate-ignore",
|
|
398
|
+
title: "Aggregated DNase signal, all ENCODE biosamples",
|
|
399
|
+
url: "https://downloads.wenglab.org/DNAse_All_ENCODE_MAR20_2024_merged.bw",
|
|
400
|
+
},
|
|
401
|
+
];
|
|
402
|
+
|
|
403
|
+
const defaultMouseTracks = [
|
|
404
|
+
{
|
|
405
|
+
...defaultTranscript,
|
|
406
|
+
color: ASSAY_COLORS.ccre,
|
|
407
|
+
id: "mouse-genes-ignore",
|
|
408
|
+
assembly: "mm10",
|
|
409
|
+
version: 21,
|
|
410
|
+
},
|
|
411
|
+
{
|
|
412
|
+
...defaultBigBed,
|
|
413
|
+
color: ASSAY_COLORS.ccre,
|
|
414
|
+
id: "mouse-ccre-ignore",
|
|
415
|
+
title: "All cCREs colored by group",
|
|
416
|
+
url: "https://downloads.wenglab.org/mm10-cCREs.DCC.bigBed",
|
|
417
|
+
},
|
|
418
|
+
{
|
|
419
|
+
...defaultBigWig,
|
|
420
|
+
color: ASSAY_COLORS.dnase,
|
|
421
|
+
id: "mouse-dnase-aggregate-ignore",
|
|
422
|
+
title: "Aggregated DNase signal, all ENCODE biosamples",
|
|
423
|
+
url: "https://downloads.wenglab.org/DNase_MM10_ENCODE_DEC2024_merged_nanrm.bigWig",
|
|
424
|
+
},
|
|
425
|
+
];
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|