Skip to content

Commit

Permalink
Add new coloring options for dotplot and ability to "rectangularize" …
Browse files Browse the repository at this point in the history
…dotplot view (#2791)

* Dotplot mods

* Updates

* Draw open circles for large CIGAR

* Remove ctrl+scroll in dotplot

* Misc

* Add method to only connect indels of a certain size

* Add a br breakpoint in dotplot header

* Add dotplot renderer line width

* Fix lint

* Put target assembly on x-axis for dotplot

* Color by qual

* Line width 2.5

* Re-organize paf record

* Update comment

* Thresholds config editing

* Less circles

* Create MashMap adapter, since mashmap doesn't follow the format of paf
after col 9, this let's us load score more reliably

* Remove large indel limit

* Back to main

* Code simplify

* Add ability to load MCScan .anchors and .anchors.simple files using the GUI import forms for dotplot/synteny views (#2792)


* Update mcscan anchors adapter to take a bed1Location and bed2Location

* Standardize on left and right columns for mcscan anchors

* Improve anchors importing

* Add simple anchors example

* Add simple anchors to import form

* Update mcscan synteny config

* Add delta example to grape vs peach dotplot

* T1

* Unify simpleanchors and anchors somewhat
  • Loading branch information
cmdcolin committed Mar 9, 2022
1 parent 2ea642b commit 795b30d
Show file tree
Hide file tree
Showing 36 changed files with 1,342 additions and 15,666 deletions.
12 changes: 12 additions & 0 deletions packages/core/util/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1121,3 +1121,15 @@ export function viewBpToPx({

return undefined
}

export function getBpDisplayStr(totalBp: number) {
let displayBp
if (Math.floor(totalBp / 1000000) > 0) {
displayBp = `${parseFloat((totalBp / 1000000).toPrecision(3))}Mbp`
} else if (Math.floor(totalBp / 1000) > 0) {
displayBp = `${parseFloat((totalBp / 1000).toPrecision(3))}Kbp`
} else {
displayBp = `${Math.floor(totalBp)}bp`
}
return displayBp
}
53 changes: 20 additions & 33 deletions plugins/comparative-adapters/src/ChainAdapter/ChainAdapter.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,8 @@
import { BaseOptions } from '@jbrowse/core/data_adapters/BaseAdapter'
import { NoAssemblyRegion } from '@jbrowse/core/util/types'
import { openLocation } from '@jbrowse/core/util/io'
import { readConfObject } from '@jbrowse/core/configuration'
import { unzip } from '@gmod/bgzf-filehandle'
import PAFAdapter from '../PAFAdapter/PAFAdapter'

interface PafRecord {
records: NoAssemblyRegion[]
extra: {
blockLen: number
mappingQual: number
numMatches: number
strand: number
}
}

function isGzip(buf: Buffer) {
return buf[0] === 31 && buf[1] === 139 && buf[2] === 8
}
Expand Down Expand Up @@ -45,29 +33,31 @@ function isGzip(buf: Buffer) {
*/

function generate_record(
q_name: string,
q_start: number,
q_end: number,
q_strand: string,
t_name: string,
t_start: number,
t_end: number,
qname: string,
qstart: number,
qend: number,
qstrand: string,
tname: string,
tstart: number,
tend: number,
cigar: string,
num_matches: number,
numMatches: number,
) {
return {
records: [
{ refName: q_name, start: q_start, end: q_end },
{ refName: t_name, start: t_start, end: t_end },
],
qname,
qstart,
qend,
tname,
tstart,
tend,
strand: qstrand === '-' ? -1 : 1,
extra: {
numMatches: num_matches,
blockLen: Math.max(q_end - q_start, t_end - t_start),
strand: q_strand === '-' ? -1 : 1,
numMatches,
blockLen: Math.max(qend - qstart, tend - tstart),
mappingQual: 0,
cg: cigar,
},
} as PafRecord
}
}

function paf_chain2paf(lines: string[]) {
Expand Down Expand Up @@ -179,11 +169,8 @@ function paf_chain2paf(lines: string[]) {

export default class ChainAdapter extends PAFAdapter {
async setupPre(opts?: BaseOptions) {
const chainLocation = openLocation(
readConfObject(this.config, 'chainLocation'),
this.pluginManager,
)
const buffer = (await chainLocation.readFile(opts)) as Buffer
const loc = openLocation(this.getConf('chainLocation'), this.pluginManager)
const buffer = (await loc.readFile(opts)) as Buffer
const buf = isGzip(buffer) ? await unzip(buffer) : buffer
// 512MB max chrome string length is 512MB
if (buf.length > 536_870_888) {
Expand Down
12 changes: 12 additions & 0 deletions plugins/comparative-adapters/src/ChainAdapter/configSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,18 @@ export default ConfigurationSchema(
assemblyNames: {
type: 'stringArray',
defaultValue: [],
description:
'Target is the first value in the array, query is the second',
},
targetAssembly: {
type: 'string',
defaultValue: '',
description: 'Alternative to assemblyNames array: the target assembly',
},
queryAssembly: {
type: 'string',
defaultValue: '',
description: 'Alternative to assemblyNames array: the query assembly',
},
chainLocation: {
type: 'fileLocation',
Expand Down
38 changes: 13 additions & 25 deletions plugins/comparative-adapters/src/DeltaAdapter/DeltaAdapter.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,8 @@
import { BaseOptions } from '@jbrowse/core/data_adapters/BaseAdapter'
import { NoAssemblyRegion } from '@jbrowse/core/util/types'
import { openLocation } from '@jbrowse/core/util/io'
import { readConfObject } from '@jbrowse/core/configuration'
import { unzip } from '@gmod/bgzf-filehandle'
import PAFAdapter from '../PAFAdapter/PAFAdapter'

interface PafRecord {
records: NoAssemblyRegion[]
extra: {
blockLen: number
mappingQual: number
numMatches: number
strand: number
}
}

function isGzip(buf: Buffer) {
return buf[0] === 31 && buf[1] === 139 && buf[2] === 8
}
Expand Down Expand Up @@ -101,24 +89,27 @@ function paf_delta2paf(lines: string[]) {
}
cigar.push((re - rs - x) << 4)
for (let i = 0; i < cigar.length; ++i) {
blen += cigar[i] >> 4
cigar_str.push((cigar[i] >> 4) + 'MID'.charAt(cigar[i] & 0xf))
const rlen = cigar[i] >> 4
blen += rlen
cigar_str.push(rlen + 'MID'.charAt(cigar[i] & 0xf))
}

records.push({
records: [
{ refName: qname, start: qs, end: qe },
{ refName: rname, start: rs, end: re },
],
qname,
qstart: qs,
qend: qe,
tname: rname,
tstart: rs,
tend: re,
strand,
extra: {
numMatches: blen - NM,
blockLen: blen,
strand,
mappingQual: 0,
NM,
cg: cigar_str.join(''),
},
} as PafRecord)
})
} else if (d > 0) {
const l = d - 1
x += l + 1
Expand Down Expand Up @@ -151,11 +142,8 @@ function paf_delta2paf(lines: string[]) {

export default class DeltaAdapter extends PAFAdapter {
async setupPre(opts?: BaseOptions) {
const deltaLocation = openLocation(
readConfObject(this.config, 'deltaLocation'),
this.pluginManager,
)
const buffer = (await deltaLocation.readFile(opts)) as Buffer
const loc = openLocation(this.getConf('deltaLocation'), this.pluginManager)
const buffer = (await loc.readFile(opts)) as Buffer
const buf = isGzip(buffer) ? await unzip(buffer) : buffer
// 512MB max chrome string length is 512MB
if (buf.length > 536_870_888) {
Expand Down
12 changes: 12 additions & 0 deletions plugins/comparative-adapters/src/DeltaAdapter/configSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,18 @@ export default ConfigurationSchema(
assemblyNames: {
type: 'stringArray',
defaultValue: [],
description:
'Array of assembly names to use for this file. The target assembly name is the first value in the array, query assembly name is the second',
},
targetAssembly: {
type: 'string',
defaultValue: '',
description: 'Alternative to assemblyNames: the target assembly name',
},
queryAssembly: {
type: 'string',
defaultValue: '',
description: 'Alternative to assemblyNames: the query assembly name',
},
deltaLocation: {
type: 'fileLocation',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,4 @@
import { ObservableCreate } from '@jbrowse/core/util/rxjs'
import SimpleFeature, { Feature } from '@jbrowse/core/util/simpleFeature'
import { Region } from '@jbrowse/core/util/types'
import { toArray } from 'rxjs/operators'
import { getSubAdapterType } from '@jbrowse/core/data_adapters/dataAdapterCache'
import { ConfigurationSchema } from '@jbrowse/core/configuration/configurationSchema'
import { BaseFeatureDataAdapter } from '@jbrowse/core/data_adapters/BaseAdapter'
import Adapter from './MCScanAnchorsAdapter'
import { TextEncoder, TextDecoder } from 'web-encoding'
import configSchema from './configSchema'
Expand All @@ -16,85 +10,42 @@ if (!window.TextDecoder) {
window.TextDecoder = TextDecoder
}

class CustomAdapter extends BaseFeatureDataAdapter {
async getRefNames() {
return []
}

freeResources() {}

getFeatures(region: Region) {
return ObservableCreate<Feature>(async observer => {
if (region.assemblyName === 'peach') {
observer.next(
new SimpleFeature({
uniqueId: '1',
start: 0,
end: 100,
refName: 'peach_chr1',
syntenyId: 1,
name: 'GSVIVT01012253001',
}),
)
}
if (region.assemblyName === 'grape') {
observer.next(
new SimpleFeature({
start: 0,
uniqueId: '2',
end: 100,
refName: 'grape_chr1',
syntenyId: 1,
name: 'Prupe.1G290800.1',
}),
)
}
observer.complete()
})
}
}

const getSubAdapter: getSubAdapterType = async () => {
return {
dataAdapter: new CustomAdapter(ConfigurationSchema('empty', {}).create()),
sessionIds: new Set(),
}
}
test('adapter can fetch features from volvox.bam', async () => {
test('adapter can fetch features from mcscan anchors file', async () => {
const adapter = new Adapter(
configSchema.create({
mcscanAnchorsLocation: {
localPath: require.resolve('./test_data/grape.peach.anchors'),
localPath: require.resolve('./test_data/grape.peach.anchors.gz'),
locationType: 'LocalPathLocation',
},
subadapters: [
ConfigurationSchema('empty', {}).create(),
ConfigurationSchema('empty', {}).create(),
],
bed1Location: {
localPath: require.resolve('./test_data/grape.bed.gz'),
locationType: 'LocalPathLocation',
},
bed2Location: {
localPath: require.resolve('./test_data/peach.bed.gz'),
locationType: 'LocalPathLocation',
},

assemblyNames: ['grape', 'peach'],
}),
getSubAdapter,
)

const features1 = adapter.getFeatures({
refName: 'peach_chr1',
refName: 'Pp01',
start: 0,
end: 20000,
end: 200000,
assemblyName: 'peach',
})

const features2 = adapter.getFeatures({
refName: 'grape_chr1',
refName: 'chr1',
start: 0,
end: 20000,
end: 200000,
assemblyName: 'grape',
})

const fa1 = await features1.pipe(toArray()).toPromise()
const fa2 = await features2.pipe(toArray()).toPromise()
expect(fa1.length).toBe(2)
expect(fa2.length).toBe(1)
expect(fa1[0].get('refName')).toBe('peach_chr1')
expect(fa2[0].get('refName')).toBe('grape_chr1')
expect(fa1[0].get('syntenyId')).toEqual(fa2[0].get('syntenyId'))
expect(fa1.length).toBe(7)
expect(fa2.length).toBe(8)
})
Loading

0 comments on commit 795b30d

Please sign in to comment.