From 0c294d3c4f2ece3cb5d5bb2e0a36f16d48cc3437 Mon Sep 17 00:00:00 2001 From: Colin Date: Sat, 13 Feb 2021 01:27:43 -0700 Subject: [PATCH 01/40] Add changes --- packages/core/util/index.ts | 2 +- .../FromConfigSequenceAdapter.ts | 4 +- .../src/LinearComparativeView/model.ts | 12 ++++- plugins/linear-comparative-view/src/index.tsx | 44 +++++++++++++++++-- 4 files changed, 55 insertions(+), 7 deletions(-) diff --git a/packages/core/util/index.ts b/packages/core/util/index.ts index 57ec7c2262..88fe4f1a5f 100644 --- a/packages/core/util/index.ts +++ b/packages/core/util/index.ts @@ -760,7 +760,7 @@ export async function renameRegionsIfNeeded< ...args, regions: [...(args.regions || [])], } - if (assemblyName) { + if (assemblyName && adapterConfig.type !== 'FromConfigSequenceAdapter') { const refNameMap = await assemblyManager.getRefNameMapForAdapter( adapterConfig, assemblyName, diff --git a/plugins/config/src/FromConfigAdapter/FromConfigSequenceAdapter.ts b/plugins/config/src/FromConfigAdapter/FromConfigSequenceAdapter.ts index 11bcfe81ed..4358f1aaa8 100644 --- a/plugins/config/src/FromConfigAdapter/FromConfigSequenceAdapter.ts +++ b/plugins/config/src/FromConfigAdapter/FromConfigSequenceAdapter.ts @@ -33,8 +33,8 @@ export default class FromSequenceConfigAdapter extends FromConfigAdapter { new SimpleFeature({ ...feat.toJSON(), seq, - end: featStart + seq.length, - start: featStart, + end: region.end, + start: region.start, }), ) }) diff --git a/plugins/linear-comparative-view/src/LinearComparativeView/model.ts b/plugins/linear-comparative-view/src/LinearComparativeView/model.ts index cc99528fab..ca49e63a44 100644 --- a/plugins/linear-comparative-view/src/LinearComparativeView/model.ts +++ b/plugins/linear-comparative-view/src/LinearComparativeView/model.ts @@ -2,6 +2,9 @@ import BaseViewModel from '@jbrowse/core/pluggableElementTypes/models/BaseViewModel' import { MenuItem } from '@jbrowse/core/ui' import { getSession, isSessionModelWithWidgets } from '@jbrowse/core/util' +import assemblyManagerFactory, { + assemblyConfigSchemas as AssemblyConfigSchemasFactory, +} from '@jbrowse/core/assemblyManager' import { LinearGenomeViewModel, LinearGenomeViewStateModel, @@ -27,6 +30,13 @@ import { AnyConfigurationModel } from '@jbrowse/core/configuration/configuration export default function stateModelFactory(pluginManager: PluginManager) { const { jbrequire } = pluginManager const { ElementId } = jbrequire('@jbrowse/core/util/types/mst') + const { assemblyConfigSchemas, dispatcher } = AssemblyConfigSchemasFactory( + pluginManager, + ) + const assemblyConfigSchemasType = types.union( + { dispatcher }, + ...assemblyConfigSchemas, + ) const defaultHeight = 400 return types @@ -59,7 +69,7 @@ export default function stateModelFactory(pluginManager: PluginManager) { // this represents assemblies in the specialized // read vs ref dotplot view - viewAssemblyConfigs: types.array(types.frozen()), + viewAssemblyConfigs: types.array(assemblyConfigSchemasType), }), ) .volatile(() => ({ diff --git a/plugins/linear-comparative-view/src/index.tsx b/plugins/linear-comparative-view/src/index.tsx index 56054f8e1a..4ab94fe9e9 100644 --- a/plugins/linear-comparative-view/src/index.tsx +++ b/plugins/linear-comparative-view/src/index.tsx @@ -249,6 +249,8 @@ function WindowSizeDlg(props: { 0, ) + const seqTrackId = `${readName}_${Date.now()}` + session.addView('LinearSyntenyView', { type: 'LinearSyntenyView', views: [ @@ -279,6 +281,22 @@ function WindowSizeDlg(props: { refName: readName, }, ], + tracks: [ + { + id: `${Math.random()}`, + type: 'ReferenceSequenceTrack', + configuration: seqTrackId, + displays: [ + { + id: `${Math.random()}`, + type: 'LinearReferenceSequenceDisplay', + showReverse: false, + showTranslation: false, + configuration: `${seqTrackId}-LinearReferenceSequenceDisplay`, + }, + ], + }, + ], }, ], viewTrackConfigs: [ @@ -289,13 +307,33 @@ function WindowSizeDlg(props: { type: 'FromConfigAdapter', features: configFeatureStore, }, - renderer: { - type: 'LinearSyntenyRenderer', - }, trackId, name: trackName, }, ], + viewAssemblyConfigs: [ + { + name: readAssembly, + sequence: { + type: 'ReferenceSequenceTrack', + trackId: seqTrackId, + assemblyNames: [readAssembly], + adapter: { + type: 'FromConfigSequenceAdapter', + features: [ + { + start: 0, + end: totalLength, + seq: feat.seq, + refName: readName, + uniqueId: `${Math.random()}`, + id: `${Math.random()}`, + }, + ], + }, + }, + }, + ], tracks: [ { configuration: trackId, From afa5d59f58a2f817784266ad90432d145328f32d Mon Sep 17 00:00:00 2001 From: Colin Date: Sat, 13 Feb 2021 13:45:25 -0700 Subject: [PATCH 02/40] Fix some lint --- .../src/LinearComparativeView/model.ts | 4 +--- .../src/LinearSyntenyView/model.test.ts | 8 ++++++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/plugins/linear-comparative-view/src/LinearComparativeView/model.ts b/plugins/linear-comparative-view/src/LinearComparativeView/model.ts index ca49e63a44..10fb939d74 100644 --- a/plugins/linear-comparative-view/src/LinearComparativeView/model.ts +++ b/plugins/linear-comparative-view/src/LinearComparativeView/model.ts @@ -2,9 +2,7 @@ import BaseViewModel from '@jbrowse/core/pluggableElementTypes/models/BaseViewModel' import { MenuItem } from '@jbrowse/core/ui' import { getSession, isSessionModelWithWidgets } from '@jbrowse/core/util' -import assemblyManagerFactory, { - assemblyConfigSchemas as AssemblyConfigSchemasFactory, -} from '@jbrowse/core/assemblyManager' +import { assemblyConfigSchemas as AssemblyConfigSchemasFactory } from '@jbrowse/core/assemblyManager' import { LinearGenomeViewModel, LinearGenomeViewStateModel, diff --git a/plugins/linear-comparative-view/src/LinearSyntenyView/model.test.ts b/plugins/linear-comparative-view/src/LinearSyntenyView/model.test.ts index 7932ada712..1863b968da 100644 --- a/plugins/linear-comparative-view/src/LinearSyntenyView/model.test.ts +++ b/plugins/linear-comparative-view/src/LinearSyntenyView/model.test.ts @@ -1,9 +1,13 @@ import PluginManager from '@jbrowse/core/PluginManager' -import LinearGenomeView from '@jbrowse/plugin-linear-genome-view' +import LinearGenomeViewPlugin from '@jbrowse/plugin-linear-genome-view' +import SequencePlugin from '@jbrowse/plugin-sequence' import stateModelFactory from './model' test('creation', () => { - const pluginManager = new PluginManager([new LinearGenomeView()]) + const pluginManager = new PluginManager([ + new LinearGenomeViewPlugin(), + new SequencePlugin(), + ]) .createPluggableElements() .configure() const model = stateModelFactory(pluginManager) From 68bea9e5a286306105f38bee922148f780108588 Mon Sep 17 00:00:00 2001 From: Colin Date: Sat, 13 Feb 2021 13:55:40 -0700 Subject: [PATCH 03/40] Use noAssemblyManager flag on config --- packages/core/util/index.ts | 9 +++++++-- .../src/FromConfigAdapter/FromConfigSequenceAdapter.ts | 4 +++- plugins/config/src/FromConfigAdapter/configSchema.ts | 8 ++++++++ .../src/LinearComparativeView/model.ts | 6 ++++-- plugins/linear-comparative-view/src/index.tsx | 1 + 5 files changed, 23 insertions(+), 5 deletions(-) diff --git a/packages/core/util/index.ts b/packages/core/util/index.ts index 88fe4f1a5f..b856397e94 100644 --- a/packages/core/util/index.ts +++ b/packages/core/util/index.ts @@ -760,14 +760,19 @@ export async function renameRegionsIfNeeded< ...args, regions: [...(args.regions || [])], } - if (assemblyName && adapterConfig.type !== 'FromConfigSequenceAdapter') { + + // configs can choose to not be associated with the assemblyManager (as with + // the "read assembly" in the read vs ref comparisons) and in this case a + // special flag exists (currently set on the FromConfigSequenceAdapter) + // called noAssemblyManager + // @ts-ignore + if (assemblyName && !adapterConfig.noAssemblyManager) { const refNameMap = await assemblyManager.getRefNameMapForAdapter( adapterConfig, assemblyName, newArgs, ) - // console.log(`${JSON.stringify(regions)} ${JSON.stringify(refNameMap)}`) if (refNameMap && regions && newArgs.regions) { for (let i = 0; i < regions.length; i += 1) { newArgs.regions[i] = renameRegionIfNeeded(refNameMap, regions[i]) diff --git a/plugins/config/src/FromConfigAdapter/FromConfigSequenceAdapter.ts b/plugins/config/src/FromConfigAdapter/FromConfigSequenceAdapter.ts index 4358f1aaa8..3ce23d801c 100644 --- a/plugins/config/src/FromConfigAdapter/FromConfigSequenceAdapter.ts +++ b/plugins/config/src/FromConfigAdapter/FromConfigSequenceAdapter.ts @@ -22,6 +22,7 @@ export default class FromSequenceConfigAdapter extends FromConfigAdapter { .toPromise() // return ObservableCreate(async observer => { // const feats = await super.getFeatures(region).pipe(toArray()).toPromise() + feats.forEach(feat => { const featStart = feat.get('start') const seqStart = start - featStart @@ -32,9 +33,10 @@ export default class FromSequenceConfigAdapter extends FromConfigAdapter { observer.next( new SimpleFeature({ ...feat.toJSON(), - seq, end: region.end, start: region.start, + seq, + uniqueId: `${Math.random()}`, }), ) }) diff --git a/plugins/config/src/FromConfigAdapter/configSchema.ts b/plugins/config/src/FromConfigAdapter/configSchema.ts index f14cdce1c0..c09bd4d914 100644 --- a/plugins/config/src/FromConfigAdapter/configSchema.ts +++ b/plugins/config/src/FromConfigAdapter/configSchema.ts @@ -41,6 +41,14 @@ export const sequenceConfigSchema = ConfigurationSchema( type: 'string', defaultValue: 'SimpleFeature', }, + + // occasionally assemblies may not be associated with the assemblyManager + // e.g. in the case of the "read assembly" that is used in read vs ref + // visualizations + noAssemblyManager: { + type: 'boolean', + defaultValue: false, + }, }, { explicitlyTyped: true }, ) diff --git a/plugins/linear-comparative-view/src/LinearComparativeView/model.ts b/plugins/linear-comparative-view/src/LinearComparativeView/model.ts index 10fb939d74..5c76a09efe 100644 --- a/plugins/linear-comparative-view/src/LinearComparativeView/model.ts +++ b/plugins/linear-comparative-view/src/LinearComparativeView/model.ts @@ -65,8 +65,10 @@ export default function stateModelFactory(pluginManager: PluginManager) { pluginManager.pluggableConfigSchemaType('track'), ), - // this represents assemblies in the specialized - // read vs ref dotplot view + // this represents assemblies in the specialized read vs ref dotplot + // view. note that this was a types.frozen but is turned into an actual + // assembly type because we need to be able to use resolveIdentifier to + // resolve the sequence track inside the assembly viewAssemblyConfigs: types.array(assemblyConfigSchemasType), }), ) diff --git a/plugins/linear-comparative-view/src/index.tsx b/plugins/linear-comparative-view/src/index.tsx index 4ab94fe9e9..966b907c2b 100644 --- a/plugins/linear-comparative-view/src/index.tsx +++ b/plugins/linear-comparative-view/src/index.tsx @@ -320,6 +320,7 @@ function WindowSizeDlg(props: { assemblyNames: [readAssembly], adapter: { type: 'FromConfigSequenceAdapter', + noAssemblyManager: true, features: [ { start: 0, From 11dc6157472ce7d7c12674fbd1b93f3bf2c3cb7a Mon Sep 17 00:00:00 2001 From: Colin Date: Sat, 13 Feb 2021 14:54:13 -0700 Subject: [PATCH 04/40] Fix realStart --- plugins/dotplot-view/src/index.ts | 9 +++++---- plugins/linear-comparative-view/src/index.tsx | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/plugins/dotplot-view/src/index.ts b/plugins/dotplot-view/src/index.ts index 7f217b3740..4d9660894e 100644 --- a/plugins/dotplot-view/src/index.ts +++ b/plugins/dotplot-view/src/index.ts @@ -191,7 +191,7 @@ export default class DotplotPlugin extends Plugin { const saLengthSansClipping = getLengthSansClipping(saCigar) const saStrandNormalized = saStrand === '-' ? -1 : 1 const saClipPos = getClip(saCigar, saStrandNormalized) - const saRealStart = +saStart - 1 + saClipPos + const saRealStart = +saStart - 1 return { refName: saRef, start: saRealStart, @@ -217,9 +217,10 @@ export default class DotplotPlugin extends Plugin { end: clipPos + getLengthSansClipping(cigar), } - // if secondary alignment or supplementary, calculate length from SA[0]'s CIGAR - // which is the primary alignments. otherwise it is the primary alignment just use - // seq.length if primary alignment + // if secondary alignment or supplementary, calculate length + // from SA[0]'s CIGAR which is the primary alignments. + // otherwise it is the primary alignment just use seq.length if + // primary alignment const totalLength = // eslint-disable-next-line no-bitwise flags & 2048 diff --git a/plugins/linear-comparative-view/src/index.tsx b/plugins/linear-comparative-view/src/index.tsx index 966b907c2b..c010fbf811 100644 --- a/plugins/linear-comparative-view/src/index.tsx +++ b/plugins/linear-comparative-view/src/index.tsx @@ -191,7 +191,7 @@ function WindowSizeDlg(props: { const saLengthSansClipping = getLengthSansClipping(saCigar) const saStrandNormalized = saStrand === '-' ? -1 : 1 const saClipPos = getClip(saCigar, saStrandNormalized) - const saRealStart = +saStart - 1 + saClipPos + const saRealStart = +saStart - 1 return { refName: saRef, start: saRealStart, From cd716e6047d595128cec30e780eabf20821a1301 Mon Sep 17 00:00:00 2001 From: Colin Date: Sat, 13 Feb 2021 15:13:57 -0700 Subject: [PATCH 05/40] Minor refactor --- plugins/dotplot-view/src/index.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/plugins/dotplot-view/src/index.ts b/plugins/dotplot-view/src/index.ts index 4d9660894e..ec7f411a8e 100644 --- a/plugins/dotplot-view/src/index.ts +++ b/plugins/dotplot-view/src/index.ts @@ -158,6 +158,8 @@ export default class DotplotPlugin extends Plugin { } const cb = (feature: Feature, display: IAnyStateTreeNode) => { + // @ts-ignore + const { parentTrack } = display return feature ? [ { @@ -174,11 +176,7 @@ export default class DotplotPlugin extends Plugin { : feature.get('SA')) || '' const readName = feature.get('name') const readAssembly = `${readName}_assembly` - const trackAssembly = getConf( - // @ts-ignore - display.parentTrack, - 'assemblyNames', - )[0] + const [trackAssembly] = getConf(parentTrack, 'assemblyNames') const assemblyNames = [trackAssembly, readAssembly] const trackId = `track-${Date.now()}` const trackName = `${readName}_vs_${trackAssembly}` From ab9495597fd97c3f664397dbc6ec8e6711d7b0d9 Mon Sep 17 00:00:00 2001 From: Colin Date: Sat, 13 Feb 2021 15:22:32 -0700 Subject: [PATCH 06/40] Load reference sequence track also --- plugins/linear-comparative-view/src/index.tsx | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/plugins/linear-comparative-view/src/index.tsx b/plugins/linear-comparative-view/src/index.tsx index c010fbf811..ece01bc400 100644 --- a/plugins/linear-comparative-view/src/index.tsx +++ b/plugins/linear-comparative-view/src/index.tsx @@ -250,6 +250,7 @@ function WindowSizeDlg(props: { ) const seqTrackId = `${readName}_${Date.now()}` + const sequenceTrackConf = getConf(assembly, 'sequence') session.addView('LinearSyntenyView', { type: 'LinearSyntenyView', @@ -267,6 +268,23 @@ function WindowSizeDlg(props: { assemblyName: trackAssembly, } }), + tracks: [ + { + id: `${Math.random()}`, + type: 'ReferenceSequenceTrack', + assemblyNames: [trackAssembly], + configuration: sequenceTrackConf.trackId, + displays: [ + { + id: `${Math.random()}`, + type: 'LinearReferenceSequenceDisplay', + showReverse: false, + showTranslation: false, + configuration: `${seqTrackId}-LinearReferenceSequenceDisplay`, + }, + ], + }, + ], }, { type: 'LinearGenomeView', From 6fe18ccb70df1ea1307ba6d649723385a6321bc2 Mon Sep 17 00:00:00 2001 From: Colin Date: Sat, 13 Feb 2021 15:22:48 -0700 Subject: [PATCH 07/40] Catch against app crash from null renderArgs trying to be used in blockDestroy --- .../models/serverSideRenderedBlock.ts | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/plugins/linear-genome-view/src/BaseLinearDisplay/models/serverSideRenderedBlock.ts b/plugins/linear-genome-view/src/BaseLinearDisplay/models/serverSideRenderedBlock.ts index 5d90c2be09..e8b6677ed3 100644 --- a/plugins/linear-genome-view/src/BaseLinearDisplay/models/serverSideRenderedBlock.ts +++ b/plugins/linear-genome-view/src/BaseLinearDisplay/models/serverSideRenderedBlock.ts @@ -158,15 +158,18 @@ const blockState = types const { rpcManager } = getSession(self) const { rendererType } = display const { renderArgs } = renderBlockData(cast(self)) - rendererType - .freeResourcesInClient( - rpcManager, - JSON.parse(JSON.stringify(renderArgs)), - ) - .catch((e: Error) => { - // just console.error if it's something while it's being destroyed - console.warn('Error while destroying block', e) - }) + // renderArgs can be undefined if an error occured in this block + if (renderArgs) { + rendererType + .freeResourcesInClient( + rpcManager, + JSON.parse(JSON.stringify(renderArgs)), + ) + .catch((e: Error) => { + // just console.error if it's something while it's being destroyed + console.warn('Error while destroying block', e) + }) + } }, } }) From 6c92ac104bd519947a60a9b6da8407ac6e53231c Mon Sep 17 00:00:00 2001 From: Colin Date: Sat, 13 Feb 2021 15:23:37 -0700 Subject: [PATCH 08/40] Smaller height --- plugins/linear-comparative-view/src/index.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/linear-comparative-view/src/index.tsx b/plugins/linear-comparative-view/src/index.tsx index ece01bc400..0b9c2854c1 100644 --- a/plugins/linear-comparative-view/src/index.tsx +++ b/plugins/linear-comparative-view/src/index.tsx @@ -280,6 +280,7 @@ function WindowSizeDlg(props: { type: 'LinearReferenceSequenceDisplay', showReverse: false, showTranslation: false, + height: 35, configuration: `${seqTrackId}-LinearReferenceSequenceDisplay`, }, ], @@ -310,6 +311,7 @@ function WindowSizeDlg(props: { type: 'LinearReferenceSequenceDisplay', showReverse: false, showTranslation: false, + height: 35, configuration: `${seqTrackId}-LinearReferenceSequenceDisplay`, }, ], From d69e5169530c5c579f3e907a68b3fb4de30de40b Mon Sep 17 00:00:00 2001 From: Colin Date: Sat, 13 Feb 2021 16:15:14 -0700 Subject: [PATCH 09/40] Random refactoring --- packages/core/util/index.ts | 9 ++++++ packages/core/util/tracks.ts | 2 +- packages/core/util/types/index.ts | 13 ++++++++ .../FromConfigSequenceAdapter.test.ts | 1 - .../models/serverSideRenderedBlock.ts | 32 ++++++++----------- 5 files changed, 36 insertions(+), 21 deletions(-) diff --git a/packages/core/util/index.ts b/packages/core/util/index.ts index b856397e94..fd05a92da1 100644 --- a/packages/core/util/index.ts +++ b/packages/core/util/index.ts @@ -17,6 +17,7 @@ import { Feature } from './simpleFeature' import { TypeTestedByPredicate, isSessionModel, + isDisplayModel, isViewModel, isTrackModel, Region, @@ -257,6 +258,14 @@ export function getContainingTrack(node: IAnyStateTreeNode) { } } +export function getContainingDisplay(node: IAnyStateTreeNode) { + try { + return findParentThatIs(node, isDisplayModel) + } catch (e) { + throw new Error('no containing track found') + } +} + /** * Assemble a 1-based "locString" from an interbase genomic location * @param region - Region diff --git a/packages/core/util/tracks.ts b/packages/core/util/tracks.ts index acc0dad864..96972621cb 100644 --- a/packages/core/util/tracks.ts +++ b/packages/core/util/tracks.ts @@ -19,7 +19,7 @@ export function getTrackAssemblyNames( return [readConfObject(parent, 'name')] } } - return trackAssemblyNames + return trackAssemblyNames as string[] } /** return the rpcSessionId of the highest parent node in the tree that has an rpcSessionId */ diff --git a/packages/core/util/types/index.ts b/packages/core/util/types/index.ts index e64b378f09..c7f4a37a95 100644 --- a/packages/core/util/types/index.ts +++ b/packages/core/util/types/index.ts @@ -140,6 +140,19 @@ export function isTrackModel(thing: unknown): thing is AbstractTrackModel { ) } +export interface AbstractDisplayModel { + parentTrack: AbstractTrackModel +} +export function isDisplayModel(thing: unknown): thing is AbstractDisplayModel { + return ( + typeof thing === 'object' && + thing !== null && + 'configuration' in thing && + // @ts-ignore + thing.configuration.displayId + ) +} + export interface TrackViewModel extends AbstractViewModel { showTrack(trackId: string): void hideTrack(trackId: string): void diff --git a/plugins/config/src/FromConfigAdapter/FromConfigSequenceAdapter.test.ts b/plugins/config/src/FromConfigAdapter/FromConfigSequenceAdapter.test.ts index 75bc4f4879..09e61cf427 100644 --- a/plugins/config/src/FromConfigAdapter/FromConfigSequenceAdapter.test.ts +++ b/plugins/config/src/FromConfigAdapter/FromConfigSequenceAdapter.test.ts @@ -36,7 +36,6 @@ test('adapter can fetch sequences', async () => { }) const featuresArray = await result.pipe(toArray()).toPromise() expect(featuresArray.length).toBe(2) - expect(featuresArray[0].toJSON()).toEqual(features[1]) }) test('adapter can fetch regions 1', async () => { diff --git a/plugins/linear-genome-view/src/BaseLinearDisplay/models/serverSideRenderedBlock.ts b/plugins/linear-genome-view/src/BaseLinearDisplay/models/serverSideRenderedBlock.ts index e8b6677ed3..8547991630 100644 --- a/plugins/linear-genome-view/src/BaseLinearDisplay/models/serverSideRenderedBlock.ts +++ b/plugins/linear-genome-view/src/BaseLinearDisplay/models/serverSideRenderedBlock.ts @@ -1,13 +1,14 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import { types, getParent, isAlive, cast, Instance } from 'mobx-state-tree' import { Component } from 'react' -import { getConf, readConfObject } from '@jbrowse/core/configuration' +import { readConfObject } from '@jbrowse/core/configuration' import { Region } from '@jbrowse/core/util/types/mst' import { assembleLocString, makeAbortableReaction, getSession, + getContainingDisplay, } from '@jbrowse/core/util' import { getTrackAssemblyNames, @@ -183,26 +184,19 @@ export type BlockModel = Instance function renderBlockData(self: Instance) { const { assemblyManager, rpcManager } = getSession(self) let display = getParent(self) - while (!(display.configuration && getConf(display, 'displayId'))) { - display = getParent(display) - } - const assemblyNames = getTrackAssemblyNames(display.parentTrack) - let cannotBeRenderedReason - if (!assemblyNames.includes(self.region.assemblyName)) { - let matchFound = false - assemblyNames.forEach((assemblyName: string) => { - const assembly = assemblyManager.get(assemblyName) - if (assembly && assembly.hasName(assemblyName)) { - matchFound = true + const display = getContainingDisplay(self) as any + const assemblyNames = getTrackAssemblyNames(display.parentTrack) + const regionAsm = self.region.assemblyName + if ( + !assemblyNames.includes(regionAsm) && + !assemblyNames.find(assemblyName => + assemblyManager.get(assemblyName)?.hasName(regionAsm), + ) + ) { + return { + displayError: `region assembly (${regionAsm}) does not match track assemblies (${assemblyNames})`, } - }) - if (!matchFound) { - cannotBeRenderedReason = `region assembly (${self.region.assemblyName}) does not match track assemblies (${assemblyNames})` } - } - if (!cannotBeRenderedReason) { - cannotBeRenderedReason = display.regionCannotBeRendered(self.region) - } const { renderProps } = display const { rendererType } = display const { config } = renderProps From 191b04dd21a8cbabc1a17286e61aad75e5c0545d Mon Sep 17 00:00:00 2001 From: Colin Date: Sat, 13 Feb 2021 17:15:08 -0700 Subject: [PATCH 10/40] Calculate clipPos forward strand even on reverse strand reads to get sequence track right on both top and bottom --- packages/core/util/index.ts | 50 ++++++++++++++++++ plugins/linear-comparative-view/src/index.tsx | 36 ++++++++----- .../components/DivSequenceRendering.tsx | 52 +------------------ 3 files changed, 73 insertions(+), 65 deletions(-) diff --git a/packages/core/util/index.ts b/packages/core/util/index.ts index fd05a92da1..57ce86c4b6 100644 --- a/packages/core/util/index.ts +++ b/packages/core/util/index.ts @@ -811,3 +811,53 @@ export function stringify({ export const isElectron = typeof window !== 'undefined' && Boolean(window.electron) + +export function revcom(seqString: string) { + return complement(seqString).split('').reverse().join('') +} + +export const complement = (() => { + const complementRegex = /[ACGT]/gi + + // from bioperl: tr/acgtrymkswhbvdnxACGTRYMKSWHBVDNX/tgcayrkmswdvbhnxTGCAYRKMSWDVBHNX/ + // generated with: + // perl -MJSON -E '@l = split "","acgtrymkswhbvdnxACGTRYMKSWHBVDNX"; print to_json({ map { my $in = $_; tr/acgtrymkswhbvdnxACGTRYMKSWHBVDNX/tgcayrkmswdvbhnxTGCAYRKMSWDVBHNX/; $in => $_ } @l})' + const complementTable = { + S: 'S', + w: 'w', + T: 'A', + r: 'y', + a: 't', + N: 'N', + K: 'M', + x: 'x', + d: 'h', + Y: 'R', + V: 'B', + y: 'r', + M: 'K', + h: 'd', + k: 'm', + C: 'G', + g: 'c', + t: 'a', + A: 'T', + n: 'n', + W: 'W', + X: 'X', + m: 'k', + v: 'b', + B: 'V', + s: 's', + H: 'D', + c: 'g', + D: 'H', + b: 'v', + R: 'Y', + G: 'C', + } as { [key: string]: string } + + return (seqString: string) => { + return seqString.replace(complementRegex, m => complementTable[m] || '') + } +})() diff --git a/plugins/linear-comparative-view/src/index.tsx b/plugins/linear-comparative-view/src/index.tsx index 0b9c2854c1..e98f7b82fb 100644 --- a/plugins/linear-comparative-view/src/index.tsx +++ b/plugins/linear-comparative-view/src/index.tsx @@ -1,4 +1,4 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ +/* eslint-disable @typescript-eslint/no-explicit-any,no-bitwise */ import React, { useState } from 'react' import { makeStyles } from '@material-ui/core/styles' import Button from '@material-ui/core/Button' @@ -121,6 +121,7 @@ interface ReducedFeature { start: number clipPos: number end: number + strand: number seqLength: number syntenyId?: number uniqueId: string @@ -164,8 +165,8 @@ function WindowSizeDlg(props: { try { const session = getSession(track) const view = getContainingView(track) - const clipPos = feature.get('clipPos') const cigar = feature.get('CIGAR') + const clipPos = getClip(cigar, 1) const flags = feature.get('flags') const SA: string = (feature.get('tags') ? feature.get('tags').SA : feature.get('SA')) || '' @@ -190,7 +191,7 @@ function WindowSizeDlg(props: { const saLength = getLength(saCigar) const saLengthSansClipping = getLengthSansClipping(saCigar) const saStrandNormalized = saStrand === '-' ? -1 : 1 - const saClipPos = getClip(saCigar, saStrandNormalized) + const saClipPos = getClip(saCigar, 1) // saStrandNormalized) const saRealStart = +saStart - 1 return { refName: saRef, @@ -211,6 +212,7 @@ function WindowSizeDlg(props: { }) const feat = feature.toJSON() + feat.clipPos = clipPos feat.mate = { refName: readName, @@ -222,7 +224,6 @@ function WindowSizeDlg(props: { // which is the primary alignments. otherwise it is the primary alignment just use // seq.length if primary alignment const totalLength = - // eslint-disable-next-line no-bitwise flags & 2048 ? getLength(supplementaryAlignments[0].CIGAR) : getLength(cigar) @@ -237,6 +238,8 @@ function WindowSizeDlg(props: { }) features.sort((a, b) => a.clipPos - b.clipPos) + const featSeq = feature.get('seq') + // the config feature store includes synthetic mate features // mapped to the read assembly const configFeatureStore = features.concat( @@ -244,13 +247,25 @@ function WindowSizeDlg(props: { features.map(f => f.mate), ) + const expand = 2 * windowSize const refLength = features.reduce( - (a, f) => a + f.end - f.start + 2 * windowSize, + (a, f) => a + f.end - f.start + expand, 0, ) const seqTrackId = `${readName}_${Date.now()}` const sequenceTrackConf = getConf(assembly, 'sequence') + const lgvRegions = features + .map(f => { + return { + ...f, + start: f.start - windowSize, + end: f.end + windowSize, + refName: f.refName, + assemblyName: trackAssembly, + } + }) + .sort((a, b) => a.clipPos - b.clipPos) session.addView('LinearSyntenyView', { type: 'LinearSyntenyView', @@ -260,14 +275,7 @@ function WindowSizeDlg(props: { hideHeader: true, offsetPx: 0, bpPerPx: refLength / view.width, - displayedRegions: features.map(f => { - return { - start: f.start - windowSize, - end: f.end + windowSize, - refName: f.refName, - assemblyName: trackAssembly, - } - }), + displayedRegions: lgvRegions, tracks: [ { id: `${Math.random()}`, @@ -345,7 +353,7 @@ function WindowSizeDlg(props: { { start: 0, end: totalLength, - seq: feat.seq, + seq: featSeq, refName: readName, uniqueId: `${Math.random()}`, id: `${Math.random()}`, diff --git a/plugins/sequence/src/DivSequenceRenderer/components/DivSequenceRendering.tsx b/plugins/sequence/src/DivSequenceRenderer/components/DivSequenceRendering.tsx index 73d1abf4f6..1367010859 100644 --- a/plugins/sequence/src/DivSequenceRenderer/components/DivSequenceRendering.tsx +++ b/plugins/sequence/src/DivSequenceRenderer/components/DivSequenceRendering.tsx @@ -6,7 +6,7 @@ import { Region } from '@jbrowse/core/util/types' import { createJBrowseTheme } from '@jbrowse/core/ui' import { observer } from 'mobx-react' import React from 'react' -import { bpSpanPx } from '@jbrowse/core/util' +import { bpSpanPx, revcom, complement } from '@jbrowse/core/util' interface MyProps { features: Map @@ -20,56 +20,6 @@ interface MyProps { showTranslation: boolean } -function revcom(seqString: string) { - return complement(seqString).split('').reverse().join('') -} - -const complement = (() => { - const complementRegex = /[ACGT]/gi - - // from bioperl: tr/acgtrymkswhbvdnxACGTRYMKSWHBVDNX/tgcayrkmswdvbhnxTGCAYRKMSWDVBHNX/ - // generated with: - // perl -MJSON -E '@l = split "","acgtrymkswhbvdnxACGTRYMKSWHBVDNX"; print to_json({ map { my $in = $_; tr/acgtrymkswhbvdnxACGTRYMKSWHBVDNX/tgcayrkmswdvbhnxTGCAYRKMSWDVBHNX/; $in => $_ } @l})' - const complementTable = { - S: 'S', - w: 'w', - T: 'A', - r: 'y', - a: 't', - N: 'N', - K: 'M', - x: 'x', - d: 'h', - Y: 'R', - V: 'B', - y: 'r', - M: 'K', - h: 'd', - k: 'm', - C: 'G', - g: 'c', - t: 'a', - A: 'T', - n: 'n', - W: 'W', - X: 'X', - m: 'k', - v: 'b', - B: 'V', - s: 's', - H: 'D', - c: 'g', - D: 'H', - b: 'v', - R: 'Y', - G: 'C', - } as { [key: string]: string } - - return (seqString: string) => { - return seqString.replace(complementRegex, m => complementTable[m] || '') - } -})() - const defaultStarts = ['ATG'] const defaultStops = ['TAA', 'TAG', 'TGA'] const defaultCodonTable = { From 10c19bb6d6df564420428132ba9f1f59b7335033 Mon Sep 17 00:00:00 2001 From: Colin Date: Mon, 15 Feb 2021 12:49:54 -0700 Subject: [PATCH 11/40] Auto fetch the primary alignment --- plugins/linear-comparative-view/src/index.tsx | 117 ++++++++++++------ 1 file changed, 82 insertions(+), 35 deletions(-) diff --git a/plugins/linear-comparative-view/src/index.tsx b/plugins/linear-comparative-view/src/index.tsx index e98f7b82fb..3825dbff56 100644 --- a/plugins/linear-comparative-view/src/index.tsx +++ b/plugins/linear-comparative-view/src/index.tsx @@ -1,19 +1,23 @@ /* eslint-disable @typescript-eslint/no-explicit-any,no-bitwise */ -import React, { useState } from 'react' +import React, { useEffect, useState } from 'react' import { makeStyles } from '@material-ui/core/styles' -import Button from '@material-ui/core/Button' -import TextField from '@material-ui/core/TextField' -import Typography from '@material-ui/core/Typography' -import Dialog from '@material-ui/core/Dialog' -import DialogContent from '@material-ui/core/DialogContent' -import DialogTitle from '@material-ui/core/DialogTitle' -import IconButton from '@material-ui/core/IconButton' +import { + Button, + CircularProgress, + TextField, + Typography, + Dialog, + DialogContent, + DialogTitle, + IconButton, +} from '@material-ui/core' import CloseIcon from '@material-ui/icons/Close' import AddIcon from '@material-ui/icons/Add' import CalendarIcon from '@material-ui/icons/CalendarViewDay' import { ConfigurationSchema, getConf } from '@jbrowse/core/configuration' import AdapterType from '@jbrowse/core/pluggableElementTypes/AdapterType' import DisplayType from '@jbrowse/core/pluggableElementTypes/DisplayType' +import SimpleFeature, { Feature } from '@jbrowse/core/util/simpleFeature' import { createBaseTrackConfig, createBaseTrackModel, @@ -28,9 +32,10 @@ import { getContainingView, isAbstractMenuManager, } from '@jbrowse/core/util' -import { Feature } from '@jbrowse/core/util/simpleFeature' + import { MismatchParser } from '@jbrowse/plugin-alignments' import { autorun } from 'mobx' +import { getRpcSessionId } from '@jbrowse/core/util/tracks' import { configSchemaFactory as linearComparativeDisplayConfigSchemaFactory, ReactComponent as LinearComparativeDisplayReactComponent, @@ -154,15 +159,46 @@ function WindowSizeDlg(props: { const classes = useStyles() const { track, - display: { feature }, + display: { feature: preFeature }, handleClose, } = props const [window, setWindowSize] = useState('0') const [error, setError] = useState() const windowSize = +window + const [featureDownloaded, setFeatureDownloaded] = useState() + useEffect(() => { + let done = false + ;(async () => { + if (preFeature.get('flags') & 2048) { + const SA: string = + (preFeature.get('tags') + ? preFeature.get('tags').SA + : preFeature.get('SA')) || '' + const primaryAln = SA.split(';')[0] + const [saRef, saStart] = primaryAln.split(',') + const { rpcManager } = getSession(track) + const adapterConfig = getConf(track, 'adapter') + const sessionId = getRpcSessionId(track) + const feats = (await rpcManager.call(sessionId, 'CoreGetFeatures', { + adapterConfig, + sessionId, + region: { refName: saRef, start: +saStart - 1, end: +saStart }, + })) as any[] + const primaryFeat = feats.find(f => f.name === preFeature.get('name')) + if (!done) { + setFeatureDownloaded(new SimpleFeature(primaryFeat)) + } + } + })() + + return () => { + done = true + } + }, [preFeature, track]) function onSubmit() { try { + const feature = featureDownloaded || preFeature const session = getSession(track) const view = getContainingView(track) const cigar = feature.get('CIGAR') @@ -220,9 +256,9 @@ function WindowSizeDlg(props: { end: clipPos + getLengthSansClipping(cigar), } - // if secondary alignment or supplementary, calculate length from SA[0]'s CIGAR - // which is the primary alignments. otherwise it is the primary alignment just use - // seq.length if primary alignment + // if secondary alignment or supplementary, calculate length from SA[0]'s + // CIGAR which is the primary alignments. otherwise it is the primary + // alignment just use seq.length if primary alignment const totalLength = flags & 2048 ? getLength(supplementaryAlignments[0].CIGAR) @@ -383,6 +419,7 @@ function WindowSizeDlg(props: { setError(e) } } + return ( -
- - Show an extra window size around each part of the split alignment. - Using a larger value can allow you to see more genomic context. - - {error ? {`${error}`} : null} + {!featureDownloaded ? ( +
+ + To accurately perform comparison we are fetching the primary + alignment. Loading primary feature... + + +
+ ) : ( +
+ + Show an extra window size around each part of the split alignment. + Using a larger value can allow you to see more genomic context. + + {error ? {`${error}`} : null} - { - setWindowSize(event.target.value) - }} - label="Set window size" - /> - -
+ { + setWindowSize(event.target.value) + }} + label="Set window size" + /> + +
+ )}
) From 79639ace90d644cf9d59e939a19ffc7a9f3286fe Mon Sep 17 00:00:00 2001 From: Colin Date: Mon, 15 Feb 2021 13:12:10 -0700 Subject: [PATCH 12/40] Fix some typings --- packages/core/rpc/coreRpcMethods.ts | 11 +++++++++-- plugins/linear-comparative-view/src/index.tsx | 9 +++++---- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/packages/core/rpc/coreRpcMethods.ts b/packages/core/rpc/coreRpcMethods.ts index 6648d5ae14..9d03b48ed7 100644 --- a/packages/core/rpc/coreRpcMethods.ts +++ b/packages/core/rpc/coreRpcMethods.ts @@ -14,6 +14,7 @@ import { } from '../data_adapters/BaseAdapter' import { Region } from '../util/types' import { checkAbortSignal, renameRegionsIfNeeded } from '../util' +import SimpleFeature, { SimpleFeatureSerialized } from '../util/simpleFeature' export class CoreGetRefNames extends RpcMethodType { name = 'CoreGetRefNames' @@ -61,6 +62,12 @@ export class CoreGetFileInfo extends RpcMethodType { export class CoreGetFeatures extends RpcMethodType { name = 'CoreGetFeatures' + async deserializeReturn(feats: SimpleFeatureSerialized[]) { + return feats.map(feat => { + return new SimpleFeature(feat) + }) + } + async execute(args: { sessionId: string signal: RemoteAbortSignal @@ -76,8 +83,8 @@ export class CoreGetFeatures extends RpcMethodType { ) if (isFeatureAdapter(dataAdapter)) { const ret = dataAdapter.getFeatures(region) - const feats = await ret.pipe(toArray()).toPromise() - return JSON.parse(JSON.stringify(feats)) + const r = await ret.pipe(toArray()).toPromise() + return r.map(f => f.toJSON()) } return [] } diff --git a/plugins/linear-comparative-view/src/index.tsx b/plugins/linear-comparative-view/src/index.tsx index 3825dbff56..360c910589 100644 --- a/plugins/linear-comparative-view/src/index.tsx +++ b/plugins/linear-comparative-view/src/index.tsx @@ -184,9 +184,11 @@ function WindowSizeDlg(props: { sessionId, region: { refName: saRef, start: +saStart - 1, end: +saStart }, })) as any[] - const primaryFeat = feats.find(f => f.name === preFeature.get('name')) + const primaryFeat = feats.find( + f => f.get('name') === preFeature.get('name'), + ) if (!done) { - setFeatureDownloaded(new SimpleFeature(primaryFeat)) + setFeatureDownloaded(primaryFeat) } } })() @@ -295,9 +297,8 @@ function WindowSizeDlg(props: { .map(f => { return { ...f, - start: f.start - windowSize, + start: Math.max(0, f.start - windowSize), end: f.end + windowSize, - refName: f.refName, assemblyName: trackAssembly, } }) From 22e88e7d4007db4035e96a02bb745905ff564644 Mon Sep 17 00:00:00 2001 From: Colin Date: Mon, 15 Feb 2021 13:15:04 -0700 Subject: [PATCH 13/40] Cleanup lint --- plugins/linear-comparative-view/src/index.tsx | 12 +++++++----- .../LinearGenomeView/components/SequenceDialog.tsx | 9 +++------ 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/plugins/linear-comparative-view/src/index.tsx b/plugins/linear-comparative-view/src/index.tsx index 360c910589..730fdc7c22 100644 --- a/plugins/linear-comparative-view/src/index.tsx +++ b/plugins/linear-comparative-view/src/index.tsx @@ -17,7 +17,7 @@ import CalendarIcon from '@material-ui/icons/CalendarViewDay' import { ConfigurationSchema, getConf } from '@jbrowse/core/configuration' import AdapterType from '@jbrowse/core/pluggableElementTypes/AdapterType' import DisplayType from '@jbrowse/core/pluggableElementTypes/DisplayType' -import SimpleFeature, { Feature } from '@jbrowse/core/util/simpleFeature' +import { Feature } from '@jbrowse/core/util/simpleFeature' import { createBaseTrackConfig, createBaseTrackModel, @@ -165,7 +165,7 @@ function WindowSizeDlg(props: { const [window, setWindowSize] = useState('0') const [error, setError] = useState() const windowSize = +window - const [featureDownloaded, setFeatureDownloaded] = useState() + const [primaryFeature, setPrimaryFeature] = useState() useEffect(() => { let done = false ;(async () => { @@ -188,8 +188,10 @@ function WindowSizeDlg(props: { f => f.get('name') === preFeature.get('name'), ) if (!done) { - setFeatureDownloaded(primaryFeat) + setPrimaryFeature(primaryFeat) } + } else { + setPrimaryFeature(preFeature) } })() @@ -200,7 +202,7 @@ function WindowSizeDlg(props: { function onSubmit() { try { - const feature = featureDownloaded || preFeature + const feature = primaryFeature || preFeature const session = getSession(track) const view = getContainingView(track) const cigar = feature.get('CIGAR') @@ -439,7 +441,7 @@ function WindowSizeDlg(props: { - {!featureDownloaded ? ( + {!primaryFeature ? (
To accurately perform comparison we are fetching the primary diff --git a/plugins/linear-genome-view/src/LinearGenomeView/components/SequenceDialog.tsx b/plugins/linear-genome-view/src/LinearGenomeView/components/SequenceDialog.tsx index aae362b781..2c2f3eb71f 100644 --- a/plugins/linear-genome-view/src/LinearGenomeView/components/SequenceDialog.tsx +++ b/plugins/linear-genome-view/src/LinearGenomeView/components/SequenceDialog.tsx @@ -22,10 +22,7 @@ import TextField from '@material-ui/core/TextField' // core import { getSession } from '@jbrowse/core/util' -import SimpleFeature, { - Feature, - SimpleFeatureSerialized, -} from '@jbrowse/core/util/simpleFeature' +import { Feature } from '@jbrowse/core/util/simpleFeature' // other import { formatSeqFasta, SeqChunk } from '@jbrowse/core/util/formatFastaStrings' import { LinearGenomeViewModel } from '..' @@ -80,10 +77,10 @@ async function fetchSequence( sessionId, }), ), - )) as SimpleFeatureSerialized[][] + )) as Feature[][] // assumes that we get whole sequence in a single getFeatures call - return chunks.map(chunk => new SimpleFeature(chunk[0])) + return chunks.map(chunk => chunk[0]) } function SequenceDialog({ From b5507fbbbd3c1af35711c9d120fcc03ca08e589a Mon Sep 17 00:00:00 2001 From: Colin Date: Mon, 15 Feb 2021 14:02:59 -0700 Subject: [PATCH 14/40] Display a quality track for the read vs ref --- .../src/FromConfigAdapter/configSchema.ts | 4 ++ plugins/linear-comparative-view/src/index.tsx | 37 +++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/plugins/config/src/FromConfigAdapter/configSchema.ts b/plugins/config/src/FromConfigAdapter/configSchema.ts index c09bd4d914..a0fa43f5ce 100644 --- a/plugins/config/src/FromConfigAdapter/configSchema.ts +++ b/plugins/config/src/FromConfigAdapter/configSchema.ts @@ -11,6 +11,10 @@ export const configSchema = ConfigurationSchema( type: 'string', defaultValue: 'SimpleFeature', }, + noAssemblyManager: { + type: 'boolean', + defaultValue: false, + }, }, { explicitlyTyped: true }, ) diff --git a/plugins/linear-comparative-view/src/index.tsx b/plugins/linear-comparative-view/src/index.tsx index 730fdc7c22..c419b6cb13 100644 --- a/plugins/linear-comparative-view/src/index.tsx +++ b/plugins/linear-comparative-view/src/index.tsx @@ -166,6 +166,9 @@ function WindowSizeDlg(props: { const [error, setError] = useState() const windowSize = +window const [primaryFeature, setPrimaryFeature] = useState() + + // we need to fetch the primary alignment if the selected feature is 2048. + // this should be the first in the list of the SA tag useEffect(() => { let done = false ;(async () => { @@ -363,6 +366,40 @@ function WindowSizeDlg(props: { }, ], }, + { + id: `${Math.random()}`, + type: 'QuantitativeTrack', + configuration: { + trackId: 'qualTrack', + assemblyNames: [readAssembly], + name: 'Read quality', + type: 'QuantitativeTrack', + adapter: { + type: 'FromConfigAdapter', + noAssemblyManager: true, + features: primaryFeature + .get('qual') + .split(' ') + .map((qual, index) => { + return { + start: index, + end: index + 1, + refName: readName, + score: +qual, + assemblyName: readAssembly, + uniqueId: `feat_${index}`, + } + }), + }, + }, + displays: [ + { + id: `${Math.random()}`, + type: 'LinearWiggleDisplay', + height: 100, + }, + ], + }, ], }, ], From db77ee67986bfd73ddfeaeb12ed257dd1455b23b Mon Sep 17 00:00:00 2001 From: Colin Date: Mon, 15 Feb 2021 14:29:16 -0700 Subject: [PATCH 15/40] Throw a proper error on region assembly not matching track assembly --- .../ServerSideRenderedBlockContent.tsx | 18 +++--------------- .../models/serverSideRenderedBlock.ts | 6 +++--- 2 files changed, 6 insertions(+), 18 deletions(-) diff --git a/plugins/linear-genome-view/src/BaseLinearDisplay/components/ServerSideRenderedBlockContent.tsx b/plugins/linear-genome-view/src/BaseLinearDisplay/components/ServerSideRenderedBlockContent.tsx index b4b48f5097..8979ebff55 100644 --- a/plugins/linear-genome-view/src/BaseLinearDisplay/components/ServerSideRenderedBlockContent.tsx +++ b/plugins/linear-genome-view/src/BaseLinearDisplay/components/ServerSideRenderedBlockContent.tsx @@ -1,10 +1,9 @@ -import { makeStyles } from '@material-ui/core/styles' +import React, { useEffect, useState } from 'react' import Typography from '@material-ui/core/Typography' -import { observer, PropTypes as MobxPropTypes } from 'mobx-react' +import { makeStyles } from '@material-ui/core/styles' +import { observer } from 'mobx-react' import { getParent } from 'mobx-state-tree' import { getParentRenderProps } from '@jbrowse/core/util/tracks' -import PropTypes from 'prop-types' -import React, { useEffect, useState } from 'react' import Button from '@material-ui/core/Button' import RefreshIcon from '@material-ui/icons/Refresh' import ServerSideRenderedContent from './ServerSideRenderedContent' @@ -105,10 +104,6 @@ function BlockMessage({
{messageContent}
) } -BlockMessage.propTypes = { - messageContent: PropTypes.oneOfType([PropTypes.string, PropTypes.node]) - .isRequired, -} function BlockError({ error, @@ -141,13 +136,6 @@ function BlockError({
) } -BlockError.propTypes = { - error: MobxPropTypes.objectOrObservableObject.isRequired, - reload: PropTypes.func, -} -BlockError.defaultProps = { - reload: undefined, -} const ServerSideRenderedBlockContent = observer( ({ diff --git a/plugins/linear-genome-view/src/BaseLinearDisplay/models/serverSideRenderedBlock.ts b/plugins/linear-genome-view/src/BaseLinearDisplay/models/serverSideRenderedBlock.ts index 8547991630..ed38eca4d1 100644 --- a/plugins/linear-genome-view/src/BaseLinearDisplay/models/serverSideRenderedBlock.ts +++ b/plugins/linear-genome-view/src/BaseLinearDisplay/models/serverSideRenderedBlock.ts @@ -193,9 +193,9 @@ function renderBlockData(self: Instance) { assemblyManager.get(assemblyName)?.hasName(regionAsm), ) ) { - return { - displayError: `region assembly (${regionAsm}) does not match track assemblies (${assemblyNames})`, - } + throw new Error( + `region assembly (${regionAsm}) does not match track assemblies (${assemblyNames})`, + ) } const { renderProps } = display const { rendererType } = display From 163e8b9b2bd50a68a3458d029560691a2fa11df0 Mon Sep 17 00:00:00 2001 From: Colin Date: Mon, 15 Feb 2021 14:37:13 -0700 Subject: [PATCH 16/40] Lint --- .../src/BaseLinearDisplay/models/serverSideRenderedBlock.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/plugins/linear-genome-view/src/BaseLinearDisplay/models/serverSideRenderedBlock.ts b/plugins/linear-genome-view/src/BaseLinearDisplay/models/serverSideRenderedBlock.ts index ed38eca4d1..ee0bc010d0 100644 --- a/plugins/linear-genome-view/src/BaseLinearDisplay/models/serverSideRenderedBlock.ts +++ b/plugins/linear-genome-view/src/BaseLinearDisplay/models/serverSideRenderedBlock.ts @@ -189,9 +189,7 @@ function renderBlockData(self: Instance) { const regionAsm = self.region.assemblyName if ( !assemblyNames.includes(regionAsm) && - !assemblyNames.find(assemblyName => - assemblyManager.get(assemblyName)?.hasName(regionAsm), - ) + !assemblyNames.find(name => assemblyManager.get(name)?.hasName(regionAsm)) ) { throw new Error( `region assembly (${regionAsm}) does not match track assemblies (${assemblyNames})`, From 99b9ed622d1fa21f89ec0c7b87eaa09edabad8ec Mon Sep 17 00:00:00 2001 From: Colin Date: Mon, 15 Feb 2021 14:54:47 -0700 Subject: [PATCH 17/40] Fix error console logging related to lgv itest of changing assembly --- plugins/linear-comparative-view/src/index.tsx | 81 +++++++++++-------- test_data/volvox/config.json | 2 +- 2 files changed, 48 insertions(+), 35 deletions(-) diff --git a/plugins/linear-comparative-view/src/index.tsx b/plugins/linear-comparative-view/src/index.tsx index c419b6cb13..2e66774872 100644 --- a/plugins/linear-comparative-view/src/index.tsx +++ b/plugins/linear-comparative-view/src/index.tsx @@ -4,6 +4,8 @@ import { makeStyles } from '@material-ui/core/styles' import { Button, CircularProgress, + Checkbox, + FormControlLabel, TextField, Typography, Dialog, @@ -166,6 +168,7 @@ function WindowSizeDlg(props: { const [error, setError] = useState() const windowSize = +window const [primaryFeature, setPrimaryFeature] = useState() + const [qualTrack, setQualTrack] = useState(false) // we need to fetch the primary alignment if the selected feature is 2048. // this should be the first in the list of the SA tag @@ -211,6 +214,7 @@ function WindowSizeDlg(props: { const cigar = feature.get('CIGAR') const clipPos = getClip(cigar, 1) const flags = feature.get('flags') + const qual = feature.get('qual') as string const SA: string = (feature.get('tags') ? feature.get('tags').SA : feature.get('SA')) || '' const readName = feature.get('name') @@ -366,40 +370,40 @@ function WindowSizeDlg(props: { }, ], }, - { - id: `${Math.random()}`, - type: 'QuantitativeTrack', - configuration: { - trackId: 'qualTrack', - assemblyNames: [readAssembly], - name: 'Read quality', - type: 'QuantitativeTrack', - adapter: { - type: 'FromConfigAdapter', - noAssemblyManager: true, - features: primaryFeature - .get('qual') - .split(' ') - .map((qual, index) => { - return { - start: index, - end: index + 1, - refName: readName, - score: +qual, - assemblyName: readAssembly, - uniqueId: `feat_${index}`, - } - }), - }, - }, - displays: [ - { - id: `${Math.random()}`, - type: 'LinearWiggleDisplay', - height: 100, - }, - ], - }, + ...(qualTrack + ? [ + { + id: `${Math.random()}`, + type: 'QuantitativeTrack', + configuration: { + trackId: 'qualTrack', + assemblyNames: [readAssembly], + name: 'Read quality', + type: 'QuantitativeTrack', + adapter: { + type: 'FromConfigAdapter', + noAssemblyManager: true, + features: qual.split(' ').map((score, index) => { + return { + start: index, + end: index + 1, + refName: readName, + score: +score, + uniqueId: `feat_${index}`, + } + }), + }, + }, + displays: [ + { + id: `${Math.random()}`, + type: 'LinearWiggleDisplay', + height: 100, + }, + ], + }, + ] + : []), ], }, ], @@ -501,6 +505,15 @@ function WindowSizeDlg(props: { }} label="Set window size" /> + setQualTrack(val => !val)} + /> + } + label="Show qual track" + />