MetadataView

class MetadataView()

Bases: MetaSubsetTabView

Subclass of MetaSubsetTabView for visualizing and interacting with metadata plots.

This view supports a wide variety of statistical visualizations, including: 1D histograms, KDEs, capture rates, scatterplots, heatmaps, and event overlays. Also provides walkthroughs and export options.

Attributes:

metadata_plots (List[str]): List of supported metadata-based plot types. event_data_plots (List[str]): List of supported event-based plot types. subset_export_count (int): Counter for naming exported subsets. plot_initialized (bool): Indicates whether a plot is currently initialized. no_cached_data (bool): True if data is not cached due to size.

Public Methods

MetadataView.format_axis_label(label: str, unit: str | None) → str

Ensure the axis label contains the correct unit exactly once. Removes any existing trailing unit in parentheses.

MetadataView.get_current_view() → str

Abstract method to get the name of the current view.

Subclasses must override this to return the current view name.

Returns:

The name of the view currently displayed.

Return type:

str

Raises:

NotImplementedError – Always, unless overridden by a subclass.

MetadataView.get_walkthrough_steps() → List[Tuple[str, str, str, Callable[[], QWidget | List[QWidget]]]]

Abstract method to retrieve the walkthrough steps for the current view.

Subclasses must override this to return a list of walkthrough steps, each a (title, description, view name, widget getter) tuple.

Returns:

The ordered walkthrough steps for this view.

Return type:

List[WalkthroughStep]

Raises:

NotImplementedError – Always, unless overridden by a subclass.

MetadataView.handle_parameter_change(submodel_name: str, action_name: str, args: tuple) → None

Handle changes triggered by UI controls such as updates to axis selection or filters.

Parameters:
  • submodel_name (str) – Name of the submodel that triggered the action.

  • action_name (str) – Name of the action triggered.

  • args (tuple) – Tuple containing action-specific arguments.

Raises:

NotImplementedError – If action_name is “new_axis” (not currently supported).

MetadataView.is_categorical_type(data_type: str | None) → bool

Evaluates an SQLite column datatype string. Returns True if categorical/discrete (or blank/None), False if explicitly continuous.

MetadataView.notify_plugin_state_changed(metaclass: str, plugin_key: str, reason: str) → None

Called when some other plugin instance’s state changed elsewhere in the app. Refreshes this tab’s column list only when the change concerns a MetaDatabaseLoader’s columns and the loader that changed is the one currently selected here; any other metaclass, reason, or a loader that isn’t currently selected in this tab is ignored.

Parameters:
  • metaclass (str) – The metaclass of the plugin instance whose state changed.

  • plugin_key (str) – The unique key identifying the plugin instance that changed.

  • reason (str) – A short string identifying what kind of change occurred.

Returns:

None

Return type:

None

MetadataView.on_subset_export_started() → None

Move to the next export index, now that this one is running.

The index names the export in the dialog and keys its worker, so it advances only for an export that was actually staged - which is what the Controller calling this says. The Controller counts the subset before staging anything, so an export refused for being empty never reaches here and the next dialog offers the same name again. Kept here rather than counted in the Controller because the dialog needs it before the request goes out, and one owner cannot drift from itself.

Returns:

None

Return type:

None

MetadataView.set_3d_scatterplot(columns: Sequence[ndarray[tuple[int, ...], dtype[float64]]], ax: Axes3D, axis_labels: Sequence[str], dataset_label: str) → None

Draw a 3-D scatterplot of three filtered columns.

The answering half of scatterplot_3d_requested, and the same reasoning as set_scatterplot(). The axes are rebuilt here if what arrived is a 2-D pair, which a change of plot type can leave behind.

Parameters:
  • columns (Sequence[npt.NDArray[np.float64]]) – the filtered x, y and z values

  • ax (Axes3D) – the axis object on which to plot

  • axis_labels (Sequence[str]) – the x, y and z axis labels, already formatted

  • dataset_label (str) – Label to apply to the scatter points.

Returns:

None

Return type:

None

MetadataView.set_all_points_histogram(bincenters: ndarray[tuple[int, ...], dtype[float64]], counts: ndarray[tuple[int, ...], dtype[float64]], hist_min: float, hist_max: float, plot_type: str, dataset_label: str) → None

Draw one subset’s all-points histogram, and take the limits it widened.

The answering half of all_points_histogram_requested. The tally is made by MetadataModel.build_all_points_histogram(), because walking a subset’s events and binning every sample of them is aggregation rather than drawing, and the result is exported with the plot.

Parameters:
  • bincenters (npt.NDArray[np.float64]) – the current level at the middle of each bin

  • counts (npt.NDArray[np.float64]) – how many samples fell in each bin

  • hist_min (float) – the shared lower limit, widened by this subset

  • hist_max (float) – the shared upper limit, widened by this subset

  • plot_type (str) – the all-points histogram variant being drawn

  • dataset_label (str) – the label this subset is drawn under

Returns:

None

Return type:

None

MetadataView.set_capture_rate(bin_edges: ndarray[tuple[int, ...], dtype[float64]], bincenters: ndarray[tuple[int, ...], dtype[float64]], val: ndarray[tuple[int, ...], dtype[float64]], fit: ndarray[tuple[int, ...], dtype[float64]], rate: float, error: float, data: ndarray[tuple[int, ...], dtype[float64]], ax: Axes, x_label: str, y_label: str, dataset_label: str) → None

Draw the inter-event time histogram and the exponential fitted to it.

The answering half of capture_rate_requested. The binning and the fit are made together below, so both describe the same intervals.

The histogram is drawn on the edges the fit was made against, rather than on this widget’s own binning of the same request. Handing matplotlib a bin count instead would let it bin independently, and the counts the fit used and the bars the user sees could then differ with nothing to say so.

Parameters:
  • bin_edges (npt.NDArray[np.float64]) – the edges the counts and the fit were computed on

  • bincenters (npt.NDArray[np.float64]) – the center of each bin

  • val (npt.NDArray[np.float64]) – the counts in each bin

  • fit (npt.NDArray[np.float64]) – the fitted curve evaluated at the bin centers

  • rate (float) – the fitted capture rate in Hz

  • error (float) – the 95% confidence half-width on the rate

  • data (npt.NDArray[np.float64]) – the log inter-event times the histogram is built from

  • ax (Axes) – the axis object on which to plot

  • x_label (str) – the x axis label, already formatted

  • y_label (str) – the y axis label

  • dataset_label (str) – string to label the dataset

Returns:

None

Return type:

None

MetadataView.set_categorical_counts(counts: Sequence[Tuple[Sequence[str], ndarray[tuple[int, ...], dtype[float64]]]], labels: Sequence[str], ax: Axes, x_label: str, y_label: str) → None

Draw one bar series per overlaid dataset.

The answering half of categorical_counts_requested. The tallies are made by MetadataModel.categorical_counts(), because counting occurrences is aggregation rather than drawing and the tallies are exported with the plot.

Parameters:
  • counts (Sequence[Tuple[Sequence[str], npt.NDArray[np.float64]]]) – per dataset, its category names and their counts, index-aligned with labels

  • labels (Sequence[str]) – one label per overlaid dataset

  • ax (Axes) – the axis object to draw on

  • x_label (str) – the x axis label, already formatted

  • y_label (str) – the y axis label

Returns:

None

Return type:

None

MetadataView.set_column_type(column_type: str | None) → None

Receive the type asked for by column_type_requested.

Set only when the lookup succeeded, so the None the caller cleared it to survives a failure and the categorical guard refuses the plot.

Parameters:

column_type (Optional[str]) – SQL type name of the queried column, or None on failure.

MetadataView.set_column_units(units: List[str | None]) → None

Receive one units string per plotted column, in the columns’ own order.

One list in one call, rather than one string per round trip accumulated here. Accumulating them meant a lookup that failed appended the previous column’s units instead of nothing, and the axis was labelled with the wrong unit; handed over together, the count either matches the columns or the answer is missing entirely.

Parameters:

units (List[Optional[str]]) – one units string per column, None where the loader has none

Returns:

None

Return type:

None

MetadataView.set_event_overlay(traces: Sequence[Tuple[ndarray[tuple[int, ...], dtype[float64]], ndarray[tuple[int, ...], dtype[float64]]]]) → None

Overlay one subset’s event traces on a shared normalised time axis.

The answering half of event_overlay_requested. The baseline subtraction and the per-event time base are made by MetadataModel.build_event_overlay() - both are exported with the plot; what is left here is the drawing, including the alpha each trace is given - a shorter event is drawn more opaquely than a longer one so the short ones are not lost under the crowd, and that number is read by nothing outside these axes.

Parameters:

traces (Sequence[Tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]]]) – one (normalised time, rectified current) pair per event

Returns:

None

Return type:

None

MetadataView.set_heatmap(x: ndarray[tuple[int, ...], dtype[float64]], y: ndarray[tuple[int, ...], dtype[float64]], z: ndarray[tuple[int, ...], dtype[float64]], ax: Axes, x_label: str, y_label: str, dataset_label: str) → None

Draw the binned heatmap, its colourbar and its cache entry.

The answering half of heatmap_requested. The binning is made by MetadataModel; everything here is matplotlib configuration, which stays because none of it leaves the View.

Parameters:
  • x (npt.NDArray[np.float64]) – bin-center x values

  • y (npt.NDArray[np.float64]) – bin-center y values

  • z (npt.NDArray[np.float64]) – the log2-scaled 2-D histogram counts

  • ax (Axes) – the axis object on which to plot

  • x_label (str) – the x axis label, already formatted

  • y_label (str) – the y axis label, already formatted

  • dataset_label (str) – string to label the dataset

Returns:

None

Return type:

None

MetadataView.set_histogram_bins(values: ndarray[tuple[int, ...], dtype[float64]], dataset_label: str, bincenters: ndarray[tuple[int, ...], dtype[float64]], widths: ndarray[tuple[int, ...], dtype[float64]], counts: Sequence[ndarray[tuple[int, ...], dtype[float64]]], hist_min: float, hist_max: float, ax: Axes, x_label: str, logx: bool, norm: bool) → None

Draw every overlaid dataset onto one shared set of bin edges.

The answering half of histogram_bins_requested. This is handed each dataset’s tallies rather than the edges to tally against, and the edges themselves do not come back: nothing here draws with them once the counting is done elsewhere, and returning them would invite a second tally against them.

Parameters:
  • values (npt.NDArray[np.float64]) – the newest dataset’s raw column values, to accumulate

  • dataset_label (str) – the newest dataset’s label

  • bincenters (npt.NDArray[np.float64]) – the center of each bin, which the bars are drawn at

  • widths (npt.NDArray[np.float64]) – the width of each bin

  • counts (Sequence[npt.NDArray[np.float64]]) – one array of per-bin counts per overlaid dataset, index-aligned with the accumulated labels

  • hist_min (float) – the shared lower limit, widened by this dataset

  • hist_max (float) – the shared upper limit, widened by this dataset

  • ax (Axes) – the axis object on which to plot

  • x_label (str) – the x axis label, already formatted but not yet log-marked

  • logx (bool) – was the data log-scaled, and so should the label say so

  • norm (bool) – normalise each dataset to a fraction rather than a count

Returns:

None

Return type:

None

MetadataView.set_kernel_densities(values: ndarray[tuple[int, ...], dtype[float64]], dataset_label: str, densities: Sequence[Tuple[ndarray[tuple[int, ...], dtype[float64]], ndarray[tuple[int, ...], dtype[float64]]]], hist_min: float, hist_max: float, ax: Axes, x_label: str) → None

Draw one filled density curve per overlaid dataset.

The answering half of density_requested. The curve arrives already evaluated, so it is computed once rather than the three times drawing it would otherwise need. The newest dataset joins the overlay here as its raw column, because the Model re-filters every accumulated dataset on each update and a pre-filtered one would be filtered twice.

Parameters:
  • values (npt.NDArray[np.float64]) – the newest dataset’s raw column values, to accumulate

  • dataset_label (str) – the newest dataset’s label

  • densities (Sequence[Tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]]]) – one (positions, density) pair per dataset

  • hist_min (float) – the shared lower limit, widened by this dataset

  • hist_max (float) – the shared upper limit, widened by this dataset

  • ax (Axes) – the axis object on which to plot

  • x_label (str) – the x axis label, already formatted

Returns:

None

Return type:

None

MetadataView.update_available_plugins(available_plugins: Dict[str, List[str]]) → None

Called whenever a new plugin is instantiated elsewhere in the app, to keep an up-to-date list of possible data sources for use by this plugin.

Parameters:

available_plugins (Dict[str, List[str]]) – dict of lists keyed by MetaClass, listing the identifiers of all instantiated plugins throughout the app.

MetadataView.update_column_names(column_names: List[str]) → None

Relay function to update the list of available columns.

Parameters:

column_names (List[str]) – List of column names.

MetadataView.update_column_units(column_units: str | None, axis: str) → None

Relay function to update the column unit label in the UI.

Parameters:
  • column_units (Optional[str]) – Unit string for the column, or None if the loader could not resolve one.

  • axis (str) – Axis being updated.

MetadataView.update_plot(plot_type: str, data: DataFrame, cols: Sequence[str], units: Sequence[str | None], logscales: Sequence[bool], dataset_label: str = '', bins: Any = None, sizes: bool = False) → None

Update the plot area with the provided data across multiple channels in a grid layout.

Parameters:
  • plot_type (str) – The kind of plot to draw (e.g. “Histogram”, “Scatterplot”, “Heatmap”); selects which internal plotting method is dispatched to.

  • data (pd.DataFrame) – a pandas dataframe with column headers matching x_col, y_col, z_col

  • cols (Sequence[str]) – a sequence of strings corresponding to column headers in the dataframe

  • units (Sequence[Optional[str]]) – a sequence of strings corresponding to column units in the dataframe

  • logscales (Sequence[bool]) – a sequence of bools indicating whether the given axis should be logscaled

  • dataset_label (str) – string to label the dataset

  • bins (Any) – Number of bins (if sizes==False) or size of bins (if sizes==True) for use when binning. Arrives as a single-element list from the controls and is rebound to a scalar (or None, to fall back to an automatic estimate) in the body, hence the loose annotation.

  • sizes (bool) – does the bins parameter refer to bin sizes (True) or widths (False)

Raises:

NotImplementedError – If plot_type is not one of the supported plot types.

MetadataView.update_plot_features(vertical: List[float] | None = None, horizontal: List[float] | None = None, points: List[Tuple[float, float]] | None = None, vlabels: List[str] | None = None, hlabels: List[str] | None = None, plabels: List[str] | None = None) → None

Update feature overlays for the plot, such as vertical/horizontal lines and labeled points.

Parameters:
  • vertical (Optional[List[float]]) – List of vertical line positions.

  • horizontal (Optional[List[float]]) – List of horizontal line positions.

  • points (Optional[List[Tuple[float, float]]]) – List of (x, y) point coordinates.

  • vlabels (Optional[List[str]]) – Labels for vertical lines.

  • hlabels (Optional[List[str]]) – Labels for horizontal lines.

  • plabels (Optional[List[str]]) – Labels for points.

MetadataView.update_units(loader: str, column: str, axis: str) → None

Ask the Controller for a column’s units, for this tab’s axis unit labels.

On this tab rather than on MetaSubsetTabView, although both subset tabs inherit that base: the protein tab has no units label, keeps no units cache and labels its axes with hardcoded literals, so it has nothing to do with the answer. Putting it back on the base would give that tab an inherited request nothing answers.

Parameters:
  • loader (str) – Name of the database loader.

  • column (str) – Name of the column to get units for.

  • axis (str) – Axis being updated (‘x_axis’, ‘y_axis’, etc.).

Returns:

None

Return type:

None

Private Methods

MetadataView._init() → None

Initialize the MetadataView instance.

MetadataView._reset_actions(axis_type: str = '2d') → None

Clears the figure and reinitializes axes. This will also add a flag to the tab action history if @register_action is being used to keep track of actions. Only actions applied after the most recent call to this function will be recreated if the related file is loaded.

Parameters:

axis_type (str) – Either ‘2d’ or ‘3d’ to determine plot projection.

Properties

MetadataView._subset_controls

The controls panel, under the name MetaSubsetTabView’s shared methods use.

Annotated with the base’s type rather than MetadataControls so the override matches the declaration verbatim, which is what the plugin compliance test compares. Tab-specific code keeps using self.metadatacontrols.

Returns:

the panel built by _build_controls

Return type:

MetaSubsetTabControls