From 9b2c217a5db5c302efafbc4870b1f781a1e9a9b4 Mon Sep 17 00:00:00 2001 From: Colin Date: Fri, 24 Jan 2025 18:50:24 -0500 Subject: [PATCH] Rename some files --- plugins/bed/src/BedpeAdapter/BedpeAdapter.ts | 63 +------- plugins/bed/src/BedpeAdapter/util.ts | 58 ++++++++ .../LaunchBreakendPanel.tsx | 2 +- .../LaunchBreakendWidgetArea.tsx | 64 +++++++++ .../VariantConsequenceDataGrid.tsx | 25 ++++ ... => VariantConsequenceDataGridWrapper.tsx} | 11 +- ...nTable.tsx => VariantConsequencePanel.tsx} | 6 +- .../VariantFeatureWidget.tsx | 135 +++++++++--------- .../VariantSampleFilters.tsx | 34 +++++ .../VariantSampleGrid.tsx | 52 ++----- .../VariantFeatureWidget/stateModelFactory.ts | 7 + .../src/VariantFeatureWidget/types.ts | 17 +++ 12 files changed, 306 insertions(+), 168 deletions(-) create mode 100644 plugins/bed/src/BedpeAdapter/util.ts create mode 100644 plugins/variants/src/VariantFeatureWidget/LaunchBreakendWidgetArea.tsx create mode 100644 plugins/variants/src/VariantFeatureWidget/VariantConsequenceDataGrid.tsx rename plugins/variants/src/VariantFeatureWidget/{AnnotGrid.tsx => VariantConsequenceDataGridWrapper.tsx} (79%) rename plugins/variants/src/VariantFeatureWidget/{VariantAnnotationTable.tsx => VariantConsequencePanel.tsx} (72%) create mode 100644 plugins/variants/src/VariantFeatureWidget/VariantSampleFilters.tsx create mode 100644 plugins/variants/src/VariantFeatureWidget/types.ts diff --git a/plugins/bed/src/BedpeAdapter/BedpeAdapter.ts b/plugins/bed/src/BedpeAdapter/BedpeAdapter.ts index ca9845a002..d09f5cf510 100644 --- a/plugins/bed/src/BedpeAdapter/BedpeAdapter.ts +++ b/plugins/bed/src/BedpeAdapter/BedpeAdapter.ts @@ -1,69 +1,14 @@ import IntervalTree from '@flatten-js/interval-tree' import { BaseFeatureDataAdapter } from '@jbrowse/core/data_adapters/BaseAdapter' -import { SimpleFeature, fetchAndMaybeUnzipText } from '@jbrowse/core/util' +import { fetchAndMaybeUnzipText } from '@jbrowse/core/util' import { openLocation } from '@jbrowse/core/util/io' import { ObservableCreate } from '@jbrowse/core/util/rxjs' +import { featureData } from './util' + import type { BaseOptions } from '@jbrowse/core/data_adapters/BaseAdapter' import type { Feature, Region } from '@jbrowse/core/util' -const svTypes = new Set(['DUP', 'TRA', 'INV', 'CNV', 'DEL']) - -export function featureData( - line: string, - uniqueId: string, - flip: boolean, - names?: string[], -) { - const l = line.split('\t') - const ref1 = l[flip ? 3 : 0]! - const start1 = +l[flip ? 4 : 1]! - const end1 = +l[flip ? 5 : 2]! - const ref2 = l[!flip ? 3 : 0]! - const start2 = +l[!flip ? 4 : 1]! - const end2 = +l[!flip ? 5 : 2]! - const name = l[6]! - const score = +l[7]! - const strand1 = parseStrand(l[8]!) - const strand2 = parseStrand(l[9]!) - const extra = l.slice(10) - const rest = names - ? Object.fromEntries(names.slice(10).map((n, idx) => [n, extra[idx]])) - : {} - const ALT = svTypes.has(extra[0]!) ? `<${extra[0]}>` : undefined - - return new SimpleFeature({ - ...rest, - start: start1, - end: end1, - type: 'paired_feature', - refName: ref1, - strand: strand1, - name, - score, - uniqueId, - mate: { - refName: ref2, - start: start2, - end: end2, - strand: strand2, - }, - ...(ALT ? { ALT: [ALT] } : {}), // ALT is an array in VCF - }) -} - -function parseStrand(strand: string) { - if (strand === '+') { - return 1 - } else if (strand === '-') { - return -1 - } else if (strand === '.') { - return 0 - } else { - return undefined - } -} - export default class BedpeAdapter extends BaseFeatureDataAdapter { protected bedpeFeatures?: Promise<{ header: string @@ -81,7 +26,7 @@ export default class BedpeAdapter extends BaseFeatureDataAdapter { private async loadDataP(opts?: BaseOptions) { const data = await fetchAndMaybeUnzipText( - openLocation(this.getConf('bedLoc'), this.pluginManager), + openLocation(this.getConf('bedpeLocation'), this.pluginManager), opts, ) diff --git a/plugins/bed/src/BedpeAdapter/util.ts b/plugins/bed/src/BedpeAdapter/util.ts new file mode 100644 index 0000000000..09eb7388cf --- /dev/null +++ b/plugins/bed/src/BedpeAdapter/util.ts @@ -0,0 +1,58 @@ +import { SimpleFeature } from '@jbrowse/core/util' + +const svTypes = new Set(['DUP', 'TRA', 'INV', 'CNV', 'DEL']) + +export function featureData( + line: string, + uniqueId: string, + flip: boolean, + names?: string[], +) { + const l = line.split('\t') + const ref1 = l[flip ? 3 : 0]! + const start1 = +l[flip ? 4 : 1]! + const end1 = +l[flip ? 5 : 2]! + const ref2 = l[!flip ? 3 : 0]! + const start2 = +l[!flip ? 4 : 1]! + const end2 = +l[!flip ? 5 : 2]! + const name = l[6]! + const score = +l[7]! + const strand1 = parseStrand(l[8]!) + const strand2 = parseStrand(l[9]!) + const extra = l.slice(10) + const rest = names + ? Object.fromEntries(names.slice(10).map((n, idx) => [n, extra[idx]])) + : {} + const ALT = svTypes.has(extra[0]!) ? `<${extra[0]}>` : undefined + + return new SimpleFeature({ + ...rest, + start: start1, + end: end1, + type: 'paired_feature', + refName: ref1, + strand: strand1, + name, + score, + uniqueId, + mate: { + refName: ref2, + start: start2, + end: end2, + strand: strand2, + }, + ...(ALT ? { ALT: [ALT] } : {}), // ALT is an array in VCF + }) +} + +function parseStrand(strand: string) { + if (strand === '+') { + return 1 + } else if (strand === '-') { + return -1 + } else if (strand === '.') { + return 0 + } else { + return undefined + } +} diff --git a/plugins/variants/src/VariantFeatureWidget/LaunchBreakendPanel.tsx b/plugins/variants/src/VariantFeatureWidget/LaunchBreakendPanel.tsx index 9f736bfaa5..35be27d97b 100644 --- a/plugins/variants/src/VariantFeatureWidget/LaunchBreakendPanel.tsx +++ b/plugins/variants/src/VariantFeatureWidget/LaunchBreakendPanel.tsx @@ -123,7 +123,7 @@ function LaunchBreakpointSplitViewPanel({ ) } -export default function BreakendPanel(props: { +export default function LaunchBreakendPanel(props: { locStrings: string[] model: VariantFeatureWidgetModel feature: SimpleFeatureSerialized diff --git a/plugins/variants/src/VariantFeatureWidget/LaunchBreakendWidgetArea.tsx b/plugins/variants/src/VariantFeatureWidget/LaunchBreakendWidgetArea.tsx new file mode 100644 index 0000000000..16023cf209 --- /dev/null +++ b/plugins/variants/src/VariantFeatureWidget/LaunchBreakendWidgetArea.tsx @@ -0,0 +1,64 @@ +import { Suspense, lazy } from 'react' + +import { parseBreakend } from '@gmod/vcf' + +import type { VariantFeatureWidgetModel } from './stateModelFactory' + +// lazies +const LaunchBreakendPanel = lazy(() => import('./LaunchBreakendPanelEntry')) + +export default function LaunchBreakendWidgetArea({ + model, +}: { + model: VariantFeatureWidgetModel +}) { + const { featureData } = model + const feat = JSON.parse(JSON.stringify(featureData)) + const { type = '' } = feat + + return ( + + {type === 'breakend' ? ( + parseBreakend(alt)?.MatePosition || '', + )} + model={model} + /> + ) : type === 'translocation' ? ( + + ) : type === 'paired_feature' ? ( + + ) : type.includes('inversion') || + type.includes('deletion') || + type.includes('duplication') || + type.includes('cnv') || + type.includes('sv') ? ( + + ) : null} + + ) +} diff --git a/plugins/variants/src/VariantFeatureWidget/VariantConsequenceDataGrid.tsx b/plugins/variants/src/VariantFeatureWidget/VariantConsequenceDataGrid.tsx new file mode 100644 index 0000000000..bd327e421b --- /dev/null +++ b/plugins/variants/src/VariantFeatureWidget/VariantConsequenceDataGrid.tsx @@ -0,0 +1,25 @@ +import BaseCard from '@jbrowse/core/BaseFeatureWidget/BaseFeatureDetail/BaseCard' + +import VariantConsequenceDataGridWrapper from './VariantConsequenceDataGridWrapper' + +export default function VariantConsequenceDataGrid({ + data, + fields, + title, +}: { + data: string[] + fields: string[] + title: string +}) { + return data.length ? ( + + ({ + id, + ...Object.fromEntries(elt.split('|').map((e, i) => [fields[i], e])), + }))} + columns={fields.map(c => ({ field: c }))} + /> + + ) : null +} diff --git a/plugins/variants/src/VariantFeatureWidget/AnnotGrid.tsx b/plugins/variants/src/VariantFeatureWidget/VariantConsequenceDataGridWrapper.tsx similarity index 79% rename from plugins/variants/src/VariantFeatureWidget/AnnotGrid.tsx rename to plugins/variants/src/VariantFeatureWidget/VariantConsequenceDataGridWrapper.tsx index 9fd6c4ce86..95aa3ec7ac 100644 --- a/plugins/variants/src/VariantFeatureWidget/AnnotGrid.tsx +++ b/plugins/variants/src/VariantFeatureWidget/VariantConsequenceDataGridWrapper.tsx @@ -6,7 +6,7 @@ import { DataGrid, GridToolbar } from '@mui/x-data-grid' import type { GridColDef, GridValidRowModel } from '@mui/x-data-grid' -export default function VariantAnnotPanel({ +export default function VariantConsequenceDataGridWrapper({ rows, columns, }: { @@ -33,8 +33,13 @@ export default function VariantAnnotPanel({ ({ ...c, width: widths[i] }))} - slots={{ toolbar: checked ? GridToolbar : null }} + columns={columns.map((c, i) => ({ + ...c, + width: widths[i], + }))} + slots={{ + toolbar: checked ? GridToolbar : null, + }} /> ) : null diff --git a/plugins/variants/src/VariantFeatureWidget/VariantAnnotationTable.tsx b/plugins/variants/src/VariantFeatureWidget/VariantConsequencePanel.tsx similarity index 72% rename from plugins/variants/src/VariantFeatureWidget/VariantAnnotationTable.tsx rename to plugins/variants/src/VariantFeatureWidget/VariantConsequencePanel.tsx index 49f7480daa..8bd9145915 100644 --- a/plugins/variants/src/VariantFeatureWidget/VariantAnnotationTable.tsx +++ b/plugins/variants/src/VariantFeatureWidget/VariantConsequencePanel.tsx @@ -1,8 +1,8 @@ import BaseCard from '@jbrowse/core/BaseFeatureWidget/BaseFeatureDetail/BaseCard' -import AnnotGrid from './AnnotGrid' +import VariantConsequenceDataGridWrapper from './VariantConsequenceDataGridWrapper' -export default function VariantAnnotationTable({ +export default function VariantConsequencePanel({ data, fields, title, @@ -13,7 +13,7 @@ export default function VariantAnnotationTable({ }) { return data.length ? ( - ({ id, ...Object.fromEntries(elt.split('|').map((e, i) => [fields[i], e])), diff --git a/plugins/variants/src/VariantFeatureWidget/VariantFeatureWidget.tsx b/plugins/variants/src/VariantFeatureWidget/VariantFeatureWidget.tsx index 31af7d1116..19aa7de937 100644 --- a/plugins/variants/src/VariantFeatureWidget/VariantFeatureWidget.tsx +++ b/plugins/variants/src/VariantFeatureWidget/VariantFeatureWidget.tsx @@ -5,38 +5,31 @@ import FeatureDetails from '@jbrowse/core/BaseFeatureWidget/BaseFeatureDetail/Fe import { Paper } from '@mui/material' import { observer } from 'mobx-react' -import VariantAnnotationTable from './VariantAnnotationTable' import VariantSampleGrid from './VariantSampleGrid' import { variantFieldDescriptions } from './variantFieldDescriptions' import type { VariantFeatureWidgetModel } from './stateModelFactory' +import type { Descriptions, ReducedFeature } from './types' // lazies const LaunchBreakendPanel = lazy(() => import('./LaunchBreakendPanel')) +const VariantConsequenceDataGrid = lazy( + () => import('./VariantConsequenceDataGrid'), +) function AnnPanel({ descriptions, feature, }: { - descriptions?: { - INFO?: { - ANN?: { - Description?: string - } - } - } - feature: { - INFO?: { - ANN?: string[] - } - } + descriptions?: Descriptions + feature: ReducedFeature }) { const annDesc = descriptions?.INFO?.ANN?.Description const annFields = annDesc?.match(/.*Functional annotations:'(.*)'$/)?.[1]?.split('|') || [] const ann = feature.INFO?.ANN || [] return ( - parseBreakend(alt)?.MatePosition || '', + )} + model={model} + /> + ) : type === 'translocation' ? ( + + ) : type === 'paired_feature' ? ( + + ) : type.includes('inversion') || + type.includes('deletion') || + type.includes('duplication') || + type.includes('cnv') || + type.includes('sv') ? ( + + ) : null +} + const VariantFeatureWidget = observer(function (props: { model: VariantFeatureWidgetModel }) { const { model } = props const { featureData, descriptions } = model const feat = JSON.parse(JSON.stringify(featureData)) - const { samples, ALT, type = '', ...rest } = feat + const { samples, ALT, ...rest } = feat return ( - - - {type === 'breakend' ? ( - parseBreakend(alt)?.MatePosition || '', - )} - model={model} - /> - ) : null} - {type === 'translocation' ? ( - - ) : null} - {type === 'paired_feature' ? ( - - ) : null} - {type.includes('inversion') || - type.includes('deletion') || - type.includes('duplication') || - type.includes('cnv') || - type.includes('sv') ? ( - - ) : null} + + + + +export default function SampleFilters({ + columns, + filter, + setFilter, +}: { + columns: { field: string }[] + filter: Filters + setFilter: (arg: Filters) => void +}) { + return ( + <> + + These filters can use a plain text search or regex style query, e.g. in + the genotype field, entering 1 will query for all genotypes that include + the first alternate allele e.g. 0|1 or 1|1, entering [1-9]\d* will find + any non-zero allele e.g. 0|2 or 2/33 + + {columns.map(({ field }) => ( + { + setFilter({ ...filter, [field]: event.target.value }) + }} + /> + ))} + + ) +} diff --git a/plugins/variants/src/VariantFeatureWidget/VariantSampleGrid.tsx b/plugins/variants/src/VariantFeatureWidget/VariantSampleGrid.tsx index c1d8d59fc4..e1b77a517a 100644 --- a/plugins/variants/src/VariantFeatureWidget/VariantSampleGrid.tsx +++ b/plugins/variants/src/VariantFeatureWidget/VariantSampleGrid.tsx @@ -2,14 +2,11 @@ import { useState } from 'react' import BaseCard from '@jbrowse/core/BaseFeatureWidget/BaseFeatureDetail/BaseCard' import { measureGridWidth } from '@jbrowse/core/util' -import { - Checkbox, - FormControlLabel, - TextField, - Typography, -} from '@mui/material' +import { Checkbox, FormControlLabel, Typography } from '@mui/material' import { DataGrid, GridToolbar } from '@mui/x-data-grid' +import SampleFilters from './VariantSampleFilters' + import type { SimpleFeatureSerialized } from '@jbrowse/core/util' interface Entry { @@ -21,40 +18,16 @@ interface Entry { type InfoFields = Record type Filters = Record -function SampleFilters({ - columns, - filter, - setFilter, -}: { - columns: { field: string }[] - filter: Filters - setFilter: (arg: Filters) => void -}) { - return ( - <> - - These filters can use a plain text search or regex style query, e.g. in - the genotype field, entering 1 will query for all genotypes that include - the first alternate allele e.g. 0|1 or 1|1, entering [1-9]\d* will find - any non-zero allele e.g. 0|2 or 2/33 - - {columns.map(({ field }) => ( - { - setFilter({ ...filter, [field]: event.target.value }) - }} - /> - ))} - - ) +interface FormatRecord { + Description?: string +} +interface Descriptions { + FORMAT?: Record } export default function VariantSamples(props: { feature: SimpleFeatureSerialized - descriptions?: { FORMAT?: Record } | null + descriptions?: Descriptions | null }) { const { feature, descriptions = {} } = props const [filter, setFilter] = useState({}) @@ -126,7 +99,12 @@ export default function VariantSamples(props: { /> ) : null} -
+