Skip to content

TraceViewer ​

Sanger sequencing chromatogram with four-channel traces, quality scores, base calls, and alignment to reference.

Demo ​

Usage ​

svelte
<script>
  import { TraceViewer } from '@molbiohive/hatchlings';
</script>

<TraceViewer data={traceData} width={800} height={300} zoom={2} />

Data Type — TraceData ​

FieldTypeRequiredDescription
baseCallsstringyesCalled bases
qualityScoresnumber[]yesPhred quality per base
channelsTraceChannelyes{ A, C, G, T } signal arrays
peakPositionsnumber[]yesPeak center positions
alignmentTraceAlignmentnoAlignment to reference
labelstringnoTrace label
trimQualitynumbernoQuality trim threshold

Props ​

PropTypeDefaultDescription
dataTraceData—Primary data prop
widthnumber800Canvas width
heightnumber300Canvas height
showQualitybooleantrueShow quality score bars
trimQualitynumber20Quality trim threshold
highlightIndelsbooleantrueHighlight indels
zoomnumber1Zoom level
showScrollbarbooleantrueShow horizontal scrollbar

Example — Constructing Data ​

ts
import type { TraceData, TraceChannel, TraceAlignment } from '@molbiohive/hatchlings';

const baseCalls = 'ATCGATCGATCGATCGATCGATCGATCGATCGATCGATCGATCGATCGATCGATCGATCG';
const numBases = baseCalls.length;  // 60
const ppb = 10;                     // data points per base
const tp = numBases * ppb;          // 600 total data points

// Deterministic quality scores — mostly 32–45, with dips at positions 8, 22, 37, 51
// and ramps at the start/end of the read
const qualityScores: number[] = [];
for (let i = 0; i < numBases; i++) {
  let q = 32 + ((i * 7 + 3) % 14);
  if (i === 8 || i === 22 || i === 37 || i === 51) q = 12;
  if (i < 4) q = Math.max(15, q - (4 - i) * 5);
  if (i > numBases - 5) q = Math.max(12, q - (i - numBases + 5) * 4);
  qualityScores.push(q);
}

const peakPositions = Array.from({ length: numBases }, (_, i) => 5 + i * ppb);

// Channel signals generated via Gaussian peaks centered at each base call.
// Each channel is a number[] of length 600.
// Primary base gets amplitude ~800, off-bases get ~5% crosstalk.
const channels: TraceChannel = {
  A: [/* ... 600 values generated programmatically */],
  C: [/* ... 600 values */],
  G: [/* ... 600 values */],
  T: [/* ... 600 values */],
};

// Reference has substitutions at positions 12 and 30
const traceAlignment: TraceAlignment = {
  refSeq: 'ATCGATCGATCGGTCGATCGATCGATCGATCCTCGATCGATCGATCGATCGATCGATCG',
  querySeq: baseCalls,
  mismatches: [
    { pos: 12, type: 'substitution', refBase: 'G', queryBase: 'A' },
    { pos: 30, type: 'substitution', refBase: 'C', queryBase: 'T' },
  ],
  identity: 0.9667,
};

const traceData: TraceData = {
  label: 'Forward',
  baseCalls,
  qualityScores,
  channels,
  peakPositions,
  alignment: traceAlignment,
};

This is the data used in the demo above. Channel arrays are generated via Gaussian peak functions -- see docs/data/trace.ts for the full source.

The channels object contains raw fluorescence arrays (same length). peakPositions maps each base call to a signal index in the channel arrays. qualityScores and baseCalls must be the same length.