spacr.qt.widgets.gene_panel¶
Click a gene, see everything spaCR knows about it – in one panel.
Two modules already hold the two halves of the answer and neither of them is a widget, which is deliberate: the parts that can be WRONG are testable without a window.
spacr.gene_tileWHICH gene this dot is – guide to gene, theambiguous protospacers, and THIS SCREEN’s own effect / p / q / guides, read out of the results frame that is already on screen.
spacr.gene_factsWHAT that gene is – product, topology with theDeepTMHMM coordinates, hyperLOPIT compartment, the published CRISPR fitness screens and the stage expression, all of it out of
spacr.annotation.
This module puts them one above the other and does nothing else with the numbers. THE PANEL IS NOT A SECOND SOURCE OF TRUTH: the coefficient, the p-value, the q-value and the guide agreement are whatever the table on screen says they are, because two places computing one number is how they start disagreeing.
THE GUI THREAD DOES NOT READ FILES¶
Cold, the first click costs 360 ms of CSV reading – five bundled annotation
tables, DeepTMHMM’s 8,140 rows, and the gRNA reference and metadata indices
spacr.gene_tile keeps – inside a mouse press. A plot that freezes for
a third of a second when clicked reads as broken.
So warm_annotation() does all of it on a worker thread, through
spacr.qt.job_runner.JobRunner, which is the module that already
gets the threading rules right: the worker’s finished is relayed through
a Signal whose receiver is a BOUND METHOD of a GUI-thread object, never a
closure, so the handler runs on the GUI thread and the QThread is retired.
Given the screen’s own terms it warms every gene in one join – 400 genes
cost the same 21 ms as one – after which a click is a dictionary lookup.
Until it is warm, the panel says so, and the one control it has is greyed out with the reason on it. A gene with no annotation likewise says “no row in the bundled annotation” rather than showing a form of empty fields, which reads as “measured, found nothing”.
Classes¶
The gene tile: which gene this is, and everything known about it. |
Functions¶
|
Read every table a gene tile needs. RUNS ON A WORKER THREAD. |
Module Contents¶
- class spacr.qt.widgets.gene_panel.GenePanel(frame_provider: Callable[[], Any] | None = None, *, threaded: bool = True, parent=None)[source]¶
Bases:
PySide6.QtWidgets.QWidgetThe gene tile: which gene this is, and everything known about it.
- Parameters:
frame_provider – called with no arguments for the current results frame. A callable rather than a stored frame so a newly loaded regression is never answered out of the previous one.
threaded –
Falsewarms inline instead of on a worker thread, so a test can drive the panel synchronously without the behaviour diverging –JobRunneremits the same signals in the same order either way.parent – the usual.
Build the gene panel: the record above what spaCR knows about it.
The annotation lookup is warmed on a worker, and only once the panel has actually been shown: a panel re-set with the same table on every filter move would otherwise start a thread per redraw for no new genes at all. The thread’s lifetime is guarded twice, because Qt aborts the process if a running
QThreadis destroyed and a panel can be dropped without ever being closed – a tab rebuilt, a screen replaced, an interpreter shutting down.- Parameters:
frame_provider – called for the coefficient table the record half reads its numbers from.
threaded – warm the annotation lookup on a worker thread.
parent – parent widget, or
None.
- __del__()[source]¶
The last guard, and the only one that needs nothing to happen.
THREE THINGS CAN START THE WARM-UP – the first show,
warm_now, and a frame arriving – so guarding each start site is guarding the wrong end. This guards the LIFETIME: whenever the panel is collected, with or without a close, with or without an event loop, the thread is asked to stop first.The other two guards each need an event to fire.
closeEventneeds somebody to close the panel;QApplication.aboutToQuitneeds an event loop to quit. A panel built, handed a table and dropped – a tab rebuilt, a screen replaced, a headless script, a test – reaches neither, and Qt callsabort()on the running thread. That was SIGABRT onQApplication([]); RegressionResultsPanel().Everything here is swallowed on purpose.
__del__runs during garbage collection and at interpreter shutdown, where the C++ half may already be gone and the module globals may already be None; an exception raised here is printed and ignored by Python anyway, and the one thing worth doing is the shutdown attempt.
- annotation_columns() Tuple[str, ...][source]¶
The annotation columns this install can show. Empty until warm.
- closeEvent(event)[source]¶
Stop the warm-up before the widget goes.
Qt aborts the process if a running QThread is destroyed, and a warm-up outliving its panel is exactly that.
- Parameters:
event – the close event; passed on to the base class after the warm-up worker is stopped.
- save_topology(path) bool[source]¶
Write the clicked gene’s full DeepTMHMM record to
path.- Parameters:
path – the CSV file to write, passed to
spacr.annotation.supplementary(). Nothing is written when no clicked gene is known or DeepTMHMM is not bundled.- Returns:
whether a file was written.
Straight through
spacr.annotation.supplementary(), which is the function that defines what that table is. Rewriting the columns here would be a second definition of the supplementary file, differing from the one an export writes in ways nobody would notice until a reviewer compared them.
- set_frame_provider(provider: Callable[[], Any] | None) None[source]¶
Point the panel at where the current results frame lives.
- Parameters:
provider – a no-argument callable returning the current results frame, called each time a feature is shown;
Nonebuilds tiles without a frame.
- showEvent(event)[source]¶
Start annotation warm-up when the panel first becomes visible.
Deferring the worker until the panel is shown avoids creating a background thread for panels that are constructed but never used.
- Parameters:
event – the show event; passed on to the base class before the warm-up starts.
- show_feature(key) None[source]¶
Build and show the tile for one clicked feature.
THE SLOT
key_selectedCONNECTS TO. It takes the feature string and nothing else, so a volcano click and a results-row click reach it identically – and it is connected once, on the table, because that is the funnel both directions already pass through.Driven straight rather than off
summary.tile_shown: that signal is not emitted when the resolver RAISES, and the one case where the lower half must not be left showing the previous gene is exactly the one where the upper half failed.- Parameters:
key – the clicked feature string, e.g. a gene or results-row key; it is passed to the summary tile as given.
- to_pixmap(width: int = TILE_WIDTH) PySide6.QtGui.QPixmap[source]¶
The whole tile – both halves – as one
QPixmap.The figure grid’s cells take a pixmap and size themselves from its aspect ratio, so rendering to one lets the gene tile be a tile in that grid without
_FigureCelllearning about text.
- topology_reason() str[source]¶
Why “Save topology CSV” cannot run, or
""when it can.The design: a control that cannot do anything is greyed out AND says why. This is the sentence, and it is the button’s tooltip.
- warm_for(frame) bool[source]¶
Warm the annotation for every gene in
frame. Call on load.- Parameters:
frame – the results table that was just loaded.
- Returns:
whether a warm-up was started.
The terms are read off the frame HERE, on the GUI thread, because that is a list comprehension over a column that is already in memory. The join they feed is what goes to the worker.
- warm_now() bool[source]¶
Start the pending annotation warm-up.
- Returns:
bool – Whether a worker was started.
- property facts: Tuple[Any, ...][source]¶
One
spacr.gene_facts.GeneFactsper candidate gene.
- property tile[source]¶
The
spacr.gene_tile.GeneTileon screen, orNone.
- spacr.qt.widgets.gene_panel.warm_annotation(features: Sequence[Any] = ()) Tuple[str, ...][source]¶
Read every table a gene tile needs. RUNS ON A WORKER THREAD.
- Parameters:
features – the terms the user might click – pass the results table’s whole
featurecolumn. Every gene among them is joined in one pass, which costs the same as joining one.- Returns:
the annotation columns that came out available; empty when the bundled tables are not installed, which is a state the panel shows rather than hides.
Touches no widget and returns only data – that is the contract for anything handed to
spacr.qt.job_runner.JobRunner.submit().It warms
spacr.gene_tiletoo, by resolving one term. That module keeps its own indices over the gRNA reference and the curated metadata, and they are just as cold on the first click as the annotation tables are; warming one and not the other would move the freeze rather than remove it.