spacr.qt.widgets.volcano_explorer

The volcano you can click, restyle and export.

The pipeline writes a volcano PDF, and until now that was the end of it: to change an axis label, recolour by a covariate or find out which guide a dot was, you re-ran the analysis or opened the CSV. This widget makes the plot the thing you interrogate.

Three ideas hold it together:

  • One renderer. Every pixel comes from spacr.volcano_style.render_volcano(), the same function the headless pipeline calls. Exporting re-renders from the same VolcanoStyle at print size rather than screenshotting the widget, so what is saved is what was on screen, at full vector quality.

  • The style is a value. Controls write into a VolcanoStyle and ask for a redraw. That makes the whole appearance saveable to JSON, reloadable, and reproducible.

  • Clicking is a lookup, not a hit test on pixels. The nearest point is found in data space normalised by the axis ranges, so a click is as accurate on a squashed axis as on a square one.

Annotation files can be dropped in to colour or shape the points by anything: the file is merged onto the results by a join column, and every column it brings becomes available in the colour-by and shape-by menus.

Classes

VolcanoExplorer

An interactive volcano: click a point, restyle it, export it.

Module Contents

class spacr.qt.widgets.volcano_explorer.VolcanoExplorer(results: pandas.DataFrame | None = None, style: spacr.volcano_style.VolcanoStyle | None = None, parent=None)[source]

Bases: PySide6.QtWidgets.QWidget

An interactive volcano: click a point, restyle it, export it.

Parameters:
  • results – the fitted table to plot. Copied with the index reset, so the row numbers a clicked point reports are positions in the plot rather than whatever index the caller happened to carry.

  • style – the styling to open with. A fresh VolcanoStyle is used when none is given.

  • parent – parent widget.

Build the volcano, its style controls and its detail panel.

The plot (“Volcano plot”) and the selected-point table (“Selected point”) are sections of a vertical CollapsibleSplitter – each folds by its heading, and the edge between them drags – and that column shares a draggable edge with the style controls, whose categories already fold.

Parameters:
  • results – the fitted table to plot.

  • style – how to draw it.

  • parent – parent widget.

build_style_menu()[source]

Build the context menu for styling the current volcano plot.

Returns:

PySide6.QtWidgets.QMenu – A menu containing live style controls and style-file actions. Changes update both the plot and its side-panel controls.

compartments() → list[source]

The LOPIT compartments this screen actually has, commonest first.

NOT ALL 27 IN THE REFERENCE TABLE: a tick box that would colour nothing is indistinguishable from a broken one. Empty when no column of the results names a gene, which is a volcano without compartment colouring rather than an error.

dragEnterEvent(event)[source]

Accept a drag carrying a table this explorer can plot.

Parameters:

event – the Qt drag event.

dropEvent(event)[source]

Plot the dropped table.

Parameters:

event – the Qt drop event.

export(fmt: str = 'pdf', path: str | None = None) → str | None[source]

Re-render at print size and write the file. Returns the path written, or None.

Not a screenshot: the figure is drawn again from the same style, so a PDF stays vector and a PNG honours the dpi under Frame regardless of how large the widget happens to be on screen.

label_for(setting: str) → PySide6.QtWidgets.QLabel | None[source]

Return the label associated with a style setting.

Parameters:

setting – the style setting’s key, as its control was registered; an unknown key gives None.

menu_settings() → set[source]

The style fields the right-click menu offers, by name.

merge_annotation_file(path, *, on: str | None = None) → int[source]

Merge a CSV/Excel of annotations onto the results.

Every column it brings becomes selectable for colour and shape. The join column is inferred from whichever shared column matches most rows, so a file keyed on gene and one keyed on guide both work without the user being asked which is which.

Parameters:

path – annotation file; .xlsx/.xls is read as Excel, anything else as CSV. It must share a column with the results (unless on names one) or ValueError is raised.

Returns:

the number of columns added.

nearest_point(x: float, y: float, axes=None) → int | None[source]

Index of the point closest to (x, y) in axis-normalised space.

Normalising by each axis’s visible range is what makes a click land on the point that LOOKS closest. Raw Euclidean distance in data units picks the wrong point whenever the axes have different scales, which on a volcano they always do.

Parameters:
  • x – the click’s x position in data units of the x column.

  • y – the click’s y position in plotted units (after the -log10 transform when the style applies one).

Returns:

the row position, or None when no point lies within 0.05 of the normalised visible range.

panel_settings() → set[source]

The style fields the side panel offers, by name.

problems() → dict[source]

Return validation problems recorded during the latest redraw.

refresh() → None[source]

Redraw the canvas, and name the settings that could not be used.

A BAD SETTING DOES NOT COST THE READER THE PICTURE. One mistyped colour used to replace the whole volcano with the words “cannot draw this plot”, which takes away the only thing on screen over a single field and does not say which field. Instead the offending settings fall back to the last value that drew, the figure stays up, the name of each offending setting goes red and the reasons are printed under the plot.

screen=True: this render is being read, so it takes VolcanoStyle.screen_background. The export path does not pass it and therefore keeps the transparent figure default.

results() → pandas.DataFrame[source]

The table being plotted.

A COPY, so a caller cannot change what is on screen by editing what it was handed.

Returns:

the results table.

section_for(setting: str)[source]

Return the collapsible section containing a style setting.

Parameters:

setting – the style setting’s key; an unknown key, or one registered outside a section, gives None.

sections() → list[source]

Return unique settings sections in panel order.

select_point(index: int) → dict[source]

Select a point by row index and show everything known about it.

Parameters:

index – positional row index into the results frame (not a label).

selected_index() → int | None[source]

Which row the user has clicked, if any.

A POSITION into the plotted frame, not a label – see set_results().

Returns:

the row position, or None when nothing is selected.

set_results(results: pandas.DataFrame) → None[source]

Plot a new fitted table, clearing any selection.

THE INDEX IS RESET. Point picking is by POSITION in the plotted frame, so a table carrying its old index would have every click resolve to the wrong row.

Parameters:

results – the fitted table to plot.

set_style(style: spacr.volcano_style.VolcanoStyle) → None[source]

Restyle the plot and push the new values into the controls.

BOTH, so a style set from code leaves the controls agreeing with the plot rather than showing what they were last set to by hand.

Parameters:

style – the style to apply.

style() → spacr.volcano_style.VolcanoStyle[source]

How the volcano is currently drawn.

Returns:

the style.

Nested helpers

VolcanoExplorer.build_style_menu.changed(_name=None, _value=None)

Re-apply the style after any menu entry changes it.

spacr/qt/widgets/volcano_explorer.py:477