-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(components): initial mutations over time component
- Loading branch information
1 parent
956d1a7
commit 1bda5d4
Showing
16 changed files
with
894 additions
and
18 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
92 changes: 92 additions & 0 deletions
92
components/src/preact/mutationOverTime/mutation-over-time-grid.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
import { Fragment, type FunctionComponent } from 'preact'; | ||
|
||
import { | ||
type MutationOverTimeDataGroupedByMutation, | ||
type MutationOverTimeMutationValue, | ||
} from '../../query/queryMutationOverTime'; | ||
import { type Deletion, type Substitution } from '../../utils/mutations'; | ||
import { compareTemporal, type Temporal } from '../../utils/temporal'; | ||
import { singleGraphColorRGBByName } from '../shared/charts/colors'; | ||
import { formatProportion } from '../shared/table/formatProportion'; | ||
|
||
export interface MutationOverTimeGridProps { | ||
data: MutationOverTimeDataGroupedByMutation; | ||
} | ||
|
||
const MutationOverTimeGrid: FunctionComponent<MutationOverTimeGridProps> = ({ data }) => { | ||
const mutations = data.getFirstAxisKeys(); | ||
const dates = data.getSecondAxisKeys().sort((a, b) => compareTemporal(a, b)); | ||
|
||
return ( | ||
<div | ||
style={{ | ||
display: 'grid', | ||
gridTemplateRows: `repeat(${mutations.length}, 24px)`, | ||
gridTemplateColumns: `8rem repeat(${dates.length}, minmax(1.5rem, 1fr))`, | ||
}} | ||
> | ||
{mutations.map((mutation, i) => { | ||
return ( | ||
<Fragment key={`fragment-${mutation.toString()}`}> | ||
<div | ||
key={`mutation-${mutation.toString()}`} | ||
style={{ gridRowStart: i + 1, gridColumnStart: 1 }} | ||
> | ||
<MutationCell mutation={mutation} /> | ||
</div> | ||
{dates.map((date, j) => { | ||
const value = data.get(mutation, date) ?? 0; | ||
return ( | ||
<div | ||
style={{ gridRowStart: i + 1, gridColumnStart: j + 2 }} | ||
key={`${mutation.toString()}-${date.toString()}`} | ||
> | ||
<ProportionCell value={value} date={date} mutation={mutation} /> | ||
</div> | ||
); | ||
})} | ||
</Fragment> | ||
); | ||
})} | ||
</div> | ||
); | ||
}; | ||
|
||
const ProportionCell: FunctionComponent<{ | ||
value: MutationOverTimeMutationValue; | ||
date: Temporal; | ||
mutation: Substitution | Deletion; | ||
}> = ({ value }) => { | ||
// TODO(#353): Add tooltip with date, mutation and proportion | ||
return ( | ||
<> | ||
<div className={'py-1'}> | ||
<div | ||
style={{ backgroundColor: backgroundColor(value), color: textColor(value) }} | ||
className='text-center hover:font-bold text-xs' | ||
> | ||
{formatProportion(value, 0)} | ||
</div> | ||
</div> | ||
</> | ||
); | ||
}; | ||
|
||
const backgroundColor = (proportion: number) => { | ||
// TODO(#353): Make minAlpha and maxAlpha configurable | ||
const minAlpha = 0.0; | ||
const maxAlpha = 1; | ||
|
||
const alpha = minAlpha + (maxAlpha - minAlpha) * proportion; | ||
return singleGraphColorRGBByName('indigo', alpha); | ||
}; | ||
|
||
const textColor = (proportion: number) => { | ||
return proportion > 0.5 ? 'white' : 'black'; | ||
}; | ||
|
||
const MutationCell: FunctionComponent<{ mutation: Substitution | Deletion }> = ({ mutation }) => { | ||
return <div className='text-center'>{mutation.toString()}</div>; | ||
}; | ||
|
||
export default MutationOverTimeGrid; |
41 changes: 41 additions & 0 deletions
41
components/src/preact/mutationOverTime/mutation-over-time-table.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
import { type FunctionComponent } from 'preact'; | ||
|
||
import { type MutationOverTimeDataGroupedByMutation } from '../../query/queryMutationOverTime'; | ||
import type { Deletion, Substitution } from '../../utils/mutations'; | ||
import { Table } from '../components/table'; | ||
import { sortSubstitutionsAndDeletions } from '../shared/sort/sortSubstitutionsAndDeletions'; | ||
import { formatProportion } from '../shared/table/formatProportion'; | ||
|
||
export interface MutationOverTimeTableProps { | ||
data: MutationOverTimeDataGroupedByMutation; | ||
pageSize: boolean | number; | ||
} | ||
|
||
const MutationOverTimeTable: FunctionComponent<MutationOverTimeTableProps> = ({ data, pageSize }) => { | ||
const getHeaders = () => { | ||
return [ | ||
{ | ||
name: 'Mutation', | ||
sort: { | ||
compare: sortSubstitutionsAndDeletions, | ||
}, | ||
formatter: (cell: Substitution | Deletion) => cell.toString(), | ||
}, | ||
...data.getSecondAxisKeys().map((date) => { | ||
return { | ||
name: date.toString(), | ||
sort: true, | ||
formatter: (cell: number) => formatProportion(cell), | ||
}; | ||
}), | ||
]; | ||
}; | ||
|
||
const tableData = data.getFirstAxisKeys().map((mutation) => { | ||
return [mutation, ...data.getRow(mutation, 0)]; | ||
}); | ||
|
||
return <Table data={tableData} columns={getHeaders()} pageSize={pageSize} />; | ||
}; | ||
|
||
export default MutationOverTimeTable; |
67 changes: 67 additions & 0 deletions
67
components/src/preact/mutationOverTime/mutation-over-time.stories.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
import { type Meta, type StoryObj } from '@storybook/preact'; | ||
|
||
import { MutationOverTime, type MutationOverTimeProps } from './mutation-over-time'; | ||
import { LAPIS_URL } from '../../constants'; | ||
import referenceGenome from '../../lapisApi/__mockData__/referenceGenome.json'; | ||
import { LapisUrlContext } from '../LapisUrlContext'; | ||
import { ReferenceGenomeContext } from '../ReferenceGenomeContext'; | ||
|
||
const meta: Meta<MutationOverTimeProps> = { | ||
title: 'Visualization/Mutation over time', | ||
component: MutationOverTime, | ||
argTypes: { | ||
lapisFilter: { control: 'object' }, | ||
sequenceType: { | ||
options: ['nucleotide', 'amino acid'], | ||
control: { type: 'radio' }, | ||
}, | ||
views: { | ||
options: ['table', 'grid', 'insertions'], | ||
control: { type: 'check' }, | ||
}, | ||
width: { control: 'text' }, | ||
height: { control: 'text' }, | ||
headline: { control: 'text' }, | ||
pageSize: { control: 'object' }, | ||
}, | ||
}; | ||
|
||
export default meta; | ||
|
||
const Template = { | ||
render: (args: MutationOverTimeProps) => ( | ||
<LapisUrlContext.Provider value={LAPIS_URL}> | ||
<ReferenceGenomeContext.Provider value={referenceGenome}> | ||
<MutationOverTime | ||
lapisFilter={args.lapisFilter} | ||
sequenceType={args.sequenceType} | ||
views={args.views} | ||
width={args.width} | ||
height={args.height} | ||
headline={args.headline} | ||
pageSize={args.pageSize} | ||
granularity={args.granularity} | ||
/> | ||
</ReferenceGenomeContext.Provider> | ||
</LapisUrlContext.Provider> | ||
), | ||
}; | ||
|
||
export const Default: StoryObj<MutationOverTimeProps> = { | ||
...Template, | ||
args: { | ||
lapisFilter: { pangoLineage: 'JN.1*', dateFrom: '2024-01-15', dateTo: '2024-07-10' }, | ||
sequenceType: 'nucleotide', | ||
views: ['grid'], | ||
width: '100%', | ||
height: '700px', | ||
headline: 'Mutation over time', | ||
pageSize: true, | ||
granularity: 'year', | ||
}, | ||
parameters: { | ||
fetchMock: { | ||
mocks: [], | ||
}, | ||
}, | ||
}; |
Oops, something went wrong.