diff --git a/components/src/preact/components/mutation-type-selector.tsx b/components/src/preact/components/mutation-type-selector.tsx new file mode 100644 index 00000000..b75a7679 --- /dev/null +++ b/components/src/preact/components/mutation-type-selector.tsx @@ -0,0 +1,30 @@ +import { type FunctionComponent } from 'preact/compat'; + +import { type CheckboxItem, CheckboxSelector } from './checkbox-selector'; +import type { SubstitutionOrDeletion } from '../../types'; + +export type DisplayedMutationType = CheckboxItem & { + type: SubstitutionOrDeletion; +}; + +export type MutationTypeSelectorProps = { + displayedMutationTypes: DisplayedMutationType[]; + setDisplayedMutationTypes: (mutationTypes: DisplayedMutationType[]) => void; +}; + +export const MutationTypeSelector: FunctionComponent = ({ + displayedMutationTypes, + setDisplayedMutationTypes, +}) => { + const checkedLabels = displayedMutationTypes.filter((type) => type.checked).map((type) => type.label); + const mutationTypesSelectorLabel = `Types: ${checkedLabels.length > 0 ? checkedLabels.join(', ') : 'None'}`; + + return ( + setDisplayedMutationTypes(items)} + /> + ); +}; diff --git a/components/src/preact/mutationComparison/mutation-comparison.tsx b/components/src/preact/mutationComparison/mutation-comparison.tsx index 8c8e3a07..91d5bf1d 100644 --- a/components/src/preact/mutationComparison/mutation-comparison.tsx +++ b/components/src/preact/mutationComparison/mutation-comparison.tsx @@ -5,15 +5,15 @@ import { getMutationComparisonTableData } from './getMutationComparisonTableData import { MutationComparisonTable } from './mutation-comparison-table'; import { MutationComparisonVenn } from './mutation-comparison-venn'; import { filterMutationData, type MutationData, queryMutationData } from './queryMutationData'; -import { type LapisFilter, type SequenceType, type SubstitutionOrDeletion } from '../../types'; +import { type LapisFilter, type SequenceType } from '../../types'; import { LapisUrlContext } from '../LapisUrlContext'; import { type DisplayedSegment, SegmentSelector } from '../components/SegmentSelector'; -import { type CheckboxItem, CheckboxSelector } from '../components/checkbox-selector'; import { CsvDownloadButton } from '../components/csv-download-button'; import { ErrorDisplay } from '../components/error-display'; import Headline from '../components/headline'; import Info from '../components/info'; import { LoadingDisplay } from '../components/loading-display'; +import { type DisplayedMutationType, MutationTypeSelector } from '../components/mutation-type-selector'; import { NoDataDisplay } from '../components/no-data-display'; import { type ProportionInterval } from '../components/proportion-selector'; import { ProportionSelectorDropdown } from '../components/proportion-selector-dropdown'; @@ -33,10 +33,6 @@ export interface MutationComparisonProps { views: View[]; } -export type DisplayedMutationType = CheckboxItem & { - type: SubstitutionOrDeletion; -}; - export const MutationComparison: FunctionComponent = ({ variants, sequenceType, views }) => { const lapis = useContext(LapisUrlContext); @@ -166,9 +162,6 @@ const Toolbar: FunctionComponent = ({ proportionInterval, setProportionInterval, }) => { - const checkedLabels = displayedMutationTypes.filter((type) => type.checked).map((type) => type.label); - const mutationTypesSelectorLabel = `Types: ${checkedLabels.length > 0 ? checkedLabels.join(', ') : 'None'}`; - return (
= ({ setMaxProportion={(max) => setProportionInterval((prev) => ({ ...prev, max }))} /> - setDisplayedMutationTypes(items)} + = ({ variant, sequenceType, views }) => { const lapis = useContext(LapisUrlContext); - const [proportionInterval, setProportionInterval] = useState({ min: 0.05, max: 1 }); - const { data, error, isLoading } = useQuery(async () => { - const substitutionsOrDeletions = await querySubstitutionsOrDeletions(variant, sequenceType, lapis); - const insertions = await queryInsertions(variant, sequenceType, lapis); - - const mutationSegments = substitutionsOrDeletions.content - .map((mutationEntry) => mutationEntry.mutation.segment) - .filter((segment): segment is string => segment !== undefined); - - const segments = [...new Set(mutationSegments)]; - - return { - data: { substitutionsOrDeletions: substitutionsOrDeletions.content, insertions: insertions.content }, - segments, - }; + return queryMutationsData(variant, sequenceType, lapis); }, [variant, sequenceType, lapis]); - const [displayedSegments, setDisplayedSegments] = useState([]); - useEffect(() => { - if (data !== null) { - setDisplayedSegments( - data.segments.map((segment) => ({ - segment, - label: segment, - checked: true, - })), - ); - } - }, [data]); - const headline = 'Mutations'; if (isLoading) { return ( @@ -94,59 +67,116 @@ export const Mutations: FunctionComponent = ({ variant, sequence ); } - const bySelectedSegments = (mutationEntry: MutationEntry) => { - if (mutationEntry.mutation.segment === undefined) { - return true; - } - return displayedSegments.some( - (displayedSegment) => - displayedSegment.segment === mutationEntry.mutation.segment && displayedSegment.checked, - ); - }; + return ( + + + + ); +}; - const byProportion = (mutationEntry: SubstitutionOrDeletionEntry) => { - return mutationEntry.proportion >= proportionInterval.min && mutationEntry.proportion <= proportionInterval.max; - }; +type MutationTabsProps = { + mutationsData: { insertions: InsertionEntry[]; substitutionsOrDeletions: SubstitutionOrDeletionEntry[] }; + segments: string[]; + sequenceType: SequenceType; + views: View[]; +}; - const getTab = ( - view: View, - data: { substitutionsOrDeletions: SubstitutionOrDeletionEntry[]; insertions: InsertionEntry[] }, - ) => { +const MutationsTabs: FunctionComponent = ({ mutationsData, segments, sequenceType, views }) => { + const [proportionInterval, setProportionInterval] = useState({ min: 0.05, max: 1 }); + + const [displayedSegments, setDisplayedSegments] = useState( + segments.map((segment) => ({ + segment, + label: segment, + checked: true, + })), + ); + const [displayedMutationTypes, setDisplayedMutationTypes] = useState([ + { label: 'Substitutions', checked: true, type: 'substitution' }, + { label: 'Deletions', checked: true, type: 'deletion' }, + ]); + + const filteredData = filterMutationsData( + mutationsData, + displayedSegments, + proportionInterval.min, + proportionInterval.max, + displayedMutationTypes, + ); + + const getTab = (view: View) => { switch (view) { case 'table': return { title: 'Table', - content: ( - - ), + content: , }; case 'grid': return { title: 'Grid', - content: ( - - ), + content: , }; case 'insertions': return { title: 'Insertions', - content: , + content: , }; } }; - const tabs = views.map((view) => { - return getTab(view, data.data); - }); + const tabs = views.map((view) => getTab(view)); const toolbar = (activeTab: string) => ( + + ); + + return ; +}; + +type ToolbarProps = { + activeTab: string; + displayedSegments: DisplayedSegment[]; + setDisplayedSegments: (segments: DisplayedSegment[]) => void; + displayedMutationTypes: DisplayedMutationType[]; + setDisplayedMutationTypes: (types: DisplayedMutationType[]) => void; + filteredData: { tableData: SubstitutionOrDeletionEntry[]; insertions: InsertionEntry[] }; + proportionInterval: ProportionInterval; + setProportionInterval: Dispatch>; +}; + +const Toolbar: FunctionComponent = ({ + activeTab, + displayedSegments, + setDisplayedSegments, + displayedMutationTypes, + setDisplayedMutationTypes, + filteredData, + proportionInterval, + setProportionInterval, +}) => { + return (
+ {activeTab === 'Table' && ( + + )} {(activeTab === 'Table' || activeTab === 'Grid') && ( <> = ({ variant, sequence /> getMutationsTableData(data.data.substitutionsOrDeletions)} + getData={() => getMutationsTableData(filteredData.tableData)} filename='substitutionsAndDeletions.csv' /> @@ -165,17 +195,11 @@ export const Mutations: FunctionComponent = ({ variant, sequence {activeTab === 'Insertions' && ( getInsertionsTableData(data.data.insertions)} + getData={() => getInsertionsTableData(filteredData.insertions)} filename='insertions.csv' /> )}
); - - return ( - - - - ); }; diff --git a/components/src/preact/mutations/queryMutations.ts b/components/src/preact/mutations/queryMutations.ts new file mode 100644 index 00000000..904ef4bc --- /dev/null +++ b/components/src/preact/mutations/queryMutations.ts @@ -0,0 +1,69 @@ +import { queryInsertions } from '../../query/queryInsertions'; +import { querySubstitutionsOrDeletions } from '../../query/querySubstitutionsOrDeletions'; +import { + type InsertionEntry, + type LapisFilter, + type MutationEntry, + type SubstitutionOrDeletionEntry, +} from '../../types'; +import { type DisplayedSegment } from '../components/SegmentSelector'; +import { type DisplayedMutationType } from '../components/mutation-type-selector'; + +export async function queryMutationsData( + variant: LapisFilter, + sequenceType: 'nucleotide' | 'amino acid', + lapis: string, +) { + const substitutionsOrDeletions = (await querySubstitutionsOrDeletions(variant, sequenceType, lapis)).content; + const insertions = (await queryInsertions(variant, sequenceType, lapis)).content; + + const mutationSegments = substitutionsOrDeletions + .map((mutationEntry) => mutationEntry.mutation.segment) + .filter((segment): segment is string => segment !== undefined); + + const segments = [...new Set(mutationSegments)]; + + return { + mutationsData: { substitutionsOrDeletions, insertions }, + segments, + }; +} + +export function filterMutationsData( + data: { insertions: InsertionEntry[]; substitutionsOrDeletions: SubstitutionOrDeletionEntry[] }, + displayedSegments: DisplayedSegment[], + minProportion: number, + maxProportion: number, + displayedMutationTypes: DisplayedMutationType[], +) { + function bySelectedSegments(mutationEntry: MutationEntry) { + if (mutationEntry.mutation.segment === undefined) { + return true; + } + return displayedSegments.some( + (displayedSegment) => + displayedSegment.segment === mutationEntry.mutation.segment && displayedSegment.checked, + ); + } + + const byProportion = (mutationEntry: SubstitutionOrDeletionEntry) => { + return mutationEntry.proportion >= minProportion && mutationEntry.proportion <= maxProportion; + }; + + const byDisplayedMutationTypes = (mutationEntry: SubstitutionOrDeletionEntry) => { + return displayedMutationTypes.some( + (displayedMutationType) => + displayedMutationType.checked && displayedMutationType.type === mutationEntry.type, + ); + }; + + const filteredSubstitutionsOrDeletions = data.substitutionsOrDeletions + .filter(byProportion) + .filter(bySelectedSegments); + + return { + insertions: data.insertions.filter(bySelectedSegments), + tableData: filteredSubstitutionsOrDeletions.filter(byDisplayedMutationTypes), + gridData: filteredSubstitutionsOrDeletions, + }; +} diff --git a/components/src/preact/textInput/test-input.stories.tsx b/components/src/preact/textInput/text-input.stories.tsx similarity index 90% rename from components/src/preact/textInput/test-input.stories.tsx rename to components/src/preact/textInput/text-input.stories.tsx index 0199b6b0..602c9929 100644 --- a/components/src/preact/textInput/test-input.stories.tsx +++ b/components/src/preact/textInput/text-input.stories.tsx @@ -1,8 +1,9 @@ -import { Meta, StoryObj } from '@storybook/preact'; -import { TextInput, TextInputProps } from './text-input'; +import { type Meta, type StoryObj } from '@storybook/preact'; + +import data from './__mockData__/aggregated_hosts.json'; +import { TextInput, type TextInputProps } from './text-input'; import { AGGREGATED_ENDPOINT, LAPIS_URL } from '../../constants'; import { LapisUrlContext } from '../LapisUrlContext'; -import data from './__mockData__/aggregated_hosts.json'; const meta: Meta = { title: 'Input/TextInput', diff --git a/components/src/preact/textInput/text-input.tsx b/components/src/preact/textInput/text-input.tsx index 82917184..44e5bc6c 100644 --- a/components/src/preact/textInput/text-input.tsx +++ b/components/src/preact/textInput/text-input.tsx @@ -1,11 +1,12 @@ -import { FunctionComponent } from 'preact'; +import { type FunctionComponent } from 'preact'; import { useContext, useRef } from 'preact/hooks'; -import { LapisUrlContext } from '../LapisUrlContext'; -import { useQuery } from '../useQuery'; + import { fetchAutocompleteList } from './fetchAutocompleteList'; -import { LoadingDisplay } from '../components/loading-display'; +import { LapisUrlContext } from '../LapisUrlContext'; import { ErrorDisplay } from '../components/error-display'; +import { LoadingDisplay } from '../components/loading-display'; import { NoDataDisplay } from '../components/no-data-display'; +import { useQuery } from '../useQuery'; export interface TextInputProps { lapisField: string; diff --git a/components/src/web-components/input/text-input-component.stories.ts b/components/src/web-components/input/text-input-component.stories.ts index fc9de364..d946383a 100644 --- a/components/src/web-components/input/text-input-component.stories.ts +++ b/components/src/web-components/input/text-input-component.stories.ts @@ -1,12 +1,12 @@ +import { expect, fn, userEvent, waitFor } from '@storybook/test'; import type { Meta, StoryObj } from '@storybook/web-components'; -import { AGGREGATED_ENDPOINT, LAPIS_URL } from '../../constants'; - import { html } from 'lit'; + +import { AGGREGATED_ENDPOINT, LAPIS_URL } from '../../constants'; import '../app'; import './text-input-component'; -import { withinShadowRoot } from '../withinShadowRoot.story'; -import { expect, fn, userEvent, waitFor } from '@storybook/test'; import data from '../../preact/textInput/__mockData__/aggregated_hosts.json'; +import { withinShadowRoot } from '../withinShadowRoot.story'; const meta: Meta = { title: 'Input/Text input', diff --git a/components/src/web-components/input/text-input-component.tsx b/components/src/web-components/input/text-input-component.tsx index b423d024..4f84057e 100644 --- a/components/src/web-components/input/text-input-component.tsx +++ b/components/src/web-components/input/text-input-component.tsx @@ -1,6 +1,7 @@ -import { PreactLitAdapter } from '../PreactLitAdapter'; import { customElement, property } from 'lit/decorators.js'; + import { TextInput } from '../../preact/textInput/text-input'; +import { PreactLitAdapter } from '../PreactLitAdapter'; @customElement('gs-text-input') export class TextInputComponent extends PreactLitAdapter { diff --git a/components/tests/snapshots.spec.ts-snapshots/Mutations-Download-of-visualization-mutations--default-should-match-snapshot-1-chromium-linux.txt b/components/tests/snapshots.spec.ts-snapshots/Mutations-Download-of-visualization-mutations--default-should-match-snapshot-1-chromium-linux.txt index 642aa1b1..fc60ffb7 100644 --- a/components/tests/snapshots.spec.ts-snapshots/Mutations-Download-of-visualization-mutations--default-should-match-snapshot-1-chromium-linux.txt +++ b/components/tests/snapshots.spec.ts-snapshots/Mutations-Download-of-visualization-mutations--default-should-match-snapshot-1-chromium-linux.txt @@ -1,98 +1,8 @@ mutation,type,count,proportion -G160A,substitution,1,0.00006093845216331505 -G210T,substitution,239,0.014548332115899683 C241T,substitution,16325,0.9940932894897089 -C632T,substitution,2,0.00012178784557301182 -T727A,substitution,1,0.00006041565973900435 -G1280A,substitution,7,0.0004216105523098235 -C2790T,substitution,3,0.0001825372680255552 C3037T,substitution,16526,0.9993348249380177 -C3927T,substitution,3,0.00018334046324023712 -G4181T,substitution,8,0.00048443744701465424 -G4184A,substitution,2,0.00012110936175366356 -C4321T,substitution,8,0.00048306261699172754 -C4586T,substitution,20,0.0012117540139351712 -C5183T,substitution,12,0.0007391438250692947 -C6402T,substitution,97,0.005873448380260369 -C7006T,substitution,16,0.0009975684269592868 -C7124T,substitution,7,0.000430530782950981 -A7219G,substitution,18,0.0011079650375477041 -T8269C,substitution,1,0.00006030635628995296 -T8654C,substitution,2,0.00012232415902140674 -C8986T,substitution,12,0.0007258210851025222 -G9053T,substitution,8,0.0004836174585902551 -C9344T,substitution,65,0.00396124078249741 -C9534T,substitution,2,0.00012162490878131841 -C9866T,substitution,2,0.00012111669593653485 -C10029T,substitution,2,0.00012097749818533752 -C10078T,substitution,7,0.0004226287508301636 -C10198T,substitution,12,0.000724812756704518 -C11031T,substitution,1,0.00006028817748839453 -G11048T,substitution,1,0.00006028090903610827 -A11201G,substitution,3,0.00018129079042784627 -A11332G,substitution,3,0.00018144429660094352 C11750T,substitution,895,0.05428190198932557 -C12876T,substitution,3,0.00018133462282398453 -C12880T,substitution,76,0.004594088133953938 -A13222G,substitution,5,0.00030389594602808 -C14214T,substitution,4,0.0002414875633904854 C14408T,substitution,16531,0.9990330573517858 -G15451A,substitution,15,0.0009048681908668637 -C15495T,substitution,1,0.000060240963855421684 -C15714T,substitution,10,0.000602918123718799 -A15788G,substitution,1,0.0000602918123718799 -C16466T,substitution,6,0.00036175087423127937 -T17033C,substitution,6,0.0003618599601954044 -C17410T,substitution,94,0.005659922928709056 -A17725C,substitution,4,0.0002409058058299205 -G18583A,substitution,2,0.00012113136696747623 -C18657T,substitution,123,0.00741812918400579 -C18664T,substitution,2,0.00012061998673180146 -C19955T,substitution,9,0.0005600149337315662 -A20055G,substitution,4,0.00024775472282440383 -T20372C,substitution,1,0.00006239860227130913 -C21618G,substitution,5,0.0003059975520195838 -C21618T,substitution,10,0.0006119951040391676 -G21839T,substitution,9,0.000544464609800363 -A22029-,deletion,5,0.0003027550711474417 -G22030-,deletion,5,0.0003026817603971185 -T22031-,deletion,5,0.0003027550711474417 -T22032-,deletion,5,0.00030281007751937984 -C22033-,deletion,5,0.00030286510388273063 -A22034-,deletion,5,0.00030315891590371673 -T22917G,substitution,11,0.0006888346170705743 -C22995A,substitution,6,0.000373366521468575 A23403G,substitution,16568,0.9993967909277356 -C23604G,substitution,17,0.001029616619223548 -G24410A,substitution,10,0.0006027727546714888 -A24568C,substitution,1,0.0000603974149906384 -T25210G,substitution,3,0.00018167504390480228 -C25308T,substitution,1,0.00006020469596628537 -C25469T,substitution,18,0.001087087812537746 -A25983T,substitution,1,0.000060379181258302136 -T26488G,substitution,1,0.00006103515625 -T26593C,substitution,9,0.0005483792347063124 -T26767C,substitution,22,0.0013264198721813579 -T27638C,substitution,5,0.00031474254060178774 -C27752T,substitution,8,0.0004990953896063385 -T27811G,substitution,3,0.000181422351233672 -C27864A,substitution,81,0.004928806133625411 -C27874T,substitution,8,0.0004867956675185591 -A28030G,substitution,6,0.0003661662394727206 -T28110C,substitution,1,0.00006031363088057901 -G28248-,deletion,21,0.001267886252490491 -A28249-,deletion,21,0.001267886252490491 -T28250-,deletion,21,0.001267733172351343 -T28251-,deletion,15,0.0009054690329590728 -T28252-,deletion,32,0.0019315506730246876 -C28253-,deletion,25,0.001509115054931788 A28271-,deletion,15500,0.9529079060617238 -A28461G,substitution,10,0.0006024822267743102 -G28881T,substitution,9,0.0005452893062708271 -G28916T,substitution,1,0.00006049240820277055 -C29400T,substitution,5,0.00030892801977139327 -G29402T,substitution,13,0.0008031136096867857 -G29711A,substitution,6,0.00036458649814668533 -G29742T,substitution,35,0.0022132287846212215 -T29867A,substitution,1456,0.5103399929898352 -T29867G,substitution,1,0.0003505082369435682 \ No newline at end of file +T29867A,substitution,1456,0.5103399929898352 \ No newline at end of file diff --git a/components/tests/snapshots.spec.ts-snapshots/Mutations-Download-of-visualization-mutations--default-should-match-snapshot-1-firefox-linux.txt b/components/tests/snapshots.spec.ts-snapshots/Mutations-Download-of-visualization-mutations--default-should-match-snapshot-1-firefox-linux.txt index 642aa1b1..fc60ffb7 100644 --- a/components/tests/snapshots.spec.ts-snapshots/Mutations-Download-of-visualization-mutations--default-should-match-snapshot-1-firefox-linux.txt +++ b/components/tests/snapshots.spec.ts-snapshots/Mutations-Download-of-visualization-mutations--default-should-match-snapshot-1-firefox-linux.txt @@ -1,98 +1,8 @@ mutation,type,count,proportion -G160A,substitution,1,0.00006093845216331505 -G210T,substitution,239,0.014548332115899683 C241T,substitution,16325,0.9940932894897089 -C632T,substitution,2,0.00012178784557301182 -T727A,substitution,1,0.00006041565973900435 -G1280A,substitution,7,0.0004216105523098235 -C2790T,substitution,3,0.0001825372680255552 C3037T,substitution,16526,0.9993348249380177 -C3927T,substitution,3,0.00018334046324023712 -G4181T,substitution,8,0.00048443744701465424 -G4184A,substitution,2,0.00012110936175366356 -C4321T,substitution,8,0.00048306261699172754 -C4586T,substitution,20,0.0012117540139351712 -C5183T,substitution,12,0.0007391438250692947 -C6402T,substitution,97,0.005873448380260369 -C7006T,substitution,16,0.0009975684269592868 -C7124T,substitution,7,0.000430530782950981 -A7219G,substitution,18,0.0011079650375477041 -T8269C,substitution,1,0.00006030635628995296 -T8654C,substitution,2,0.00012232415902140674 -C8986T,substitution,12,0.0007258210851025222 -G9053T,substitution,8,0.0004836174585902551 -C9344T,substitution,65,0.00396124078249741 -C9534T,substitution,2,0.00012162490878131841 -C9866T,substitution,2,0.00012111669593653485 -C10029T,substitution,2,0.00012097749818533752 -C10078T,substitution,7,0.0004226287508301636 -C10198T,substitution,12,0.000724812756704518 -C11031T,substitution,1,0.00006028817748839453 -G11048T,substitution,1,0.00006028090903610827 -A11201G,substitution,3,0.00018129079042784627 -A11332G,substitution,3,0.00018144429660094352 C11750T,substitution,895,0.05428190198932557 -C12876T,substitution,3,0.00018133462282398453 -C12880T,substitution,76,0.004594088133953938 -A13222G,substitution,5,0.00030389594602808 -C14214T,substitution,4,0.0002414875633904854 C14408T,substitution,16531,0.9990330573517858 -G15451A,substitution,15,0.0009048681908668637 -C15495T,substitution,1,0.000060240963855421684 -C15714T,substitution,10,0.000602918123718799 -A15788G,substitution,1,0.0000602918123718799 -C16466T,substitution,6,0.00036175087423127937 -T17033C,substitution,6,0.0003618599601954044 -C17410T,substitution,94,0.005659922928709056 -A17725C,substitution,4,0.0002409058058299205 -G18583A,substitution,2,0.00012113136696747623 -C18657T,substitution,123,0.00741812918400579 -C18664T,substitution,2,0.00012061998673180146 -C19955T,substitution,9,0.0005600149337315662 -A20055G,substitution,4,0.00024775472282440383 -T20372C,substitution,1,0.00006239860227130913 -C21618G,substitution,5,0.0003059975520195838 -C21618T,substitution,10,0.0006119951040391676 -G21839T,substitution,9,0.000544464609800363 -A22029-,deletion,5,0.0003027550711474417 -G22030-,deletion,5,0.0003026817603971185 -T22031-,deletion,5,0.0003027550711474417 -T22032-,deletion,5,0.00030281007751937984 -C22033-,deletion,5,0.00030286510388273063 -A22034-,deletion,5,0.00030315891590371673 -T22917G,substitution,11,0.0006888346170705743 -C22995A,substitution,6,0.000373366521468575 A23403G,substitution,16568,0.9993967909277356 -C23604G,substitution,17,0.001029616619223548 -G24410A,substitution,10,0.0006027727546714888 -A24568C,substitution,1,0.0000603974149906384 -T25210G,substitution,3,0.00018167504390480228 -C25308T,substitution,1,0.00006020469596628537 -C25469T,substitution,18,0.001087087812537746 -A25983T,substitution,1,0.000060379181258302136 -T26488G,substitution,1,0.00006103515625 -T26593C,substitution,9,0.0005483792347063124 -T26767C,substitution,22,0.0013264198721813579 -T27638C,substitution,5,0.00031474254060178774 -C27752T,substitution,8,0.0004990953896063385 -T27811G,substitution,3,0.000181422351233672 -C27864A,substitution,81,0.004928806133625411 -C27874T,substitution,8,0.0004867956675185591 -A28030G,substitution,6,0.0003661662394727206 -T28110C,substitution,1,0.00006031363088057901 -G28248-,deletion,21,0.001267886252490491 -A28249-,deletion,21,0.001267886252490491 -T28250-,deletion,21,0.001267733172351343 -T28251-,deletion,15,0.0009054690329590728 -T28252-,deletion,32,0.0019315506730246876 -C28253-,deletion,25,0.001509115054931788 A28271-,deletion,15500,0.9529079060617238 -A28461G,substitution,10,0.0006024822267743102 -G28881T,substitution,9,0.0005452893062708271 -G28916T,substitution,1,0.00006049240820277055 -C29400T,substitution,5,0.00030892801977139327 -G29402T,substitution,13,0.0008031136096867857 -G29711A,substitution,6,0.00036458649814668533 -G29742T,substitution,35,0.0022132287846212215 -T29867A,substitution,1456,0.5103399929898352 -T29867G,substitution,1,0.0003505082369435682 \ No newline at end of file +T29867A,substitution,1456,0.5103399929898352 \ No newline at end of file