Skip to content

Commit

Permalink
Phase set handling
Browse files Browse the repository at this point in the history
  • Loading branch information
cmdcolin committed Jan 29, 2025
1 parent 06c5f9f commit 7f60bee
Show file tree
Hide file tree
Showing 10 changed files with 216 additions and 51 deletions.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ const LinesConnectingMatrixToGenomicPosition = observer(function ({
}) {
const { assemblyManager } = getSession(model)
const view = getContainingView(model) as LinearGenomeViewModel
const { featuresVolatile } = model
const { lineZoneHeight, featuresVolatile } = model
const { offsetPx, assemblyNames, dynamicBlocks } = view
const assembly = assemblyManager.get(assemblyNames[0]!)
const b0 = dynamicBlocks.contentBlocks[0]?.widthPx || 0
Expand All @@ -60,11 +60,11 @@ const LinesConnectingMatrixToGenomicPosition = observer(function ({
})?.offsetPx || 0) - l
return (
<line
stroke="#0006"
stroke="#0004"
key={f.id()}
x1={i * w + w / 2}
x2={c}
y1={20}
y1={lineZoneHeight}
y2={0}
/>
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {
getColorAlleleCount,
getColorPhased,
getColorPhasedWithPhaseSet,
} from '../shared/multiVariantColor'
import { getFeaturesThatPassMinorAlleleFrequencyFilter } from '../util'

Expand Down Expand Up @@ -29,8 +30,12 @@ function drawPhased(
w: number,
h: number,
HP: number,
PS?: string,
) {
ctx.fillStyle = getColorPhased(alleles, HP)
ctx.fillStyle =
PS !== undefined
? getColorPhasedWithPhaseSet(alleles, HP, PS)
: getColorPhased(alleles, HP)
ctx.fillRect(x - f2, y - f2, w + f2, h + f2)
}

Expand Down Expand Up @@ -65,30 +70,62 @@ export function makeImageData({
const m = mafs.length
const w = canvasWidth / m
for (let i = 0; i < m; i++) {
const f = mafs[i]!
const samp = f.get('genotypes') as Record<string, string>

const x = (i / mafs.length) * canvasWidth
const s = sources.length
const arr2 = [] as string[]
for (let j = 0; j < s; j++) {
const y = (j / s) * canvasHeight
const { name, HP } = sources[j]!
const genotype = samp[name]
if (genotype) {
arr2.push(genotype)
const isPhased = genotype.includes('|')
if (renderingMode === 'phased') {
if (isPhased) {
const alleles = genotype.split('|')
drawPhased(alleles, ctx, x, y, w, h, HP!)
const f = mafs[i]!
const hasPhaseSet = (f.get('format') as string).includes('PS')
if (hasPhaseSet) {
const samp = f.get('samples') as Record<string, Record<string, string[]>>
const x = (i / mafs.length) * canvasWidth
const sln = sources.length
for (let j = 0; j < sln; j++) {
const y = (j / sln) * canvasHeight
const { name, HP } = sources[j]!
const s = samp[name]
if (s) {
const genotype = s.GT?.[0]
if (genotype) {
arr2.push(genotype)
const isPhased = genotype.includes('|')
if (renderingMode === 'phased') {
if (isPhased) {
const PS = s.PS?.[0]
const alleles = genotype.split('|')
drawPhased(alleles, ctx, x, y, w, h, HP!, PS)
} else {
ctx.fillStyle = 'black'
ctx.fillRect(x - f2, y - f2, w + f2, h + f2)
}
} else {
const alleles = genotype.split(/[/|]/)
drawColorAlleleCount(alleles, ctx, x, y, w, h)
}
}
}
}
} else {
const samp = f.get('genotypes') as Record<string, string>
const x = (i / mafs.length) * canvasWidth
const sln = sources.length
const arr2 = [] as string[]
for (let j = 0; j < sln; j++) {
const y = (j / sln) * canvasHeight
const { name, HP } = sources[j]!
const genotype = samp[name]
if (genotype) {
arr2.push(genotype)
const isPhased = genotype.includes('|')
if (renderingMode === 'phased') {
if (isPhased) {
const alleles = genotype.split('|')
drawPhased(alleles, ctx, x, y, w, h, HP!)
} else {
ctx.fillStyle = 'black'
ctx.fillRect(x - f2, y - f2, w + f2, h + f2)
}
} else {
ctx.fillStyle = 'black'
ctx.fillRect(x - f2, y - f2, w + f2, h + f2)
const alleles = genotype.split(/[/|]/)
drawColorAlleleCount(alleles, ctx, x, y, w, h)
}
} else {
const alleles = genotype.split(/[/|]/)
drawColorAlleleCount(alleles, ctx, x, y, w, h)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ exports[`adapter can fetch variants from volvox.vcf 2`] = `
"aliases": undefined,
"description": "SNV T -> C",
"end": 277,
"format": "GT:PL:GQ",
"name": undefined,
"refName": "ctgA",
"samples": {
Expand Down Expand Up @@ -115,6 +116,7 @@ exports[`adapter can fetch variants from volvox.vcf 2`] = `
"aliases": undefined,
"description": "SNV T -> C",
"end": 1694,
"format": "GT:PL:GQ",
"name": undefined,
"refName": "ctgA",
"samples": {
Expand Down Expand Up @@ -182,6 +184,7 @@ exports[`adapter can fetch variants from volvox.vcf 2`] = `
"aliases": undefined,
"description": "SNV T -> G",
"end": 2644,
"format": "GT:PL:GQ",
"name": undefined,
"refName": "ctgA",
"samples": {
Expand Down Expand Up @@ -243,6 +246,7 @@ exports[`adapter can fetch variants from volvox.vcf 2`] = `
"aliases": undefined,
"description": "SNV T -> A",
"end": 3213,
"format": "GT:PL:GQ",
"name": undefined,
"refName": "ctgA",
"samples": {
Expand Down Expand Up @@ -305,6 +309,7 @@ exports[`adapter can fetch variants from volvox.vcf 2`] = `
"aliases": undefined,
"description": "deletion ctt -> ct",
"end": 3860,
"format": "GT:PL:GQ",
"name": undefined,
"refName": "ctgA",
"samples": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ exports[`null ALT 1`] = `
"aliases": undefined,
"description": "no alternative alleles",
"end": 100,
"format": undefined,
"name": "rs123",
"refName": "chr1",
"samples": {},
Expand Down
3 changes: 2 additions & 1 deletion plugins/variants/src/VcfFeature/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import type { Feature } from '@jbrowse/core/util'
type FeatureData = ReturnType<typeof dataFromVariant>

function dataFromVariant(variant: Variant, parser: VCFParser) {
const { REF = '', ALT, POS, CHROM, ID } = variant
const { FORMAT, REF = '', ALT, POS, CHROM, ID } = variant
const start = POS - 1
const [type, description] = getSOTermAndDescription(REF, ALT, parser)

Expand All @@ -19,6 +19,7 @@ function dataFromVariant(variant: Variant, parser: VCFParser) {
type,
name: ID?.join(','),
aliases: ID && ID.length > 1 ? ID.slice(1) : undefined,
format: FORMAT,
}
}
function getEnd(variant: Variant) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ exports[`adapter can fetch variants from volvox.vcf.gz 2`] = `
"aliases": undefined,
"description": "SNV T -> C",
"end": 277,
"format": "GT:PL:GQ",
"name": undefined,
"refName": "ctgA",
"samples": {
Expand Down Expand Up @@ -115,6 +116,7 @@ exports[`adapter can fetch variants from volvox.vcf.gz 2`] = `
"aliases": undefined,
"description": "SNV T -> C",
"end": 1694,
"format": "GT:PL:GQ",
"name": undefined,
"refName": "ctgA",
"samples": {
Expand Down Expand Up @@ -182,6 +184,7 @@ exports[`adapter can fetch variants from volvox.vcf.gz 2`] = `
"aliases": undefined,
"description": "SNV T -> G",
"end": 2644,
"format": "GT:PL:GQ",
"name": undefined,
"refName": "ctgA",
"samples": {
Expand Down Expand Up @@ -243,6 +246,7 @@ exports[`adapter can fetch variants from volvox.vcf.gz 2`] = `
"aliases": undefined,
"description": "SNV T -> A",
"end": 3213,
"format": "GT:PL:GQ",
"name": undefined,
"refName": "ctgA",
"samples": {
Expand Down Expand Up @@ -305,6 +309,7 @@ exports[`adapter can fetch variants from volvox.vcf.gz 2`] = `
"aliases": undefined,
"description": "deletion ctt -> ct",
"end": 3860,
"format": "GT:PL:GQ",
"name": undefined,
"refName": "ctgA",
"samples": {
Expand Down
47 changes: 24 additions & 23 deletions plugins/variants/src/shared/MultiVariantBaseModel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { stopStopToken } from '@jbrowse/core/util/stopToken'
import { linearBareDisplayStateModelFactory } from '@jbrowse/plugin-linear-genome-view'
import FilterListIcon from '@mui/icons-material/FilterList'
import HeightIcon from '@mui/icons-material/Height'
import PaletteIcon from '@mui/icons-material/Palette'
import SplitscreenIcon from '@mui/icons-material/Splitscreen'
import VisibilityIcon from '@mui/icons-material/Visibility'
import deepEqual from 'fast-deep-equal'
import { types } from 'mobx-state-tree'
Expand Down Expand Up @@ -314,29 +314,30 @@ export default function MultiVariantBaseModelF(
],
},
{
label: 'Color by',
icon: PaletteIcon,
label: 'Rendering mode',
icon: SplitscreenIcon,
subMenu: [
...(self.hasPhased
? [
{
label: 'Allele count',
type: 'radio',
checked: self.renderingMode === 'alleleCount',
onClick: () => {
self.setPhasedMode('alleleCount')
},
},
{
label: 'Phased',
checked: self.renderingMode === 'phased',
type: 'radio',
onClick: () => {
self.setPhasedMode('phased')
},
},
]
: []),
{
label: 'Allele count',
type: 'radio',
checked: self.renderingMode === 'alleleCount',
onClick: () => {
self.setPhasedMode('alleleCount')
},
},
{
label:
'Phased' +
(self.hasPhased
? ' (disabled, no phased variants found)'
: ''),
disabled: self.hasPhased,
checked: self.renderingMode === 'phased',
type: 'radio',
onClick: () => {
self.setPhasedMode('phased')
},
},
],
},
{
Expand Down
11 changes: 11 additions & 0 deletions plugins/variants/src/shared/multiVariantColor.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { set1 } from '@jbrowse/core/ui/colors'
import { colord } from '@jbrowse/core/util/colord'

import { colorify } from '../util'

export function getColorAlleleCount(alleles: string[]) {
const total = alleles.length
let alt = 0
Expand Down Expand Up @@ -39,3 +41,12 @@ export function getColorPhased(alleles: string[], HP: number) {
const c = +alleles[HP]!
return c ? set1[c - 1] || 'black' : '#ccc'
}

export function getColorPhasedWithPhaseSet(
alleles: string[],
HP: number,
PS: string,
) {
const c = +alleles[HP]!
return c ? colorify(+PS) || 'black' : '#ccc'
}
7 changes: 5 additions & 2 deletions plugins/variants/src/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,12 @@ export function randomColor(str: string) {
for (let i = 0; i < str.length; i++) {
sum += str.charCodeAt(i)
}
return `hsl(${sum * 10}, 50%, 50%)`
return `hsl(${colorify(sum * 10)}, 50%, 50%)`
}

export function colorify(n: number) {
return `hsl(${n % 255}, 50%, 50%)`
}
// used for calculating minor allele
export function findSecondLargest(arr: Iterable<number>) {
let firstMax = 0
Expand Down Expand Up @@ -91,7 +94,7 @@ export function getFeaturesThatPassMinorAlleleFrequencyFilter(
) {
const mafs = [] as Feature[]
for (const feat of feats) {
if (calculateMinorAlleleFrequency(feat) > minorAlleleFrequencyFilter) {
if (calculateMinorAlleleFrequency(feat) >= minorAlleleFrequencyFilter) {
mafs.push(feat)
}
}
Expand Down

0 comments on commit 7f60bee

Please sign in to comment.