spacr.gene_facts

Collect the bundled annotation for one gene, grouped for display on a gene tile.

Clicking a gene in an interactive regression opens the information available for that gene. spacr.gene_tile resolves which gene a clicked guide names and whether that mapping is ambiguous. This module returns the annotation spaCR holds for a given gene.

All values come from spacr.annotation – the same join that writes the annotated exports – so the tile and the exported CSV report the same values (for example GRA14’s compartment). This module reads no file, parses no gene id and owns no table; it groups spacr.annotation.annotate()’s 23 columns into reading order and adds the per-segment DeepTMHMM coordinates that annotate leaves out of a coefficient export.

The module follows four rules:

  1. Gene ids are parsed in one place. TGGT1_224750, gene_fraction:gene[224750] and the guide 224750_2 are all gene 224750, as determined by spacr.annotation.gene_number(); a second parser could make the volcano and the hit list name different genes.

  2. Missing annotation is reported as text. A gene with no annotation row gets GeneFacts.reason – “no row in the bundled Toxoplasma annotation” – rather than a block of empty fields, which would read as “measured, found nothing”. GeneFacts.known is the flag a caller uses to grey out a control.

  3. Groups are derived from the table. The fitness and expression rows are every fit_/expr_ column spacr.annotation.columns() reports, so a screen added to phenotype.csv appears on the tile without a change to this file, and an unrecognised column is listed under “other annotation” instead of being dropped.

  4. Loading can be done off the GUI thread. The first call reads five bundled CSVs (360 ms) and the first GeneFacts.segments reads DeepTMHMM’s 8,140 rows. warm() does both in advance and joins the screen’s terms in one pass: annotate re-checks all five right-hand keys for uniqueness on every call, so one gene costs 20 ms and four hundred cost 21. A click after warming is a dict lookup, 0.02 ms.

Public API:

from spacr import gene_facts

known = gene_facts.facts("fraction:grna[239740_3]")
known.known                 # True
known.value("gene_name")    # 'GRA14'
known.sections()            # (('identity', (('gene name', 'GRA14'), ...

Classes

GeneFacts

Everything the bundled annotation holds about one gene.

Segment

One DeepTMHMM segment of a protein, with its residue coordinates.

Functions

available(→ Tuple[str, ...])

Every annotation column this module can show, in reading order.

clear_cache(→ None)

Forget the derived indices. For tests, and for a reinstall mid-session.

facts(→ GeneFacts)

Everything the bundled annotation holds about the gene value names.

facts_for(→ Dict[str, GeneFacts])

The facts for several genes at once, keyed by gene number.

unavailable_reason(→ str)

Why there is no annotation on this install, or "".

warm() → Tuple[str, ...])

Load every table this module reads; intended to run off the GUI thread.

Module Contents

class spacr.gene_facts.GeneFacts[source]

Everything the bundled annotation holds about one gene.

Parameters:
  • gene – the bare gene number, or "" when the caller’s value named no gene at all.

  • values – the annotation columns that had something in them, keyed by the column name spacr.annotation.columns() uses. A column with a gap is absent here rather than present and empty.

  • segments – the DeepTMHMM signal peptide and transmembrane segments, in residue order. Empty for a soluble protein, and empty for a gene DeepTMHMM never saw – reason is what tells those apart.

  • reason – a sentence explaining why no values are available, or "" when there are values. An empty record carries a reason, so the panel shows an explanation instead of an empty table.

sections() → Tuple[Tuple[str, Tuple[Tuple[str, str], ...]], ...][source]

The facts as ((heading, ((label, value), ...)), ...).

This is the single ordering used by both the Qt tile and the text form, and the same shape spacr.gene_tile.GeneTile.sections() returns, so one renderer lays out both halves of a tile.

A group with no values is not emitted (rule 2), because a heading over an empty space would suggest that the values were looked for and not found.

to_html() → str[source]

The facts as HTML, for a Qt rich-text view.

Matches spacr.gene_tile.GeneTile.to_html() mark for mark, so the two halves of one tile do not read as two different documents.

to_text() → str[source]

The facts as plain text – what a test reads and a log records.

value(column: str, default: Any = None) → Any[source]

One annotation column, or default when it had a gap.

Parameters:

column – annotation column whose value is requested.

property known: bool[source]

Whether the annotation holds any value for this gene.

Callers use it to grey out a control, and show reason to explain why the control is unavailable.

class spacr.gene_facts.Segment[source]

One DeepTMHMM segment of a protein, with its residue coordinates.

Parameters:
  • kind – signal peptide or transmembrane.

  • index – 1-based position among the segments of that kind; 1 for a signal peptide, of which there is at most one.

  • start – first residue, 1-based and inclusive, as DeepTMHMM reports.

  • end – last residue, inclusive.

  • length – residues spanned, as the source file records it rather than recomputed, so a disagreement with end - start + 1 in the source data is preserved rather than corrected.

property label: str[source]

signal peptide span or TM 3 – the tile’s left column.

“span”, not “signal peptide”: the summary row two lines above is already labelled “signal peptide”, and two rows with one label reads as the panel having printed the same field twice.

property text: str[source]

residues 62-78 (17 aa).

spacr.gene_facts.available() → Tuple[str, ...][source]

Every annotation column this module can show, in reading order.

Empty when nothing is bundled, which is what unavailable_reason() turns into a sentence.

spacr.gene_facts.clear_cache() → None[source]

Forget the derived indices. For tests, and for a reinstall mid-session.

spacr.annotation.clear_cache() is called too: the layout here is derived from that module’s tables, and dropping one without the other leaves a layout describing columns that are no longer loaded.

spacr.gene_facts.facts(value: Any) → GeneFacts[source]

Everything the bundled annotation holds about the gene value names.

Parameters:

value – a design term, an accession, a guide id or a bare gene number – every spelling spacr.annotation.gene_number() takes.

Returns:

a GeneFacts; None is never returned. A term that names no gene returns a record with GeneFacts.known false and a GeneFacts.reason saying so, so callers do not need a separate None check.

spacr.gene_facts.facts_for(values: Iterable[Any]) → Dict[str, GeneFacts][source]

The facts for several genes at once, keyed by gene number.

Parameters:

values – anything spacr.annotation.gene_number() accepts – design terms, accessions, guide ids, bare numbers, in any mixture.

Returns:

one entry per distinct gene named, in the order first named. A value naming no gene contributes nothing, so an empty result means nothing in values was a gene.

Uncached genes are joined in one call. An ambiguous guide can name three genes that each need the same 23 columns; one join costs a third of three separate merges and builds the key once.

spacr.gene_facts.unavailable_reason() → str[source]

Why there is no annotation on this install, or "".

A sentence rather than a flag, because it is shown to the user, so an unavailable panel is distinguishable from a failed one.

spacr.gene_facts.warm(values: Iterable[Any] = ()) → Tuple[str, ...][source]

Load every table this module reads; intended to run off the GUI thread.

Parameters:

values – the terms a user might click – a whole results table’s feature column is the intended argument. Every gene among them is joined in one pass and cached, so passing four hundred costs about the same (21 ms) as passing one.

Returns:

the columns that came out available, so a caller can tell “the tables loaded” from “the tables are not installed” without a second call.

Measured without warming, the first click spends 360 ms reading CSVs plus a 20 ms join inside the mouse-press handler, freezing the plot for about a third of a second. After warming with the screen’s terms, a click is a dict lookup – 0.02 ms.

Nested helpers

_segment_index.collect(kind: str, index: int, start: str, end: str, length: str) → None

Collect one supplementary-table segment slot by gene.

Parameters:
  • kind – segment family recorded on each result.

  • index – one-based position within that family.

  • start – supplementary column holding the first residue.

  • end – supplementary column holding the last residue.

  • length – optional supplementary column holding the segment span.

Returns:

None. Missing coordinate columns and invalid gene IDs are skipped; valid rows append to the captured index using a finite recorded numeric length or the inclusive end - start + 1 fallback.

spacr/gene_facts.py:387