Skip to content

Commit

Permalink
Render alignment shape
Browse files Browse the repository at this point in the history
  • Loading branch information
cmdcolin committed Nov 6, 2024
1 parent 58d5e36 commit 1f014a8
Show file tree
Hide file tree
Showing 6 changed files with 454 additions and 356 deletions.
22 changes: 10 additions & 12 deletions plugins/alignments/src/LinearPileupDisplay/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,12 @@ import {
} from '@jbrowse/core/configuration'
import { getRpcSessionId } from '@jbrowse/core/util/tracks'
import { getEnv, getSession, getContainingView } from '@jbrowse/core/util'
import { getUniqueModificationValues } from '../shared'

import { createAutorun, randomColor, modificationColors } from '../util'
import { LinearGenomeViewModel } from '@jbrowse/plugin-linear-genome-view'

// utils
import { getUniqueModificationValues } from '../shared'
import { createAutorun, getColorForModification } from '../util'

// icons
import VisibilityIcon from '@mui/icons-material/Visibility'
import SortIcon from '@mui/icons-material/Sort'
Expand All @@ -26,7 +27,7 @@ import { observable } from 'mobx'
// lazies
const SortByTagDialog = lazy(() => import('./components/SortByTagDialog'))
const GroupByDialog = lazy(() => import('./components/GroupByDialog'))
const ModificationsDialog = lazy(
const ColorByModificationsDialog = lazy(
() => import('./components/ColorByModificationsDialog'),
)

Expand Down Expand Up @@ -92,14 +93,11 @@ function stateModelFactory(configSchema: AnyConfigurationSchemaType) {
* #action
*/
updateModificationColorMap(uniqueModifications: string[]) {
uniqueModifications.forEach(value => {
if (!self.modificationTagMap.has(value)) {
self.modificationTagMap.set(
value,
modificationColors[value] || randomColor(value),
)
for (const m in uniqueModifications) {

Check failure on line 96 in plugins/alignments/src/LinearPileupDisplay/model.ts

View workflow job for this annotation

GitHub Actions / Lint, typecheck, test

For-in loops over arrays skips holes, returns indices as strings, and may visit the prototype chain or other enumerable properties. Use a more robust iteration method such as for-of or array.forEach instead
if (!self.modificationTagMap.has(m)) {
self.modificationTagMap.set(m, getColorForModification(m))
}
})
}
},
/**
* #action
Expand Down Expand Up @@ -317,7 +315,7 @@ function stateModelFactory(configSchema: AnyConfigurationSchemaType) {
label: 'Modifications or methylation',
onClick: () => {
getSession(self).queueDialog(doneCallback => [
ModificationsDialog,
ColorByModificationsDialog,
{
model: self,
handleClose: doneCallback,
Expand Down
17 changes: 9 additions & 8 deletions plugins/alignments/src/LinearSNPCoverageDisplay/models/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,11 @@ import SerializableFilterChain from '@jbrowse/core/pluggableElementTypes/rendere

// locals
import { FilterModel, IFilter, getUniqueModificationValues } from '../../shared'
import { createAutorun, modificationColors } from '../../util'
import {
createAutorun,
getColorForModification,
modificationColors,

Check warning on line 23 in plugins/alignments/src/LinearSNPCoverageDisplay/models/model.ts

View workflow job for this annotation

GitHub Actions / Lint, typecheck, test

'modificationColors' is defined but never used
} from '../../util'
import { randomColor } from '../../util'

Check warning on line 25 in plugins/alignments/src/LinearSNPCoverageDisplay/models/model.ts

View workflow job for this annotation

GitHub Actions / Lint, typecheck, test

'randomColor' is defined but never used

// lazies
Expand Down Expand Up @@ -111,14 +115,11 @@ function stateModelFactory(
* #action
*/
updateModificationColorMap(uniqueModifications: string[]) {
uniqueModifications.forEach(value => {
if (!self.modificationTagMap.has(value)) {
self.modificationTagMap.set(
value,
modificationColors[value] || randomColor(value),
)
for (const m of uniqueModifications) {
if (!self.modificationTagMap.has(m)) {
self.modificationTagMap.set(m, getColorForModification(m))
}
})
}
},
}))
.views(self => {
Expand Down
141 changes: 120 additions & 21 deletions plugins/alignments/src/PileupRenderer/renderAlignmentShape.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { bpSpanPx } from '@jbrowse/core/util'
import { RenderArgsDeserialized } from './PileupRenderer'
import { LayoutFeature } from './util'
import { parseCigar } from '../MismatchParser'

export function renderAlignmentShape({
ctx,
Expand All @@ -16,30 +17,128 @@ export function renderAlignmentShape({
const region = regions[0]!
const s = feature.get('start')
const e = feature.get('end')
const [leftPx, rightPx] = bpSpanPx(s, e, region, bpPerPx)
const CIGAR = feature.get('CIGAR')
const flip = region.reversed ? -1 : 1
const strand = feature.get('strand') * flip
if (bpPerPx < 10 && heightPx > 5) {
if (strand === -1) {
ctx.beginPath()
ctx.moveTo(leftPx - 5, topPx + heightPx / 2)
ctx.lineTo(leftPx, topPx + heightPx)
ctx.lineTo(rightPx, topPx + heightPx)
ctx.lineTo(rightPx, topPx)
ctx.lineTo(leftPx, topPx)
ctx.closePath()
ctx.fill()
} else {
ctx.beginPath()
ctx.moveTo(leftPx, topPx)
ctx.lineTo(leftPx, topPx + heightPx)
ctx.lineTo(rightPx, topPx + heightPx)
ctx.lineTo(rightPx + 5, topPx + heightPx / 2)
ctx.lineTo(rightPx, topPx)
ctx.closePath()
ctx.fill()
const cigarOps = parseCigar(CIGAR)
const renderChevrons = bpPerPx < 10 && heightPx > 5
if (CIGAR) {
if (strand === 1) {
let drawLen = 0
let drawStart = s
for (let i = 0; i < cigarOps.length; i += 2) {
const opLen = +cigarOps[i]!
const op = cigarOps[i + 1]!
if (op === 'M' || op === 'X' || op === '=' || op === 'D') {
drawLen += opLen
} else if (op === 'N') {
if (drawStart !== drawLen) {
const [leftPx, rightPx] = bpSpanPx(
drawStart,
drawStart + drawLen,
region,
bpPerPx,
)
const w = rightPx - leftPx
ctx.fillRect(leftPx, topPx, w, heightPx)
}
drawStart += drawLen + opLen
drawLen = 0
}
}

if (drawStart !== drawLen) {
const [leftPx, rightPx] = bpSpanPx(
drawStart,
drawStart + drawLen,
region,
bpPerPx,
)
const w = rightPx - leftPx

if (renderChevrons) {
ctx.beginPath()
ctx.moveTo(leftPx, topPx)
ctx.lineTo(leftPx, topPx + heightPx)
ctx.lineTo(rightPx, topPx + heightPx)
ctx.lineTo(rightPx + 5, topPx + heightPx / 2)
ctx.lineTo(rightPx, topPx)
ctx.closePath()
ctx.fill()
} else {
ctx.fillRect(leftPx, topPx, w, heightPx)
}
}
} else if (strand === -1) {
let drawLen = 0
let drawStart = e
for (let i = cigarOps.length - 2; i >= 0; i -= 2) {
const opLen = +cigarOps[i]!
const op = cigarOps[i + 1]!
if (op === 'M' || op === 'X' || op === '=' || op === 'D') {
drawLen += opLen
} else if (op === 'N') {
if (drawLen !== 0) {
const [leftPx, rightPx] = bpSpanPx(
drawStart - drawLen,
drawStart,
region,
bpPerPx,
)
ctx.fillRect(leftPx, topPx, rightPx - leftPx, heightPx)
}
drawStart -= drawLen + opLen
drawLen = 0
}
}

if (drawLen !== 0) {
const [leftPx, rightPx] = bpSpanPx(
drawStart - drawLen,
drawStart,
region,
bpPerPx,
)
const w = rightPx - leftPx

if (renderChevrons) {
ctx.beginPath()
ctx.moveTo(leftPx - 5, topPx + heightPx / 2)
ctx.lineTo(leftPx, topPx + heightPx)
ctx.lineTo(rightPx, topPx + heightPx)
ctx.lineTo(rightPx, topPx)
ctx.lineTo(leftPx, topPx)
ctx.closePath()
ctx.fill()
} else {
ctx.fillRect(leftPx, topPx, w, heightPx)
}
}
}
} else {
ctx.fillRect(leftPx, topPx, rightPx - leftPx, heightPx)
const [leftPx, rightPx] = bpSpanPx(s, e, region, bpPerPx)
if (bpPerPx < 10 && heightPx > 5) {
if (strand === -1) {
ctx.beginPath()
ctx.moveTo(leftPx - 5, topPx + heightPx / 2)
ctx.lineTo(leftPx, topPx + heightPx)
ctx.lineTo(rightPx, topPx + heightPx)
ctx.lineTo(rightPx, topPx)
ctx.lineTo(leftPx, topPx)
ctx.closePath()
ctx.fill()
} else {
ctx.beginPath()
ctx.moveTo(leftPx, topPx)
ctx.lineTo(leftPx, topPx + heightPx)
ctx.lineTo(rightPx, topPx + heightPx)
ctx.lineTo(rightPx + 5, topPx + heightPx / 2)
ctx.lineTo(rightPx, topPx)
ctx.closePath()
ctx.fill()
}
} else {
ctx.fillRect(leftPx, topPx, rightPx - leftPx, heightPx)
}
}
}
16 changes: 6 additions & 10 deletions plugins/alignments/src/PileupRenderer/renderMismatches.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,20 +142,16 @@ export function renderMismatches({
} else if (mismatch.type === 'skip') {
// fix to avoid bad rendering note that this was also related to chrome
// bug https://bugs.chromium.org/p/chromium/issues/detail?id=1131528
//
// also affected firefox ref #1236 #2750
if (leftPx + widthPx > 0) {
// make small exons more visible when zoomed far out
const adjustPx = widthPx - (bpPerPx > 10 ? 1.5 : 0)
ctx.clearRect(leftPx, topPx, adjustPx, heightPx)
fillRect(
ctx,
Math.max(0, leftPx),
topPx + heightPx / 2 - 1,
adjustPx + Math.min(leftPx, 0),
1,
canvasWidth,
'#333',
)
const l = Math.max(0, leftPx)
const t = topPx + heightPx / 2 - 1
const w = adjustPx + Math.min(leftPx, 0)
const h = 1
fillRect(ctx, l, t, w, h, canvasWidth, 'rgb(151,184,201)')
}
}
}
Expand Down
4 changes: 4 additions & 0 deletions plugins/alignments/src/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -159,3 +159,7 @@ export function randomColor(str: string) {
}
return `hsl(${sum * 10}, 20%, 50%)`
}

export function getColorForModification(str: string) {
return modificationColors[str] || randomColor(str)
}
Loading

0 comments on commit 1f014a8

Please sign in to comment.