@weng-lab/genomebrowser-ui 0.3.6 → 0.4.0-beta.1

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.
Files changed (91) hide show
  1. package/.env.local +1 -1
  2. package/dist/TrackSelect/Folders/biosamples/shared/BiosampleViewSelector.d.ts +7 -0
  3. package/dist/TrackSelect/Folders/biosamples/shared/createFolder.d.ts +1 -13
  4. package/dist/TrackSelect/Folders/biosamples/shared/toTrack.d.ts +20 -0
  5. package/dist/TrackSelect/Folders/biosamples/shared/types.d.ts +4 -13
  6. package/dist/TrackSelect/Folders/genes/shared/columns.d.ts +2 -2
  7. package/dist/TrackSelect/Folders/genes/shared/createFolder.d.ts +1 -3
  8. package/dist/TrackSelect/Folders/genes/shared/toTrack.d.ts +18 -0
  9. package/dist/TrackSelect/Folders/genes/shared/types.d.ts +2 -0
  10. package/dist/TrackSelect/Folders/index.d.ts +6 -12
  11. package/dist/TrackSelect/Folders/mohd/data/human.json.d.ts +2948 -0
  12. package/dist/TrackSelect/Folders/mohd/human.d.ts +1 -0
  13. package/dist/TrackSelect/Folders/mohd/shared/MohdGroupingCell.d.ts +2 -0
  14. package/dist/TrackSelect/Folders/mohd/shared/MohdTreeItem.d.ts +3 -0
  15. package/dist/TrackSelect/Folders/mohd/shared/MohdViewSelector.d.ts +7 -0
  16. package/dist/TrackSelect/Folders/mohd/shared/columns.d.ts +5 -0
  17. package/dist/TrackSelect/Folders/mohd/shared/config.d.ts +42 -0
  18. package/dist/TrackSelect/Folders/mohd/shared/createFolder.d.ts +9 -0
  19. package/dist/TrackSelect/Folders/mohd/shared/toTrack.d.ts +9 -0
  20. package/dist/TrackSelect/Folders/mohd/shared/types.d.ts +40 -0
  21. package/dist/TrackSelect/Folders/other-tracks/shared/toTrack.d.ts +5 -0
  22. package/dist/TrackSelect/Folders/other-tracks/shared/types.d.ts +1 -0
  23. package/dist/TrackSelect/Folders/types.d.ts +23 -55
  24. package/dist/TrackSelect/TrackSelect.d.ts +10 -7
  25. package/dist/TrackSelect/TreeView/TreeViewWrapper.d.ts +1 -1
  26. package/dist/TrackSelect/buildSelectedTree.d.ts +15 -0
  27. package/dist/TrackSelect/managedTracks.d.ts +13 -0
  28. package/dist/TrackSelect/resolveFolderView.d.ts +2 -0
  29. package/dist/TrackSelect/trackContext.d.ts +5 -0
  30. package/dist/TrackSelect/types.d.ts +12 -33
  31. package/dist/genomebrowser-ui.es.js +2231 -1732
  32. package/dist/genomebrowser-ui.es.js.map +1 -1
  33. package/dist/lib.d.ts +4 -4
  34. package/dist/muiLicense.d.ts +1 -0
  35. package/package.json +6 -3
  36. package/src/TrackSelect/Dialogs/ClearDialog.tsx +3 -8
  37. package/src/TrackSelect/Dialogs/ResetDialog.tsx +5 -4
  38. package/src/TrackSelect/FolderList/FolderCard.tsx +1 -1
  39. package/src/TrackSelect/Folders/biosamples/shared/BiosampleViewSelector.tsx +33 -0
  40. package/src/TrackSelect/Folders/biosamples/shared/createFolder.ts +39 -58
  41. package/src/TrackSelect/Folders/biosamples/shared/toTrack.ts +138 -0
  42. package/src/TrackSelect/Folders/biosamples/shared/types.ts +4 -16
  43. package/src/TrackSelect/Folders/genes/shared/columns.tsx +2 -2
  44. package/src/TrackSelect/Folders/genes/shared/createFolder.ts +11 -31
  45. package/src/TrackSelect/Folders/genes/shared/toTrack.ts +59 -0
  46. package/src/TrackSelect/Folders/genes/shared/types.ts +2 -0
  47. package/src/TrackSelect/Folders/index.ts +14 -17
  48. package/src/TrackSelect/Folders/mohd/data/human.json +2945 -0
  49. package/src/TrackSelect/Folders/mohd/human.ts +10 -0
  50. package/src/TrackSelect/Folders/mohd/shared/MohdGroupingCell.tsx +68 -0
  51. package/src/TrackSelect/Folders/mohd/shared/MohdTreeItem.tsx +17 -0
  52. package/src/TrackSelect/Folders/mohd/shared/MohdViewSelector.tsx +33 -0
  53. package/src/TrackSelect/Folders/mohd/shared/columns.tsx +79 -0
  54. package/src/TrackSelect/Folders/mohd/shared/config.tsx +71 -0
  55. package/src/TrackSelect/Folders/mohd/shared/createFolder.ts +144 -0
  56. package/src/TrackSelect/Folders/mohd/shared/toTrack.ts +164 -0
  57. package/src/TrackSelect/Folders/mohd/shared/types.ts +46 -0
  58. package/src/TrackSelect/Folders/other-tracks/shared/createFolder.ts +13 -14
  59. package/src/TrackSelect/Folders/other-tracks/shared/toTrack.ts +17 -0
  60. package/src/TrackSelect/Folders/other-tracks/shared/types.ts +1 -0
  61. package/src/TrackSelect/Folders/types.ts +26 -69
  62. package/src/TrackSelect/TrackSelect.tsx +301 -257
  63. package/src/TrackSelect/TreeView/CustomTreeItem.tsx +9 -9
  64. package/src/TrackSelect/TreeView/TreeViewWrapper.tsx +84 -6
  65. package/src/TrackSelect/buildSelectedTree.ts +145 -0
  66. package/src/TrackSelect/managedTracks.ts +92 -0
  67. package/src/TrackSelect/resolveFolderView.ts +20 -0
  68. package/src/TrackSelect/trackContext.ts +9 -0
  69. package/src/TrackSelect/types.ts +14 -39
  70. package/src/lib.ts +13 -7
  71. package/src/muiLicense.ts +9 -0
  72. package/src/vite-env.d.ts +9 -0
  73. package/test/TrackSelect.test.tsx +435 -0
  74. package/test/main.tsx +36 -352
  75. package/test/mocks/logo-test.tsx +11 -0
  76. package/test/mohdDisplay.test.tsx +45 -0
  77. package/test/startup.test.ts +206 -0
  78. package/test/trackSelectState.test.ts +176 -0
  79. package/vite.config.ts +1 -0
  80. package/vitest.config.ts +20 -0
  81. package/dist/TrackSelect/Folders/biosamples/shared/AssayToggle.d.ts +0 -18
  82. package/dist/TrackSelect/Folders/biosamples/shared/treeBuilder.d.ts +0 -28
  83. package/dist/TrackSelect/Folders/genes/shared/treeBuilder.d.ts +0 -13
  84. package/dist/TrackSelect/Folders/other-tracks/shared/treeBuilder.d.ts +0 -4
  85. package/dist/TrackSelect/store.d.ts +0 -4
  86. package/src/TrackSelect/Folders/NEW.md +0 -929
  87. package/src/TrackSelect/Folders/biosamples/shared/AssayToggle.tsx +0 -78
  88. package/src/TrackSelect/Folders/biosamples/shared/treeBuilder.ts +0 -224
  89. package/src/TrackSelect/Folders/genes/shared/treeBuilder.ts +0 -45
  90. package/src/TrackSelect/Folders/other-tracks/shared/treeBuilder.ts +0 -34
  91. 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 { buildTreeView } from "./treeBuilder";
8
+ import { createOtherTrack } from "./toTrack";
9
9
 
10
- function transformData(data: OtherTrackDataFile): {
11
- rows: OtherTrackInfo[];
12
- rowById: Map<string, OtherTrackInfo>;
13
- } {
14
- const rowById = new Map<string, OtherTrackInfo>(
15
- data.map((row) => [row.id, row]),
16
- );
17
- return { rows: data, rowById };
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 { rowById } = transformData(data);
32
+ const rows = transformData(id, data);
32
33
 
33
34
  return {
34
35
  id,
35
36
  label,
36
37
  description,
37
- rowById,
38
- getRowId: (row) => row.id,
38
+ rows,
39
39
  columns: defaultColumns,
40
40
  groupingModel: defaultGroupingModel,
41
41
  leafField: defaultLeafField,
42
- buildTree: (selectedIds, rowById) =>
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
+ }