@weng-lab/genomebrowser-ui 0.3.6 → 0.4.0-beta.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/.env.local +1 -1
- package/dist/TrackSelect/Folders/biosamples/shared/BiosampleViewSelector.d.ts +7 -0
- package/dist/TrackSelect/Folders/biosamples/shared/createFolder.d.ts +1 -13
- package/dist/TrackSelect/Folders/biosamples/shared/toTrack.d.ts +20 -0
- package/dist/TrackSelect/Folders/biosamples/shared/types.d.ts +4 -13
- package/dist/TrackSelect/Folders/genes/shared/createFolder.d.ts +1 -3
- package/dist/TrackSelect/Folders/genes/shared/toTrack.d.ts +18 -0
- package/dist/TrackSelect/Folders/index.d.ts +6 -12
- package/dist/TrackSelect/Folders/mohd/data/human.json.d.ts +2948 -0
- package/dist/TrackSelect/Folders/mohd/human.d.ts +1 -0
- package/dist/TrackSelect/Folders/mohd/shared/MohdGroupingCell.d.ts +2 -0
- package/dist/TrackSelect/Folders/mohd/shared/MohdTreeItem.d.ts +3 -0
- package/dist/TrackSelect/Folders/mohd/shared/MohdViewSelector.d.ts +7 -0
- package/dist/TrackSelect/Folders/mohd/shared/columns.d.ts +5 -0
- package/dist/TrackSelect/Folders/mohd/shared/config.d.ts +42 -0
- package/dist/TrackSelect/Folders/mohd/shared/createFolder.d.ts +9 -0
- package/dist/TrackSelect/Folders/mohd/shared/toTrack.d.ts +9 -0
- package/dist/TrackSelect/Folders/mohd/shared/types.d.ts +40 -0
- package/dist/TrackSelect/Folders/other-tracks/shared/toTrack.d.ts +5 -0
- package/dist/TrackSelect/Folders/other-tracks/shared/types.d.ts +1 -0
- package/dist/TrackSelect/Folders/types.d.ts +23 -55
- package/dist/TrackSelect/TrackSelect.d.ts +10 -7
- package/dist/TrackSelect/TreeView/TreeViewWrapper.d.ts +1 -1
- package/dist/TrackSelect/buildSelectedTree.d.ts +15 -0
- package/dist/TrackSelect/managedTracks.d.ts +13 -0
- package/dist/TrackSelect/resolveFolderView.d.ts +2 -0
- package/dist/TrackSelect/trackContext.d.ts +5 -0
- package/dist/TrackSelect/types.d.ts +12 -33
- package/dist/genomebrowser-ui.es.js +2224 -1717
- package/dist/genomebrowser-ui.es.js.map +1 -1
- package/dist/lib.d.ts +4 -4
- package/dist/muiLicense.d.ts +1 -0
- package/package.json +6 -3
- package/src/TrackSelect/Dialogs/ResetDialog.tsx +3 -2
- package/src/TrackSelect/FolderList/FolderCard.tsx +1 -1
- package/src/TrackSelect/Folders/biosamples/shared/BiosampleViewSelector.tsx +33 -0
- package/src/TrackSelect/Folders/biosamples/shared/createFolder.ts +39 -58
- package/src/TrackSelect/Folders/biosamples/shared/toTrack.ts +138 -0
- package/src/TrackSelect/Folders/biosamples/shared/types.ts +4 -16
- package/src/TrackSelect/Folders/genes/shared/createFolder.ts +10 -31
- package/src/TrackSelect/Folders/genes/shared/toTrack.ts +59 -0
- package/src/TrackSelect/Folders/index.ts +14 -17
- package/src/TrackSelect/Folders/mohd/data/human.json +2945 -0
- package/src/TrackSelect/Folders/mohd/human.ts +10 -0
- package/src/TrackSelect/Folders/mohd/shared/MohdGroupingCell.tsx +68 -0
- package/src/TrackSelect/Folders/mohd/shared/MohdTreeItem.tsx +17 -0
- package/src/TrackSelect/Folders/mohd/shared/MohdViewSelector.tsx +33 -0
- package/src/TrackSelect/Folders/mohd/shared/columns.tsx +79 -0
- package/src/TrackSelect/Folders/mohd/shared/config.tsx +71 -0
- package/src/TrackSelect/Folders/mohd/shared/createFolder.ts +144 -0
- package/src/TrackSelect/Folders/mohd/shared/toTrack.ts +164 -0
- package/src/TrackSelect/Folders/mohd/shared/types.ts +46 -0
- package/src/TrackSelect/Folders/other-tracks/shared/createFolder.ts +13 -14
- package/src/TrackSelect/Folders/other-tracks/shared/toTrack.ts +17 -0
- package/src/TrackSelect/Folders/other-tracks/shared/types.ts +1 -0
- package/src/TrackSelect/Folders/types.ts +26 -69
- package/src/TrackSelect/TrackSelect.tsx +299 -255
- package/src/TrackSelect/TreeView/CustomTreeItem.tsx +6 -6
- package/src/TrackSelect/TreeView/TreeViewWrapper.tsx +84 -6
- package/src/TrackSelect/buildSelectedTree.ts +145 -0
- package/src/TrackSelect/managedTracks.ts +92 -0
- package/src/TrackSelect/resolveFolderView.ts +20 -0
- package/src/TrackSelect/trackContext.ts +9 -0
- package/src/TrackSelect/types.ts +14 -39
- package/src/lib.ts +13 -7
- package/src/muiLicense.ts +9 -0
- package/src/vite-env.d.ts +9 -0
- package/test/TrackSelect.test.tsx +435 -0
- package/test/main.tsx +36 -352
- package/test/mocks/logo-test.tsx +11 -0
- package/test/mohdDisplay.test.tsx +45 -0
- package/test/startup.test.ts +206 -0
- package/test/trackSelectState.test.ts +176 -0
- package/vite.config.ts +1 -0
- package/vitest.config.ts +20 -0
- package/dist/TrackSelect/Folders/biosamples/shared/AssayToggle.d.ts +0 -18
- package/dist/TrackSelect/Folders/biosamples/shared/treeBuilder.d.ts +0 -28
- package/dist/TrackSelect/Folders/genes/shared/treeBuilder.d.ts +0 -13
- package/dist/TrackSelect/Folders/other-tracks/shared/treeBuilder.d.ts +0 -4
- package/dist/TrackSelect/store.d.ts +0 -4
- package/src/TrackSelect/Folders/NEW.md +0 -929
- package/src/TrackSelect/Folders/biosamples/shared/AssayToggle.tsx +0 -78
- package/src/TrackSelect/Folders/biosamples/shared/treeBuilder.ts +0 -224
- package/src/TrackSelect/Folders/genes/shared/treeBuilder.ts +0 -45
- package/src/TrackSelect/Folders/other-tracks/shared/treeBuilder.ts +0 -34
- package/src/TrackSelect/store.ts +0 -117
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import humanData from "./data/human.json";
|
|
2
|
+
import { createMohdFolder } from "./shared/createFolder";
|
|
3
|
+
import { MohdDataFile } from "./shared/types";
|
|
4
|
+
|
|
5
|
+
export const humanMohdFolder = createMohdFolder({
|
|
6
|
+
id: "human-mohd",
|
|
7
|
+
label: "MOHD",
|
|
8
|
+
description: "Public MOHD signal, methylation, and annotation tracks.",
|
|
9
|
+
data: humanData as MohdDataFile,
|
|
10
|
+
});
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import ChevronRightIcon from "@mui/icons-material/ChevronRight";
|
|
2
|
+
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
|
|
3
|
+
import { Box, IconButton, Stack, Tooltip } from "@mui/material";
|
|
4
|
+
import {
|
|
5
|
+
GridGroupNode,
|
|
6
|
+
GridRenderCellParams,
|
|
7
|
+
useGridApiContext,
|
|
8
|
+
} from "@mui/x-data-grid-premium";
|
|
9
|
+
import { isMohdOmeLabel, MohdOmeIcon } from "./config";
|
|
10
|
+
|
|
11
|
+
export function MohdGroupingCell(params: GridRenderCellParams) {
|
|
12
|
+
const apiRef = useGridApiContext();
|
|
13
|
+
const isGroup = params.rowNode.type === "group";
|
|
14
|
+
const groupNode = params.rowNode as GridGroupNode;
|
|
15
|
+
const isExpanded = isGroup ? groupNode.childrenExpanded : false;
|
|
16
|
+
const groupingField = isGroup ? groupNode.groupingField : null;
|
|
17
|
+
const depth = params.rowNode.depth ?? 0;
|
|
18
|
+
const value = String(params.value ?? "");
|
|
19
|
+
const showOmeIcon =
|
|
20
|
+
(isGroup && groupingField === "ome") || isMohdOmeLabel(value);
|
|
21
|
+
|
|
22
|
+
const handleExpandClick = (e: React.MouseEvent) => {
|
|
23
|
+
e.stopPropagation();
|
|
24
|
+
apiRef.current.setRowChildrenExpansion(params.id, !isExpanded);
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
<Box
|
|
29
|
+
sx={{
|
|
30
|
+
display: "flex",
|
|
31
|
+
alignItems: "center",
|
|
32
|
+
width: "100%",
|
|
33
|
+
ml: depth * 2,
|
|
34
|
+
}}
|
|
35
|
+
>
|
|
36
|
+
{isGroup && (
|
|
37
|
+
<IconButton size="small" onClick={handleExpandClick} sx={{ mr: 0.5 }}>
|
|
38
|
+
{isExpanded ? (
|
|
39
|
+
<ExpandMoreIcon fontSize="small" />
|
|
40
|
+
) : (
|
|
41
|
+
<ChevronRightIcon fontSize="small" />
|
|
42
|
+
)}
|
|
43
|
+
</IconButton>
|
|
44
|
+
)}
|
|
45
|
+
<Stack
|
|
46
|
+
direction="row"
|
|
47
|
+
spacing={1}
|
|
48
|
+
alignItems="center"
|
|
49
|
+
sx={{ flex: 1, overflow: "hidden" }}
|
|
50
|
+
>
|
|
51
|
+
{showOmeIcon && <MohdOmeIcon type={value} />}
|
|
52
|
+
<Tooltip title={value} placement="top-start" enterDelay={500}>
|
|
53
|
+
<Box
|
|
54
|
+
sx={{
|
|
55
|
+
overflow: "hidden",
|
|
56
|
+
textOverflow: "ellipsis",
|
|
57
|
+
whiteSpace: "nowrap",
|
|
58
|
+
flex: 1,
|
|
59
|
+
fontWeight: isGroup ? "bold" : undefined,
|
|
60
|
+
}}
|
|
61
|
+
>
|
|
62
|
+
{params.formattedValue}
|
|
63
|
+
</Box>
|
|
64
|
+
</Tooltip>
|
|
65
|
+
</Stack>
|
|
66
|
+
</Box>
|
|
67
|
+
);
|
|
68
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { CustomTreeItem } from "../../../TreeView/CustomTreeItem";
|
|
3
|
+
import { CustomTreeItemProps } from "../../../types";
|
|
4
|
+
import { MohdOmeIcon } from "./config";
|
|
5
|
+
|
|
6
|
+
export const MohdTreeItem = React.forwardRef<
|
|
7
|
+
HTMLLIElement,
|
|
8
|
+
CustomTreeItemProps
|
|
9
|
+
>(function MohdTreeItem(props, ref) {
|
|
10
|
+
return (
|
|
11
|
+
<CustomTreeItem
|
|
12
|
+
{...props}
|
|
13
|
+
ref={ref}
|
|
14
|
+
renderIcon={(type) => <MohdOmeIcon type={type} />}
|
|
15
|
+
/>
|
|
16
|
+
);
|
|
17
|
+
});
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { ToggleButton, ToggleButtonGroup } from "@mui/material";
|
|
2
|
+
import { FolderView } from "../../types";
|
|
3
|
+
|
|
4
|
+
export interface MohdViewSelectorProps {
|
|
5
|
+
views: FolderView[];
|
|
6
|
+
activeViewId: string;
|
|
7
|
+
onChange: (viewId: string) => void;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function MohdViewSelector({
|
|
11
|
+
views,
|
|
12
|
+
activeViewId,
|
|
13
|
+
onChange,
|
|
14
|
+
}: MohdViewSelectorProps) {
|
|
15
|
+
return (
|
|
16
|
+
<ToggleButtonGroup
|
|
17
|
+
exclusive
|
|
18
|
+
value={activeViewId}
|
|
19
|
+
size="small"
|
|
20
|
+
onChange={(_event, viewId: string | null) => {
|
|
21
|
+
if (viewId) {
|
|
22
|
+
onChange(viewId);
|
|
23
|
+
}
|
|
24
|
+
}}
|
|
25
|
+
>
|
|
26
|
+
{views.map((view) => (
|
|
27
|
+
<ToggleButton key={view.id} value={view.id}>
|
|
28
|
+
{view.label}
|
|
29
|
+
</ToggleButton>
|
|
30
|
+
))}
|
|
31
|
+
</ToggleButtonGroup>
|
|
32
|
+
);
|
|
33
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { GridColDef } from "@mui/x-data-grid-premium";
|
|
2
|
+
import { FolderView } from "../../types";
|
|
3
|
+
import { MohdRowInfo } from "./types";
|
|
4
|
+
|
|
5
|
+
const descriptionCol: GridColDef<MohdRowInfo> = {
|
|
6
|
+
field: "description",
|
|
7
|
+
headerName: "Description",
|
|
8
|
+
minWidth: 220,
|
|
9
|
+
flex: 1.5,
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
const sampleIdCol: GridColDef<MohdRowInfo> = {
|
|
13
|
+
field: "sampleId",
|
|
14
|
+
headerName: "Sample ID",
|
|
15
|
+
minWidth: 180,
|
|
16
|
+
flex: 1,
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const trackCategoryCol: GridColDef<MohdRowInfo> = {
|
|
20
|
+
field: "trackCategory",
|
|
21
|
+
headerName: "Track Type",
|
|
22
|
+
minWidth: 140,
|
|
23
|
+
width: 140,
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const omeCol: GridColDef<MohdRowInfo> = {
|
|
27
|
+
field: "ome",
|
|
28
|
+
headerName: "Ome",
|
|
29
|
+
minWidth: 120,
|
|
30
|
+
width: 120,
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const siteCol: GridColDef<MohdRowInfo> = {
|
|
34
|
+
field: "site",
|
|
35
|
+
headerName: "Site",
|
|
36
|
+
minWidth: 100,
|
|
37
|
+
width: 100,
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const sexCol: GridColDef<MohdRowInfo> = {
|
|
41
|
+
field: "sex",
|
|
42
|
+
headerName: "Sex",
|
|
43
|
+
minWidth: 120,
|
|
44
|
+
width: 120,
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const statusCol: GridColDef<MohdRowInfo> = {
|
|
48
|
+
field: "status",
|
|
49
|
+
headerName: "Status",
|
|
50
|
+
minWidth: 120,
|
|
51
|
+
flex: 1,
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export const mohdColumns: GridColDef<MohdRowInfo>[] = [
|
|
55
|
+
descriptionCol,
|
|
56
|
+
trackCategoryCol,
|
|
57
|
+
sampleIdCol,
|
|
58
|
+
omeCol,
|
|
59
|
+
siteCol,
|
|
60
|
+
sexCol,
|
|
61
|
+
statusCol,
|
|
62
|
+
];
|
|
63
|
+
|
|
64
|
+
export const mohdViews: FolderView[] = [
|
|
65
|
+
{
|
|
66
|
+
id: "ome",
|
|
67
|
+
label: "Ome",
|
|
68
|
+
columns: mohdColumns,
|
|
69
|
+
groupingModel: ["ome", "site", "sampleId"],
|
|
70
|
+
leafField: "description",
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
id: "site",
|
|
74
|
+
label: "Site",
|
|
75
|
+
columns: mohdColumns,
|
|
76
|
+
groupingModel: ["site", "ome", "sampleId"],
|
|
77
|
+
leafField: "description",
|
|
78
|
+
},
|
|
79
|
+
];
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { Box } from "@mui/material";
|
|
2
|
+
|
|
3
|
+
export const MOHD_BASE_URL = "https://downloads.mohdconsortium.org";
|
|
4
|
+
|
|
5
|
+
export const MOHD_OME_CONFIG = {
|
|
6
|
+
atac: {
|
|
7
|
+
label: "ATAC",
|
|
8
|
+
color: "#02c7b9",
|
|
9
|
+
downloadPath: "2_ATAC",
|
|
10
|
+
},
|
|
11
|
+
rna: {
|
|
12
|
+
label: "RNA",
|
|
13
|
+
color: "#00aa00",
|
|
14
|
+
downloadPath: "3_RNA",
|
|
15
|
+
},
|
|
16
|
+
wgbs: {
|
|
17
|
+
label: "WGBS",
|
|
18
|
+
color: "#648bd8",
|
|
19
|
+
downloadPath: "1_WGBS",
|
|
20
|
+
},
|
|
21
|
+
} as const;
|
|
22
|
+
|
|
23
|
+
export type MohdRawOme = keyof typeof MOHD_OME_CONFIG;
|
|
24
|
+
export type MohdOme = (typeof MOHD_OME_CONFIG)[MohdRawOme]["label"];
|
|
25
|
+
|
|
26
|
+
const MOHD_OME_LABELS = Object.values(MOHD_OME_CONFIG).map(
|
|
27
|
+
(config) => config.label,
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
export function getMohdOmeConfig(rawOme: string) {
|
|
31
|
+
const config = MOHD_OME_CONFIG[rawOme.toLowerCase() as MohdRawOme];
|
|
32
|
+
|
|
33
|
+
if (!config) {
|
|
34
|
+
throw new Error(`Unknown MOHD ome: ${rawOme}`);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return config;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function createMohdFileUrl({
|
|
41
|
+
ome,
|
|
42
|
+
sampleId,
|
|
43
|
+
filename,
|
|
44
|
+
}: {
|
|
45
|
+
ome: string;
|
|
46
|
+
sampleId: string;
|
|
47
|
+
filename: string;
|
|
48
|
+
}) {
|
|
49
|
+
const { downloadPath } = getMohdOmeConfig(ome);
|
|
50
|
+
return `${MOHD_BASE_URL}/${downloadPath}/${sampleId}/${filename}`;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function isMohdOmeLabel(value: string) {
|
|
54
|
+
return MOHD_OME_LABELS.includes(value as MohdOme);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function MohdOmeIcon({ type }: { type: string }) {
|
|
58
|
+
const { color } = getMohdOmeConfig(type);
|
|
59
|
+
|
|
60
|
+
return (
|
|
61
|
+
<Box
|
|
62
|
+
data-testid={`mohd-ome-icon-${type.toLowerCase()}`}
|
|
63
|
+
sx={{
|
|
64
|
+
width: 12,
|
|
65
|
+
height: 12,
|
|
66
|
+
borderRadius: "20%",
|
|
67
|
+
bgcolor: color,
|
|
68
|
+
}}
|
|
69
|
+
/>
|
|
70
|
+
);
|
|
71
|
+
}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { FolderDefinition } from "../../types";
|
|
2
|
+
import { MohdDataFile, MohdRowInfo } from "./types";
|
|
3
|
+
import { getMohdOmeConfig } from "./config";
|
|
4
|
+
import { mohdViews } from "./columns";
|
|
5
|
+
import { MohdGroupingCell } from "./MohdGroupingCell";
|
|
6
|
+
import { MohdTreeItem } from "./MohdTreeItem";
|
|
7
|
+
import { createMohdTrack } from "./toTrack";
|
|
8
|
+
import { MohdViewSelector } from "./MohdViewSelector";
|
|
9
|
+
|
|
10
|
+
const WGBS_DESCRIPTION = "DNA Methylation";
|
|
11
|
+
|
|
12
|
+
function createBaseRow(folderId: string, row: MohdDataFile[number]) {
|
|
13
|
+
return {
|
|
14
|
+
id: `${folderId}/${row.sample_id}::${row.filename}`,
|
|
15
|
+
ome: getMohdOmeConfig(row.ome).label,
|
|
16
|
+
site: row.site,
|
|
17
|
+
sampleId: row.sample_id,
|
|
18
|
+
sex: row.sex,
|
|
19
|
+
status: row.status,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function createFileRow(
|
|
24
|
+
folderId: string,
|
|
25
|
+
row: MohdDataFile[number],
|
|
26
|
+
): MohdRowInfo {
|
|
27
|
+
const trackCategory = row.filename.endsWith(".bigBed")
|
|
28
|
+
? "Annotation"
|
|
29
|
+
: "Signal";
|
|
30
|
+
|
|
31
|
+
return {
|
|
32
|
+
...createBaseRow(folderId, row),
|
|
33
|
+
kind: "file",
|
|
34
|
+
description: row.file_type,
|
|
35
|
+
trackCategory,
|
|
36
|
+
filename: row.filename,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function getRequiredWgbsFilename(
|
|
41
|
+
sampleRows: MohdDataFile,
|
|
42
|
+
includesText: string,
|
|
43
|
+
) {
|
|
44
|
+
const match = sampleRows.find((row) => row.filename.includes(includesText));
|
|
45
|
+
|
|
46
|
+
if (!match) {
|
|
47
|
+
throw new Error(`Missing WGBS file matching ${includesText}`);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return match.filename;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function createWgbsMethylRow(
|
|
54
|
+
folderId: string,
|
|
55
|
+
sampleRows: MohdDataFile,
|
|
56
|
+
): MohdRowInfo {
|
|
57
|
+
const sampleId = sampleRows[0]?.sample_id;
|
|
58
|
+
|
|
59
|
+
if (!sampleId) {
|
|
60
|
+
throw new Error("Cannot build WGBS row without a sample ID");
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const base = createBaseRow(folderId, sampleRows[0]!);
|
|
64
|
+
|
|
65
|
+
return {
|
|
66
|
+
...base,
|
|
67
|
+
id: `${folderId}/${sampleId}`,
|
|
68
|
+
kind: "wgbs-methyl",
|
|
69
|
+
description: WGBS_DESCRIPTION,
|
|
70
|
+
trackCategory: "Methylation",
|
|
71
|
+
filenames: {
|
|
72
|
+
plusStrand: {
|
|
73
|
+
cpg: getRequiredWgbsFilename(sampleRows, "DNAme-CpG-plus"),
|
|
74
|
+
chg: getRequiredWgbsFilename(sampleRows, "DNAme-CHG-plus"),
|
|
75
|
+
chh: getRequiredWgbsFilename(sampleRows, "DNAme-CHH-plus"),
|
|
76
|
+
depth: getRequiredWgbsFilename(sampleRows, "coverage-plus"),
|
|
77
|
+
},
|
|
78
|
+
minusStrand: {
|
|
79
|
+
cpg: getRequiredWgbsFilename(sampleRows, "DNAme-CpG-minus"),
|
|
80
|
+
chg: getRequiredWgbsFilename(sampleRows, "DNAme-CHG-minus"),
|
|
81
|
+
chh: getRequiredWgbsFilename(sampleRows, "DNAme-CHH-minus"),
|
|
82
|
+
depth: getRequiredWgbsFilename(sampleRows, "coverage-minus"),
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function transformData(folderId: string, data: MohdDataFile): MohdRowInfo[] {
|
|
89
|
+
const signalRows = data
|
|
90
|
+
.filter((row) => row.ome !== "wgbs")
|
|
91
|
+
.map((row) => createFileRow(folderId, row));
|
|
92
|
+
const wgbsRowsBySampleId = new Map<string, MohdDataFile>();
|
|
93
|
+
|
|
94
|
+
data.forEach((row) => {
|
|
95
|
+
if (row.ome !== "wgbs") {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const sampleRows = wgbsRowsBySampleId.get(row.sample_id);
|
|
100
|
+
|
|
101
|
+
if (sampleRows) {
|
|
102
|
+
sampleRows.push(row);
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
wgbsRowsBySampleId.set(row.sample_id, [row]);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
const methylationRows = Array.from(wgbsRowsBySampleId.values()).map(
|
|
110
|
+
(sampleRows) => createWgbsMethylRow(folderId, sampleRows),
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
return [...signalRows, ...methylationRows];
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export interface CreateMohdFolderOptions {
|
|
117
|
+
id: string;
|
|
118
|
+
label: string;
|
|
119
|
+
description?: string;
|
|
120
|
+
data: MohdDataFile;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export function createMohdFolder(
|
|
124
|
+
options: CreateMohdFolderOptions,
|
|
125
|
+
): FolderDefinition<MohdRowInfo> {
|
|
126
|
+
const { id, label, description, data } = options;
|
|
127
|
+
const rows = transformData(id, data);
|
|
128
|
+
const defaultView = mohdViews[0]!;
|
|
129
|
+
|
|
130
|
+
return {
|
|
131
|
+
id,
|
|
132
|
+
label,
|
|
133
|
+
description,
|
|
134
|
+
rows,
|
|
135
|
+
columns: defaultView.columns,
|
|
136
|
+
groupingModel: defaultView.groupingModel,
|
|
137
|
+
leafField: defaultView.leafField,
|
|
138
|
+
createTrack: createMohdTrack,
|
|
139
|
+
views: mohdViews,
|
|
140
|
+
ViewSelector: MohdViewSelector,
|
|
141
|
+
GroupingCellComponent: MohdGroupingCell,
|
|
142
|
+
TreeItemComponent: MohdTreeItem,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import {
|
|
2
|
+
BigBedConfig,
|
|
3
|
+
BigWigConfig,
|
|
4
|
+
DisplayMode,
|
|
5
|
+
MethylCConfig,
|
|
6
|
+
Track,
|
|
7
|
+
TrackType,
|
|
8
|
+
ValuedPoint,
|
|
9
|
+
} from "@weng-lab/genomebrowser";
|
|
10
|
+
import type { FC } from "react";
|
|
11
|
+
import { CreateTrackOptions } from "../../types";
|
|
12
|
+
import { createMohdFileUrl, getMohdOmeConfig } from "./config";
|
|
13
|
+
import { MohdRowInfo } from "./types";
|
|
14
|
+
|
|
15
|
+
export type MohdTrackContext = {
|
|
16
|
+
mohdSignalTooltip?: FC<ValuedPoint[]>;
|
|
17
|
+
mohdMethylTooltip?: FC<ValuedPoint[]>;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const defaultBigWig: Omit<BigWigConfig, "id" | "title" | "url"> = {
|
|
21
|
+
trackType: TrackType.BigWig,
|
|
22
|
+
height: 30,
|
|
23
|
+
displayMode: DisplayMode.Full,
|
|
24
|
+
titleSize: 12,
|
|
25
|
+
color: "#02c7b9",
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const defaultBigBed: Omit<BigBedConfig, "id" | "title" | "url"> = {
|
|
29
|
+
trackType: TrackType.BigBed,
|
|
30
|
+
height: 20,
|
|
31
|
+
displayMode: DisplayMode.Dense,
|
|
32
|
+
titleSize: 12,
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const defaultMethylC: Omit<MethylCConfig, "id" | "title" | "urls"> = {
|
|
36
|
+
trackType: TrackType.MethylC,
|
|
37
|
+
height: 75,
|
|
38
|
+
displayMode: DisplayMode.Split,
|
|
39
|
+
titleSize: 12,
|
|
40
|
+
color: "#648bd8",
|
|
41
|
+
maskCpgByCoverage: true,
|
|
42
|
+
colors: {
|
|
43
|
+
cpg: "#648bd8",
|
|
44
|
+
chg: "#ff944d",
|
|
45
|
+
chh: "#ff00ff",
|
|
46
|
+
depth: "#525252",
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
function createTrackTitle(row: MohdRowInfo) {
|
|
51
|
+
return `${row.sampleId} ${row.description}`;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function createMohdTrack(
|
|
55
|
+
row: MohdRowInfo,
|
|
56
|
+
options: CreateTrackOptions,
|
|
57
|
+
): Track | null {
|
|
58
|
+
const trackContext = options.trackContext;
|
|
59
|
+
|
|
60
|
+
if (row.kind === "wgbs-methyl") {
|
|
61
|
+
return {
|
|
62
|
+
...defaultMethylC,
|
|
63
|
+
id: row.id,
|
|
64
|
+
title: createTrackTitle(row),
|
|
65
|
+
tooltip: trackContext?.mohdMethylTooltip,
|
|
66
|
+
urls: {
|
|
67
|
+
plusStrand: {
|
|
68
|
+
cpg: {
|
|
69
|
+
url: createMohdFileUrl({
|
|
70
|
+
ome: row.ome,
|
|
71
|
+
sampleId: row.sampleId,
|
|
72
|
+
filename: row.filenames.plusStrand.cpg,
|
|
73
|
+
}),
|
|
74
|
+
},
|
|
75
|
+
chg: {
|
|
76
|
+
url: createMohdFileUrl({
|
|
77
|
+
ome: row.ome,
|
|
78
|
+
sampleId: row.sampleId,
|
|
79
|
+
filename: row.filenames.plusStrand.chg,
|
|
80
|
+
}),
|
|
81
|
+
},
|
|
82
|
+
chh: {
|
|
83
|
+
url: createMohdFileUrl({
|
|
84
|
+
ome: row.ome,
|
|
85
|
+
sampleId: row.sampleId,
|
|
86
|
+
filename: row.filenames.plusStrand.chh,
|
|
87
|
+
}),
|
|
88
|
+
},
|
|
89
|
+
depth: {
|
|
90
|
+
url: createMohdFileUrl({
|
|
91
|
+
ome: row.ome,
|
|
92
|
+
sampleId: row.sampleId,
|
|
93
|
+
filename: row.filenames.plusStrand.depth,
|
|
94
|
+
}),
|
|
95
|
+
},
|
|
96
|
+
},
|
|
97
|
+
minusStrand: {
|
|
98
|
+
cpg: {
|
|
99
|
+
url: createMohdFileUrl({
|
|
100
|
+
ome: row.ome,
|
|
101
|
+
sampleId: row.sampleId,
|
|
102
|
+
filename: row.filenames.minusStrand.cpg,
|
|
103
|
+
}),
|
|
104
|
+
},
|
|
105
|
+
chg: {
|
|
106
|
+
url: createMohdFileUrl({
|
|
107
|
+
ome: row.ome,
|
|
108
|
+
sampleId: row.sampleId,
|
|
109
|
+
filename: row.filenames.minusStrand.chg,
|
|
110
|
+
}),
|
|
111
|
+
},
|
|
112
|
+
chh: {
|
|
113
|
+
url: createMohdFileUrl({
|
|
114
|
+
ome: row.ome,
|
|
115
|
+
sampleId: row.sampleId,
|
|
116
|
+
filename: row.filenames.minusStrand.chh,
|
|
117
|
+
}),
|
|
118
|
+
},
|
|
119
|
+
depth: {
|
|
120
|
+
url: createMohdFileUrl({
|
|
121
|
+
ome: row.ome,
|
|
122
|
+
sampleId: row.sampleId,
|
|
123
|
+
filename: row.filenames.minusStrand.depth,
|
|
124
|
+
}),
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (row.kind !== "file") {
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const { color } = getMohdOmeConfig(row.ome);
|
|
136
|
+
const url = createMohdFileUrl({
|
|
137
|
+
ome: row.ome,
|
|
138
|
+
sampleId: row.sampleId,
|
|
139
|
+
filename: row.filename,
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
if (row.filename.endsWith(".bigWig")) {
|
|
143
|
+
return {
|
|
144
|
+
...defaultBigWig,
|
|
145
|
+
id: row.id,
|
|
146
|
+
title: createTrackTitle(row),
|
|
147
|
+
url,
|
|
148
|
+
color,
|
|
149
|
+
tooltip: trackContext?.mohdSignalTooltip,
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (row.filename.endsWith(".bigBed")) {
|
|
154
|
+
return {
|
|
155
|
+
...defaultBigBed,
|
|
156
|
+
id: row.id,
|
|
157
|
+
title: createTrackTitle(row),
|
|
158
|
+
url,
|
|
159
|
+
color,
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return null;
|
|
164
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { MohdOme } from "./config";
|
|
2
|
+
|
|
3
|
+
export type MohdMethylStrandUrls = {
|
|
4
|
+
cpg: string;
|
|
5
|
+
chg: string;
|
|
6
|
+
chh: string;
|
|
7
|
+
depth: string;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export type MohdDataRow = {
|
|
11
|
+
ome: string;
|
|
12
|
+
site: string;
|
|
13
|
+
sample_id: string;
|
|
14
|
+
file_type: string;
|
|
15
|
+
filename: string;
|
|
16
|
+
sex: string;
|
|
17
|
+
status: string;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
type MohdBaseRowInfo = {
|
|
21
|
+
id: string;
|
|
22
|
+
ome: MohdOme;
|
|
23
|
+
site: string;
|
|
24
|
+
sampleId: string;
|
|
25
|
+
sex: string;
|
|
26
|
+
status: string;
|
|
27
|
+
description: string;
|
|
28
|
+
trackCategory: "Signal" | "Annotation" | "Methylation";
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export type MohdFileRowInfo = MohdBaseRowInfo & {
|
|
32
|
+
kind: "file";
|
|
33
|
+
filename: string;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export type MohdWgbsMethylRowInfo = MohdBaseRowInfo & {
|
|
37
|
+
kind: "wgbs-methyl";
|
|
38
|
+
filenames: {
|
|
39
|
+
plusStrand: MohdMethylStrandUrls;
|
|
40
|
+
minusStrand: MohdMethylStrandUrls;
|
|
41
|
+
};
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export type MohdRowInfo = MohdFileRowInfo | MohdWgbsMethylRowInfo;
|
|
45
|
+
|
|
46
|
+
export type MohdDataFile = MohdDataRow[];
|
|
@@ -5,16 +5,17 @@ import {
|
|
|
5
5
|
defaultGroupingModel,
|
|
6
6
|
defaultLeafField,
|
|
7
7
|
} from "./columns";
|
|
8
|
-
import {
|
|
8
|
+
import { createOtherTrack } from "./toTrack";
|
|
9
9
|
|
|
10
|
-
function transformData(
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
10
|
+
function transformData(
|
|
11
|
+
folderId: string,
|
|
12
|
+
data: OtherTrackDataFile,
|
|
13
|
+
): OtherTrackInfo[] {
|
|
14
|
+
return data.map((row) => ({
|
|
15
|
+
...row,
|
|
16
|
+
sourceId: row.id,
|
|
17
|
+
id: `${folderId}/${row.id}`,
|
|
18
|
+
}));
|
|
18
19
|
}
|
|
19
20
|
|
|
20
21
|
export interface CreateOtherTracksFolderOptions {
|
|
@@ -28,18 +29,16 @@ export function createOtherTracksFolder(
|
|
|
28
29
|
options: CreateOtherTracksFolderOptions,
|
|
29
30
|
): FolderDefinition<OtherTrackInfo> {
|
|
30
31
|
const { id, label, description, data } = options;
|
|
31
|
-
const
|
|
32
|
+
const rows = transformData(id, data);
|
|
32
33
|
|
|
33
34
|
return {
|
|
34
35
|
id,
|
|
35
36
|
label,
|
|
36
37
|
description,
|
|
37
|
-
|
|
38
|
-
getRowId: (row) => row.id,
|
|
38
|
+
rows,
|
|
39
39
|
columns: defaultColumns,
|
|
40
40
|
groupingModel: defaultGroupingModel,
|
|
41
41
|
leafField: defaultLeafField,
|
|
42
|
-
|
|
43
|
-
buildTreeView(selectedIds, rowById, label),
|
|
42
|
+
createTrack: createOtherTrack,
|
|
44
43
|
};
|
|
45
44
|
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Track } from "@weng-lab/genomebrowser";
|
|
2
|
+
import { tfPeaksTrack } from "../../../Custom/TfPeaks";
|
|
3
|
+
import { CreateTrackOptions } from "../../types";
|
|
4
|
+
import { OtherTrackInfo } from "./types";
|
|
5
|
+
|
|
6
|
+
export type OtherTracksTrackContext = {};
|
|
7
|
+
|
|
8
|
+
export function createOtherTrack(
|
|
9
|
+
row: OtherTrackInfo,
|
|
10
|
+
_options: CreateTrackOptions,
|
|
11
|
+
): Track | null {
|
|
12
|
+
if ((row.sourceId ?? row.id) === "tf-peaks") {
|
|
13
|
+
return { ...tfPeaksTrack, id: row.id };
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return null;
|
|
17
|
+
}
|