diff --git a/apps/platform/src/App.tsx b/apps/platform/src/App.tsx index 9d5c62827..1cd6fb6d0 100644 --- a/apps/platform/src/App.tsx +++ b/apps/platform/src/App.tsx @@ -30,6 +30,13 @@ const router = createBrowserRouter([ path: "/api", lazy: () => import("./pages/APIPage/APIPage").then(m => ({ Component: m.default })), }, + { + path: "/metrics", + lazy: () => + import("./pages/MetricsPage/MetricsPageWrapper").then(m => ({ + Component: m.default, + })), + }, { path: "/search", lazy: () => diff --git a/apps/platform/src/pages/MetricsPage/AssociationPlot.tsx b/apps/platform/src/pages/MetricsPage/AssociationPlot.tsx new file mode 100644 index 000000000..67bd9c013 --- /dev/null +++ b/apps/platform/src/pages/MetricsPage/AssociationPlot.tsx @@ -0,0 +1,33 @@ +import { Box, Paper, Typography, useTheme } from "@mui/material"; +import * as Plot from "@observablehq/plot"; +import { ObsPlot } from "ui"; +import dataSourcesAssoc from "../../components/AssociationsToolkit/static_datasets/dataSourcesAssoc"; +import { CATEGORICAL_COLORS } from "../../components/AssociationsToolkit/components/Table/NoveltyCharts"; +import type { MetricRow } from "./MetricsPage"; + +type AssociationCount = { name: string; group: string; count: number }; +const dataSourceTypes = new Map(dataSourcesAssoc.map((source) => [source.id, source.aggregation])); + +function AssociationPlot({ data, datasetPrefix, title, labelFromDataset = false }: { data: MetricRow[]; datasetPrefix: string; title: string; labelFromDataset?: boolean }) { + const theme = useTheme(); + const chartData: AssociationCount[] = data.filter((row) => row.dataset.startsWith(datasetPrefix) && row.kind === "grouping" && row.group_value) + .map((row) => { + const sourceId = labelFromDataset ? row.dataset.replace(datasetPrefix, "") : row.group_value; + return { name: labelFromDataset ? sourceId : row.group_value, group: dataSourceTypes.get(sourceId) ?? "Other", count: row.value }; + }); + const groupMaxCounts = new Map(); + chartData.forEach((item) => groupMaxCounts.set(item.group, Math.max(groupMaxCounts.get(item.group) ?? 0, item.count))); + chartData.sort((a, b) => (groupMaxCounts.get(b.group) ?? 0) - (groupMaxCounts.get(a.group) ?? 0) || a.group.localeCompare(b.group) || b.count - a.count); + if (chartData.length === 0) return null; + return + {title} + item.count} yTooltip={(item) => item.name} xAnchorTooltip="adapt" yAnchorTooltip="adapt" gapInfo={0} renderInfo={() => null} /> + ; + function renderChart({ data, width, height }: { data: AssociationCount[]; width?: number; height: number }) { + const plotWidth = Math.max((width ?? 0) - 210 - 24, 0), maxCount = Math.max(...data.map((item) => item.count)); + const insideData = data.filter((item) => (item.count / maxCount) * plotWidth >= `${item.count.toLocaleString()}`.length * 7 + 12); + const outsideData = data.filter((item) => !insideData.includes(item)); + return Plot.plot({ width: width ?? 0, height, style: { fontSize: "13.5px" }, marginTop: 4, marginBottom: 4, marginLeft: 240, marginRight: 0, x: { axis: null }, color: { domain: [...new Set(data.map((item) => item.group))], range: CATEGORICAL_COLORS, legend: true }, y: { domain: data.map((item) => item.name), label: null, tickSize: 0, tickPadding: 8, tickFormat: (name) => name.replaceAll("_", " ") }, marks: [Plot.barX(data, { x: "count", y: "name", fill: "group", insetTop: 2, insetBottom: 2, className: "obs-tooltip" }), Plot.text(insideData, { x: "count", y: "name", text: (item) => item.count.toLocaleString(), textAnchor: "end", dx: -6, fill: "white", lineAnchor: "middle", fontSize: 12.5, className: "obs-tooltip" }), Plot.text(outsideData, { x: "count", y: "name", text: (item) => item.count.toLocaleString(), textAnchor: "start", dx: 6, fill: theme.palette.text.primary, lineAnchor: "middle", fontSize: 12.5, className: "obs-tooltip" })] }); + } +} +export default AssociationPlot; diff --git a/apps/platform/src/pages/MetricsPage/ByStudyType.tsx b/apps/platform/src/pages/MetricsPage/ByStudyType.tsx new file mode 100644 index 000000000..d8d261e2f --- /dev/null +++ b/apps/platform/src/pages/MetricsPage/ByStudyType.tsx @@ -0,0 +1,34 @@ +import { Box, Paper, Typography, useTheme } from "@mui/material"; +import * as Plot from "@observablehq/plot"; +import { ObsPlot } from "ui"; +import type { MetricRow } from "./MetricsPage"; + +type StudyTypeCount = { name: string; count: number }; + +function ByStudyType({ data, dataset, title }: { data: MetricRow[]; dataset: string; title: string }) { + const theme = useTheme(); + const chartData: StudyTypeCount[] = data + .filter((row) => row.dataset === dataset && row.kind === "grouping" && row.expression === "studyType" && row.group_value) + .map((row) => ({ name: row.group_value, count: row.value })) + .sort((a, b) => b.count - a.count); + if (chartData.length === 0) return null; + + return + {title} + item.count} yTooltip={(item) => item.name} xAnchorTooltip="adapt" yAnchorTooltip="adapt" gapInfo={0} renderInfo={() => null} /> + ; + + function renderChart({ data, width, height }: { data: StudyTypeCount[]; width?: number; height: number }) { + const plotWidth = Math.max((width ?? 0) - 210 - 24, 0); + const maxCount = Math.max(...data.map((item) => item.count)); + const insideData = data.filter((item) => (item.count / maxCount) * plotWidth >= `${item.count.toLocaleString()}`.length * 7 + 12); + const outsideData = data.filter((item) => !insideData.includes(item)); + return Plot.plot({ width: width ?? 0, height, style: { fontSize: "13.5px" }, marginTop: 4, marginBottom: 4, marginLeft: 240, marginRight: 0, x: { axis: null }, y: { domain: data.map((item) => item.name), label: null, tickSize: 0, tickPadding: 8, tickFormat: (label) => label.replaceAll(/(gwas|qtl)/ig, m => m.toUpperCase()) }, marks: [ + Plot.barX(data, { x: "count", y: "name", fill: theme.palette.primary.main, insetTop: 2, insetBottom: 2, className: "obs-tooltip" }), + Plot.text(insideData, { x: "count", y: "name", text: (item) => item.count.toLocaleString(), textAnchor: "end", dx: -6, fill: "white", lineAnchor: "middle", fontSize: 12.5, className: "obs-tooltip" }), + Plot.text(outsideData, { x: "count", y: "name", text: (item) => item.count.toLocaleString(), textAnchor: "start", dx: 6, fill: theme.palette.text.primary, lineAnchor: "middle", fontSize: 12.5, className: "obs-tooltip" }), + ] }); + } +} + +export default ByStudyType; diff --git a/apps/platform/src/pages/MetricsPage/ClinicalReportsByStage.tsx b/apps/platform/src/pages/MetricsPage/ClinicalReportsByStage.tsx new file mode 100644 index 000000000..c31e228fe --- /dev/null +++ b/apps/platform/src/pages/MetricsPage/ClinicalReportsByStage.tsx @@ -0,0 +1,14 @@ +import ClinicalStageChart from "./ClinicalStageChart"; +import type { MetricRow } from "./MetricsPage"; + +function ClinicalReportsByStage({ data }: { data: MetricRow[] }) { + return ( + + ); +} + +export default ClinicalReportsByStage; diff --git a/apps/platform/src/pages/MetricsPage/ClinicalStageChart.tsx b/apps/platform/src/pages/MetricsPage/ClinicalStageChart.tsx new file mode 100644 index 000000000..3910f1715 --- /dev/null +++ b/apps/platform/src/pages/MetricsPage/ClinicalStageChart.tsx @@ -0,0 +1,60 @@ +import { Box, Paper, Typography, useTheme } from "@mui/material"; +import * as Plot from "@observablehq/plot"; +import { clinicalStageCategories } from "@ot/constants"; +import { ObsPlot } from "ui"; +import type { MetricRow } from "./MetricsPage"; + +type ClinicalStageCount = { name: string; count: number; index: number }; + +function ClinicalStageChart({ data, dataset, title }: { data: MetricRow[]; dataset: string; title: string }) { + const theme = useTheme(); + const chartData: ClinicalStageCount[] = data + .filter((row) => row.dataset === dataset && row.kind === "grouping" && row.metric === "clinicalStage" && row.group_value) + .map((row) => { + const category = clinicalStageCategories[row.group_value as keyof typeof clinicalStageCategories]; + return { name: category?.label ?? row.group_value, count: row.value, index: category?.index ?? Number.MAX_SAFE_INTEGER }; + }) + .sort((a, b) => a.index - b.index); + + if (chartData.length === 0) return null; + + return ( + + + {title} + item.count} + yTooltip={(item) => item.name} + xAnchorTooltip="adapt" + yAnchorTooltip="adapt" + gapInfo={0} + renderInfo={() => null} + /> + + + ); + + function renderChart({ data, width, height }: { data: ClinicalStageCount[]; width?: number; height: number }) { + const plotWidth = Math.max((width ?? 0) - 210 - 24, 0); + const maxCount = Math.max(...data.map((item) => item.count)); + const insideData = data.filter((item) => (item.count / maxCount) * plotWidth >= `${item.count.toLocaleString()}`.length * 7 + 12); + const outsideData = data.filter((item) => !insideData.includes(item)); + + return Plot.plot({ + width: width ?? 0, height, style: { fontSize: "13.5px" }, marginTop: 4, marginBottom: 4, marginLeft: 240, marginRight: 0, + x: { axis: null }, y: { domain: data.map((item) => item.name), label: null, tickSize: 0, tickPadding: 8 }, + marks: [ + Plot.barX(data, { x: "count", y: "name", fill: theme.palette.primary.main, insetTop: 2, insetBottom: 2, className: "obs-tooltip" }), + Plot.text(insideData, { x: "count", y: "name", text: (item) => item.count.toLocaleString(), textAnchor: "end", dx: -6, fill: "white", lineAnchor: "middle", fontSize: 12.5, className: "obs-tooltip" }), + Plot.text(outsideData, { x: "count", y: "name", text: (item) => item.count.toLocaleString(), textAnchor: "start", dx: 6, fill: theme.palette.text.primary, lineAnchor: "middle", fontSize: 12.5, className: "obs-tooltip" }), + ], + }); + } +} + +export default ClinicalStageChart; diff --git a/apps/platform/src/pages/MetricsPage/ColocalisationByType.tsx b/apps/platform/src/pages/MetricsPage/ColocalisationByType.tsx new file mode 100644 index 000000000..82a8a337e --- /dev/null +++ b/apps/platform/src/pages/MetricsPage/ColocalisationByType.tsx @@ -0,0 +1,69 @@ +import { Box, Paper, Typography, useTheme } from "@mui/material"; +import * as Plot from "@observablehq/plot"; +import { ObsPlot } from "ui"; +import type { MetricRow } from "./MetricsPage"; + +type ColocalisationCount = { name: string; count: number }; + +function ColocalisationByType({ data }: { data: MetricRow[] }) { + const theme = useTheme(); + const chartData: ColocalisationCount[] = data + .filter((row) => row.dataset === "colocalisation" && row.kind === "grouping" && row.metric === "studyTypePair" && row.group_value) + .map((row) => ({ name: row.group_value, count: row.value })) + .sort((a, b) => b.count - a.count); + + if (chartData.length === 0) return null; + + return ( + + + Colocalisation by type + item.count} + yTooltip={(item) => item.name} + xAnchorTooltip="adapt" + yAnchorTooltip="adapt" + gapInfo={0} + renderInfo={() => null} + /> + + + ); + + function renderChart({ data, width, height }: { data: ColocalisationCount[]; width?: number; height: number }) { + const plotWidth = Math.max((width ?? 0) - 210 - 24, 0); + const maxCount = Math.max(...data.map((item) => item.count)); + const insideData = data.filter((item) => (item.count / maxCount) * plotWidth >= `${item.count.toLocaleString()}`.length * 7 + 12); + const outsideData = data.filter((item) => !insideData.includes(item)); + + return Plot.plot({ + width: width ?? 0, + height, + style: { fontSize: "13.5px" }, + marginTop: 4, + marginBottom: 4, + marginLeft: 240, + marginRight: 0, + x: { axis: null }, + y: { + domain: data.map((item) => item.name), + label: null, + tickSize: 0, + tickPadding: 8, + tickFormat: (label) => label.replaceAll(/(gwas|qtl)/ig, m => m.toUpperCase()), + }, + marks: [ + Plot.barX(data, { x: "count", y: "name", fill: theme.palette.primary.main, insetTop: 2, insetBottom: 2, className: "obs-tooltip" }), + Plot.text(insideData, { x: "count", y: "name", text: (item) => item.count.toLocaleString(), textAnchor: "end", dx: -6, fill: "white", lineAnchor: "middle", fontSize: 12.5, className: "obs-tooltip" }), + Plot.text(outsideData, { x: "count", y: "name", text: (item) => item.count.toLocaleString(), textAnchor: "start", dx: 6, fill: theme.palette.text.primary, lineAnchor: "middle", fontSize: 12.5, className: "obs-tooltip" }), + ], + }); + } +} + +export default ColocalisationByType; diff --git a/apps/platform/src/pages/MetricsPage/CredibleSetsByStudyType.tsx b/apps/platform/src/pages/MetricsPage/CredibleSetsByStudyType.tsx new file mode 100644 index 000000000..15b306c39 --- /dev/null +++ b/apps/platform/src/pages/MetricsPage/CredibleSetsByStudyType.tsx @@ -0,0 +1,8 @@ +import ByStudyType from "./ByStudyType"; +import type { MetricRow } from "./MetricsPage"; + +function CredibleSetsByStudyType({ data }: { data: MetricRow[] }) { + return ; +} + +export default CredibleSetsByStudyType; diff --git a/apps/platform/src/pages/MetricsPage/DiseasesByTherapeuticArea.tsx b/apps/platform/src/pages/MetricsPage/DiseasesByTherapeuticArea.tsx new file mode 100644 index 000000000..a7b393ffd --- /dev/null +++ b/apps/platform/src/pages/MetricsPage/DiseasesByTherapeuticArea.tsx @@ -0,0 +1,179 @@ +import { Box, Typography, Paper, useTheme } from "@mui/material"; +import * as Plot from "@observablehq/plot"; +import { therapeuticAreas } from "@ot/constants"; +import { ObsPlot } from "ui"; +import type { MetricRow } from "./MetricsPage"; + +type TherapeuticAreaCount = { + name: string; + count: number; + areas?: TherapeuticAreaCount[]; +}; + +const count = (rows: MetricRow[], dataset: string) => + rows.find( + (row) => + row.dataset === dataset && + row.kind === "scalar" && + row.metric === "count", + )?.value ?? 0; + +function DiseasesByTherapeuticArea({ data }: { data: MetricRow[] }) { + const theme = useTheme(); + console.log(theme) + const areas = data + .filter( + (row) => + row.dataset === "disease" && + row.kind === "grouping" && + row.metric === "therapeuticArea", + ) + .map((row) => ({ + name: therapeuticAreas[row.group_value] ?? row.group_value, + count: row.value, + })); + const total = count(data, "disease"); + const otherAreas = areas + .filter((area) => area.count < total * 0.02) + .sort((a, b) => b.count - a.count); + const chartData: TherapeuticAreaCount[] = areas + .filter((area) => area.count >= total * 0.02) + .sort((a, b) => b.count - a.count); + + if (otherAreas.length > 0) { + chartData.push({ + name: "Other", + count: otherAreas.reduce((sum, area) => sum + area.count, 0), + areas: otherAreas, + }); + } + + if (chartData.length === 0) return null; + + return ( + + + + Diseases by therapeutic area + + area.count} + yTooltip={(area) => area.name} + xAnchorTooltip="adapt" + yAnchorTooltip="adapt" + renderTooltip={renderTooltip} + gapInfo={0} + renderInfo={() => null} + /> + + + A disease can belong to more than one therapeutic area + + + ); + + function renderChart({ + data, + otherData, + width, + height, + }: { + data: TherapeuticAreaCount[]; + otherData?: { textColor: string }; + width?: number; + height: number; + }) { + const plotWidth = Math.max((width ?? 0) - 210 - 24, 0); + const maxCount = Math.max(...data.map((area) => area.count)); + const countLabelWidth = (area: TherapeuticAreaCount) => + `${area.count.toLocaleString()}`.length * 7 + 12; + const insideData = data.filter( + (area) => (area.count / maxCount) * plotWidth >= countLabelWidth(area), + ); + const outsideData = data.filter((area) => !insideData.includes(area)); + + return Plot.plot({ + width: width ?? 0, + height, + style: { fontSize: "13.5px" }, + marginTop: 4, + marginBottom: 4, + marginLeft: 240, + marginRight: 0, + x: { axis: null }, + y: { + domain: data.map((area) => area.name), + label: null, + tickSize: 0, + tickPadding: 8, + tickFormat: (name) => name, + }, + marks: [ + Plot.barX(data, { + x: "count", + y: "name", + // fill: (area) => (area.areas ? "#5b89b0" : "#1963a3"), + fill: (area) => (area.areas ? theme.palette.primary.light : theme.palette.primary.main), + insetTop: 2, + insetBottom: 2, + className: "obs-tooltip", + }), + Plot.text(insideData, { + x: (area) => area.count, + y: "name", + text: (area) => area.count.toLocaleString(), + textAnchor: "end", + dx: -6, + fill: "white", + lineAnchor: "middle", + fontSize: 12.5, + pointerEvents: "none", + className: "obs-tooltip", + }), + Plot.text(outsideData, { + x: (area) => area.count, + y: "name", + text: (area) => area.count.toLocaleString(), + textAnchor: "start", + dx: 6, + fill: otherData?.textColor ?? "currentColor", + lineAnchor: "middle", + fontSize: 12.5, + pointerEvents: "none", + className: "obs-tooltip", + }), + ], + }); + } + +} + +function renderTooltip(area: TherapeuticAreaCount) { + if (!area.areas) return null; + + return ( + + {area.areas.map((otherArea) => ( + + {otherArea.name}: {otherArea.count.toLocaleString()} + + ))} + + ); +} + +export default DiseasesByTherapeuticArea; diff --git a/apps/platform/src/pages/MetricsPage/DrugsByClinicalStage.tsx b/apps/platform/src/pages/MetricsPage/DrugsByClinicalStage.tsx new file mode 100644 index 000000000..672b40cb9 --- /dev/null +++ b/apps/platform/src/pages/MetricsPage/DrugsByClinicalStage.tsx @@ -0,0 +1,8 @@ +import ClinicalStageChart from "./ClinicalStageChart"; +import type { MetricRow } from "./MetricsPage"; + +function DrugsByClinicalStage({ data }: { data: MetricRow[] }) { + return ; +} + +export default DrugsByClinicalStage; diff --git a/apps/platform/src/pages/MetricsPage/EvidenceChart.tsx b/apps/platform/src/pages/MetricsPage/EvidenceChart.tsx new file mode 100644 index 000000000..0ff2c8917 --- /dev/null +++ b/apps/platform/src/pages/MetricsPage/EvidenceChart.tsx @@ -0,0 +1,8 @@ +import AssociationPlot from "./AssociationPlot"; +import type { MetricRow } from "./MetricsPage"; + +function EvidenceChart({ data }: { data: MetricRow[] }) { + return ; +} + +export default EvidenceChart; diff --git a/apps/platform/src/pages/MetricsPage/MetricsCards.tsx b/apps/platform/src/pages/MetricsPage/MetricsCards.tsx new file mode 100644 index 000000000..7b5d12ee6 --- /dev/null +++ b/apps/platform/src/pages/MetricsPage/MetricsCards.tsx @@ -0,0 +1,73 @@ +import { Box, Card, CardContent, Typography } from "@mui/material"; +import { format } from "d3"; +import { + faChartBar, + faDna, + faMapPin, + faPrescriptionBottleMedical, + faStethoscope, + faProjectDiagram, + faCircleNodes +} from "@fortawesome/free-solid-svg-icons"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import type { IconDefinition } from "@fortawesome/fontawesome-svg-core"; +import { Tooltip } from "ui"; +import type { MetricRow } from "./MetricsPage"; + +const count = (rows: MetricRow[], dataset: string) => + rows.find((row) => row.dataset === dataset && row.kind === "scalar" && row.metric === "count")?.value ?? 0; + +const formatRoundedCount = (value: number) => { + if (value === 0) return "0"; + + return format(".2~s")(value); +}; + +function MetricsCards({ data }: { data: MetricRow[] }) { + const metrics = [ + ["Targets", faDna, count(data, "target")], + ["Diseases", faStethoscope, count(data, "disease")], + ["Drugs", faPrescriptionBottleMedical, count(data, "drug_molecule")], + ["Clinical reports", faChartBar, count(data, "clinical_report")], + ["GWAS", faChartBar, count(data, "study")], + ["Credible sets", faProjectDiagram, count(data, "credible_set")], + ["Direct target-disease association", faProjectDiagram, count(data, "association_overall_direct")], + ["Indirect target-disease association", faProjectDiagram, count(data, "association_overall_indirect")], + ["Target-disease Evidence", faProjectDiagram, data.filter((row) => row.dataset.startsWith("evidence_") && row.metric === "count").reduce((sum, row) => sum + row.value, 0)], + ["Variants", faMapPin, count(data, "variant")], + ] as const; + + return ( + + {metrics.map(([label, icon, value]) => ( + + + + + + + {label} + + {formatRoundedCount(value)} + + + + + ))} + + ); +} + +export default MetricsCards; diff --git a/apps/platform/src/pages/MetricsPage/MetricsPage.tsx b/apps/platform/src/pages/MetricsPage/MetricsPage.tsx new file mode 100644 index 000000000..759dca4e6 --- /dev/null +++ b/apps/platform/src/pages/MetricsPage/MetricsPage.tsx @@ -0,0 +1,63 @@ +import { useEffect, useState } from "react"; +import { autoType, csv } from "d3"; +import { Typography } from "@mui/material"; +import metricsCsv from "./metrics.csv?url"; +import MetricsCards from "./MetricsCards"; +import DiseasesByTherapeuticArea from "./DiseasesByTherapeuticArea"; +import EvidenceChart from "./EvidenceChart"; +import AssociationPlot from "./AssociationPlot"; +import DrugsByClinicalStage from "./DrugsByClinicalStage"; +import ClinicalReportsByStage from "./ClinicalReportsByStage"; +import CredibleSetsByStudyType from "./CredibleSetsByStudyType"; +import ColocalisationByType from "./ColocalisationByType"; +import StudiesByStudyType from "./StudiesByStudyType"; +import VariantsByConsequence from "./VariantsByConsequence"; + +export type MetricRow = { dataset: string; kind: string; metric: string; group_value: string; value: number }; + +function MetricsPage() { + const [data, setData] = useState([]); + + useEffect(() => { + csv(metricsCsv, autoType).then((d) => setData(d as unknown as MetricRow[])); + }, []); + + return ( + <> + Data Metrics + + {/* Polish: do these look like buttons? + Todo: finalise card order and icons - what for coloc? evidence and cred sets ok to be same? more info in tooltip where approp? - e.g. explain a prioritised gene + Alternative: more hierarchical, e.g. split into top-level entity counts then evidence linking targets and diseases, credible sets and colocs in variants section. */} + + Coverage + + {/* Alternative: Replace Other+tooltip with 'show more'? */} + +
+ +
+ +
+ {/* Alternative: */} + +
+ + {/* Alternative: */} + + Genetics + +
+ +
+ {/* Alternative: */} + +
+ + {/* Polish:Can we remove "variant" from every bar label? */} + {/* Alternative:Replace Other+tooltip with 'show more'? */} + + ); +} + +export default MetricsPage; diff --git a/apps/platform/src/pages/MetricsPage/MetricsPageWrapper.tsx b/apps/platform/src/pages/MetricsPage/MetricsPageWrapper.tsx new file mode 100644 index 000000000..12ede9bf1 --- /dev/null +++ b/apps/platform/src/pages/MetricsPage/MetricsPageWrapper.tsx @@ -0,0 +1,24 @@ +import { Suspense, lazy } from "react"; +import { useLocation } from "react-router"; +import { LoadingBackdrop, PageMeta } from "ui"; + +const MetricsPage = lazy(() => import("./MetricsPage")); + +function MetricsPageWrapper() { + const location = useLocation(); + + return ( + <> + + }> + + + + ); +} + +export default MetricsPageWrapper; diff --git a/apps/platform/src/pages/MetricsPage/StudiesByStudyType.tsx b/apps/platform/src/pages/MetricsPage/StudiesByStudyType.tsx new file mode 100644 index 000000000..e159761ea --- /dev/null +++ b/apps/platform/src/pages/MetricsPage/StudiesByStudyType.tsx @@ -0,0 +1,8 @@ +import ByStudyType from "./ByStudyType"; +import type { MetricRow } from "./MetricsPage"; + +function StudiesByStudyType({ data }: { data: MetricRow[] }) { + return ; +} + +export default StudiesByStudyType; diff --git a/apps/platform/src/pages/MetricsPage/VariantsByConsequence.tsx b/apps/platform/src/pages/MetricsPage/VariantsByConsequence.tsx new file mode 100644 index 000000000..7ccc733cd --- /dev/null +++ b/apps/platform/src/pages/MetricsPage/VariantsByConsequence.tsx @@ -0,0 +1,166 @@ +import { Box, Paper, Typography, useTheme } from "@mui/material"; +import * as Plot from "@observablehq/plot"; +import { PREDICTED_CONSEQUENCE_LOOKUP } from "@ot/constants"; +import { ObsPlot } from "ui"; +import type { MetricRow } from "./MetricsPage"; + +type ConsequenceCount = { name: string; count: number; consequences?: ConsequenceCount[] }; + +function VariantsByConsequence({ data }: { data: MetricRow[] }) { + const theme = useTheme(); + const consequences: ConsequenceCount[] = data + .filter( + (row) => + row.dataset === "variant" && + row.kind === "grouping" && + row.expression === "mostSevereConsequenceId" && + row.group_value, + ) + .map((row) => ({ + name: + PREDICTED_CONSEQUENCE_LOOKUP[ + row.group_value.replace("_", ":") as keyof typeof PREDICTED_CONSEQUENCE_LOOKUP + ]?.displayTerm ?? row.group_value, + count: row.value, + })) + .sort((a, b) => b.count - a.count); + const total = consequences.reduce((sum, consequence) => sum + consequence.count, 0); + const otherConsequences = consequences.filter( + (consequence) => consequence.count < total * 0.01, + ); + const chartData = consequences.filter((consequence) => consequence.count >= total * 0.01); + + if (otherConsequences.length > 0) { + chartData.push({ + name: "Other", + count: otherConsequences.reduce((sum, consequence) => sum + consequence.count, 0), + consequences: otherConsequences, + }); + } + + if (chartData.length === 0) return null; + + return ( + + + + Variants by most severe consequence + + item.count} + yTooltip={(item) => item.name} + xAnchorTooltip="adapt" + yAnchorTooltip="adapt" + renderTooltip={renderTooltip} + gapInfo={0} + renderInfo={() => null} + /> + + + ); + + function renderChart({ + data, + width, + height, + }: { + data: ConsequenceCount[]; + width?: number; + height: number; + }) { + const plotWidth = Math.max((width ?? 0) - 210 - 24, 0); + const maxCount = Math.max(...data.map((item) => item.count)); + const insideData = data.filter( + (item) => + (item.count / maxCount) * plotWidth >= + `${item.count.toLocaleString()}`.length * 7 + 12, + ); + const outsideData = data.filter((item) => !insideData.includes(item)); + + return Plot.plot({ + width: width ?? 0, + height, + style: { fontSize: "13.5px" }, + marginTop: 4, + marginBottom: 4, + marginLeft: 240, + marginRight: 0, + x: { axis: null }, + y: { + domain: data.map((item) => item.name), + label: null, + tickSize: 0, + tickPadding: 8, + }, + marks: [ + Plot.barX(data, { + x: "count", + y: "name", + fill: (item) => + item.consequences ? theme.palette.primary.light : theme.palette.primary.main, + insetTop: 2, + insetBottom: 2, + className: "obs-tooltip", + }), + Plot.text(insideData, { + x: (item) => item.count, + y: "name", + text: (item) => item.count.toLocaleString(), + textAnchor: "end", + dx: -6, + fill: "white", + lineAnchor: "middle", + fontSize: 12.5, + pointerEvents: "none", + className: "obs-tooltip", + }), + Plot.text(outsideData, { + x: (item) => item.count, + y: "name", + text: (item) => item.count.toLocaleString(), + textAnchor: "start", + dx: 6, + fill: theme.palette.text.primary, + lineAnchor: "middle", + fontSize: 12.5, + pointerEvents: "none", + className: "obs-tooltip", + }), + ], + }); + } +} + +function renderTooltip(consequence: ConsequenceCount) { + if (!consequence.consequences) return null; + + return ( + + {consequence.consequences.map((item) => ( + + {item.name}: {item.count.toLocaleString()} + + ))} + + ); +} + +export default VariantsByConsequence; diff --git a/apps/platform/src/pages/MetricsPage/index.ts b/apps/platform/src/pages/MetricsPage/index.ts new file mode 100644 index 000000000..7ae3523b1 --- /dev/null +++ b/apps/platform/src/pages/MetricsPage/index.ts @@ -0,0 +1 @@ +export { default } from "./MetricsPageWrapper"; diff --git a/apps/platform/src/pages/MetricsPage/metrics.csv b/apps/platform/src/pages/MetricsPage/metrics.csv new file mode 100644 index 000000000..045d0c13c --- /dev/null +++ b/apps/platform/src/pages/MetricsPage/metrics.csv @@ -0,0 +1,382 @@ +run,dataset,kind,metric,expression,group_value,value +26.03-test5,association_by_datasource_direct,grouping,datasource,aggregationValue,europepmc,2510811 +26.03-test5,association_by_datasource_direct,grouping,datasource,aggregationValue,gwas_credible_sets,949600 +26.03-test5,association_by_datasource_direct,grouping,datasource,aggregationValue,impc,838318 +26.03-test5,association_by_datasource_direct,grouping,datasource,aggregationValue,expression_atlas,166503 +26.03-test5,association_by_datasource_direct,grouping,datasource,aggregationValue,cancer_gene_census,91572 +26.03-test5,association_by_datasource_direct,grouping,datasource,aggregationValue,clinical_precedence,66282 +26.03-test5,association_by_datasource_direct,grouping,datasource,aggregationValue,eva,41347 +26.03-test5,association_by_datasource_direct,grouping,datasource,aggregationValue,genomics_england,12536 +26.03-test5,association_by_datasource_direct,grouping,datasource,aggregationValue,crispr_screen,10960 +26.03-test5,association_by_datasource_direct,grouping,datasource,aggregationValue,gene_burden,7729 +26.03-test5,association_by_datasource_direct,grouping,datasource,aggregationValue,orphanet,7232 +26.03-test5,association_by_datasource_direct,grouping,datasource,aggregationValue,uniprot_literature,6574 +26.03-test5,association_by_datasource_direct,grouping,datasource,aggregationValue,uniprot_variants,5126 +26.03-test5,association_by_datasource_direct,grouping,datasource,aggregationValue,gene2phenotype,4915 +26.03-test5,association_by_datasource_direct,grouping,datasource,aggregationValue,clingen,3824 +26.03-test5,association_by_datasource_direct,grouping,datasource,aggregationValue,reactome,2928 +26.03-test5,association_by_datasource_direct,grouping,datasource,aggregationValue,intogen,2595 +26.03-test5,association_by_datasource_direct,grouping,datasource,aggregationValue,eva_somatic,2373 +26.03-test5,association_by_datasource_direct,grouping,datasource,aggregationValue,crispr,517 +26.03-test5,association_by_datasource_direct,grouping,datasource,aggregationValue,cancer_biomarkers,469 +26.03-test5,association_by_datasource_direct,scalar,count,,,4732211 +26.03-test5,association_by_datasource_direct,scalar,file_size,,,655362472 +26.03-test5,association_by_datasource_direct,scalar,number_of_partitions,,,53 +26.03-test5,association_by_datasource_indirect,grouping,datasource,aggregationValue,europepmc,8246446 +26.03-test5,association_by_datasource_indirect,grouping,datasource,aggregationValue,gwas_credible_sets,2622428 +26.03-test5,association_by_datasource_indirect,grouping,datasource,aggregationValue,impc,2461182 +26.03-test5,association_by_datasource_indirect,grouping,datasource,aggregationValue,cancer_gene_census,382883 +26.03-test5,association_by_datasource_indirect,grouping,datasource,aggregationValue,clinical_precedence,259530 +26.03-test5,association_by_datasource_indirect,grouping,datasource,aggregationValue,eva,228202 +26.03-test5,association_by_datasource_indirect,grouping,datasource,aggregationValue,expression_atlas,166503 +26.03-test5,association_by_datasource_indirect,grouping,datasource,aggregationValue,genomics_england,99619 +26.03-test5,association_by_datasource_indirect,grouping,datasource,aggregationValue,orphanet,74195 +26.03-test5,association_by_datasource_indirect,grouping,datasource,aggregationValue,uniprot_literature,73310 +26.03-test5,association_by_datasource_indirect,grouping,datasource,aggregationValue,uniprot_variants,57366 +26.03-test5,association_by_datasource_indirect,grouping,datasource,aggregationValue,crispr_screen,50614 +26.03-test5,association_by_datasource_indirect,grouping,datasource,aggregationValue,gene2phenotype,45286 +26.03-test5,association_by_datasource_indirect,grouping,datasource,aggregationValue,clingen,39587 +26.03-test5,association_by_datasource_indirect,grouping,datasource,aggregationValue,intogen,28827 +26.03-test5,association_by_datasource_indirect,grouping,datasource,aggregationValue,eva_somatic,27621 +26.03-test5,association_by_datasource_indirect,grouping,datasource,aggregationValue,gene_burden,25546 +26.03-test5,association_by_datasource_indirect,grouping,datasource,aggregationValue,reactome,19537 +26.03-test5,association_by_datasource_indirect,grouping,datasource,aggregationValue,crispr,7486 +26.03-test5,association_by_datasource_indirect,grouping,datasource,aggregationValue,cancer_biomarkers,5243 +26.03-test5,association_by_datasource_indirect,scalar,count,,,14921411 +26.03-test5,association_by_datasource_indirect,scalar,file_size,,,2579684447 +26.03-test5,association_by_datasource_indirect,scalar,number_of_partitions,,,206 +26.03-test5,association_by_datatype_direct,grouping,datatype,aggregationValue,literature,2510811 +26.03-test5,association_by_datatype_direct,grouping,datatype,aggregationValue,genetic_association,997062 +26.03-test5,association_by_datatype_direct,grouping,datatype,aggregationValue,animal_model,838318 +26.03-test5,association_by_datatype_direct,grouping,datatype,aggregationValue,rna_expression,166503 +26.03-test5,association_by_datatype_direct,grouping,datatype,aggregationValue,somatic_mutation,94789 +26.03-test5,association_by_datatype_direct,grouping,datatype,aggregationValue,known_drug,66282 +26.03-test5,association_by_datatype_direct,grouping,datatype,aggregationValue,genetic_literature,17323 +26.03-test5,association_by_datatype_direct,grouping,datatype,aggregationValue,affected_pathway,14820 +26.03-test5,association_by_datatype_direct,scalar,count,,,4705908 +26.03-test5,association_by_datatype_direct,scalar,file_size,,,651994922 +26.03-test5,association_by_datatype_direct,scalar,number_of_partitions,,,52 +26.03-test5,association_by_datatype_indirect,grouping,datatype,aggregationValue,literature,8246446 +26.03-test5,association_by_datatype_indirect,grouping,datatype,aggregationValue,genetic_association,2823514 +26.03-test5,association_by_datatype_indirect,grouping,datatype,aggregationValue,animal_model,2461182 +26.03-test5,association_by_datatype_indirect,grouping,datatype,aggregationValue,somatic_mutation,406376 +26.03-test5,association_by_datatype_indirect,grouping,datatype,aggregationValue,known_drug,259530 +26.03-test5,association_by_datatype_indirect,grouping,datatype,aggregationValue,rna_expression,166503 +26.03-test5,association_by_datatype_indirect,grouping,datatype,aggregationValue,genetic_literature,123072 +26.03-test5,association_by_datatype_indirect,grouping,datatype,aggregationValue,affected_pathway,80993 +26.03-test5,association_by_datatype_indirect,scalar,count,,,14567616 +26.03-test5,association_by_datatype_indirect,scalar,file_size,,,2521892963 +26.03-test5,association_by_datatype_indirect,scalar,number_of_partitions,,,200 +26.03-test5,association_overall_direct,scalar,count,,,4508002 +26.03-test5,association_overall_direct,scalar,file_size,,,633763096 +26.03-test5,association_overall_direct,scalar,number_of_partitions,,,43 +26.03-test5,association_overall_indirect,scalar,count,,,12466856 +26.03-test5,association_overall_indirect,scalar,file_size,,,2217540168 +26.03-test5,association_overall_indirect,scalar,number_of_partitions,,,143 +26.03-test5,biosample,scalar,count,,,35744 +26.03-test5,biosample,scalar,file_size,,,8254341 +26.03-test5,biosample,scalar,number_of_partitions,,,1 +26.03-test5,clinical_indication,scalar,count,,,53950 +26.03-test5,clinical_indication,scalar,file_size,,,3453490 +26.03-test5,clinical_indication,scalar,number_of_partitions,,,1 +26.03-test5,clinical_report,grouping,clinicalStage,clinicalStage,PHASE_2,63105 +26.03-test5,clinical_report,grouping,clinicalStage,clinicalStage,PHASE_1,49053 +26.03-test5,clinical_report,grouping,clinicalStage,clinicalStage,UNKNOWN,39393 +26.03-test5,clinical_report,grouping,clinicalStage,clinicalStage,PHASE_3,38277 +26.03-test5,clinical_report,grouping,clinicalStage,clinicalStage,PHASE_4,29917 +26.03-test5,clinical_report,grouping,clinicalStage,clinicalStage,APPROVAL,29502 +26.03-test5,clinical_report,grouping,clinicalStage,clinicalStage,PHASE_1_2,15701 +26.03-test5,clinical_report,grouping,clinicalStage,clinicalStage,PHASE_2_3,6106 +26.03-test5,clinical_report,grouping,clinicalStage,clinicalStage,EARLY_PHASE_1,4703 +26.03-test5,clinical_report,grouping,clinicalStage,clinicalStage,IND,4626 +26.03-test5,clinical_report,grouping,clinicalStage,clinicalStage,PRECLINICAL,3812 +26.03-test5,clinical_report,grouping,clinicalStage,clinicalStage,WITHDRAWAL,858 +26.03-test5,clinical_report,grouping,clinicalStage,clinicalStage,PREAPPROVAL,160 +26.03-test5,clinical_report,scalar,count,,,285213 +26.03-test5,clinical_report,scalar,file_size,,,74933170 +26.03-test5,clinical_report,scalar,number_of_partitions,,,1 +26.03-test5,clinical_target,scalar,count,,,13407 +26.03-test5,clinical_target,scalar,file_size,,,2776591 +26.03-test5,clinical_target,scalar,number_of_partitions,,,1 +26.03-test5,colocalisation,grouping,studyTypePair,"concat('gwas-', rightStudyType)",gwas-gwas,167048267 +26.03-test5,colocalisation,grouping,studyTypePair,"concat('gwas-', rightStudyType)",gwas-eqtl,28944408 +26.03-test5,colocalisation,grouping,studyTypePair,"concat('gwas-', rightStudyType)",gwas-tuqtl,8500302 +26.03-test5,colocalisation,grouping,studyTypePair,"concat('gwas-', rightStudyType)",gwas-pqtl,6264043 +26.03-test5,colocalisation,grouping,studyTypePair,"concat('gwas-', rightStudyType)",gwas-sqtl,4706298 +26.03-test5,colocalisation,grouping,studyTypePair,"concat('gwas-', rightStudyType)",gwas-sceqtl,2450996 +26.03-test5,colocalisation,scalar,count,,,217914314 +26.03-test5,colocalisation,scalar,file_size,,,17493948221 +26.03-test5,colocalisation,scalar,number_of_partitions,,,200 +26.03-test5,credible_set,grouping,studyType,studyType,gwas,1446959 +26.03-test5,credible_set,grouping,studyType,studyType,eqtl,1349418 +26.03-test5,credible_set,grouping,studyType,studyType,tuqtl,384849 +26.03-test5,credible_set,grouping,studyType,studyType,sqtl,223500 +26.03-test5,credible_set,grouping,studyType,studyType,sceqtl,52738 +26.03-test5,credible_set,grouping,studyType,studyType,pqtl,33718 +26.03-test5,credible_set,scalar,count,,,3491182 +26.03-test5,credible_set,scalar,file_size,,,3187753665 +26.03-test5,credible_set,scalar,number_of_partitions,,,200 +26.03-test5,disease,grouping,therapeuticArea,therapeuticAreas,EFO_0001444,25050 +26.03-test5,disease,grouping,therapeuticArea,therapeuticAreas,OTAR_0000018,11779 +26.03-test5,disease,grouping,therapeuticArea,therapeuticAreas,EFO_0000651,6143 +26.03-test5,disease,grouping,therapeuticArea,therapeuticAreas,EFO_0000618,4680 +26.03-test5,disease,grouping,therapeuticArea,therapeuticAreas,MONDO_0045024,3692 +26.03-test5,disease,grouping,therapeuticArea,therapeuticAreas,OTAR_0000006,3237 +26.03-test5,disease,grouping,therapeuticArea,therapeuticAreas,OTAR_0000020,2211 +26.03-test5,disease,grouping,therapeuticArea,therapeuticAreas,EFO_0010285,1490 +26.03-test5,disease,grouping,therapeuticArea,therapeuticAreas,EFO_0001379,1467 +26.03-test5,disease,grouping,therapeuticArea,therapeuticAreas,MONDO_0024458,1455 +26.03-test5,disease,grouping,therapeuticArea,therapeuticAreas,OTAR_0000017,1358 +26.03-test5,disease,grouping,therapeuticArea,therapeuticAreas,EFO_0010282,1348 +26.03-test5,disease,grouping,therapeuticArea,therapeuticAreas,EFO_0000540,1289 +26.03-test5,disease,grouping,therapeuticArea,therapeuticAreas,EFO_0000319,1221 +26.03-test5,disease,grouping,therapeuticArea,therapeuticAreas,EFO_0005803,1160 +26.03-test5,disease,grouping,therapeuticArea,therapeuticAreas,EFO_0005741,891 +26.03-test5,disease,grouping,therapeuticArea,therapeuticAreas,GO_0008150,812 +26.03-test5,disease,grouping,therapeuticArea,therapeuticAreas,EFO_0009690,763 +26.03-test5,disease,grouping,therapeuticArea,therapeuticAreas,OTAR_0000010,602 +26.03-test5,disease,grouping,therapeuticArea,therapeuticAreas,MONDO_0002025,370 +26.03-test5,disease,grouping,therapeuticArea,therapeuticAreas,OTAR_0000009,151 +26.03-test5,disease,grouping,therapeuticArea,therapeuticAreas,OTAR_0000014,75 +26.03-test5,disease,grouping,therapeuticArea,therapeuticAreas,MONDO_0021205,71 +26.03-test5,disease,grouping,therapeuticArea,therapeuticAreas,EFO_0002571,61 +26.03-test5,disease,grouping,therapeuticArea,therapeuticAreas,EFO_0005932,61 +26.03-test5,disease,scalar,count,,,47030 +26.03-test5,disease,scalar,file_size,,,7312633 +26.03-test5,disease,scalar,number_of_partitions,,,1 +26.03-test5,disease_hpo,scalar,count,,,31529 +26.03-test5,disease_hpo,scalar,file_size,,,1804225 +26.03-test5,disease_hpo,scalar,number_of_partitions,,,1 +26.03-test5,disease_phenotype,scalar,count,,,180981 +26.03-test5,disease_phenotype,scalar,file_size,,,7930460 +26.03-test5,disease_phenotype,scalar,number_of_partitions,,,1 +26.03-test5,drug_mechanism_of_action,scalar,count,,,6505 +26.03-test5,drug_mechanism_of_action,scalar,file_size,,,579870 +26.03-test5,drug_mechanism_of_action,scalar,number_of_partitions,,,2 +26.03-test5,drug_molecule,grouping,clinicalStage,maximumClinicalStage,UNKNOWN,10771 +26.03-test5,drug_molecule,grouping,clinicalStage,maximumClinicalStage,APPROVAL,5200 +26.03-test5,drug_molecule,grouping,clinicalStage,maximumClinicalStage,PHASE_2,2575 +26.03-test5,drug_molecule,grouping,clinicalStage,maximumClinicalStage,PHASE_3,1454 +26.03-test5,drug_molecule,grouping,clinicalStage,maximumClinicalStage,PHASE_1,1339 +26.03-test5,drug_molecule,grouping,clinicalStage,maximumClinicalStage,PHASE_1_2,411 +26.03-test5,drug_molecule,grouping,clinicalStage,maximumClinicalStage,PHASE_2_3,213 +26.03-test5,drug_molecule,grouping,clinicalStage,maximumClinicalStage,IND,129 +26.03-test5,drug_molecule,grouping,clinicalStage,maximumClinicalStage,PRECLINICAL,60 +26.03-test5,drug_molecule,grouping,clinicalStage,maximumClinicalStage,EARLY_PHASE_1,44 +26.03-test5,drug_molecule,grouping,clinicalStage,maximumClinicalStage,PREAPPROVAL,34 +26.03-test5,drug_molecule,scalar,count,,,22230 +26.03-test5,drug_molecule,scalar,file_size,,,2679269 +26.03-test5,drug_molecule,scalar,number_of_partitions,,,5 +26.03-test5,drug_warning,scalar,count,,,2302 +26.03-test5,drug_warning,scalar,file_size,,,250932 +26.03-test5,drug_warning,scalar,number_of_partitions,,,1 +26.03-test5,enhancer_to_gene,scalar,count,,,48810390 +26.03-test5,enhancer_to_gene,scalar,file_size,,,2647632759 +26.03-test5,enhancer_to_gene,scalar,number_of_partitions,,,30 +26.03-test5,evidence_cancer_biomarkers,grouping,datatype,datatypeId,affected_pathway,1301 +26.03-test5,evidence_cancer_biomarkers,scalar,count,,,1301 +26.03-test5,evidence_cancer_biomarkers,scalar,file_size,,,122065 +26.03-test5,evidence_cancer_biomarkers,scalar,number_of_partitions,,,1 +26.03-test5,evidence_cancer_gene_census,grouping,datatype,datatypeId,somatic_mutation,91572 +26.03-test5,evidence_cancer_gene_census,scalar,count,,,91572 +26.03-test5,evidence_cancer_gene_census,scalar,file_size,,,5971585 +26.03-test5,evidence_cancer_gene_census,scalar,number_of_partitions,,,5 +26.03-test5,evidence_clingen,grouping,datatype,datatypeId,genetic_literature,3894 +26.03-test5,evidence_clingen,scalar,count,,,3894 +26.03-test5,evidence_clingen,scalar,file_size,,,509278 +26.03-test5,evidence_clingen,scalar,number_of_partitions,,,1 +26.03-test5,evidence_clinical_precedence,grouping,datatype,datatypeId,clinical,599344 +26.03-test5,evidence_clinical_precedence,scalar,count,,,599344 +26.03-test5,evidence_clinical_precedence,scalar,file_size,,,47458531 +26.03-test5,evidence_clinical_precedence,scalar,number_of_partitions,,,11 +26.03-test5,evidence_crispr,grouping,datatype,datatypeId,affected_pathway,517 +26.03-test5,evidence_crispr,scalar,count,,,517 +26.03-test5,evidence_crispr,scalar,file_size,,,70147 +26.03-test5,evidence_crispr,scalar,number_of_partitions,,,1 +26.03-test5,evidence_crispr_screen,grouping,datatype,datatypeId,affected_pathway,21659 +26.03-test5,evidence_crispr_screen,scalar,count,,,21659 +26.03-test5,evidence_crispr_screen,scalar,file_size,,,1563599 +26.03-test5,evidence_crispr_screen,scalar,number_of_partitions,,,4 +26.03-test5,evidence_europepmc,grouping,datatype,datatypeId,literature,24376290 +26.03-test5,evidence_europepmc,scalar,count,,,24376290 +26.03-test5,evidence_europepmc,scalar,file_size,,,8671824871 +26.03-test5,evidence_europepmc,scalar,number_of_partitions,,,200 +26.03-test5,evidence_eva,grouping,datatype,datatypeId,genetic_association,4035263 +26.03-test5,evidence_eva,scalar,count,,,4035263 +26.03-test5,evidence_eva,scalar,file_size,,,452083288 +26.03-test5,evidence_eva,scalar,number_of_partitions,,,22 +26.03-test5,evidence_eva_somatic,grouping,datatype,datatypeId,somatic_mutation,9366 +26.03-test5,evidence_eva_somatic,scalar,count,,,9366 +26.03-test5,evidence_eva_somatic,scalar,file_size,,,1099065 +26.03-test5,evidence_eva_somatic,scalar,number_of_partitions,,,3 +26.03-test5,evidence_expression_atlas,grouping,datatype,datatypeId,rna_expression,237329 +26.03-test5,evidence_expression_atlas,scalar,count,,,237329 +26.03-test5,evidence_expression_atlas,scalar,file_size,,,16703575 +26.03-test5,evidence_expression_atlas,scalar,number_of_partitions,,,5 +26.03-test5,evidence_gene2phenotype,grouping,datatype,datatypeId,genetic_literature,5026 +26.03-test5,evidence_gene2phenotype,scalar,count,,,5026 +26.03-test5,evidence_gene2phenotype,scalar,file_size,,,562314 +26.03-test5,evidence_gene2phenotype,scalar,number_of_partitions,,,1 +26.03-test5,evidence_gene_burden,grouping,datatype,datatypeId,genetic_association,40444 +26.03-test5,evidence_gene_burden,scalar,count,,,40444 +26.03-test5,evidence_gene_burden,scalar,file_size,,,4585295 +26.03-test5,evidence_gene_burden,scalar,number_of_partitions,,,5 +26.03-test5,evidence_genomics_england,grouping,datatype,datatypeId,genetic_literature,46905 +26.03-test5,evidence_genomics_england,scalar,count,,,46905 +26.03-test5,evidence_genomics_england,scalar,file_size,,,6236722 +26.03-test5,evidence_genomics_england,scalar,number_of_partitions,,,5 +26.03-test5,evidence_gwas_credible_sets,grouping,datatype,datatypeId,genetic_association,3029759 +26.03-test5,evidence_gwas_credible_sets,scalar,count,,,3029759 +26.03-test5,evidence_gwas_credible_sets,scalar,file_size,,,289413549 +26.03-test5,evidence_gwas_credible_sets,scalar,number_of_partitions,,,8 +26.03-test5,evidence_impc,grouping,datatype,datatypeId,animal_model,1522457 +26.03-test5,evidence_impc,scalar,count,,,1522457 +26.03-test5,evidence_impc,scalar,file_size,,,227703094 +26.03-test5,evidence_impc,scalar,number_of_partitions,,,23 +26.03-test5,evidence_intogen,grouping,datatype,datatypeId,somatic_mutation,4223 +26.03-test5,evidence_intogen,scalar,count,,,4223 +26.03-test5,evidence_intogen,scalar,file_size,,,319893 +26.03-test5,evidence_intogen,scalar,number_of_partitions,,,1 +26.03-test5,evidence_orphanet,grouping,datatype,datatypeId,genetic_association,7245 +26.03-test5,evidence_orphanet,scalar,count,,,7245 +26.03-test5,evidence_orphanet,scalar,file_size,,,735287 +26.03-test5,evidence_orphanet,scalar,number_of_partitions,,,1 +26.03-test5,evidence_reactome,grouping,datatype,datatypeId,affected_pathway,10748 +26.03-test5,evidence_reactome,scalar,count,,,10748 +26.03-test5,evidence_reactome,scalar,file_size,,,1078355 +26.03-test5,evidence_reactome,scalar,number_of_partitions,,,4 +26.03-test5,evidence_uniprot_literature,grouping,datatype,datatypeId,genetic_literature,6682 +26.03-test5,evidence_uniprot_literature,scalar,count,,,6682 +26.03-test5,evidence_uniprot_literature,scalar,file_size,,,830649 +26.03-test5,evidence_uniprot_literature,scalar,number_of_partitions,,,1 +26.03-test5,evidence_uniprot_variants,grouping,datatype,datatypeId,genetic_association,36814 +26.03-test5,evidence_uniprot_variants,scalar,count,,,36814 +26.03-test5,evidence_uniprot_variants,scalar,file_size,,,3534449 +26.03-test5,evidence_uniprot_variants,scalar,number_of_partitions,,,5 +26.03-test5,expression,scalar,count,,,50482 +26.03-test5,expression,scalar,file_size,,,42092909 +26.03-test5,expression,scalar,number_of_partitions,,,4 +26.03-test5,go,scalar,count,,,48251 +26.03-test5,go,scalar,file_size,,,745909 +26.03-test5,go,scalar,number_of_partitions,,,1 +26.03-test5,interaction,scalar,count,,,14618053 +26.03-test5,interaction,scalar,file_size,,,91031424 +26.03-test5,interaction,scalar,number_of_partitions,,,8 +26.03-test5,interaction_evidence,scalar,count,,,27432165 +26.03-test5,interaction_evidence,scalar,file_size,,,283743276 +26.03-test5,interaction_evidence,scalar,number_of_partitions,,,200 +26.03-test5,l2g_prediction,filter,prioritised_genes,distinct geneId where score > 0.5,,15509 +26.03-test5,l2g_prediction,scalar,count,,,2794835 +26.03-test5,l2g_prediction,scalar,file_size,,,548945225 +26.03-test5,l2g_prediction,scalar,number_of_partitions,,,200 +26.03-test5,literature,scalar,count,,,163972906 +26.03-test5,literature,scalar,file_size,,,2447297685 +26.03-test5,literature,scalar,number_of_partitions,,,334 +26.03-test5,literature_vector,scalar,count,,,58057 +26.03-test5,literature_vector,scalar,file_size,,,37038512 +26.03-test5,literature_vector,scalar,number_of_partitions,,,1 +26.03-test5,mouse_phenotype,scalar,count,,,210538 +26.03-test5,mouse_phenotype,scalar,file_size,,,10863568 +26.03-test5,mouse_phenotype,scalar,number_of_partitions,,,5 +26.03-test5,openfda_significant_adverse_drug_reactions,scalar,count,,,115698 +26.03-test5,openfda_significant_adverse_drug_reactions,scalar,file_size,,,1782397 +26.03-test5,openfda_significant_adverse_drug_reactions,scalar,number_of_partitions,,,1 +26.03-test5,pharmacogenomics,scalar,count,,,33080 +26.03-test5,pharmacogenomics,scalar,file_size,,,3507000 +26.03-test5,pharmacogenomics,scalar,number_of_partitions,,,5 +26.03-test5,so,scalar,count,,,2615 +26.03-test5,so,scalar,file_size,,,26378 +26.03-test5,so,scalar,number_of_partitions,,,1 +26.03-test5,study,grouping,datasource,projectId,GTEx,1070069 +26.03-test5,study,grouping,datasource,projectId,GCST,133923 +26.03-test5,study,grouping,datasource,projectId,Schmiedel_2018,74874 +26.03-test5,study,grouping,datasource,projectId,Quach_2016,73699 +26.03-test5,study,grouping,datasource,projectId,TwinsUK,68300 +26.03-test5,study,grouping,datasource,projectId,FUSION,64646 +26.03-test5,study,grouping,datasource,projectId,BLUEPRINT,59824 +26.03-test5,study,grouping,datasource,projectId,BrainSeq,36104 +26.03-test5,study,grouping,datasource,projectId,ROSMAP,35088 +26.03-test5,study,grouping,datasource,projectId,CommonMind,31235 +26.03-test5,study,grouping,datasource,projectId,GEUVADIS,26866 +26.03-test5,study,grouping,datasource,projectId,Lepik_2017,26603 +26.03-test5,study,grouping,datasource,projectId,HipSci,25743 +26.03-test5,study,grouping,datasource,projectId,GENCORD,25713 +26.03-test5,study,grouping,datasource,projectId,Alasoo_2018,24550 +26.03-test5,study,grouping,datasource,projectId,Nedelec_2016,22950 +26.03-test5,study,grouping,datasource,projectId,CAP,19518 +26.03-test5,study,grouping,datasource,projectId,Cytoimmgen,17045 +26.03-test5,study,grouping,datasource,projectId,Fairfax_2014,16007 +26.03-test5,study,grouping,datasource,projectId,OneK1K,14362 +26.03-test5,study,grouping,datasource,projectId,CEDAR,14213 +26.03-test5,study,grouping,datasource,projectId,Bossini-Castillo_2019,12431 +26.03-test5,study,grouping,datasource,projectId,PhLiPS,10896 +26.03-test5,study,grouping,datasource,projectId,Walker_2019,10574 +26.03-test5,study,grouping,datasource,projectId,Nathan_2022,10540 +26.03-test5,study,grouping,datasource,projectId,Steinberg_2020,7678 +26.03-test5,study,grouping,datasource,projectId,iPSCORE,6582 +26.03-test5,study,grouping,datasource,projectId,Aygun_2021,6554 +26.03-test5,study,grouping,datasource,projectId,Schwartzentruber_2018,5339 +26.03-test5,study,grouping,datasource,projectId,van_de_Bunt_2015,5280 +26.03-test5,study,grouping,datasource,projectId,Kim-Hellmuth_2017,5254 +26.03-test5,study,grouping,datasource,projectId,PISA,5020 +26.03-test5,study,grouping,datasource,projectId,Jerber_2021,4869 +26.03-test5,study,grouping,datasource,projectId,Peng_2018,4775 +26.03-test5,study,grouping,datasource,projectId,Braineac2,3307 +26.03-test5,study,grouping,datasource,projectId,Kasela_2017,3194 +26.03-test5,study,grouping,datasource,projectId,Gilchrist_2021,3056 +26.03-test5,study,grouping,datasource,projectId,UKB_PPP_EUR,2953 +26.03-test5,study,grouping,datasource,projectId,Fairfax_2012,2900 +26.03-test5,study,grouping,datasource,projectId,FINNGEN_R12,2322 +26.03-test5,study,grouping,datasource,projectId,Perez_2022,1863 +26.03-test5,study,grouping,datasource,projectId,Young_2019,1793 +26.03-test5,study,grouping,datasource,projectId,Randolph_2021,1396 +26.03-test5,study,grouping,datasource,projectId,Naranbhai_2015,1117 +26.03-test5,study,grouping,datasource,projectId,Sun_2018,802 +26.03-test5,study,grouping,studyType,studyType,eqtl,1233604 +26.03-test5,study,grouping,studyType,studyType,tuqtl,364196 +26.03-test5,study,grouping,studyType,studyType,sqtl,213952 +26.03-test5,study,grouping,studyType,studyType,gwas,136245 +26.03-test5,study,grouping,studyType,studyType,sceqtl,50075 +26.03-test5,study,grouping,studyType,studyType,pqtl,3755 +26.03-test5,study,scalar,count,,,2001827 +26.03-test5,study,scalar,file_size,,,96590973 +26.03-test5,study,scalar,number_of_partitions,,,1 +26.03-test5,target,scalar,count,,,78691 +26.03-test5,target,scalar,file_size,,,85031914 +26.03-test5,target,scalar,number_of_partitions,,,10 +26.03-test5,target_essentiality,scalar,count,,,17844 +26.03-test5,target_essentiality,scalar,file_size,,,253322991 +26.03-test5,target_essentiality,scalar,number_of_partitions,,,10 +26.03-test5,target_prioritisation,scalar,count,,,78691 +26.03-test5,target_prioritisation,scalar,file_size,,,904101 +26.03-test5,target_prioritisation,scalar,number_of_partitions,,,1 +26.03-test5,variant,grouping,consequence,mostSevereConsequenceId,SO_0001627,3600043 +26.03-test5,variant,grouping,consequence,mostSevereConsequenceId,SO_0001631,1593255 +26.03-test5,variant,grouping,consequence,mostSevereConsequenceId,SO_0001583,1041076 +26.03-test5,variant,grouping,consequence,mostSevereConsequenceId,SO_0001819,424621 +26.03-test5,variant,grouping,consequence,mostSevereConsequenceId,SO_0001624,141974 +26.03-test5,variant,grouping,consequence,mostSevereConsequenceId,SO_0001589,115302 +26.03-test5,variant,grouping,consequence,mostSevereConsequenceId,SO_0001792,99257 +26.03-test5,variant,grouping,consequence,mostSevereConsequenceId,SO_0001630,94916 +26.03-test5,variant,grouping,consequence,mostSevereConsequenceId,SO_0002169,76512 +26.03-test5,variant,grouping,consequence,mostSevereConsequenceId,SO_0001587,71274 +26.03-test5,variant,grouping,consequence,mostSevereConsequenceId,SO_0001575,45850 +26.03-test5,variant,grouping,consequence,mostSevereConsequenceId,SO_0001574,40606 +26.03-test5,variant,grouping,consequence,mostSevereConsequenceId,SO_0001623,23283 +26.03-test5,variant,grouping,consequence,mostSevereConsequenceId,SO_0002170,22324 +26.03-test5,variant,grouping,consequence,mostSevereConsequenceId,SO_0001822,15238 +26.03-test5,variant,grouping,consequence,mostSevereConsequenceId,SO_0001787,12156 +26.03-test5,variant,grouping,consequence,mostSevereConsequenceId,SO_0001821,6410 +26.03-test5,variant,grouping,consequence,mostSevereConsequenceId,SO_0001632,3210 +26.03-test5,variant,grouping,consequence,mostSevereConsequenceId,SO_0002012,2642 +26.03-test5,variant,grouping,consequence,mostSevereConsequenceId,SO_0001578,917 +26.03-test5,variant,grouping,consequence,mostSevereConsequenceId,SO_0001818,739 +26.03-test5,variant,grouping,consequence,mostSevereConsequenceId,SO_0001628,336 +26.03-test5,variant,grouping,consequence,mostSevereConsequenceId,SO_0001567,331 +26.03-test5,variant,grouping,consequence,mostSevereConsequenceId,SO_0001620,151 +26.03-test5,variant,grouping,consequence,mostSevereConsequenceId,SO_0001893,94 +26.03-test5,variant,grouping,consequence,mostSevereConsequenceId,SO_0001580,31 +26.03-test5,variant,grouping,consequence,mostSevereConsequenceId,null,1 +26.03-test5,variant,scalar,count,,,7432549 +26.03-test5,variant,scalar,file_size,,,3421215184 +26.03-test5,variant,scalar,number_of_partitions,,,25 diff --git a/packages/ot-constants/src/index.ts b/packages/ot-constants/src/index.ts index 98cfcf85c..1c313c64e 100644 --- a/packages/ot-constants/src/index.ts +++ b/packages/ot-constants/src/index.ts @@ -397,6 +397,176 @@ export const variantConsequenceSource = { }, }; +// from Ensembl: https://www.ensembl.org/info/genome/variation/prediction/predicted_data.html +export const PREDICTED_CONSEQUENCE_LOOKUP = { + "SO:0001893": { color: "#ff0000", displayTerm: "Transcript ablation", impact: "HIGH", rank: 0 }, + "SO:0001574": { + color: "#ff581a", + displayTerm: "Splice acceptor variant", + impact: "HIGH", + rank: 1, + }, + "SO:0001575": { color: "#ff581a", displayTerm: "Splice donor variant", impact: "HIGH", rank: 2 }, + "SO:0001587": { color: "#ff0000", displayTerm: "Stop gained", impact: "HIGH", rank: 3 }, + "SO:0001589": { color: "#9400d3", displayTerm: "Frameshift variant", impact: "HIGH", rank: 4 }, + "SO:0001578": { color: "#ff0000", displayTerm: "Stop lost", impact: "HIGH", rank: 5 }, + "SO:0002012": { color: "#ffd700", displayTerm: "Start lost", impact: "HIGH", rank: 6 }, + "SO:0001889": { + color: "#ff69b4", + displayTerm: "Transcript amplification", + impact: "HIGH", + rank: 7, + }, + "SO:0001907": { color: "#7f7f7f", displayTerm: "Feature elongation", impact: "HIGH", rank: 8 }, + "SO:0001906": { color: "#7f7f7f", displayTerm: "Feature truncation", impact: "HIGH", rank: 9 }, + "SO:0001821": { + color: "#ff69b4", + displayTerm: "Inframe insertion", + impact: "MODERATE", + rank: 10, + }, + "SO:0001822": { color: "#ff69b4", displayTerm: "Inframe deletion", impact: "MODERATE", rank: 11 }, + "SO:0001583": { color: "#ffd700", displayTerm: "Missense variant", impact: "MODERATE", rank: 12 }, + "SO:0001818": { + color: "#ff0080", + displayTerm: "Protein altering variant", + impact: "MODERATE", + rank: 13, + }, + "SO:0001787": { + color: "#ff7f50", + displayTerm: "Splice donor 5th base variant", + impact: "LOW", + rank: 14, + }, + "SO:0001630": { color: "#ff7f50", displayTerm: "Splice region variant", impact: "LOW", rank: 15 }, + "SO:0002170": { + color: "#ff7f50", + displayTerm: "Splice donor region variant", + impact: "LOW", + rank: 16, + }, + "SO:0002169": { + color: "#ff7f50", + displayTerm: "Splice polypyrimidine tract variant", + impact: "LOW", + rank: 17, + }, + "SO:0001626": { + color: "#ff00ff", + displayTerm: "Incomplete terminal codon variant", + impact: "LOW", + rank: 18, + }, + "SO:0002019": { + color: "#76ee00", + displayTerm: "Start retained variant", + impact: "LOW", + rank: 19, + }, + "SO:0001567": { color: "#76ee00", displayTerm: "Stop retained variant", impact: "LOW", rank: 20 }, + "SO:0001819": { color: "#76ee00", displayTerm: "Synonymous variant", impact: "LOW", rank: 21 }, + "SO:0001580": { + color: "#458b00", + displayTerm: "Coding sequence variant", + impact: "MODIFIER", + rank: 22, + }, + "SO:0001620": { + color: "#458b00", + displayTerm: "Mature miRNA variant", + impact: "MODIFIER", + rank: 23, + }, + "SO:0001623": { + color: "#7ac5cd", + displayTerm: "5 prime UTR variant", + impact: "MODIFIER", + rank: 24, + }, + "SO:0001624": { + color: "#7ac5cd", + displayTerm: "3 prime UTR variant", + impact: "MODIFIER", + rank: 25, + }, + "SO:0001792": { + color: "#32cd32", + displayTerm: "Non coding transcript exon variant", + impact: "MODIFIER", + rank: 26, + }, + "SO:0001627": { color: "#02599c", displayTerm: "Intron variant", impact: "MODIFIER", rank: 27 }, + "SO:0001621": { + color: "#ff4500", + displayTerm: "NMD transcript variant", + impact: "MODIFIER", + rank: 28, + }, + "SO:0001619": { + color: "#32cd32", + displayTerm: "Non coding transcript variant", + impact: "MODIFIER", + rank: 29, + }, + "SO:0001968": { + color: "#458b00", + displayTerm: "Coding transcript variant", + impact: "MODIFIER", + rank: 30, + }, + "SO:0001631": { + color: "#a2b5cd", + displayTerm: "Upstream gene variant", + impact: "MODIFIER", + rank: 31, + }, + "SO:0001632": { + color: "#a2b5cd", + displayTerm: "Downstream gene variant", + impact: "MODIFIER", + rank: 32, + }, + "SO:0001895": { color: "#a52a2a", displayTerm: "TFBS ablation", impact: "MODIFIER", rank: 33 }, + "SO:0001892": { + color: "#a52a2a", + displayTerm: "TFBS amplification", + impact: "MODIFIER", + rank: 34, + }, + "SO:0001782": { + color: "#a52a2a", + displayTerm: "TF binding site variant", + impact: "MODIFIER", + rank: 35, + }, + "SO:0001894": { + color: "#a52a2a", + displayTerm: "Regulatory region ablation", + impact: "MODIFIER", + rank: 36, + }, + "SO:0001891": { + color: "#a52a2a", + displayTerm: "Regulatory region amplification", + impact: "MODIFIER", + rank: 37, + }, + "SO:0001566": { + color: "#a52a2a", + displayTerm: "Regulatory region variant", + impact: "MODIFIER", + rank: 38, + }, + "SO:0001628": { + color: "#636363", + displayTerm: "Intergenic variant", + impact: "MODIFIER", + rank: 39, + }, + "SO:0001060": { color: "#636363", displayTerm: "Sequence variant", impact: "MODIFIER", rank: 40 }, +}; + // Population Mapping export const populationMap: { [key: string]: string } = { fin: "Finnish", @@ -455,6 +625,76 @@ export const baselineUnits = { "mass-spectrometry proteomics": "PPB", }; +export const therapeuticPriorities = { + EFO_0001444: { name: "measurement", rank: 1 }, + MONDO_0045024: { name: "cancer or benign tumor", rank: 2 }, + OTAR_0000018: { name: "genetic, familial or congenital", rank: 3 }, + MONDO_0005550: { name: "infectious disease", rank: 4 }, + OTAR_0000009: { name: "injury, poisoning or complication", rank: 5 }, + OTAR_0000014: { name: "pregnancy or perinatal", rank: 6 }, + MONDO_0024458: { name: "visual system", rank: 7 }, + MONDO_0004995: { name: "cardiovascular", rank: 8 }, + MONDO_0002356: { name: "pancreas", rank: 9 }, + MONDO_0002515: { name: "liver", rank: 10 }, + EFO_0010282: { name: "gastrointestinal", rank: 11 }, + OTAR_0000017: { name: "reproductive system or breast", rank: 12 }, + MONDO_0002051: { name: "integumentary system", rank: 13 }, + MONDO_0005151: { name: "endocrine system", rank: 14 }, + OTAR_0000010: { name: "respiratory or thoracic", rank: 15 }, + MONDO_0002118: { name: "urinary system", rank: 16 }, + OTAR_0000006: { name: "musculoskeletal or connective ...", rank: 17 }, + MONDO_0021205: { name: "disorder of ear", rank: 18 }, + MONDO_0005046: { name: "immune system", rank: 19 }, + MONDO_0005570: { name: "hematologic", rank: 20 }, + MONDO_0005071: { name: "nervous system", rank: 21 }, + MONDO_0002025: { name: "psychiatric", rank: 22 }, + OTAR_0000020: { name: "nutritional or metabolic", rank: 23 }, + GO_0008150: { name: "biological process", rank: 24 }, + EFO_0000651: { name: "phenotype", rank: 25 }, + EFO_0002571: { name: "medical procedure", rank: 26 }, + MONDO_0005583: { name: "animal disease", rank: 27 }, +}; + +export const therapeuticAreas: Record = { + EFO_0001444: "measurement", + MONDO_0045024: "cancer or benign tumor", + OTAR_0000018: "genetic, familial or congenital", + MONDO_0005550: "infectious disease", + OTAR_0000009: "injury, poisoning or complication", + OTAR_0000014: "pregnancy or perinatal", + MONDO_0024458: "visual system", + MONDO_0004995: "cardiovascular", + MONDO_0002356: "pancreas", + MONDO_0002515: "liver", + EFO_0010282: "gastrointestinal", + OTAR_0000017: "reproductive system or breast", + MONDO_0002051: "integumentary system", + MONDO_0005151: "endocrine system", + OTAR_0000010: "respiratory or thoracic", + MONDO_0002118: "urinary system", + OTAR_0000006: "musculoskeletal or connective tissue", + MONDO_0021205: "disorder of ear", + MONDO_0005046: "immune system", + MONDO_0005570: "hematologic", + MONDO_0005071: "nervous system", + MONDO_0002025: "psychiatric", + OTAR_0000020: "nutritional or metabolic", + GO_0008150: "biological process", + EFO_0000651: "phenotype", + EFO_0002571: "medical procedure", + MONDO_0005583: "animal disease", + EFO_0000319: "cardiovascular", + EFO_0000540: "immune system", + EFO_0000618: "nervous system", + EFO_0001379: "endocrine system", + EFO_0005741: "infectious disease", + EFO_0005803: "hematologic", + EFO_0005932: "animal disease", + EFO_0009690: "urinary system", + EFO_0010284: "liver", + EFO_0010285: "integumentary system", +}; + export * from "./alphaFold"; export * from "./dataTypes"; export * from "./particlesBackground"; diff --git a/packages/sections/src/variant/GWASCredibleSets/PheWasPlot.tsx b/packages/sections/src/variant/GWASCredibleSets/PheWasPlot.tsx index 52f1a04a6..80206b902 100644 --- a/packages/sections/src/variant/GWASCredibleSets/PheWasPlot.tsx +++ b/packages/sections/src/variant/GWASCredibleSets/PheWasPlot.tsx @@ -1,6 +1,6 @@ import { Box, Chip, Skeleton, Typography, useTheme } from "@mui/material"; import * as PlotLib from "@observablehq/plot"; -import { credsetConfidenceMap, naLabel } from "@ot/constants"; +import { credsetConfidenceMap, naLabel, therapeuticPriorities } from "@ot/constants"; import { Fragment } from "react"; import { ClinvarStars, @@ -55,36 +55,6 @@ function PheWasPlot({ ); if (data.length === 0) return null; - const therapeuticPriorities = { - EFO_0001444: { name: "measurement", rank: 1 }, - MONDO_0045024: { name: "cancer or benign tumor", rank: 2 }, - OTAR_0000018: { name: "genetic, familial or congenital", rank: 3 }, - MONDO_0005550: { name: "infectious disease", rank: 4 }, - OTAR_0000009: { name: "injury, poisoning or complication", rank: 5 }, - OTAR_0000014: { name: "pregnancy or perinatal", rank: 6 }, - MONDO_0024458: { name: "visual system", rank: 7 }, - MONDO_0004995: { name: "cardiovascular", rank: 8 }, - MONDO_0002356: { name: "pancreas", rank: 9 }, - MONDO_0002515: { name: "liver", rank: 10 }, - EFO_0010282: { name: "gastrointestinal", rank: 11 }, - OTAR_0000017: { name: "reproductive system or breast", rank: 12 }, - MONDO_0002051: { name: "integumentary system", rank: 13 }, - MONDO_0005151: { name: "endocrine system", rank: 14 }, - OTAR_0000010: { name: "respiratory or thoracic", rank: 15 }, - MONDO_0002118: { name: "urinary system", rank: 16 }, - OTAR_0000006: { name: "musculoskeletal or connective ...", rank: 17 }, - MONDO_0021205: { name: "disorder of ear", rank: 18 }, - MONDO_0005046: { name: "immune system", rank: 19 }, - MONDO_0005570: { name: "hematologic", rank: 20 }, - MONDO_0005071: { name: "nervous system", rank: 21 }, - MONDO_0002025: { name: "psychiatric", rank: 22 }, - OTAR_0000020: { name: "nutritional or metabolic", rank: 23 }, - GO_0008150: { name: "biological process", rank: 24 }, - EFO_0000651: { name: "phenotype", rank: 25 }, - EFO_0002571: { name: "medical procedure", rank: 26 }, - MONDO_0005583: { name: "animal disease", rank: 27 }, - }; - function getTherapeuticArea(row) { let bestId = null; let bestRank = Infinity;