Skip to content

Commit

Permalink
Modify mutation list to group mutation based on segment.
Browse files Browse the repository at this point in the history
In order to do this I create a segmentedMutations object which maps a segment to a list of all mutations on that segment.
  • Loading branch information
anna-parker committed May 8, 2024
1 parent 893d2c7 commit 34f2937
Show file tree
Hide file tree
Showing 6 changed files with 107 additions and 58 deletions.
2 changes: 1 addition & 1 deletion deploy.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ def handle_helm():
]

if args.for_e2e or args.dev:
parameters += ['-f', 'kubernetes/loculus/values_e2e_and_dev.yaml']
parameters += ['-f', HELM_CHART_DIR / 'values_e2e_and_dev.yaml']
if args.sha:
parameters += ['--set', f"sha={args.sha[:7]}"]

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react';

import { DataUseTermsHistoryModal } from './DataUseTermsHistoryModal';
import { SubstitutionsContainer } from './MutationBadge';
import { SubstitutionsContainers } from './MutationBadge';
import { type TableDataEntry } from './types.ts';
import { type DataUseTermsHistoryEntry } from '../../types/backend.ts';

Expand All @@ -21,7 +21,7 @@ const CustomDisplayComponent: React.FC<Props> = ({ data, dataUseTermsHistory })
(customDisplay.value === undefined ? (
<span className='italic'>N/A</span>
) : (
<SubstitutionsContainer values={customDisplay.value} />
<SubstitutionsContainers values={customDisplay.value} />
))}
{customDisplay?.type === 'link' && customDisplay.url !== undefined && (
<a
Expand Down
49 changes: 32 additions & 17 deletions website/src/components/SequenceDetailsPage/MutationBadge.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { type FC, type ReactElement, useMemo, useState } from 'react';

import type { SegmentedMutations } from '../../types/config';
import type { MutationProportionCount } from '../../types/lapis';

export type SubProps = {
Expand All @@ -9,6 +10,10 @@ export type SubProps = {
sequenceName: string | null;
};

export type Props = {
values: MutationProportionCount[];
};

export const SubBadge: FC<SubProps> = ({ position, mutationTo, mutationFrom, sequenceName }) => {
return (
<li key={position} className='inline-block'>
Expand Down Expand Up @@ -69,7 +74,16 @@ export function getColor(code: string): string {

const MAX_INITIAL_NUMBER_BADGES = 20;

export const SubstitutionsContainer = ({ values }: { values: MutationProportionCount[] }) => {
export const SubstitutionsContainers = ({ values }: { values: SegmentedMutations[] }) => {
return values.map(({ segment, mutations }) => (
<div key={segment}>
<h2 className='py-2 font-semibold border-b'>{segment}</h2>
<SubstitutionsContainer values={mutations} />
</div>
));
};

export const SubstitutionsContainer: FC<Props> = ({ values }) => {
const [showMore, setShowMore] = useState(false);

const { alwaysVisible, initiallyHidden } = useMemo(() => {
Expand Down Expand Up @@ -97,23 +111,24 @@ export const SubstitutionsContainer = ({ values }: { values: MutationProportionC
return (
<div>
{alwaysVisible}
{initiallyHidden.length > 0 && showMore ? (
<>
{initiallyHidden}
<button onClick={() => setShowMore(false)} className='underline'>
Show less
{initiallyHidden.length > 0 &&
(showMore ? (
<>
{initiallyHidden}
<button onClick={() => setShowMore(false)} className='underline'>
Show less
</button>
</>
) : (
<button
onClick={() => {
setShowMore(true);
}}
className='underline'
>
Show more
</button>
</>
) : (
<button
onClick={() => {
setShowMore(true);
}}
className='underline'
>
Show more
</button>
)}
))}
</div>
);
};
74 changes: 42 additions & 32 deletions website/src/components/SequenceDetailsPage/getTableData.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,22 +150,27 @@ describe('getTableData', () => {
type: 'badge',
value: [
{
count: 0,
mutation: 'T10A',
mutationFrom: 'T',
mutationTo: 'A',
position: 10,
proportion: 0,
sequenceName: null,
},
{
count: 0,
mutation: 'C30G',
mutationFrom: 'C',
mutationTo: 'G',
position: 30,
proportion: 0,
sequenceName: null,
segment: '',
mutations: [
{
count: 0,
mutation: 'T10A',
mutationFrom: 'T',
mutationTo: 'A',
position: 10,
proportion: 0,
sequenceName: null,
},
{
count: 0,
mutation: 'C30G',
mutationFrom: 'C',
mutationTo: 'G',
position: 30,
proportion: 0,
sequenceName: null,
},
],
},
],
},
Expand All @@ -187,22 +192,27 @@ describe('getTableData', () => {
type: 'badge',
value: [
{
count: 0,
mutation: 'gene1:N10Y',
mutationFrom: 'N',
mutationTo: 'Y',
position: 10,
proportion: 0,
sequenceName: 'gene1',
},
{
count: 0,
mutation: 'gene1:T30N',
mutationFrom: 'T',
mutationTo: 'N',
position: 30,
proportion: 0,
sequenceName: 'gene1',
segment: 'gene1',
mutations: [
{
count: 0,
mutation: 'gene1:N10Y',
mutationFrom: 'N',
mutationTo: 'Y',
position: 10,
proportion: 0,
sequenceName: 'gene1',
},
{
count: 0,
mutation: 'gene1:T30N',
mutationFrom: 'T',
mutationTo: 'N',
position: 30,
proportion: 0,
sequenceName: 'gene1',
},
],
},
],
},
Expand Down
28 changes: 23 additions & 5 deletions website/src/components/SequenceDetailsPage/getTableData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { err, Result } from 'neverthrow';
import type { TableDataEntry } from './types.js';
import { type LapisClient } from '../../services/lapisClient.ts';
import type { ProblemDetail } from '../../types/backend.ts';
import type { Metadata, Schema } from '../../types/config.ts';
import type { Metadata, Schema, SegmentedMutations } from '../../types/config.ts';
import {
type Details,
type DetailsResponse,
Expand Down Expand Up @@ -93,7 +93,7 @@ function mutationDetails(
name: 'nucleotideSubstitutions',
value: '',
header: 'Nucleotide mutations',
customDisplay: { type: 'badge', value: substitutionsList(nucleotideMutations) },
customDisplay: { type: 'badge', value: substitutionsMap(nucleotideMutations) },
type: { kind: 'mutation' },
},
{
Expand All @@ -115,7 +115,7 @@ function mutationDetails(
name: 'aminoAcidSubstitutions',
value: '',
header: 'Amino acid mutations',
customDisplay: { type: 'badge', value: substitutionsList(aminoAcidMutations) },
customDisplay: { type: 'badge', value: substitutionsMap(aminoAcidMutations) },
type: { kind: 'mutation' },
},
{
Expand Down Expand Up @@ -184,8 +184,26 @@ function mapValueToDisplayedValue(value: undefined | null | string | number | bo
return value;
}

function substitutionsList(mutationData: MutationProportionCount[]) {
return mutationData.filter((m) => m.mutationTo !== '-');
export function substitutionsMap(mutationData: MutationProportionCount[]): SegmentedMutations[] {
const result: SegmentedMutations[] = [];
const substitutionData = mutationData.filter((m) => m.mutationTo !== '-');

const segmentMutationsMap = new Map<string, MutationProportionCount[]>();
for (const entry of substitutionData) {
let sequenceName = '';
if (entry.sequenceName !== null) {
sequenceName = entry.sequenceName;
}
if (!segmentMutationsMap.has(sequenceName)) {
segmentMutationsMap.set(sequenceName, []);
}
segmentMutationsMap.get(sequenceName)!.push(entry);
}
for (const [segment, mutations] of segmentMutationsMap.entries()) {
result.push({ segment, mutations });
}

return result;
}

function deletionsToCommaSeparatedString(mutationData: MutationProportionCount[]) {
Expand Down
8 changes: 7 additions & 1 deletion website/src/types/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,15 @@ const metadataPossibleTypes = z.enum([
'authors',
] as const);

export const segmentedMutations = z.object({
segment: z.string(),
mutations: z.array(mutationProportionCount),
});

export const customDisplay = z.object({
type: z.string(),
url: z.string().optional(),
value: z.array(mutationProportionCount).optional(),
value: z.array(segmentedMutations).optional(),
});

export const metadata = z.object({
Expand All @@ -43,6 +48,7 @@ export type InputField = z.infer<typeof inputField>;
export type CustomDisplay = z.infer<typeof customDisplay>;
export type Metadata = z.infer<typeof metadata>;
export type MetadataType = z.infer<typeof metadataPossibleTypes>;
export type SegmentedMutations = z.infer<typeof segmentedMutations>;

export type MetadataFilter = Metadata & {
filterValue: string;
Expand Down

0 comments on commit 34f2937

Please sign in to comment.