Skip to content

Commit 9797f78

Browse files
Rework STR page frontend
Key changes: * Allele size distribution plot can now show, by use of stacked bars, breakdown of each bucket by population, quality, or sex. This also involved replacing some of our custom logic with calls to the visx family of libraries. * More options for y-scaling of allele size distribution plot. * Assorted refactoring, type specifying, and similar cleanup
1 parent 32853c9 commit 9797f78

23 files changed

+11008
-4988
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,6 @@ hail-*.log
3333
# Playright test dirs
3434
/tests/playwright/
3535
/playwright/.cache/
36+
37+
# Reads metadata databases
38+
reads/*.db

browser/package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@
2424
"@hot-loader/react-dom": "^17.0.0",
2525
"@visx/axis": "^3.0.0",
2626
"@visx/group": "^3.0.0",
27+
"@visx/legend": "^3.12.0",
28+
"@visx/scale": "^3.12.0",
29+
"@visx/shape": "^3.12.0",
2730
"core-js": "3.5.0",
2831
"css-loader": "^6.7.3",
2932
"d3-array": "^1.2.4",

browser/src/ShortTandemRepeatPage/ShortTandemRepeatAdjacentRepeatSection.tsx

Lines changed: 70 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,69 @@
1-
import { max, min } from 'd3-array'
2-
import React, { useState } from 'react'
1+
import React, { SetStateAction, useState, Dispatch } from 'react'
32

43
import { Modal, Select } from '@gnomad/ui'
54

65
import ControlSection from '../VariantPage/ControlSection'
76

87
import ShortTandemRepeatPopulationOptions from './ShortTandemRepeatPopulationOptions'
98
import { ShortTandemRepeatAdjacentRepeat } from './ShortTandemRepeatPage'
10-
import ShortTandemRepeatAlleleSizeDistributionPlot from './ShortTandemRepeatAlleleSizeDistributionPlot'
11-
import ShortTandemRepeatGenotypeDistributionPlot from './ShortTandemRepeatGenotypeDistributionPlot'
9+
import ShortTandemRepeatAlleleSizeDistributionPlot, {
10+
ScaleType,
11+
Sex,
12+
ColorBy,
13+
} from './ShortTandemRepeatAlleleSizeDistributionPlot'
14+
import ShortTandemRepeatGenotypeDistributionPlot, {
15+
Bin as GenotypeBin,
16+
} from './ShortTandemRepeatGenotypeDistributionPlot'
1217
import ShortTandemRepeatGenotypeDistributionBinDetails from './ShortTandemRepeatGenotypeDistributionBinDetails'
1318
import ShortTandemRepeatGenotypeDistributionRepeatUnitsSelect from './ShortTandemRepeatGenotypeDistributionRepeatUnitsSelect'
1419
import ShortTandemRepeatAdjacentRepeatAttributes from './ShortTandemRepeatAdjacentRepeatAttributes'
1520
import {
1621
getSelectedAlleleSizeDistribution,
1722
getSelectedGenotypeDistribution,
1823
getGenotypeDistributionPlotAxisLabels,
24+
genotypeRepunitPairs,
25+
maxAlleleSizeDistributionRepeats,
26+
maxGenotypeDistributionRepeats,
1927
} from './shortTandemRepeatHelpers'
28+
import { PopulationId } from '@gnomad/dataset-metadata/gnomadPopulations'
2029

2130
type Props = {
2231
adjacentRepeat: ShortTandemRepeatAdjacentRepeat
23-
populationIds: string[]
24-
selectedPopulationId: string
25-
onSelectPopulationId: (...args: any[]) => any
26-
selectedScaleType: string
27-
onSelectScaleType: (...args: any[]) => any
32+
selectedScaleType: ScaleType
33+
selectedPopulation: PopulationId | ''
34+
selectedSex: Sex | ''
35+
selectedColorBy: ColorBy | ''
36+
populations: PopulationId[]
37+
selectedGenotypeDistributionBin: GenotypeBin | null
38+
setSelectedGenotypeDistributionBin: Dispatch<SetStateAction<GenotypeBin | null>>
39+
setSelectedScaleType: Dispatch<SetStateAction<ScaleType>>
40+
setSelectedPopulation: Dispatch<SetStateAction<PopulationId | ''>>
41+
setSelectedSex: Dispatch<SetStateAction<Sex | ''>>
2842
}
2943

3044
const ShortTandemRepeatAdjacentRepeatSection = ({
3145
adjacentRepeat,
32-
populationIds,
33-
selectedPopulationId,
34-
onSelectPopulationId,
46+
populations,
3547
selectedScaleType,
36-
onSelectScaleType,
48+
selectedPopulation,
49+
selectedSex,
50+
selectedColorBy,
51+
setSelectedScaleType,
52+
setSelectedPopulation,
53+
setSelectedSex,
3754
}: Props) => {
3855
const [selectedRepeatUnit, setSelectedRepeatUnit] = useState(
3956
adjacentRepeat.repeat_units.length === 1 ? adjacentRepeat.repeat_units[0] : ''
4057
)
4158

59+
const genotypeDistributionPairs = genotypeRepunitPairs(adjacentRepeat)
60+
const defaultGenotypeDistributionRepeatUnits =
61+
genotypeDistributionPairs.length === 1 ? genotypeDistributionPairs[0] : ''
4262
const [selectedGenotypeDistributionRepeatUnits, setSelectedGenotypeDistributionRepeatUnits] =
43-
useState(
44-
adjacentRepeat.genotype_distribution.repeat_units.length === 1
45-
? adjacentRepeat.genotype_distribution.repeat_units[0].repeat_units.join(' / ')
46-
: ''
47-
)
63+
useState<string[] | ''>(defaultGenotypeDistributionRepeatUnits)
4864

49-
const [selectedGenotypeDistributionBin, setSelectedGenotypeDistributionBin] = useState(null)
65+
const [selectedGenotypeDistributionBin, setSelectedGenotypeDistributionBin] =
66+
useState<GenotypeBin | null>(null)
5067

5168
return (
5269
<section style={{ marginBottom: '3em' }}>
@@ -55,33 +72,33 @@ const ShortTandemRepeatAdjacentRepeatSection = ({
5572

5673
<h4 style={{ marginBottom: '0.66em' }}>Allele Size Distribution</h4>
5774
<ShortTandemRepeatAlleleSizeDistributionPlot
58-
// @ts-expect-error TS(2322) FIXME: Type '{ maxRepeats: number; alleleSizeDistribution... Remove this comment to see the full error message
59-
maxRepeats={
60-
adjacentRepeat.allele_size_distribution.distribution[
61-
adjacentRepeat.allele_size_distribution.distribution.length - 1
62-
][0]
63-
}
75+
maxRepeats={maxAlleleSizeDistributionRepeats(adjacentRepeat)}
6476
alleleSizeDistribution={getSelectedAlleleSizeDistribution(adjacentRepeat, {
65-
selectedPopulationId,
77+
selectedPopulation,
78+
selectedSex,
79+
selectedColorBy,
6680
selectedRepeatUnit,
6781
})}
82+
colorBy={selectedColorBy}
6883
repeatUnitLength={selectedRepeatUnit ? selectedRepeatUnit.length : null}
6984
scaleType={selectedScaleType}
7085
/>
7186
<ControlSection>
7287
<ShortTandemRepeatPopulationOptions
7388
id={`${adjacentRepeat.id}-repeat-counts`}
74-
populationIds={populationIds}
75-
selectedPopulationId={selectedPopulationId}
76-
onSelectPopulationId={onSelectPopulationId}
89+
populations={populations}
90+
selectedPopulation={selectedPopulation}
91+
selectedSex={selectedSex}
92+
setSelectedPopulation={setSelectedPopulation}
93+
setSelectedSex={setSelectedSex}
7794
/>
7895

7996
<label htmlFor={`short-tandem-repeat-${adjacentRepeat.id}-repeat-unit`}>
8097
Repeat unit: {/* @ts-expect-error TS(2769) FIXME: No overload matches this call. */}
8198
<Select
8299
id={`short-tandem-repeat-${adjacentRepeat.id}-repeat-unit`}
83100
value={selectedRepeatUnit}
84-
onChange={(e: any) => {
101+
onChange={(e: { target: { value: string } }) => {
85102
setSelectedRepeatUnit(e.target.value)
86103
}}
87104
>
@@ -98,59 +115,63 @@ const ShortTandemRepeatAdjacentRepeatSection = ({
98115
</label>
99116

100117
<label htmlFor={`short-tandem-repeat-${adjacentRepeat.id}-repeat-counts-scale`}>
101-
Scale: {/* @ts-expect-error TS(2769) FIXME: No overload matches this call. */}
118+
y-scale: {/* @ts-expect-error TS(2769) FIXME: No overload matches this call. */}
102119
<Select
103120
id={`short-tandem-repeat-${adjacentRepeat.id}-repeat-counts-scale`}
104121
value={selectedScaleType}
105-
onChange={(e: any) => {
106-
onSelectScaleType(e.target.value)
122+
onChange={(e: { target: { value: ScaleType } }) => {
123+
setSelectedScaleType(e.target.value)
107124
}}
108125
>
109126
<option value="linear">Linear</option>
110127
<option value="log">Log</option>
128+
<option value="linear-truncated-50">Linear: Truncated at 50</option>
129+
<option value="linear-truncated-200">Linear: Truncated at 200</option>
130+
<option value="linear-truncated-1000">Linear: Truncated at 1000</option>
111131
</Select>
112132
</label>
113133
</ControlSection>
114134

115135
<h4 style={{ marginBottom: '0.66em' }}>Genotype Distribution</h4>
116136
<ShortTandemRepeatGenotypeDistributionPlot
117-
// @ts-expect-error TS(2322) FIXME: Type '{ axisLabels: any; maxRepeats: (string | und... Remove this comment to see the full error message
118137
axisLabels={getGenotypeDistributionPlotAxisLabels(adjacentRepeat, {
119138
selectedRepeatUnits: selectedGenotypeDistributionRepeatUnits,
120139
})}
121-
maxRepeats={[
122-
max(adjacentRepeat.genotype_distribution.distribution, (d: any) => max(d.slice(0, 2))),
123-
max(adjacentRepeat.genotype_distribution.distribution, (d: any) => min(d.slice(0, 2))),
124-
]}
140+
maxRepeats={maxGenotypeDistributionRepeats(adjacentRepeat)}
125141
genotypeDistribution={getSelectedGenotypeDistribution(adjacentRepeat, {
126142
selectedRepeatUnits: selectedGenotypeDistributionRepeatUnits,
127-
selectedPopulationId,
143+
selectedPopulation,
144+
selectedSex,
128145
})}
129-
onSelectBin={(bin: any) => {
146+
onSelectBin={(bin: GenotypeBin) => {
130147
if (bin.xRange[0] !== bin.xRange[1] || bin.yRange[0] !== bin.yRange[1]) {
131148
setSelectedGenotypeDistributionBin(bin)
132149
}
133150
}}
151+
xRanges={[]}
152+
yRanges={[]}
134153
/>
135154

136155
<ControlSection>
137156
<ShortTandemRepeatPopulationOptions
138157
id={`${adjacentRepeat.id}-genotype-distribution`}
139-
populationIds={populationIds}
140-
selectedPopulationId={selectedPopulationId}
141-
onSelectPopulationId={onSelectPopulationId}
158+
populations={populations}
159+
selectedPopulation={selectedPopulation}
160+
selectedSex={selectedSex}
161+
setSelectedPopulation={setSelectedPopulation}
162+
setSelectedSex={setSelectedSex}
142163
/>
143164

144165
<ShortTandemRepeatGenotypeDistributionRepeatUnitsSelect
145166
shortTandemRepeatOrAdjacentRepeat={adjacentRepeat}
146-
value={selectedGenotypeDistributionRepeatUnits}
147-
onChange={setSelectedGenotypeDistributionRepeatUnits}
167+
selectedRepeatUnits={selectedGenotypeDistributionRepeatUnits}
168+
setSelectedRepeatUnits={setSelectedGenotypeDistributionRepeatUnits}
148169
/>
149170
</ControlSection>
150171

151172
{selectedGenotypeDistributionBin && (
152173
<Modal
153-
title={(selectedGenotypeDistributionBin as any).label}
174+
title={selectedGenotypeDistributionBin.label}
154175
size="large"
155176
// @ts-expect-error TS(2322) FIXME: Type '{ children: Element; title: any; size: "larg... Remove this comment to see the full error message
156177
initialFocusOnButton={false}
@@ -160,9 +181,11 @@ const ShortTandemRepeatAdjacentRepeatSection = ({
160181
>
161182
<ShortTandemRepeatGenotypeDistributionBinDetails
162183
shortTandemRepeatOrAdjacentRepeat={adjacentRepeat}
163-
selectedPopulationId={selectedPopulationId}
164184
selectedRepeatUnits={selectedGenotypeDistributionRepeatUnits}
165185
bin={selectedGenotypeDistributionBin}
186+
selectedPopulation={selectedPopulation}
187+
selectedSex={selectedSex}
188+
repeatUnitPairs={genotypeDistributionPairs}
166189
/>
167190
</Modal>
168191
)}

0 commit comments

Comments
 (0)