spacr.qt.widgets.read_view¶
Show sequencing reads as text, one read per row, with matches coloured.
A barcode mapping run claims three things about the sequencing files. The first is that a barcode was found. The second is where that barcode sat. The third is which direction it ran in.
A percentage on its own cannot prove that claim, because a percentage looks the same whether the matches are real or accidental.
The reads themselves can prove it. When the guide barcode falls in the same columns row after row, the number can be trusted. When nothing lines up, a badly configured run shows itself at once, rather than after an hour of mapping that returns no counts.
So this widget is deliberately plain. It draws the read text in a fixed pitch face, one read to a line, and it paints the characters a barcode matched in a colour belonging to that barcode type. Nothing wraps, nothing is elided, and the character in column forty of one read sits directly above the character in column forty of the next, which is the entire reason for looking at reads rather than at a table.
This module knows nothing about how matches are found. It takes reads and spans that somebody else computed, so the search engine and the screen that hosts it can change freely without touching anything here, and so this can be tested without either of them. The contract is the pair of small record types below, and it is meant to be written by hand as easily as it is generated.
A note on colour, because it is the part that is easy to get wrong. Every colour painted here is derived from the theme that is on screen, never written as a literal, and the derivation preserves the relative luminance of the theme’s own accent role. Contrast is a function of relative luminance and of nothing else, so a colour made this way clears exactly the contrast that the accent already clears on that theme, including the themes whose panels are translucent over a photograph. That is what lets an arbitrary number of barcode types each get a colour of their own without any of them becoming unreadable on some theme nobody checked.
Classes¶
One stretch of a read that a barcode of some type matched. |
|
One read and everything that matched inside it. |
|
Reads as text, one to a row, with each barcode type in its own colour. |
Functions¶
|
Give each barcode type a colour of its own, taken from the theme. |
Module Contents¶
- class spacr.qt.widgets.read_view.BarcodeSpan[source]¶
Bases:
NamedTupleOne stretch of a read that a barcode of some type matched.
The interval is half open and counted in characters from the start of the read, so it follows Python slicing exactly and the matched text is
read[start:stop]. Positions outside the read are clamped when the span is drawn, and a span whose stop is not after its start contributes nothing, so a caller doing arithmetic on read lengths cannot make the view raise.The kind is an opaque label. It is whatever the caller calls that family of barcode, it is what the legend shows, and it is what picks the colour, so two spans sharing a kind are guaranteed to share a colour on every row.
- Parameters:
start – First matched character, counting from zero.
stop – One past the last matched character.
kind – The barcode type this span belongs to.
- class spacr.qt.widgets.read_view.ReadRow[source]¶
Bases:
NamedTupleOne read and everything that matched inside it.
- Parameters:
text – The read as it should appear on screen, already trimmed to whatever window the caller wants shown.
spans – The matches inside that text. Order matters when two of them overlap, as described on
ReadView.
- class spacr.qt.widgets.read_view.ReadView(parent: PySide6.QtWidgets.QWidget | None = None)[source]¶
Bases:
PySide6.QtWidgets.QWidgetReads as text, one to a row, with each barcode type in its own colour.
Hand it reads and the spans somebody else matched inside them, and it shows them. It never searches for anything itself and never imports the code that does, so it can be dropped into any screen that has reads and positions to show.
What it guarantees. Reads are drawn in a fixed pitch face at fixed character positions, so column forty of one read sits above column forty of the next. A read never wraps onto a second visual row: a long one makes the view scroll sideways instead, because a wrapped read would break the one read per row promise that the whole widget exists to keep. A barcode type keeps one colour for as long as the view is showing it, so the eye can follow a match down the rows, and a legend above the reads says which colour is which.
How overlaps are settled. The spans of a read are read in the order they were given. The first span to cover a character keeps that character.
A later span still colours every character that is still free, so it is trimmed rather than hidden. The rule is applied before anything is drawn, which turns an overlap into a question of priority instead of a broken picture. To let one barcode type win an overlap, list its spans first.
What it costs. The reads are held in a list model and drawn by a delegate, so handing over reads costs a list assignment and drawing costs only the rows that are actually on screen. Setting ten thousand reads and showing the view resolves the character ownership of a screenful of rows, not of ten thousand, which is what keeps the interface responsive on a real FASTQ sample rather than on a toy one.
- Parameters:
parent – Optional Qt owner responsible for the widget’s lifetime.
Build an empty view with a legend above a list of reads.
- changeEvent(event) None[source]¶
Follow a theme or text size change without being told about it.
The application re-applies its stylesheet and palette when the theme changes, and Qt delivers that to every widget as a change event. Taking the colours again here means the reads re-theme with everything else instead of keeping the palette they were first drawn in.
- Parameters:
event – The Qt change event being delivered.
- clear() None[source]¶
Drop every read and forget which barcode types were being shown.
Forgetting the types is the point of having this at all rather than setting an empty list of reads. A fresh run may search for a different set of barcodes, and carrying the previous run’s assignment over would give the new first barcode the old second barcode’s colour.
- colour_for(kind: str) str | None[source]¶
Return the colour one barcode type is drawn in.
- Parameters:
kind – The barcode type name.
- Returns:
A hex colour string, or
Noneif the view has never been shown that type.
- kinds() Tuple[str, ...][source]¶
Return the barcode types being shown, in legend order.
- Returns:
The type names, which is also the order that assigned their colours.
- refresh_colours() None[source]¶
Take the colours from the theme again and repaint.
Safe to call at any time and cheap enough to call on a whim: it re-derives one colour per barcode type, not per read.
- row_count() int[source]¶
Return how many reads are being shown.
- Returns:
The number of rows in the view.
- set_reads(rows: Sequence[object], kinds: Sequence[str] | None = None) None[source]¶
Show these reads, with these barcode types in the legend.
Passing the barcode types explicitly is worth doing whenever they are known, because it fixes both the legend order and which type gets which colour. A type that is searched for but found in none of the reads on screen then still appears in the legend, which is itself information: it says the search ran and came back empty rather than leaving the user to wonder whether it ran at all.
Left unsaid, the types are taken from the spans in the order they are first seen, and any type already being shown keeps the colour it has.
- Parameters:
rows – The reads, each a
ReadRow, a plain string for a read with no matches, or a text and spans pair.kinds – Barcode type names in legend order, or
Noneto take them from the spans.
- spacr.qt.widgets.read_view.barcode_colours(kinds: Sequence[str]) Dict[str, str][source]¶
Give each barcode type a colour of its own, taken from the theme.
Colours are assigned by position, so a type keeps its colour as long as the caller keeps passing the types in the same order, and adding a type to the end of the sequence never changes the colours already handed out. Repeats are ignored after the first appearance.
The result follows the theme on screen at the moment of the call. It differs between the light and dark palettes, and between both and the image palettes, which is deliberate rather than incidental: each palette has its own readable luminance and the colours are derived from it.
- Parameters:
kinds – Barcode type names, in the order they should be coloured.
- Returns:
A mapping from each name to a hex colour string.