diff --git a/apps/platform/src/components/AssociationsToolkit/static_datasets/dataSourcesAssoc.js b/apps/platform/src/components/AssociationsToolkit/static_datasets/dataSourcesAssoc.js index eed7faea1..4a70239c6 100644 --- a/apps/platform/src/components/AssociationsToolkit/static_datasets/dataSourcesAssoc.js +++ b/apps/platform/src/components/AssociationsToolkit/static_datasets/dataSourcesAssoc.js @@ -2,7 +2,7 @@ const dataSources = [ { id: "gwas_credible_sets", sectionId: "gwasCredibleSets", - label: "GWAS credible sets", + label: "GWAS associations", aggregation: "Genetic association", aggregationId: "genetic_association", weight: 1, diff --git a/apps/platform/src/pages/CredibleSetPage/ProfileHeader.tsx b/apps/platform/src/pages/CredibleSetPage/ProfileHeader.tsx index ad7c568ee..ec5f2e263 100644 --- a/apps/platform/src/pages/CredibleSetPage/ProfileHeader.tsx +++ b/apps/platform/src/pages/CredibleSetPage/ProfileHeader.tsx @@ -221,6 +221,11 @@ function ProfileHeader() { )} {study?.studyType !== "gwas" && ( <> + {study?.projectId && ( + + {study?.projectId?.replace(/_/gi, " ")} + + )} {target?.id && ( {target.approvedSymbol} diff --git a/apps/platform/src/pages/StudyPage/Header.tsx b/apps/platform/src/pages/StudyPage/Header.tsx index 35150ea40..2d71ea058 100644 --- a/apps/platform/src/pages/StudyPage/Header.tsx +++ b/apps/platform/src/pages/StudyPage/Header.tsx @@ -67,7 +67,7 @@ function Header({ ); } sourceLink = { - id: "UKB", + id: "UKB-PPP", url: "https://www.synapse.org/Synapse:syn51364943/wiki/622119", }; } else { diff --git a/apps/platform/src/pages/StudyPage/StudyProfileHeader.gql b/apps/platform/src/pages/StudyPage/StudyProfileHeader.gql index 4f04c6e46..aebef59f1 100644 --- a/apps/platform/src/pages/StudyPage/StudyProfileHeader.gql +++ b/apps/platform/src/pages/StudyPage/StudyProfileHeader.gql @@ -5,6 +5,7 @@ fragment StudyProfileHeaderFragment on Gwas { publicationJournal pubmedId traitFromSource + projectId backgroundTraits { id name diff --git a/apps/platform/src/pages/StudyPage/StudyProfileHeader.tsx b/apps/platform/src/pages/StudyPage/StudyProfileHeader.tsx index 3e315d1ef..5f7e64198 100644 --- a/apps/platform/src/pages/StudyPage/StudyProfileHeader.tsx +++ b/apps/platform/src/pages/StudyPage/StudyProfileHeader.tsx @@ -8,6 +8,7 @@ import { SummaryStatsTable, LabelChip, DisplaySampleSize, + PublicationsDrawer, } from "ui"; import { Box } from "@mui/material"; import { populationMap } from "../../constants"; @@ -33,6 +34,7 @@ function ProfileHeader() { traitFromSource, backgroundTraits, diseases, + projectId, target, nCases, nControls, @@ -80,6 +82,11 @@ function ProfileHeader() { )} {studyType !== "gwas" && ( // QTL <> + {projectId && ( + + {projectId?.replace(/_/gi, " ")} + + )} {target?.id && ( {target.approvedSymbol} @@ -108,9 +115,10 @@ function ProfileHeader() { )} {pubmedId && - - {pubmedId} - + } diff --git a/packages/sections/src/constants.js b/packages/sections/src/constants.js index 358627ea0..34fe60d9c 100644 --- a/packages/sections/src/constants.js +++ b/packages/sections/src/constants.js @@ -119,3 +119,14 @@ export const initialResponse = { error: null, loading: true, }; + +export const QTLStudyType = [ + "scsqtl", + "sceqtl", + "scpqtl", + "sctuqtl", + "sqtl", + "eqtl", + "pqtl", + "tuqtl", +]; diff --git a/packages/sections/src/credibleSet/GWASColoc/Body.tsx b/packages/sections/src/credibleSet/GWASColoc/Body.tsx index fd5bcacd0..99355d2df 100644 --- a/packages/sections/src/credibleSet/GWASColoc/Body.tsx +++ b/packages/sections/src/credibleSet/GWASColoc/Body.tsx @@ -53,8 +53,7 @@ const columns = [ : publicationFirstAuthor || naLabel; }, exportValue: ({ otherStudyLocus }) => { - const { projectId, publicationFirstAuthor } = otherStudyLocus.study || {}; - getStudyCategory(projectId) === "FINNGEN" ? "FinnGen" : publicationFirstAuthor; + return otherStudyLocus?.study?.publicationFirstAuthor; }, }, { diff --git a/packages/sections/src/credibleSet/GWASColoc/Description.tsx b/packages/sections/src/credibleSet/GWASColoc/Description.tsx index 53a88e985..9cca248ba 100644 --- a/packages/sections/src/credibleSet/GWASColoc/Description.tsx +++ b/packages/sections/src/credibleSet/GWASColoc/Description.tsx @@ -4,7 +4,7 @@ function Description() { return ( <> Colocalisation metrics for overlapping credible sets from GWAS studies. Source:{" "} - + Open Targets > diff --git a/packages/sections/src/credibleSet/Locus2Gene/Body.tsx b/packages/sections/src/credibleSet/Locus2Gene/Body.tsx index c2b5f949a..2ea037347 100644 --- a/packages/sections/src/credibleSet/Locus2Gene/Body.tsx +++ b/packages/sections/src/credibleSet/Locus2Gene/Body.tsx @@ -21,6 +21,7 @@ const columns = [ if (!target) return naLabel; return {target?.approvedSymbol}; }, + exportValue: ({ target }) => target?.id, }, { id: "score", diff --git a/packages/sections/src/credibleSet/Locus2Gene/Description.tsx b/packages/sections/src/credibleSet/Locus2Gene/Description.tsx index 4bdaab04c..94389c54a 100644 --- a/packages/sections/src/credibleSet/Locus2Gene/Description.tsx +++ b/packages/sections/src/credibleSet/Locus2Gene/Description.tsx @@ -5,7 +5,9 @@ function Description(): ReactElement { return ( <> Gene assignment based on machine-learning prioritisation of credible set features. Source:{" "} - Open Targets + + Open Targets + > ); } diff --git a/packages/sections/src/credibleSet/MolQTLColoc/Body.tsx b/packages/sections/src/credibleSet/MolQTLColoc/Body.tsx index 3083f2954..3156448e2 100644 --- a/packages/sections/src/credibleSet/MolQTLColoc/Body.tsx +++ b/packages/sections/src/credibleSet/MolQTLColoc/Body.tsx @@ -13,7 +13,6 @@ import { definition } from "."; import Description from "./Description"; import MOLQTL_COLOC_QUERY from "./MolQTLColocQuery.gql"; import { mantissaExponentComparator, variantComparator } from "../../utils/comparators"; -import { getStudyCategory } from "../../utils/getStudyCategory"; import { useEffect, useState } from "react"; const columns = [ @@ -35,45 +34,41 @@ const columns = [ }, }, { - id: "otherStudyLocus.study.traitFromSource", - label: "Reported trait", + id: "otherStudyLocus.study.studyType", + label: "Type", renderCell: ({ otherStudyLocus }) => { - const trait = otherStudyLocus?.study?.traitFromSource; - if (!trait) return naLabel; - return trait; + const studyType = otherStudyLocus?.study?.studyType; + if (!studyType) return naLabel; + return studyType; }, }, { - id: "otherStudyLocus.study.publicationFirstAuthor", - label: "First author", + id: "otherStudyLocus.study.target.approvedSymbol", + label: "Affected gene", renderCell: ({ otherStudyLocus }) => { - const { projectId, publicationFirstAuthor } = otherStudyLocus?.study || {}; - return getStudyCategory(projectId) === "FINNGEN" - ? "FinnGen" - : publicationFirstAuthor || naLabel; - }, - exportValue: ({ otherStudyLocus }) => { - const { projectId, publicationFirstAuthor } = otherStudyLocus.study || {}; - getStudyCategory(projectId) === "FINNGEN" ? "FinnGen" : publicationFirstAuthor; + const target = otherStudyLocus?.study?.target; + if (!target) return naLabel; + return {target.approvedSymbol}; }, }, + { - id: "otherStudyLocus.study.studyType", + id: "otherStudyLocus.study.biosample.biosampleName", label: "Affected tissue/cell", renderCell: ({ otherStudyLocus }) => { const biosample = otherStudyLocus?.study?.biosample; if (!biosample) return naLabel; - return {biosample.name}; + return ( + + {biosample.biosampleName} + + ); }, }, { - id: "otherStudyLocus.study.studyType", - label: "QTL type", - renderCell: ({ otherStudyLocus }) => { - const studyType = otherStudyLocus?.study?.studyType; - if (!studyType) return naLabel; - return studyType; - }, + id: "otherStudyLocus.study.condition", + label: "Condition", + renderCell: ({ otherStudyLocus }) => otherStudyLocus?.study?.condition || naLabel, }, { id: "otherStudyLocus.variant.id", @@ -222,17 +217,15 @@ type BodyProps = { function Body({ studyLocusId, entity }: BodyProps) { const variables = { studyLocusId: studyLocusId, + size: table5HChunkSize, + index: 0, }; const [request, setRequest] = useState(initialResponse); const getData = useBatchQuery({ query: MOLQTL_COLOC_QUERY, - variables: { - studyLocusId, - size: table5HChunkSize, - index: 0, - }, + variables, dataPath: "data.credibleSet.colocalisation", size: table5HChunkSize, }); diff --git a/packages/sections/src/credibleSet/MolQTLColoc/Description.tsx b/packages/sections/src/credibleSet/MolQTLColoc/Description.tsx index 731d474ce..47ec68866 100644 --- a/packages/sections/src/credibleSet/MolQTLColoc/Description.tsx +++ b/packages/sections/src/credibleSet/MolQTLColoc/Description.tsx @@ -4,7 +4,7 @@ function Description() { return ( <> Colocalisation metrics for overlapping credible sets from molecular QTL studies. Source:{" "} - + Open Targets > diff --git a/packages/sections/src/credibleSet/MolQTLColoc/MolQTLColocQuery.gql b/packages/sections/src/credibleSet/MolQTLColoc/MolQTLColocQuery.gql index bc49ca334..29cddc9b6 100644 --- a/packages/sections/src/credibleSet/MolQTLColoc/MolQTLColocQuery.gql +++ b/packages/sections/src/credibleSet/MolQTLColoc/MolQTLColocQuery.gql @@ -1,6 +1,9 @@ query MolQTLColocQuery($studyLocusId: String!, $size: Int!, $index: Int!) { credibleSet(studyLocusId: $studyLocusId) { - colocalisation(studyTypes: [tuqtl, pqtl, eqtl, sqtl], page: { size: $size, index: $index }) { + colocalisation( + studyTypes: [scsqtl, sceqtl, scpqtl, sctuqtl, sqtl, eqtl, pqtl, tuqtl] + page: { size: $size, index: $index } + ) { count rows { otherStudyLocus { @@ -11,6 +14,7 @@ query MolQTLColocQuery($studyLocusId: String!, $size: Int!, $index: Int!) { projectId traitFromSource publicationFirstAuthor + condition target { approvedSymbol id diff --git a/packages/sections/src/credibleSet/MolQTLColoc/MolQTLColocSummaryFragment.gql b/packages/sections/src/credibleSet/MolQTLColoc/MolQTLColocSummaryFragment.gql index f560a26be..ac0d1eb97 100644 --- a/packages/sections/src/credibleSet/MolQTLColoc/MolQTLColocSummaryFragment.gql +++ b/packages/sections/src/credibleSet/MolQTLColoc/MolQTLColocSummaryFragment.gql @@ -1,6 +1,6 @@ fragment MolQTLColocSummaryFragment on credibleSet { molqtlcolocalisation: colocalisation( - studyTypes: [tuqtl, pqtl, eqtl, sqtl] + studyTypes: [scsqtl, sceqtl, scpqtl, sctuqtl, sqtl, eqtl, pqtl, tuqtl] page: { size: 1, index: 0 } ) { count diff --git a/packages/sections/src/credibleSet/Variants/Body.tsx b/packages/sections/src/credibleSet/Variants/Body.tsx index 78c4439a3..dff9808dd 100644 --- a/packages/sections/src/credibleSet/Variants/Body.tsx +++ b/packages/sections/src/credibleSet/Variants/Body.tsx @@ -91,7 +91,7 @@ function getColumns({ leadVariantId, leadReferenceAllele, leadAlternateAllele }: tooltip: "Beta with respect to the ALT allele", renderCell: ({ beta }) => { if (typeof beta !== "number") return naLabel; - return beta.toFixed(3); + return beta.toPrecision(3); }, }, { @@ -138,7 +138,7 @@ function getColumns({ leadVariantId, leadReferenceAllele, leadAlternateAllele }: sortable: true, renderCell: ({ posteriorProbability }) => { if (typeof posteriorProbability !== "number") return naLabel; - return posteriorProbability.toFixed(3); + return posteriorProbability.toPrecision(3); }, }, { diff --git a/packages/sections/src/credibleSet/Variants/Description.tsx b/packages/sections/src/credibleSet/Variants/Description.tsx index e6ad68d06..dcb6b0516 100644 --- a/packages/sections/src/credibleSet/Variants/Description.tsx +++ b/packages/sections/src/credibleSet/Variants/Description.tsx @@ -4,7 +4,7 @@ function Description() { return ( <> Set of variants with 95% probability of containing the causal variant. Source:{" "} - + Open Targets > diff --git a/packages/sections/src/evidence/GWASCredibleSets/Body.jsx b/packages/sections/src/evidence/GWASCredibleSets/Body.jsx index 3110ee9fa..b16796b67 100644 --- a/packages/sections/src/evidence/GWASCredibleSets/Body.jsx +++ b/packages/sections/src/evidence/GWASCredibleSets/Body.jsx @@ -27,6 +27,7 @@ function getColumns(targetSymbol) { renderCell: ({ credibleSet }) => { return ; }, + exportValue: ({ credibleSet }) => credibleSet?.studyLocusId, }, { id: "variantId", @@ -45,19 +46,22 @@ function getColumns(targetSymbol) { /> }, - filterValue: ({ variant: v }) => + filterValue: ({ credibleSet: { variant: v } }) => `${v?.chromosome}_${v?.position}_${v?.referenceAllele}_${v?.alternateAllele}`, + exportValue: ({ credibleSet: { variant: v } }) => `${v?.chromosome}_${v?.position}_${v?.referenceAllele}_${v?.alternateAllele}`, }, { id: "trait", label: "Reported trait", renderCell: ({ credibleSet }) => credibleSet?.study.traitFromSource, + exportValue: ({ credibleSet }) => credibleSet?.study.traitFromSource, }, { id: "disease", label: "Disease/phenotype", renderCell: ({ disease }) => {disease.name}, filterValue: ({ disease }) => disease.name, + exportValue: ({ disease }) => `${disease.name} (${disease.id})`, }, { id: "study", @@ -65,6 +69,7 @@ function getColumns(targetSymbol) { renderCell: ({ credibleSet }) => { return {credibleSet?.study.id}; }, + exportValue: ({ credibleSet }) => credibleSet?.study.id, }, { id: "nSamples", @@ -76,6 +81,7 @@ function getColumns(targetSymbol) { ? parseInt(credibleSet?.study.nSamples, 10).toLocaleString() : naLabel, filterValue: ({ credibleSet }) => parseInt(credibleSet?.study.nSamples, 10).toLocaleString(), + exportValue: ({ credibleSet }) => credibleSet?.study.nSamples, }, { id: "pValue", @@ -126,11 +132,13 @@ function getColumns(targetSymbol) { ); }, filterValue: ({ credibleSet }) => credsetConfidenceMap[credibleSet?.confidence], + exportValue: ({ credibleSet }) => credibleSet?.confidence, }, { id: "finemappingMethod", label: "Fine-mapping method", renderCell: ({ credibleSet }) => credibleSet?.finemappingMethod || naLabel, + exportValue: ({ credibleSet }) => credibleSet?.finemappingMethod, }, { id: "score", @@ -176,6 +184,7 @@ function getColumns(targetSymbol) { }, filterValue: ({ literature, publicationYear, publicationFirstAuthor }) => `${literature} ${publicationYear} ${publicationFirstAuthor}`, + exportValue: ({ credibleSet }) => credibleSet?.study.pubmedId, }, ]; } diff --git a/packages/sections/src/evidence/GWASCredibleSets/Description.jsx b/packages/sections/src/evidence/GWASCredibleSets/Description.jsx index 5f22339a4..e8e7faaa7 100644 --- a/packages/sections/src/evidence/GWASCredibleSets/Description.jsx +++ b/packages/sections/src/evidence/GWASCredibleSets/Description.jsx @@ -6,8 +6,8 @@ function Description({ symbol, name }) { <> 95% GWAS credible sets prioritisating {symbol} as likely causal gene for{" "} {name}. Source:{" "} - - Open Targets Genetics + + Open Targets > ); diff --git a/packages/sections/src/evidence/GWASCredibleSets/index.js b/packages/sections/src/evidence/GWASCredibleSets/index.js index 64a8fa54c..cc23b81e1 100644 --- a/packages/sections/src/evidence/GWASCredibleSets/index.js +++ b/packages/sections/src/evidence/GWASCredibleSets/index.js @@ -3,8 +3,8 @@ import { isPrivateEvidenceSection } from "../../utils/partnerPreviewUtils"; const id = "gwas_credible_sets"; export const definition = { id, - name: "GWAS credible sets", - shortName: "GC", + name: "GWAS associations", + shortName: "GW", hasData: data => data.gwasCredibleSets.count > 0, isPrivate: isPrivateEvidenceSection(id), }; diff --git a/packages/sections/src/study/GWASCredibleSets/Body.tsx b/packages/sections/src/study/GWASCredibleSets/Body.tsx index 54b246555..b94fce994 100644 --- a/packages/sections/src/study/GWASCredibleSets/Body.tsx +++ b/packages/sections/src/study/GWASCredibleSets/Body.tsx @@ -79,7 +79,7 @@ const columns = [ tooltip: "Beta with respect to the ALT allele", renderCell: ({ beta }) => { if (typeof beta !== "number") return naLabel; - return beta.toFixed(3); + return beta.toPrecision(3); }, }, { @@ -134,6 +134,7 @@ const columns = [ ); }, + exportValue: ({ l2GPredictions }) => l2GPredictions?.rows[0]?.score, }, { id: "credibleSetSize", diff --git a/packages/sections/src/study/GWASCredibleSets/Description.tsx b/packages/sections/src/study/GWASCredibleSets/Description.tsx index 2d6b88112..eb078487a 100644 --- a/packages/sections/src/study/GWASCredibleSets/Description.tsx +++ b/packages/sections/src/study/GWASCredibleSets/Description.tsx @@ -9,7 +9,7 @@ function Description({ studyId }: DescriptionProps) { <> 95% GWAS credible sets associated with study {" "} {studyId}. Source{" "} - + Open Targets > diff --git a/packages/sections/src/study/GWASCredibleSets/ManhattanPlot.tsx b/packages/sections/src/study/GWASCredibleSets/ManhattanPlot.tsx index 44546b99b..03626e551 100644 --- a/packages/sections/src/study/GWASCredibleSets/ManhattanPlot.tsx +++ b/packages/sections/src/study/GWASCredibleSets/ManhattanPlot.tsx @@ -1,7 +1,11 @@ -import { Skeleton, useTheme } from "@mui/material"; +import { Box, Skeleton, useTheme } from "@mui/material"; import { + ClinvarStars, Link, + Tooltip, DisplayVariantId, + Navigate, + OtScoreLinearBar, Plot, Vis, XAxis, @@ -19,13 +23,13 @@ import { HTMLTooltipTable, HTMLTooltipRow, } from "ui"; -import { scaleLinear, scaleLog, min } from "d3"; +import { scaleLinear, min } from "d3"; import { ScientificNotation } from "ui"; -import { naLabel } from "../../constants"; +import { naLabel, credsetConfidenceMap } from "../../constants"; export default function ManhattanPlot({ loading, data }) { - const plotHeight = 390; + const plotHeight = 410; const theme = useTheme(); const background = theme.palette.background.paper; const markColor = theme.palette.primary.main; @@ -42,15 +46,24 @@ export default function ManhattanPlot({ loading, data }) { d.variant != null; }); if (data.length === 0) return null; + // eslint-disable-next-line + data = structuredClone(data); + data.forEach(d => { + d._y = Math.log10(d.pValueMantissa) + d.pValueExponent; + }); - const pValueMin = min(data, pValue); - const pValueMax = 1; + const yMin = min(data, d => d._y); + const yMax = 0; const genomePositions = {}; data.forEach(({ variant }) => { genomePositions[variant.id] = cumulativePosition(variant); }); + const xScale = scaleLinear().domain([0, genomeLength]); + const yScale = scaleLinear().domain([yMin, yMax]).nice(); // ensure min scale value <= yMin + yScale.domain([yScale.domain()[0], yMax]); // ensure max scale value is yMax - in case nice changed it + return ( @@ -63,13 +76,9 @@ export default function ManhattanPlot({ loading, data }) { fontFamily={fontFamily} data={data} yReverse - scales={{ - x: scaleLinear().domain([0, genomeLength]), - y: scaleLog().domain([pValueMin, pValueMax]), - }} + scales={{ x: xScale, y: yScale }} xTick={chromosomeInfo} > - [0, ...tickData.map(chromo => chromo.end)]} tickLength={15} @@ -91,13 +100,13 @@ export default function ManhattanPlot({ loading, data }) { - -Math.log10(v)} /> + Math.abs(v)} /> genomePositions[d.variant.id]} xx={d => genomePositions[d.variant.id]} - y={pValue} - yy={pValueMax} + y={d => d._y} + yy={yMax} stroke={markColor} strokeWidth={1} strokeOpacity={0.7} @@ -105,7 +114,7 @@ export default function ManhattanPlot({ loading, data }) { /> genomePositions[d.variant.id]} - y={pValue} + y={d => d._y} fill={background} stroke={markColor} strokeWidth={1.2} @@ -119,8 +128,8 @@ export default function ManhattanPlot({ loading, data }) { x={0} xx={genomeLength} dxx={8} - y={pValueMin} - yy={pValueMax} + y={yMin} + yy={yMax} dy={-8} dyy={0} fill={background} @@ -130,8 +139,8 @@ export default function ManhattanPlot({ loading, data }) { dataFrom="hover" x={d => genomePositions[d.variant.id]} xx={d => genomePositions[d.variant.id]} - y={pValue} - yy={pValueMax} + y={d => d._y} + yy={yMax} stroke={markColor} strokeWidth={1.7} strokeOpacity={1} @@ -139,15 +148,15 @@ export default function ManhattanPlot({ loading, data }) { genomePositions[d.variant.id]} - y={pValue} + y={d => d._y} fill={markColor} area={circleArea} /> genomePositions[d.variant.id]} - y={pValue} + y={d => d._y} pxWidth={290} - pxHeight={200} + pxHeight={210} content={tooltipContent} /> @@ -164,8 +173,10 @@ export default function ManhattanPlot({ loading, data }) { function tooltipContent(data) { return ( - - view + + + + @@ -178,44 +189,60 @@ function tooltipContent(data) { - + - {data.beta?.toFixed(3) ?? naLabel} + {data.beta?.toPrecision(3) ?? naLabel} + - {data.finemappingMethod ?? naLabel} + + + Method:{" "}{data.finemappingMethod ?? naLabel} + + + Confidence:{" "} + {data.confidence + ? + + + : naLabel + } + + + - {data.l2Gpredictions?.[0]?.target - ? - - {data.l2Gpredictions[0].target.approvedSymbol} - - - : - {naLabel} - - } - - {data.l2Gpredictions?.[0]?.score != null - ? data.l2Gpredictions[0].score.toFixed(3) - : naLabel - } + + + + Top:{" "} + {data.l2GPredictions?.rows?.[0]?.target + ? + {data.l2GPredictions.rows[0].target.approvedSymbol} + + : naLabel + } + + + Score:{" "} + {data.l2GPredictions?.rows?.[0]?.score + ? + + + + + : naLabel + } + + - {data.locus?.count ?? naLabel} + {data.locus?.count ? data.locus.count.toLocaleString() : naLabel} ); } -function pValue(row) { - return Math.max( - row.pValueMantissa * 10 ** row.pValueExponent, - Number.MIN_VALUE - ); -} - // from: https://www.ncbi.nlm.nih.gov/grc/human/data // (first tab: "Chromosome lengths") const chromosomeInfo = [ diff --git a/packages/sections/src/study/QTLCredibleSets/Description.tsx b/packages/sections/src/study/QTLCredibleSets/Description.tsx index dd1e11266..bc2653ef4 100644 --- a/packages/sections/src/study/QTLCredibleSets/Description.tsx +++ b/packages/sections/src/study/QTLCredibleSets/Description.tsx @@ -12,6 +12,10 @@ function Description({ studyId }: DescriptionProps) { eQTL Catalog + ,{" "} + + UKB-PPP + > ); } diff --git a/packages/sections/src/study/SharedTraitStudies/Body.tsx b/packages/sections/src/study/SharedTraitStudies/Body.tsx index d0cd10394..c122aa94d 100644 --- a/packages/sections/src/study/SharedTraitStudies/Body.tsx +++ b/packages/sections/src/study/SharedTraitStudies/Body.tsx @@ -23,6 +23,7 @@ function getColumns(diseaseIds: string[]) { id: "studyId", label: "Study", renderCell: ({ id }) => {id}, + exportValue: ({ id }) => id, }, { id: "sharedDiseases", @@ -111,6 +112,8 @@ function getColumns(diseaseIds: string[]) { }, filterValue: ({ publicationYear, publicationFirstAuthor }) => `${publicationYear} ${publicationFirstAuthor}`, + exportValue: ({ pubmedId }) => + `${pubmedId}`, }, ]; } diff --git a/packages/sections/src/variant/GWASCredibleSets/Body.tsx b/packages/sections/src/variant/GWASCredibleSets/Body.tsx index b6813ec82..5cd9da27b 100644 --- a/packages/sections/src/variant/GWASCredibleSets/Body.tsx +++ b/packages/sections/src/variant/GWASCredibleSets/Body.tsx @@ -100,6 +100,7 @@ function getColumns({ id, referenceAllele, alternateAllele }: getColumnsType) { if (!study) return naLabel; return {study.id}; }, + exportValue: ({ study }) => study?.id, }, { id: "pValue", @@ -133,7 +134,7 @@ function getColumns({ id, referenceAllele, alternateAllele }: getColumnsType) { sortable: true, renderCell: ({ beta }) => { if (typeof beta !== "number") return naLabel; - return beta.toFixed(3); + return beta.toPrecision(3); }, }, { @@ -159,9 +160,9 @@ function getColumns({ id, referenceAllele, alternateAllele }: getColumnsType) { }, sortable: true, renderCell: ({ locus }) => - locus.count > 0 ? locus?.rows[0]?.posteriorProbability.toFixed(3) : naLabel, + locus.rows.length > 0 ? locus?.rows[0]?.posteriorProbability.toFixed(3) : naLabel, exportValue: ({ locus }) => - locus.count > 0 ? locus?.rows[0]?.posteriorProbability.toFixed(3) : naLabel, + locus.rows.length > 0 ? locus?.rows[0]?.posteriorProbability.toFixed(3) : naLabel, }, { id: "finemappingMethod", @@ -193,7 +194,7 @@ function getColumns({ id, referenceAllele, alternateAllele }: getColumnsType) { const { target } = l2GPredictions?.rows[0]; return {target.approvedSymbol}; }, - exportValue: ({ l2GPredictions }) => l2GPredictions?.target.approvedSymbol, + exportValue: ({ l2GPredictions }) => l2GPredictions?.rows[0]?.target.approvedSymbol, }, { id: "l2gScore", @@ -214,20 +215,21 @@ function getColumns({ id, referenceAllele, alternateAllele }: getColumnsType) { ); }, + exportValue: ({ l2GPredictions }) => l2GPredictions?.rows[0]?.score, }, { id: "credibleSetSize", label: "Credible set size", - comparator: (a, b) => a.locus?.count - b.locus?.count, + comparator: (a, b) => a.locusSize?.count - b.locusSize?.count, sortable: true, numeric: true, filterValue: false, - renderCell: ({ locus }) => { - return typeof locus?.count === "number" - ? locus.count.toLocaleString() + renderCell: ({ locusSize }) => { + return typeof locusSize?.count === "number" + ? locusSize.count.toLocaleString() : naLabel; }, - exportValue: ({ locus }) => locus?.count, + exportValue: ({ locusSize }) => locusSize?.count, }, ]; } @@ -281,6 +283,8 @@ function Body({ id, entity }: BodyProps) { loading={request.loading} data={request.data?.variant.gwasCredibleSets.rows} id={id} + referenceAllele={request.data?.variant.referenceAllele} + alternateAllele={request.data?.variant.alternateAllele} /> ); }} diff --git a/packages/sections/src/variant/GWASCredibleSets/Description.tsx b/packages/sections/src/variant/GWASCredibleSets/Description.tsx index 985d58e7c..3ae487f95 100644 --- a/packages/sections/src/variant/GWASCredibleSets/Description.tsx +++ b/packages/sections/src/variant/GWASCredibleSets/Description.tsx @@ -18,7 +18,7 @@ function Description({ variantId, referenceAllele, alternateAllele }: Descriptio /> . Source{" "} - + Open Targets > diff --git a/packages/sections/src/variant/GWASCredibleSets/GWASCredibleSetsQuery.gql b/packages/sections/src/variant/GWASCredibleSets/GWASCredibleSetsQuery.gql index 55cb0d234..ca730f6bd 100644 --- a/packages/sections/src/variant/GWASCredibleSets/GWASCredibleSetsQuery.gql +++ b/packages/sections/src/variant/GWASCredibleSets/GWASCredibleSetsQuery.gql @@ -32,12 +32,14 @@ query GWASCredibleSetsQuery($variantId: String!, $size: Int!, $index: Int!) { } } locus(variantIds: [$variantId]) { - count rows { posteriorProbability } } - l2GPredictions(page: { size: 1, index: 1 }) { + locusSize: locus { + count + } + l2GPredictions(page: { size: 1, index: 0 }) { rows { target { id diff --git a/packages/sections/src/variant/GWASCredibleSets/PheWasPlot.tsx b/packages/sections/src/variant/GWASCredibleSets/PheWasPlot.tsx index d97fcea9b..573f2a85c 100644 --- a/packages/sections/src/variant/GWASCredibleSets/PheWasPlot.tsx +++ b/packages/sections/src/variant/GWASCredibleSets/PheWasPlot.tsx @@ -1,4 +1,4 @@ -import { Box, Skeleton, useTheme } from "@mui/material"; +import { Box, Skeleton, Typography, useTheme } from "@mui/material"; import { faArrowRightToBracket } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { @@ -10,7 +10,6 @@ import { Plot, Vis, YAxis, - XTick, YTick, XLabel, YLabel, @@ -22,17 +21,19 @@ import { HTMLTooltipTable, HTMLTooltipRow, } from "ui"; -import { scaleLinear, scaleLog, min, scaleOrdinal, schemeCategory10, schemeDark2 } from "d3"; +import { scaleLinear, min, scaleOrdinal } from "d3"; import { ScientificNotation } from "ui"; import { naLabel, credsetConfidenceMap } from "../../constants"; import { Fragment } from "react/jsx-runtime"; -export default function PheWasPlot({ loading, data, id }) { +const plotHeight = 450; +const tooltipHeight = 310; +const tooltipWidth = 360; + +export default function PheWasPlot({ loading, data, id, referenceAllele, alternateAllele }) { - const plotHeight = 440; const theme = useTheme(); const background = theme.palette.background.paper; - // const markColor = theme.palette.primary.main; const fontFamily = theme.typography.fontFamily; const pointArea = 64; @@ -50,9 +51,6 @@ export default function PheWasPlot({ loading, data, id }) { '#188E61', '#BEE952', ]; - // const palette = schemeCategory10; - // const palette = schemeDark2; - // const palette = schemeSet1; if (loading) return ; if (data == null) return null; @@ -63,11 +61,15 @@ export default function PheWasPlot({ loading, data, id }) { d.pValueExponent != null && d.variant != null; }); - if (data.length === 0) return null; + // eslint-disable-next-line + data = structuredClone(data); + data.forEach(d => { + d._y = Math.log10(d.pValueMantissa) + d.pValueExponent; + }); - const pValueMin = min(data, pValue); - const pValueMax = 1; + const yMin = min(data, d => d._y); + const yMax = 0; const rowLookup = new Map(); // derived values for each row const diseaseGroups = new Map(); @@ -84,26 +86,20 @@ export default function PheWasPlot({ loading, data, id }) { .sort((a, b) => a[1].name.localeCompare(b[1].name)) .map(a => a[0]); if (diseaseGroups.has('__uncategorised__')) { - sortedDiseaseIds = sortedDiseaseIds.filter(id => id === '__uncategorised__'); - sortedDiseaseIds.shift('__uncategorised__'); + sortedDiseaseIds = sortedDiseaseIds.filter(id => id !== '__uncategorised__'); + sortedDiseaseIds.push('__uncategorised__'); } const xIntervals = new Map(); - // const xMidpoints = []; let xCumu = 0; - // const xGap = Math.ceil(data.length / 100); // gap between groups - // const xPad = Math.ceil(data.length / 100); // padding at ede of groups const xGap = data.length / 300; // gap between groups - // const xGap = 0; const xPad = data.length / 500; // padding at ede of groups const sortedData = []; - // const sortedDiseaseNames = []; for (const id of sortedDiseaseIds) { - const { name, data: newRows } = diseaseGroups.get(id); - // sortedDiseaseNames.push(name); + const { data: newRows } = diseaseGroups.get(id); xCumu += xGap; xIntervals.set(id, { start: xCumu }); xCumu += xPad; - newRows.sort((row1, row2) => pValue(row1) - pValue(row2)); + newRows.sort((row1, row2) => row1._y - row2._y); for (const row of newRows) { rowLookup.get(row).x = xCumu + 0.5; xCumu += 1; @@ -113,15 +109,9 @@ export default function PheWasPlot({ loading, data, id }) { xIntervals.get(id).end = xCumu; } - function xAnchor(row) { - const x = rowLookup.get(row).x; - return x < xCumu / 2 ? 'left' : 'right'; - } - - function yAnchor(row) { - const y = pValue(row); - return Math.log10(y) > Math.log10(pValueMin) / 2 ? 'bottom' : 'top'; - } + const xScale = scaleLinear().domain([0, xCumu]); + const yScale = scaleLinear().domain([yMin, yMax]).nice(); // ensure min scale value <= yMin + yScale.domain([yScale.domain()[0], yMax]); // ensure max scale value is yMax - in case nice changed it const colorDomain = ['background']; const colorRange = [background]; @@ -133,7 +123,7 @@ export default function PheWasPlot({ loading, data, id }) { const pointAttrs = { x: d => rowLookup.get(d).x, - y: pValue, + y: d => d._y, fill: d => { return d.variant.id === id ? rowLookup.get(d).therapeuticAreaId : 'background'; }, @@ -146,117 +136,129 @@ export default function PheWasPlot({ loading, data, id }) { } return ( - + <> - - {/* */} - {/* need to use different XLabel elements to use different colors */} + {/* legend */} + + ▲ Beta > 0 + ▼ Beta < 0 + ● Beta {naLabel} + Filled symbol:{" "} + + + + {" "}is lead variant + + + {/* plot */} + + + + + {[...xIntervals].map(([id, { start, end }]) => ( + + diseaseGroups.get(id).name} + padding={3} + textAnchor="start" + dx={-2} + style={{ + transformOrigin: '0% 50%', + transformBox: 'fill-box', + transform: "rotate(45deg)", + }} + fill={colorScale(id)} + /> + + ))} + d[1].start} + xx={d => d[1].end} + y={yMax} + yy={yMax} + stroke={d => d[0]} + strokeWidth={1} + /> + + -log + 10 + (pValue) + + + + Math.abs(v)} /> + - {[...xIntervals].map(([id, { start, end }]) => ( - - {/* */} - diseaseGroups.get(id).name} - padding={3} - textAnchor="start" - dx={-2} - style={{ - transformOrigin: '0% 50%', - transformBox: 'fill-box', - transform: "rotate(45deg)", - }} - fill={colorScale(id)} - /> - - ))} - d[1].start} - xx={d => d[1].end} - y={pValueMax} - yy={pValueMax} - stroke={d => d[0]} - strokeWidth={1} - /> - {/* */} - - -log - 10 - (pValue) - - - - -Math.log10(v)} /> - + {/* on hover */} + + + rowLookup.get(d).x} + y={d => yMin} + pxWidth={tooltipWidth} + pxHeight={tooltipHeight} + content={tooltipContent} + xOffset={40} + yOffset={-20} + /> - {/* on hover */} - - - rowLookup.get(d).x} - y={d => pValueMin} - // y={pValue} - pxWidth={360} - pxHeight={350} - content={tooltipContent} - xOffset={40} - yOffset={-20} - /> + {/* axes at end so fade rectangle doesn't cover them */} + {/* */} + - {/* axes at end so fade rectangle doesn't cover them */} - {/* */} - + + - - + > ); } function tooltipContent(data) { - const labelWidth = 148; - // const valueWidth = 100; + const labelWidth = 160; return ( - + - + - + {data.study?.traitFromSource ?? naLabel} - + {data.study?.diseases?.length > 0 ? <> {data.study.diseases.map((d, i) => ( @@ -282,27 +296,30 @@ function tooltipContent(data) { : naLabel } - + {data.study - ? - {data.study.studyId} + ? + {data.study.id} : naLabel } - - + + - - {data.beta?.toFixed(3) ?? naLabel} + + {data.beta?.toPrecision(3) ?? naLabel} - - {data.locus?.rows?.[0].posteriorProbability.toFixed(3) ?? naLabel} + + {data.locus?.rows?.[0].posteriorProbability.toPrecision(3) ?? naLabel} - + - Confidence: + Method:{" "}{data.finemappingMethod ?? naLabel} + + + Confidence:{" "} {data.confidence ? @@ -310,28 +327,25 @@ function tooltipContent(data) { : naLabel } - - Method:{" "}{data.finemappingMethod ?? naLabel} - - + - Top: - {data.l2Gpredictions?.[0]?.target - ? - {data.l2Gpredictions[0].target.approvedSymbol} + Top:{" "} + {data.l2GPredictions?.rows?.[0]?.target + ? + {data.l2GPredictions.rows[0].target.approvedSymbol} : naLabel } - Score: - {data.l2Gpredictions?.[0]?.score - ? + Score:{" "} + {data.l2GPredictions?.rows?.[0]?.score + ? - + : naLabel @@ -339,43 +353,36 @@ function tooltipContent(data) { - - {data.locus?.count ?? naLabel} + + {data.locusSize?.count ?? naLabel} ); } -function pValue(row) { - return Math.max( - row.pValueMantissa * 10 ** row.pValueExponent, - Number.MIN_VALUE - ); -} - const therapeuticPriorities = { - MONDO_0045024: { name: "cell proliferation disorder", rank: 1 }, + MONDO_0045024: { name: "cell proliferation", rank: 1 }, EFO_0005741: { name: "infectious disease", rank: 2 }, - OTAR_0000014: { name: "pregnancy or perinatal disease", rank: 3 }, + OTAR_0000014: { name: "pregnancy or perinatal", rank: 3 }, EFO_0005932: { name: "animal disease", rank: 4 }, - MONDO_0024458: { name: "disease of visual system", rank: 5 }, - EFO_0000319: { name: "cardiovascular disease", rank: 6 }, - EFO_0009605: { name: "pancreas disease", rank: 7 }, - EFO_0010282: { name: "gastrointestinal disease", rank: 8 }, - OTAR_0000017: { name: "reproductive system or breast disease", rank: 9 }, - EFO_0010285: { name: "integumentary system disease", rank: 10 }, - EFO_0001379: { name: "endocrine system disease", rank: 11 }, - OTAR_0000010: { name: "respiratory or thoracic disease", rank: 12 }, - EFO_0009690: { name: "urinary system disease", rank: 13 }, - OTAR_0000006: { name: "musculoskeletal or connective tissue disease", rank: 14 }, + MONDO_0024458: { name: "visual system", rank: 5 }, + EFO_0000319: { name: "cardiovascular", rank: 6 }, + EFO_0009605: { name: "pancreas", rank: 7 }, + EFO_0010282: { name: "gastrointestinal", rank: 8 }, + OTAR_0000017: { name: "reproductive system or breast", rank: 9 }, + EFO_0010285: { name: "integumentary system", rank: 10 }, + EFO_0001379: { name: "endocrine system", rank: 11 }, + OTAR_0000010: { name: "respiratory or thoracic", rank: 12 }, + EFO_0009690: { name: "urinary system", rank: 13 }, + OTAR_0000006: { name: "musculoskeletal or connective ...", rank: 14 }, MONDO_0021205: { name: "disease of ear", rank: 15 }, - EFO_0000540: { name: "immune system disease", rank: 16 }, - EFO_0005803: { name: "hematologic disease", rank: 17 }, - EFO_0000618: { name: "nervous system disease", rank: 18 }, - MONDO_0002025: { name: "psychiatric disorder", rank: 19 }, - OTAR_0000020: { name: "nutritional or metabolic disease", rank: 20 }, - OTAR_0000018: { name: "genetic, familial or congenital disease", rank: 21 }, - OTAR_0000009: { name: "injury, poisoning or other complication", rank: 22 }, + EFO_0000540: { name: "immune system", rank: 16 }, + EFO_0005803: { name: "hematologic", rank: 17 }, + EFO_0000618: { name: "nervous system", rank: 18 }, + MONDO_0002025: { name: "psychiatric", rank: 19 }, + OTAR_0000020: { name: "nutritional or metabolic", rank: 20 }, + OTAR_0000018: { name: "genetic, familial or congenital", rank: 21 }, + OTAR_0000009: { name: "injury, poisoning or complication", rank: 22 }, EFO_0000651: { name: "phenotype", rank: 23 }, EFO_0001444: { name: "measurement", rank: 24 }, GO_0008150: { name: "biological process", rank: 25 }, diff --git a/packages/sections/src/variant/InSilicoPredictors/Body.tsx b/packages/sections/src/variant/InSilicoPredictors/Body.tsx index d3817250c..c00d0e4d2 100644 --- a/packages/sections/src/variant/InSilicoPredictors/Body.tsx +++ b/packages/sections/src/variant/InSilicoPredictors/Body.tsx @@ -1,3 +1,4 @@ +import { ReactElement } from "react"; import { useQuery } from "@apollo/client"; import { Typography } from "@mui/material"; import { SectionItem, Tooltip, OtTable } from "ui"; @@ -37,12 +38,14 @@ const columns = [ { id: "score", label: "Score", - renderCell: ({ score }) => score ?? naLabel, + numeric: true, + renderCell: ({ score }) => score?.toPrecision(3) ?? naLabel, }, { id: "normalisedScore", label: "Normalised score", - renderCell: ({ normalisedScore }) => normalisedScore ?? naLabel, + numeric: true, + renderCell: ({ normalisedScore }) => normalisedScore?.toFixed(3) ?? naLabel, }, ]; @@ -51,7 +54,15 @@ type BodyProps = { entity: string; }; -export function Body({ id, entity }: BodyProps) { +function getSortedRows(request) { + return request.data?.variant?.inSilicoPredictors + ? [...request.data.variant.inSilicoPredictors] + .filter(e => e.method !== null) + .sort((row1, row2) => row1.method.localeCompare(row2.method)) + : []; +} + +export function Body({ id, entity }: BodyProps): ReactElement { const variables = { variantId: id, }; @@ -72,20 +83,19 @@ export function Body({ id, entity }: BodyProps) { alternateAllele={request.data?.variant.alternateAllele} /> )} - renderChart={() => ( - - )} + renderChart={() => { + const rows = getSortedRows(request); + return ( + + ); + }} renderBody={() => { - let rows = []; - if (request.data) - rows = [...request.data.variant.inSilicoPredictors].sort((row1, row2) => { - return row1.method.localeCompare(row2.method); - }); + const rows = getSortedRows(request); return ( ( - - ), + renderCell: ({ studyLocusId }) => , }, { id: "leadVariant", @@ -105,6 +103,7 @@ function getColumns({ id, referenceAllele, alternateAllele }: getColumnsType) { ); }, + exportValue: ({ study }) => { return `[${study?.biosample?.biosampleId}]:${study?.biosample?.biosampleName}` }, }, { id: "study.condition", @@ -143,7 +142,7 @@ function getColumns({ id, referenceAllele, alternateAllele }: getColumnsType) { sortable: true, renderCell: ({ beta }) => { if (typeof beta !== "number") return naLabel; - return beta.toFixed(3); + return beta.toPrecision(3); }, }, { @@ -153,8 +152,9 @@ function getColumns({ id, referenceAllele, alternateAllele }: getColumnsType) { filterValue: false, sortable: true, comparator: (a, b) => { - return a?.locus?.rows?.[0]?.posteriorProbability - - b?.locus?.rows?.[0]?.posteriorProbability; + return ( + a?.locus?.rows?.[0]?.posteriorProbability - b?.locus?.rows?.[0]?.posteriorProbability + ); }, tooltip: ( <> @@ -169,9 +169,9 @@ function getColumns({ id, referenceAllele, alternateAllele }: getColumnsType) { > ), renderCell: ({ locus }) => - locus.count > 0 ? locus?.rows[0]?.posteriorProbability.toFixed(3) : naLabel, + locus.rows.length > 0 ? locus?.rows[0]?.posteriorProbability.toFixed(3) : naLabel, exportValue: ({ locus }) => - locus.count > 0 ? locus?.rows[0]?.posteriorProbability.toFixed(3) : naLabel, + locus.rows.length > 0 ? locus?.rows[0]?.posteriorProbability.toFixed(3) : naLabel, }, { id: "confidence", @@ -197,15 +197,13 @@ function getColumns({ id, referenceAllele, alternateAllele }: getColumnsType) { id: "credibleSetSize", label: "Credible set size", numeric: true, - comparator: (a, b) => a.locus?.count - b.locus?.count, + comparator: (a, b) => a.locusSize?.count - b.locusSize?.count, sortable: true, filterValue: false, - renderCell: ({ locus }) => { - return typeof locus?.count === "number" - ? locus.count.toLocaleString() - : naLabel; + renderCell: ({ locusSize }) => { + return typeof locusSize?.count === "number" ? locusSize.count.toLocaleString() : naLabel; }, - exportValue: ({ locus }) => locus?.count, + exportValue: ({ locusSize }) => locusSize?.count, }, ]; } @@ -218,17 +216,15 @@ type BodyProps = { function Body({ id, entity }: BodyProps): ReactNode { const variables = { variantId: id, + size: table5HChunkSize, + index: 0, }; const [request, setRequest] = useState(initialResponse); const getAllQtlData = useBatchQuery({ query: QTL_CREDIBLE_SETS_QUERY, - variables: { - variantId: id, - size: table5HChunkSize, - index: 0, - }, + variables, dataPath: "data.variant.qtlCredibleSets", size: table5HChunkSize, }); diff --git a/packages/sections/src/variant/QTLCredibleSets/Description.tsx b/packages/sections/src/variant/QTLCredibleSets/Description.tsx index 014b09642..ce0a8e245 100644 --- a/packages/sections/src/variant/QTLCredibleSets/Description.tsx +++ b/packages/sections/src/variant/QTLCredibleSets/Description.tsx @@ -22,7 +22,10 @@ function Description({ alternateAllele={alternateAllele} /> - . Source Open Targets + . Source{" "} + + Open Targets + > ); } diff --git a/packages/sections/src/variant/QTLCredibleSets/QTLCredibleSetsQuery.gql b/packages/sections/src/variant/QTLCredibleSets/QTLCredibleSetsQuery.gql index afe5f4cec..84060a2cd 100644 --- a/packages/sections/src/variant/QTLCredibleSets/QTLCredibleSetsQuery.gql +++ b/packages/sections/src/variant/QTLCredibleSets/QTLCredibleSetsQuery.gql @@ -4,7 +4,7 @@ query QTLCredibleSetsQuery($variantId: String!, $size: Int!, $index: Int!) { referenceAllele alternateAllele qtlCredibleSets: credibleSets( - studyTypes: [sqtl, pqtl, eqtl, tuqtl] + studyTypes: [scsqtl, sceqtl, scpqtl, sctuqtl, sqtl, eqtl, pqtl, tuqtl] page: { size: $size, index: $index } ) { count @@ -37,11 +37,13 @@ query QTLCredibleSetsQuery($variantId: String!, $size: Int!, $index: Int!) { } } locus(variantIds: [$variantId]) { - count rows { posteriorProbability } } + locusSize: locus { + count + } } } } diff --git a/packages/sections/src/variant/QTLCredibleSets/QTLCredibleSetsSummaryFragment.gql b/packages/sections/src/variant/QTLCredibleSets/QTLCredibleSetsSummaryFragment.gql index d517b547c..fea6d60ad 100644 --- a/packages/sections/src/variant/QTLCredibleSets/QTLCredibleSetsSummaryFragment.gql +++ b/packages/sections/src/variant/QTLCredibleSets/QTLCredibleSetsSummaryFragment.gql @@ -1,6 +1,6 @@ fragment QTLCredibleSetsSummaryFragment on Variant { qtlCredibleSets: credibleSets( - studyTypes: [sqtl, pqtl, eqtl, tuqtl] + studyTypes: [scsqtl, sceqtl, scpqtl, sctuqtl, sqtl, eqtl, pqtl, tuqtl] page: { size: 1, index: 0 } ) { count diff --git a/packages/sections/src/variant/VariantEffectPredictor/Body.tsx b/packages/sections/src/variant/VariantEffectPredictor/Body.tsx index 8930ee328..1b0bb594d 100644 --- a/packages/sections/src/variant/VariantEffectPredictor/Body.tsx +++ b/packages/sections/src/variant/VariantEffectPredictor/Body.tsx @@ -78,6 +78,14 @@ const columns = [ } return displayElement; }, + exportValue: ({ target, transcriptId, uniprotAccessions, aminoAcidChange }) => { + const geneInfo = `Gene: ${target?.id};`; + const canonicalTranscript = transcriptId ? `Canonical transcript: ${transcriptId};` : ""; + const biotype = `Biotype: ${target?.biotype};`; + const protein = uniprotAccessions?.length ? `Protein(s): ${uniprotAccessions.join(", ")}` : ""; + const aaChange = aminoAcidChange ? `AA: ${aminoAcidChange};` : ""; + return [geneInfo, canonicalTranscript, biotype, protein, aaChange].join(""); + } }, { id: "variantConsequences.label", diff --git a/packages/ui/src/components/Plot/components/XLabel.jsx b/packages/ui/src/components/Plot/components/XLabel.jsx index 88acc0058..587a71082 100644 --- a/packages/ui/src/components/Plot/components/XLabel.jsx +++ b/packages/ui/src/components/Plot/components/XLabel.jsx @@ -4,14 +4,14 @@ import { fromFrameOrPlot } from "../util/fromFrameOrPlot"; import { finalData } from "../util/finalData"; export default function XLabel({ - values, - position = 'bottom', - padding, - dx = 0, - dy = 0, - format, - ...textAttrs - }) { + values, + position = 'bottom', + padding, + dx = 0, + dy = 0, + format, + ...textAttrs +}) { const plot = usePlot(); if (!plot) { @@ -31,15 +31,13 @@ export default function XLabel({ ? v => plot.panelWidth - ops.scales.x(v) : ops.scales.x; - const leftOrigin = `translate(${ - plot.padding.left + dx},${ - position === 'top' - ? plot.padding.top - padding + dy - : plot.height - plot.padding.bottom + padding + dy - })`; + const leftOrigin = `translate(${plot.padding.left + dx},${position === 'top' + ? plot.padding.top - padding + dy + : plot.height - plot.padding.bottom + padding + dy + })`; return ( - + {tickValues.map((v, i) => { return ( {format ? format(v, i, tickValues, ops.xTick) : v} diff --git a/packages/ui/src/components/Plot/components/XTitle.jsx b/packages/ui/src/components/Plot/components/XTitle.jsx index 018f1c783..22ec7f83b 100644 --- a/packages/ui/src/components/Plot/components/XTitle.jsx +++ b/packages/ui/src/components/Plot/components/XTitle.jsx @@ -1,15 +1,15 @@ import { usePlot } from "../contexts/PlotContext"; export default function XTitle({ - children, - position = 'bottom', - align = 'center', // 'left', 'center' or 'right' - padding, - dx = 0, - dy = 0, - ...textAttrs // be very careful if change the transform-related CSS props - // used in the element - }) { + children, + position = 'bottom', + align = 'center', // 'left', 'center' or 'right' + padding, + dx = 0, + dy = 0, + ...textAttrs // be very careful if change the transform-related CSS props + // used in the element +}) { const plot = usePlot(); if (!plot) { @@ -34,13 +34,13 @@ export default function XTitle({ } x += dx; - let y, alignmentBaseline; + let y, dominantBaseline; if (position === 'top') { y = plot.padding.top - padding; - alignmentBaseline = 'baseline'; + dominantBaseline = 'baseline'; } else { y = plot.height - plot.padding.bottom + padding; - alignmentBaseline = 'hanging'; + dominantBaseline = 'hanging'; } y += dy; @@ -54,7 +54,7 @@ export default function XTitle({ fontStyle={plot.fontStyle} fontWeight={plot.fontWeight} textAnchor={textAnchor} - alignmentBaseline={alignmentBaseline} + dominantBaseline={dominantBaseline} {...textAttrs} > {children} diff --git a/packages/ui/src/components/Plot/components/YLabel.jsx b/packages/ui/src/components/Plot/components/YLabel.jsx index 73f8e4e23..2e348213a 100644 --- a/packages/ui/src/components/Plot/components/YLabel.jsx +++ b/packages/ui/src/components/Plot/components/YLabel.jsx @@ -4,14 +4,14 @@ import { fromFrameOrPlot } from "../util/fromFrameOrPlot"; import { finalData } from "../util/finalData"; export default function YLabel({ - values, - position = 'left', - padding, - dx = 0, - dy = 0, - format, - ...textAttrs - }) { + values, + position = 'left', + padding, + dx = 0, + dy = 0, + format, + ...textAttrs +}) { const plot = usePlot(); if (!plot) { @@ -31,15 +31,13 @@ export default function YLabel({ ? ops.scales.y : v => plot.panelHeight - ops.scales.y(v); - const topOrigin = `translate(${ - position === 'right' - ? plot.width - plot.padding.right + padding + dx - : plot.padding.left - padding + dx},${ - plot.padding.top + dy - })`; + const topOrigin = `translate(${position === 'right' + ? plot.width - plot.padding.right + padding + dx + : plot.padding.left - padding + dx},${plot.padding.top + dy + })`; return ( - + {tickValues.map((v, i) => { return ( {format ? format(v, i, tickValues, ops.yTick) : v} diff --git a/packages/ui/src/components/Plot/components/htmlTooltip/HTMLTooltipRow.jsx b/packages/ui/src/components/Plot/components/htmlTooltip/HTMLTooltipRow.jsx index 74e8abbd1..93a40fea5 100644 --- a/packages/ui/src/components/Plot/components/htmlTooltip/HTMLTooltipRow.jsx +++ b/packages/ui/src/components/Plot/components/htmlTooltip/HTMLTooltipRow.jsx @@ -4,7 +4,8 @@ export default function TooltipRow({ children, label, data, - labelMinWidth, + labelWidth, + valueWidth, truncateValue, }) { @@ -18,13 +19,22 @@ export default function TooltipRow({ return ( - - + + {label}: - + {children}