spacr.qt.counting_tool

B13 — counting by hand on the layer canvas.

spacr.counting is the session: the classes, the markers, the undo stack and the export, all in plain numpy so the tally can be tested without a display. This is the mouse and the panel — a click that lands on a world coordinate, a live tally beside the image, and one button that writes the clicks out rather than the total.

Why a click removes as well as adds

A counting session is thousands of clicks and a proportion of them are wrong. The two ways of correcting a mistake are different actions: undo takes back the last thing you did, and clicking a marker again takes back a specific thing you did some time ago. Both are here, and clicking a marker removes it whatever class it was scored as — a counter who has to re-select the class before they can take a marker back will leave the wrong marker there.

The tally is derived, never typed

Everything the panel shows is read from the marker layers on every model event. There is no counter variable to drift out of step with the picture, so a marker removed through the layer list rather than through this panel changes the number too.

Classes

CountingPanel

The tally beside the image, and the button that writes it out.

CountingTool

Turns clicks on a LayerCanvas into counts.

Module Contents

class spacr.qt.counting_tool.CountingPanel(canvas: spacr.qt.layer_viewer.LayerCanvas, parent=None, *, classes: List[Any] | None = None, field: spacr.layers.FieldKey | None = None, session: spacr.counting.CountingSession | None = None)[source]

Bases: PySide6.QtWidgets.QWidget

The tally beside the image, and the button that writes it out.

Parameters:
  • canvas – the LayerCanvas to count on.

  • classes – what is being counted; see spacr.counting.CountingSession.

  • field – the FieldKey being counted, carried into the export so a count can join the measurement tables.

  • parent – parent widget; ownership only.

  • session – an already-built CountingSession. None builds one from the other arguments, which is the ordinary case; PASSING ONE HANDS THE PANEL A SESSION THAT ALREADY HAS STATE – a part-finished tally, or one a test wrote directly – so the panel resumes it instead of starting over.

Build the counting panel over a canvas.

Parameters:
  • canvas – the canvas clicks are counted on.

  • parent – parent widget, or None.

  • classes – the classes to count; ignored when session is given.

  • field – which field this count belongs to; ignored when session is given.

  • session – an existing session to continue, rather than starting a new count.

add_class(name: str | None = None) → str[source]

Count one more thing; returns the class name.

clear() → int[source]

Remove every marker of every class; returns how many went.

closeEvent(event) → None[source]

Stop listening and give the canvas its mouse back.

Parameters:

event – the close event; it is passed on unchanged to the base-class handler.

export_points() → str | None[source]

Write one row per marker, asking where.

export_summary() → str | None[source]

Write one row per class, asking where.

refresh() → None[source]

Redraw the tally from the marker layers.

start_counting() → CountingTool[source]

Attach the counting tool to the canvas and return it.

stop_counting() → None[source]

Give the canvas its mouse back.

undo() → bool[source]

Take back the last click. True if there was one.

write(path: str, *, summary: bool = False) → str | None[source]

Write the count to path without asking; returns the path.

The seam the dialog goes through, so a screen (or a test) can save a count without a modal.

Parameters:
  • path – destination CSV path, handed to the session’s to_csv; on an OSError or LayerError the error is shown in the panel and None is returned.

  • summary – write one row per class instead of one per marker.

property session: spacr.counting.CountingSession[source]

The counting session this panel drives.

property tool: CountingTool | None[source]

The tool while counting is switched on, else None.

class spacr.qt.counting_tool.CountingTool(session: spacr.counting.CountingSession)[source]

Bases: spacr.qt.layer_viewer.CanvasTool

Turns clicks on a LayerCanvas into counts.

Left click adds a marker of the active class, or takes away the marker already under the cursor. Right click only ever removes. 1–9 choose the class and Backspace undoes, so a whole session is one hand on the mouse and one on the number row.

Parameters:

session – the spacr.counting.CountingSession to count into.

Arm a tool that counts clicks into a session.

Parameters:

session – where the markers go.

Raises:

LayerError – if session is not a CountingSession – the tool writes class names and per-class tallies, which only that object holds.

key(view: spacr.qt.layer_viewer.LayerCanvas, event: Any) → bool[source]

1–9 select a class; Backspace undoes the last click.

Parameters:
  • view – the canvas that had focus; not read.

  • event – the key event; Backspace or Delete undoes, and a digit in its text() selects the class bound to that shortcut.

Returns:

True when the key was consumed.

press(view: spacr.qt.layer_viewer.LayerCanvas, world: Dict[str, float], event: Any) → bool[source]

Add or remove one marker.

Parameters:
  • view – the canvas that was clicked; not read.

  • world – world-axis coordinates of the click, as resolved by the canvas.

  • event – the mouse event; its button() is read (an event without one counts as a left click). Left toggles a marker at world, right removes the one under it.

Returns:

True for a left or right click, False otherwise.