spacr.graph_types

Match graph types and defaults to the structure of plotted data.

The module distinguishes categorical, continuous, and ordered axes. It lists compatible graph types first and supplies a reason for each incompatible option, allowing interfaces to disable unsupported choices without hiding them.

IT IS ALSO WHERE EVERY GRAPH IN spaCR GETS ITS STARTING FORM. The DEFAULT GRAPH TYPE setting is stored per data shape (spacr.qt.preferences), read back through chosen_for(), and turned into “what is drawn before the first right-click” by default_for() and start_for(). A widget asks one of those two and gets an answer that already accounts for the user’s choice, whether that choice fits the data, and whether the data is thick enough to support it – so the setting reaches a new graph by the graph doing the ordinary thing rather than by remembering to.

Functions

chosen_for(→ str)

The graph type the user asked to see FIRST for shape, or "".

default_for(→ str)

The graph type drawn FIRST for shape.

fits(→ bool)

Return whether a graph type supports a data shape.

mark_for(→ str)

The live-plot mark that draws graph_type.

mark_to_start_on(→ Tuple[str, str])

What to draw FIRST, in the vocabulary the DRAWING code speaks.

offer(→ List[Tuple[str, str, str]])

List graph choices for a frame, with compatible choices first.

shape_of(→ str)

Classify the axis structure of a data frame.

start_for(, fallback, str])

What to draw FIRST, and why that is not what was asked for.

too_thin_for(→ str)

Why graph_type cannot summarise groups this small, or "".

type_of_mark(→ str)

The graph type a live plot's mark draws.

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

Return graph types compatible with a data shape.

why_not(→ str)

Explain why a graph type is incompatible with a data shape.

Module Contents

spacr.graph_types.chosen_for(shape: str) → str[source]

The graph type the user asked to see FIRST for shape, or "".

Parameters:

shape – one of the keys of DATA_SHAPES.

Returns:

the saved graph type, or an empty string when the user has expressed no preference for this shape – or expressed one this shape cannot take.

EMPTY MEANS “NOTHING WAS CHOSEN”, which is not the same answer as the table’s default: a widget with a starting form of its own keeps it when nothing was chosen, and the preference overrides it when something was. default_for() is the caller that turns “nothing” into the table’s own answer.

A SAVED CHOICE THAT DOES NOT FIT THE DATA IS NOT A CHOICE FOR IT. Someone who prefers bars has not asked for a bar of a continuous x against a continuous y – that is a different graph of different data, and WHY_NOT says so.

A MISSING PREFERENCE STORE IS NOT AN ERROR. A headless render has no Qt and no QSettings, and a figure still has to be drawn.

spacr.graph_types.default_for(shape: str) → str[source]

The graph type drawn FIRST for shape.

Parameters:

shape – one of the keys of DATA_SHAPES.

Returns:

a graph type from GRAPH_TYPES.

Raises:

KeyError – if shape is unsupported.

THE USER’S CHOICE COMES FIRST. The preference decides which compatible graph is drawn first, and right-click can still change it afterwards. Every graph in spaCR reaches its starting form through this function or through start_for(), so the preference applies consistently across screens.

spacr.graph_types.fits(shape: str, graph_type: str) → bool[source]

Return whether a graph type supports a data shape.

Parameters:
  • shape – inferred data-shape key.

  • graph_type – graph implementation key to test.

spacr.graph_types.mark_for(graph_type: str, fallback: str = '') → str[source]

The live-plot mark that draws graph_type.

Parameters:
  • graph_type – a graph type from GRAPH_TYPES.

  • fallback – what to answer for a name MARKS has no entry for.

Returns:

a mark key from spacr.qt.widgets.fast_plots.MARK_TYPES.

spacr.graph_types.mark_to_start_on(shape: str, fallback_mark: str) → Tuple[str, str][source]

What to draw FIRST, in the vocabulary the DRAWING code speaks.

Parameters:
  • shape – one of the keys of DATA_SHAPES.

  • fallback_mark – what the caller drew BEFORE the setting existed, in mark vocabulary – 'jitter_box', 'jitter_bar' and so on.

Returns:

(mark, note), the mark to draw and the sentence explaining any fallback, empty when the choice was honoured.

TWO VOCABULARIES MEET HERE AND THEY ARE NOT THE SAME. This module stores bar_jitter and box_jitter; spacr.plot.spacrGraph and the live panels draw jitter_bar and jitter_box. A caller that reads the setting and forgets mark_for() hands matplotlib a name that plot.py’s own error message lists as unknown – which is the mistake this function exists to stop anyone making twice. Every call site that reads the setting and then draws should come through here.

THE FALLBACK IS THE CALLER’S OWN FORM, NOT THE TABLE’S DEFAULT, and it is taken in MARK vocabulary because that is what a caller already has written down. A preference nobody expressed must not move an existing view, so a caller passing what it used to hardcode gets exactly that back until someone chooses otherwise.

THE FALLBACK IS HANDED TO start_for() UNTRANSLATED, on purpose. It looks like it needs mapping back to graph-type vocabulary first, and the first version of this function did that with a reverse lookup over MARKS. A mutation test could not tell the two versions apart, and reading start_for says why: with no preference stored it answers the fallback AS GIVEN, without validating it, because “a widget knows what it can draw”. The reverse lookup was dead code.

IT WOULD STOP BEING DEAD the day a caller passes counts. start_for uses the fallback a second time on the too-thin-for-a-distribution path, where fits(shape, fallback) decides between the caller’s form and the table default – and a MARK spelling fails fits. No caller here has counts: these are settings defaults, built before any data is read. If one ever does, this function needs the mapping back and a test that reaches that path.

spacr.graph_types.offer(frame, x: str = '', y: str = '') → List[Tuple[str, str, str]][source]

List graph choices for a frame, with compatible choices first.

Parameters:
  • frame – data frame whose selected columns determine the shape.

  • x – horizontal-axis column, or an empty string for an ungrouped distribution.

  • y – vertical-axis measurement column.

Returns:

list of tuple – (graph_type, description, incompatibility_reason) for every graph type. Compatible entries have an empty reason.

spacr.graph_types.shape_of(frame, x: str = '', y: str = '') → str[source]

Classify the axis structure of a data frame.

Parameters:
  • frame (pandas.DataFrame) – Source data.

  • x (str, optional) – Column names assigned to the horizontal and vertical axes. An empty x represents an ungrouped continuous distribution.

  • y (str, optional) – Column names assigned to the horizontal and vertical axes. An empty x represents an ungrouped continuous distribution.

Returns:

str – Key from DATA_SHAPES. A numeric, unique, monotonically increasing x-axis is classified as ordered continuous data.

spacr.graph_types.start_for(shape: str, counts=(), fallback: str = '') → Tuple[str, str][source]

What to draw FIRST, and why that is not what was asked for.

Parameters:
  • shape – one of the keys of DATA_SHAPES.

  • counts – observations per group, when they are known.

  • fallback – the caller’s OWN starting form, for when the user has expressed no preference. It is answered as given – a widget knows what it can draw – and an empty one means DEFAULTS.

Returns:

(graph_type, note). The note is empty whenever the graph being drawn is the one that was asked for.

Raises:

KeyError – if shape is unsupported and no usable fallback was given.

THE FALLBACK IS SAID OUT LOUD. A preference is a blanket statement – “draw violins” – and a blanket statement meets data it cannot describe eventually. Drawing the points instead and saying nothing would leave a user who asked for violins looking at a jitter with no explanation, so the sentence comes back with the answer and the caller puts it on the plot.

THE TABLE’S OWN DEFAULT IS NEVER OVERRIDDEN THIS WAY. Only a saved choice is re-examined against the data: DEFAULTS already picks types that keep the observations, and a line of one point per x – the ordered default – would otherwise be talked out of itself every time.

spacr.graph_types.too_thin_for(graph_type: str, counts) → str[source]

Why graph_type cannot summarise groups this small, or "".

Parameters:
  • graph_type – the graph type about to be drawn.

  • counts – observations per group. Unknown sizes – an empty iterable – are not an objection: a graph that has not been handed its data yet is not yet drawing a claim.

Returns:

a sentence naming the smallest group, or an empty string when the graph type is supported by the data.

Only the types that REPLACE the observations can be too thin; see HIDES_THE_OBSERVATIONS. A jitter of two points is two points, which is the truth; a violin of two points is a density that was never measured.

spacr.graph_types.type_of_mark(mark: str, fallback: str = '') → str[source]

The graph type a live plot’s mark draws.

Parameters:
  • mark – a mark key from spacr.qt.widgets.fast_plots.MARK_TYPES.

  • fallback – what to answer for a mark no graph type draws.

Returns:

a graph type from GRAPH_TYPES.

The inverse of mark_for(), so a widget whose own starting form is written in marks can state it once and still be compared against a preference written in graph types.

spacr.graph_types.types_for(shape: str) → Tuple[str, ...][source]

Return graph types compatible with a data shape.

Parameters:

shape – one of the keys in DATA_SHAPES.

Raises:

KeyError – If shape is unsupported.

spacr.graph_types.why_not(shape: str, graph_type: str) → str[source]

Explain why a graph type is incompatible with a data shape.

Parameters:
  • shape – inferred data-shape key.

  • graph_type – graph implementation key whose mismatch is explained.

An empty string is returned for compatible pairs.

Nested helpers

shape_of.kind(name: str) → str

Classify one candidate axis against the captured data frame.

Parameters:

name – column name assigned to the axis, or an empty string for an unassigned axis.

Returns:

'absent' when the column is unavailable, 'continuous' for a numeric column, or 'categorical' for every other present column.

spacr/graph_types.py:198