Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ability to use colorBy and filterBy for alignments track configs, and group by strand #4178

Merged
merged 11 commits into from
Nov 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 12 additions & 5 deletions packages/core/assemblyManager/assemblyConfigSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,13 @@ function assemblyConfigSchema(pluginManager: PluginManager) {
{
preProcessSnapshot: snap => {
// allow refNameAliases to be unspecified
if (!snap.adapter) {
return { adapter: { type: 'RefNameAliasAdapter' } }
}
return snap
return !snap.adapter
? {
adapter: {
type: 'RefNameAliasAdapter',
},
}
: snap
},
},
),
Expand All @@ -75,7 +78,11 @@ function assemblyConfigSchema(pluginManager: PluginManager) {
preProcessSnapshot: snap => {
// allow cytoBand to be unspecified
return !snap.adapter
? { adapter: { type: 'CytobandAdapter' } }
? {
adapter: {
type: 'CytobandAdapter',
},
}
: snap
},
},
Expand Down
13 changes: 7 additions & 6 deletions packages/core/assemblyManager/assemblyManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ function assemblyManagerFactory(conf: IAnyType, pm: PluginManager) {
assemblies: types.array(assemblyFactory(conf, pm)),
})
.views(self => ({
/**
* #getter
*/
get assemblyNameMap() {
const obj = {} as Record<string, Assembly>
for (const assembly of self.assemblies) {
Expand Down Expand Up @@ -59,12 +62,10 @@ function assemblyManagerFactory(conf: IAnyType, pm: PluginManager) {

/**
* #getter
* looks at jbrowse.assemblies, session.sessionAssemblies, and
* session.temporaryAssemblies to load from
* combined jbrowse.assemblies, session.sessionAssemblies, and
* session.temporaryAssemblies
*/
get assemblyList() {
// name is the explicit identifier and can be accessed without getConf,
// hence the union with {name:string}
const {
jbrowse: { assemblies },
session: { sessionAssemblies = [], temporaryAssemblies = [] } = {},
Expand All @@ -83,8 +84,8 @@ function assemblyManagerFactory(conf: IAnyType, pm: PluginManager) {
.views(self => ({
/**
* #method
* use this method instead of assemblyManager.get(assemblyName)
* to get an assembly with regions loaded
* use this method instead of assemblyManager.get(assemblyName) to get an
* assembly with regions loaded
*/
async waitForAssembly(assemblyName: string) {
if (!assemblyName) {
Expand Down
15 changes: 15 additions & 0 deletions packages/product-core/src/RootModel/BaseRootModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ export function BaseRootModelFactory({
),
})
.volatile(self => ({
/**
* #volatile
*/
rpcManager: new RpcManager(
pluginManager,
self.jbrowse.configuration.rpc,
Expand All @@ -67,9 +70,21 @@ export function BaseRootModelFactory({
},
),

/**
* #volatile
*/
adminMode: false,
/**
* #volatile
*/
error: undefined as unknown,
/**
* #volatile
*/
textSearchManager: new TextSearchManager(pluginManager),
/**
* #volatile
*/
pluginManager,
}))
.actions(self => ({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ const AlignmentsFeatureDetails = observer(function (props: {
<FeatureDetails
{...props}
// @ts-expect-error
descriptions={{ ...tags, tags: tags }}
descriptions={{ tags }}
feature={feat}
formatter={(value, key) =>
key === 'next_segment_position' ? (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -203,9 +203,8 @@ exports[`open up a widget 1`] = `
class="css-1m8nxnb-field"
>
<div
aria-label="Mapping quality of the mate/next segment"
class="css-167enf1-fieldDescription-fieldName"
data-mui-internal-clone-element="true"
class="css-ify9vk-fieldName"
style="width: 96px;"
>
MQ
</div>
Expand Down
22 changes: 7 additions & 15 deletions plugins/alignments/src/BamAdapter/BamAdapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import QuickLRU from '@jbrowse/core/util/QuickLRU'
import BamSlightlyLazyFeature from './BamSlightlyLazyFeature'
import { FilterBy } from '../shared/types'
import { checkStopToken } from '@jbrowse/core/util/stopToken'
import { filterReadFlag, filterTagValue } from '../shared/util'

interface Header {
idToName: string[]
Expand Down Expand Up @@ -208,30 +209,21 @@ export default class BamAdapter extends BaseFeatureDataAdapter {
)
}

const flags = record.flags
if ((flags & flagInclude) !== flagInclude && !(flags & flagExclude)) {
if (filterReadFlag(record.flags, flagInclude, flagExclude)) {
continue
}

if (tagFilter) {
const readVal = record.tags[tagFilter.tag]
const filterVal = tagFilter.value
if (
filterVal === '*'
? readVal === undefined
: `${readVal}` !== `${filterVal}`
) {
continue
}
if (
tagFilter &&
filterTagValue(record.tags[tagFilter.tag], tagFilter.value)
) {
continue
}

if (readName && record.name !== readName) {
continue
}

// retrieve a feature from our feature cache if it is available, the
// features in the cache have pre-computed mismatches objects that
// can be re-used across blocks
const ret = this.ultraLongFeatureCache.get(`${record.id}`)
if (!ret) {
const elt = new BamSlightlyLazyFeature(record, this, ref)
Expand Down
36 changes: 16 additions & 20 deletions plugins/alignments/src/CramAdapter/CramAdapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import QuickLRU from '@jbrowse/core/util/QuickLRU'
import CramSlightlyLazyFeature from './CramSlightlyLazyFeature'
import { FilterBy } from '../shared/types'
import { checkStopToken } from '@jbrowse/core/util/stopToken'
import { filterReadFlag, filterTagValue } from '../shared/util'

interface Header {
idToName?: string[]
Expand Down Expand Up @@ -152,8 +153,8 @@ export default class CramAdapter extends BaseFeatureDataAdapter {
const { cram } = conf
const samHeader = await cram.cram.getSamHeader()

// use the @SQ lines in the header to figure out the
// mapping between ref ID numbers and names
// use the @SQ lines in the header to figure out the mapping between ref
// ID numbers and names
const idToName: string[] = []
const nameToId: Record<string, number> = {}
samHeader
Expand Down Expand Up @@ -195,8 +196,8 @@ export default class CramAdapter extends BaseFeatureDataAdapter {
return samHeader.idToName
}

// use info from the SAM header if possible, but fall back to using
// the ref seq order from when the browser's refseqs were loaded
// use info from the SAM header if possible, but fall back to using the ref
// seq order from when the browser's refseqs were loaded
refNameToId(refName: string) {
if (this.samHeader.nameToId) {
return this.samHeader.nameToId[refName]
Expand All @@ -207,8 +208,8 @@ export default class CramAdapter extends BaseFeatureDataAdapter {
return undefined
}

// use info from the SAM header if possible, but fall back to using
// the ref seq order from when the browser's refseqs were loaded
// use info from the SAM header if possible, but fall back to using the ref
// seq order from when the browser's refseqs were loaded
refIdToName(refId: number) {
return this.samHeader.idToName?.[refId] || this.seqIdToRefName?.[refId]
}
Expand Down Expand Up @@ -254,24 +255,19 @@ export default class CramAdapter extends BaseFeatureDataAdapter {
} = filterBy || {}

for (const record of records) {
const flags = record.flags
if ((flags & flagInclude) !== flagInclude && !(flags & flagExclude)) {
if (filterReadFlag(record.flags, flagInclude, flagExclude)) {
continue
}

if (tagFilter) {
const readVal =
if (
tagFilter &&
filterTagValue(
tagFilter.tag === 'RG'
? samHeader.readGroups?.[record.readGroupId]
: record.tags[tagFilter.tag]
const filterVal = tagFilter.value
if (
filterVal === '*'
? readVal === undefined
: `${readVal}` !== `${filterVal}`
) {
continue
}
: record.tags[tagFilter.tag],
tagFilter.value,
)
) {
continue
}

if (readName && record.readName !== readName) {
Expand Down
12 changes: 8 additions & 4 deletions plugins/alignments/src/LinearAlignmentsDisplay/configSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,25 @@ import PluginManager from '@jbrowse/core/PluginManager'
* #config LinearAlignmentsDisplay
* has a "pileup" sub-display, where you can see individual reads and a
* quantitative "snpcoverage" sub-display track showing SNP frequencies
* extends
* - [BaseLinearDisplay](../baselineardisplay)
*/
export default function configModelFactory(pm: PluginManager) {
export default function configModelFactory(pluginManager: PluginManager) {
return ConfigurationSchema(
'LinearAlignmentsDisplay',
{
/**
* #slot
*/
pileupDisplay: pm.getDisplayType('LinearPileupDisplay')!.configSchema,
pileupDisplay: pluginManager.getDisplayType('LinearPileupDisplay')!
.configSchema,

/**
* #slot
*/
snpCoverageDisplay: pm.getDisplayType('LinearSNPCoverageDisplay')!
.configSchema,
snpCoverageDisplay: pluginManager.getDisplayType(
'LinearSNPCoverageDisplay',
)!.configSchema,

/**
* #slot
Expand Down
2 changes: 1 addition & 1 deletion plugins/alignments/src/LinearAlignmentsDisplay/model.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ function stateModelFactory(
},

/**
* #getteralignmentsdisplaymodel
* #getter
*/
get DisplayBlurb() {
return self.PileupDisplay?.DisplayBlurb
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ import LinearPileupDisplayBlurb from './components/LinearPileupDisplayBlurb'
import { createAutorun } from '../util'
import { ColorBy, FilterBy } from '../shared/types'
import { getUniqueTags } from '../shared/getUniqueTags'
import { defaultFilterFlags } from '../shared/util'

// lazies
const FilterByTagDialog = lazy(
Expand All @@ -60,7 +59,8 @@ type LGV = LinearGenomeViewModel
/**
* #stateModel SharedLinearPileupDisplayMixin
* #category display
* extends `BaseLinearDisplay`
* extends
* - [BaseLinearDisplay](../baselineardisplay)
*/
export function SharedLinearPileupDisplayMixin(
configSchema: AnyConfigurationSchemaType,
Expand Down Expand Up @@ -92,22 +92,46 @@ export function SharedLinearPileupDisplayMixin(
/**
* #property
*/
colorBy: types.frozen<ColorBy | undefined>(),
colorBySetting: types.frozen<ColorBy | undefined>(),
/**
* #property
*/
filterBy: types.optional(types.frozen<FilterBy>(), defaultFilterFlags),
filterBySetting: types.frozen<FilterBy | undefined>(),
/**
* #property
*/
jexlFilters: types.optional(types.array(types.string), []),
}),
)
.volatile(() => ({
/**
* #volatile
*/
colorTagMap: observable.map<string, string>({}),
/**
* #volatile
*/
featureUnderMouseVolatile: undefined as undefined | Feature,
/**
* #volatile
*/
tagsReady: false,
}))
.views(self => ({
/**
* #getter
*/
get colorBy() {
return self.colorBySetting ?? getConf(self, 'colorBy')
},

/**
* #getter
*/
get filterBy() {
return self.filterBySetting ?? getConf(self, 'filterBy')
},
}))
.views(self => ({
get autorunReady() {
const view = getContainingView(self) as LGV
Expand Down Expand Up @@ -152,7 +176,7 @@ export function SharedLinearPileupDisplayMixin(
*/
setColorScheme(colorScheme: ColorBy) {
self.colorTagMap = observable.map({})
self.colorBy = {
self.colorBySetting = {
...colorScheme,
}
if (colorScheme.tag) {
Expand Down Expand Up @@ -237,7 +261,7 @@ export function SharedLinearPileupDisplayMixin(
* #action
*/
setFilterBy(filter: FilterBy) {
self.filterBy = {
self.filterBySetting = {
...filter,
}
},
Expand Down Expand Up @@ -655,4 +679,17 @@ export function SharedLinearPileupDisplayMixin(
)
},
}))
.preProcessSnapshot(snap => {
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (snap) {
// @ts-expect-error
const { colorBy, filterBy, ...rest } = snap
return {
...rest,
filterBySetting: filterBy,
colorBySetting: colorBy,
}
}
return snap
})
}
Loading