-
Notifications
You must be signed in to change notification settings - Fork 63
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
28 changed files
with
1,156 additions
and
1,092 deletions.
There are no files selected for viewing
1,107 changes: 19 additions & 1,088 deletions
1,107
plugins/alignments/src/PileupRenderer/PileupRenderer.ts
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
import { | ||
AnyConfigurationModel, | ||
readConfObject, | ||
} from '@jbrowse/core/configuration' | ||
import { Feature } from '@jbrowse/core/util' | ||
import { fillColor } from '../shared/color' | ||
import { orientationTypes } from '../util' | ||
|
||
export function colorByInsertSize(feature: Feature) { | ||
return feature.get('is_paired') && | ||
feature.get('refName') !== feature.get('next_ref') | ||
? '#555' | ||
: `hsl(${Math.abs(feature.get('template_length')) / 10},50%,50%)` | ||
} | ||
|
||
export function colorByMappingQuality(feature: Feature) { | ||
return `hsl(${feature.get('mq')},50%,50%)` | ||
} | ||
|
||
function getOrientation(feature: Feature, config: AnyConfigurationModel) { | ||
const orientationType = readConfObject(config, 'orientationType') as | ||
| 'fr' | ||
| 'ff' | ||
| 'rf' | ||
const type = orientationTypes[orientationType] | ||
const orientation = type[feature.get('pair_orientation') as string] | ||
return { | ||
LR: 'color_pair_lr' as const, | ||
RR: 'color_pair_rr' as const, | ||
RL: 'color_pair_rl' as const, | ||
LL: 'color_pair_ll' as const, | ||
}[orientation] | ||
} | ||
|
||
export function colorByStrand(feature: Feature) { | ||
return feature.get('strand') === -1 ? '#8F8FD8' : '#EC8B8B' | ||
} | ||
|
||
export function colorByOrientation( | ||
feature: Feature, | ||
config: AnyConfigurationModel, | ||
) { | ||
return fillColor[getOrientation(feature, config) || 'color_nostrand'] | ||
} | ||
function getStranded(feature: Feature) { | ||
const flags = feature.get('flags') | ||
const strand = feature.get('strand') | ||
// is paired | ||
if (flags & 1) { | ||
const revflag = flags & 64 | ||
const flipper = revflag ? -1 : 1 | ||
|
||
// proper pairing | ||
if (flags & 2) { | ||
return strand * flipper === 1 ? 'color_rev_strand' : 'color_fwd_strand' | ||
} else if (feature.get('multi_segment_next_segment_unmapped')) { | ||
return strand * flipper === 1 | ||
? 'color_rev_missing_mate' | ||
: 'color_fwd_missing_mate' | ||
} else if (feature.get('refName') === feature.get('next_refName')) { | ||
return strand * flipper === 1 | ||
? 'color_rev_strand_not_proper' | ||
: 'color_fwd_strand_not_proper' | ||
} else { | ||
// should only leave aberrant chr | ||
return strand === 1 ? 'color_fwd_diff_chr' : 'color_rev_diff_chr' | ||
} | ||
} | ||
return strand === 1 ? 'color_fwd_strand' : 'color_rev_strand' | ||
} | ||
|
||
export function colorByStrandedRnaSeq(feature: Feature) { | ||
return fillColor[getStranded(feature)] | ||
} |
87 changes: 87 additions & 0 deletions
87
plugins/alignments/src/PileupRenderer/getAlignmentShapeColor.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
import { | ||
AnyConfigurationModel, | ||
readConfObject, | ||
} from '@jbrowse/core/configuration' | ||
import { Feature } from '@jbrowse/core/util' | ||
import { fillColor } from '../shared/color' | ||
import { | ||
colorByInsertSize, | ||
colorByMappingQuality, | ||
colorByOrientation, | ||
colorByStrand, | ||
colorByStrandedRnaSeq, | ||
} from './colorBy' | ||
|
||
export function getAlignmentShapeColor({ | ||
colorType, | ||
tag, | ||
feature, | ||
config, | ||
defaultColor, | ||
colorTagMap, | ||
}: { | ||
colorType: string | ||
tag: string | ||
feature: Feature | ||
defaultColor: boolean | ||
config: AnyConfigurationModel | ||
colorTagMap: Record<string, string> | ||
}) { | ||
// first pass for simple color changes that change the color of the | ||
// alignment | ||
switch (colorType) { | ||
case 'insertSize': | ||
return colorByInsertSize(feature) | ||
case 'strand': | ||
return colorByStrand(feature) | ||
case 'mappingQuality': | ||
return colorByMappingQuality(feature) | ||
case 'pairOrientation': | ||
return colorByOrientation(feature, config) | ||
case 'stranded': | ||
return colorByStrandedRnaSeq(feature) | ||
case 'xs': | ||
case 'tag': { | ||
const tags = feature.get('tags') | ||
const val = tags ? tags[tag] : feature.get(tag) | ||
|
||
if (tag === 'XS' || tag === 'TS') { | ||
return fillColor[ | ||
{ | ||
'-': 'color_rev_strand' as const, | ||
'+': 'color_fwd_strand' as const, | ||
}[val as '-' | '+'] || 'color_nostrand' | ||
] | ||
} else if (tag === 'ts') { | ||
return fillColor[ | ||
{ | ||
'-': | ||
feature.get('strand') === -1 | ||
? ('color_fwd_strand' as const) | ||
: ('color_rev_strand' as const), | ||
'+': | ||
feature.get('strand') === -1 | ||
? ('color_rev_strand' as const) | ||
: ('color_fwd_strand' as const), | ||
}[val as '-' | '+'] || 'color_nostrand' | ||
] | ||
} else { | ||
return colorTagMap[val] || fillColor['color_nostrand'] | ||
} | ||
} | ||
case 'insertSizeAndPairOrientation': | ||
break | ||
|
||
case 'modifications': | ||
case 'methylation': | ||
// this coloring is similar to igv.js, and is helpful to color negative | ||
// strand reads differently because their c-g will be flipped (e.g. g-c | ||
// read right to left) | ||
return feature.get('flags') & 16 ? '#c8dcc8' : '#c8c8c8' | ||
|
||
default: | ||
return defaultColor | ||
? '#c8c8c8' | ||
: readConfObject(config, 'color', { feature }) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
import { bpSpanPx, Feature, Region } from '@jbrowse/core/util' | ||
import { BaseLayout } from '@jbrowse/core/util/layouts' | ||
// locals | ||
import { Mismatch } from '../MismatchParser' | ||
|
||
export interface LayoutRecord { | ||
feature: Feature | ||
leftPx: number | ||
rightPx: number | ||
topPx: number | ||
heightPx: number | ||
} | ||
|
||
export function layoutFeature({ | ||
feature, | ||
layout, | ||
bpPerPx, | ||
region, | ||
showSoftClip, | ||
heightPx, | ||
displayMode, | ||
}: { | ||
feature: Feature | ||
layout: BaseLayout<Feature> | ||
bpPerPx: number | ||
region: Region | ||
showSoftClip?: boolean | ||
heightPx: number | ||
displayMode: string | ||
}): LayoutRecord | null { | ||
let expansionBefore = 0 | ||
let expansionAfter = 0 | ||
|
||
// Expand the start and end of feature when softclipping enabled | ||
if (showSoftClip) { | ||
const mismatches = feature.get('mismatches') as Mismatch[] | ||
const seq = feature.get('seq') as string | ||
if (seq) { | ||
for (let i = 0; i < mismatches.length; i += 1) { | ||
const { type, start, cliplen = 0 } = mismatches[i] | ||
if (type === 'softclip') { | ||
start === 0 ? (expansionBefore = cliplen) : (expansionAfter = cliplen) | ||
} | ||
} | ||
} | ||
} | ||
|
||
const [leftPx, rightPx] = bpSpanPx( | ||
feature.get('start') - expansionBefore, | ||
feature.get('end') + expansionAfter, | ||
region, | ||
bpPerPx, | ||
) | ||
|
||
if (displayMode === 'compact') { | ||
heightPx /= 3 | ||
} | ||
if (feature.get('refName') !== region.refName) { | ||
throw new Error( | ||
`feature ${feature.id()} is not on the current region's reference sequence ${ | ||
region.refName | ||
}`, | ||
) | ||
} | ||
const topPx = layout.addRect( | ||
feature.id(), | ||
feature.get('start') - expansionBefore, | ||
feature.get('end') + expansionAfter, | ||
heightPx, | ||
feature, | ||
) | ||
if (topPx === null) { | ||
return null | ||
} | ||
|
||
return { | ||
feature, | ||
leftPx, | ||
rightPx, | ||
topPx: displayMode === 'collapse' ? 0 : topPx, | ||
heightPx, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
import { readConfObject } from '@jbrowse/core/configuration' | ||
import { iterMap } from '@jbrowse/core/util' | ||
|
||
// locals | ||
import { layoutFeature } from './layoutFeature' | ||
import { RenderArgsDeserializedWithFeaturesAndLayout } from './PileupRenderer' | ||
import { sortFeature } from './sortUtil' | ||
|
||
// layout determines the height of the canvas that we use to render | ||
export function layoutFeats( | ||
props: RenderArgsDeserializedWithFeaturesAndLayout, | ||
) { | ||
const { layout, features, sortedBy, config, bpPerPx, showSoftClip, regions } = | ||
props | ||
const [region] = regions | ||
if (!layout) { | ||
throw new Error(`layout required`) | ||
} | ||
if (!layout.addRect) { | ||
throw new Error('invalid layout object') | ||
} | ||
|
||
const featureMap = | ||
sortedBy?.type && region.start === sortedBy.pos | ||
? sortFeature(features, sortedBy) | ||
: features | ||
|
||
const heightPx = readConfObject(config, 'height') | ||
const displayMode = readConfObject(config, 'displayMode') | ||
return iterMap( | ||
featureMap.values(), | ||
feature => | ||
layoutFeature({ | ||
feature, | ||
layout, | ||
bpPerPx, | ||
region, | ||
showSoftClip, | ||
heightPx, | ||
displayMode, | ||
}), | ||
featureMap.size, | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
import { Feature } from '@jbrowse/core/util' | ||
import { RenderArgsDeserializedWithFeaturesAndLayout } from './PileupRenderer' | ||
import { readConfObject } from '@jbrowse/core/configuration' | ||
import { createJBrowseTheme } from '@jbrowse/core/ui' | ||
import { | ||
getCharWidthHeight, | ||
getColorBaseMap, | ||
getContrastBaseMap, | ||
shouldDrawIndels, | ||
shouldDrawSNPsMuted, | ||
} from './util' | ||
import { renderAlignment } from './renderAlignment' | ||
import { renderMismatches } from './renderMismatches' | ||
import { renderSoftClipping } from './renderSoftClipping' | ||
|
||
export interface RenderArgsWithColor | ||
extends RenderArgsDeserializedWithFeaturesAndLayout { | ||
Color: Awaited<typeof import('color')> | ||
} | ||
|
||
interface LayoutFeature { | ||
heightPx: number | ||
topPx: number | ||
feature: Feature | ||
} | ||
|
||
export function makeImageData({ | ||
ctx, | ||
layoutRecords, | ||
canvasWidth, | ||
renderArgs, | ||
}: { | ||
ctx: CanvasRenderingContext2D | ||
canvasWidth: number | ||
layoutRecords: LayoutFeature[] | ||
renderArgs: RenderArgsWithColor | ||
}) { | ||
const { config, showSoftClip, colorBy, theme: configTheme } = renderArgs | ||
const mismatchAlpha = readConfObject(config, 'mismatchAlpha') | ||
const minSubfeatureWidth = readConfObject(config, 'minSubfeatureWidth') | ||
const largeInsertionIndicatorScale = readConfObject( | ||
config, | ||
'largeInsertionIndicatorScale', | ||
) | ||
const defaultColor = readConfObject(config, 'color') === '#f0f' | ||
const theme = createJBrowseTheme(configTheme) | ||
const colorForBase = getColorBaseMap(theme) | ||
const contrastForBase = getContrastBaseMap(theme) | ||
ctx.font = 'bold 10px Courier New,monospace' | ||
|
||
const { charWidth, charHeight } = getCharWidthHeight() | ||
const drawSNPsMuted = shouldDrawSNPsMuted(colorBy?.type) | ||
const drawIndels = shouldDrawIndels() | ||
for (const feat of layoutRecords) { | ||
renderAlignment({ | ||
ctx, | ||
feat, | ||
renderArgs, | ||
defaultColor, | ||
colorForBase, | ||
contrastForBase, | ||
charWidth, | ||
charHeight, | ||
canvasWidth, | ||
}) | ||
renderMismatches({ | ||
ctx, | ||
feat, | ||
renderArgs, | ||
mismatchAlpha, | ||
drawSNPsMuted, | ||
drawIndels, | ||
largeInsertionIndicatorScale, | ||
minSubfeatureWidth, | ||
charWidth, | ||
charHeight, | ||
colorForBase, | ||
contrastForBase, | ||
canvasWidth, | ||
}) | ||
if (showSoftClip) { | ||
renderSoftClipping({ | ||
ctx, | ||
feat, | ||
renderArgs, | ||
colorForBase, | ||
config, | ||
theme, | ||
canvasWidth, | ||
}) | ||
} | ||
} | ||
} |
Oops, something went wrong.