Source code for geolatent.config.themes

"""Configuration management for geolatent visualizations.

Provides dataclass-based theme definitions, colour palettes, rendering parameters,
and projection settings.  The module ships with a pre-built ``DARK_SCIENTIFIC``
theme modelled after the aesthetic conventions of modern ML research publications
(Weights & Biases dark mode, Papers With Code, high-quality arXiv supplementary
materials).

All configuration objects are plain Python dataclasses and support deep-copy
via the ``.copy()`` helper, making it trivial to derive customised themes from
the defaults without mutation.
"""

from __future__ import annotations

import copy
from dataclasses import dataclass, field
from typing import Dict, List, Optional


# Colour palette


[docs] @dataclass class ColorPalette: """Specification of all colours used within a single visualisation theme. Parameters ---------- background : str Hex colour for the outermost canvas / paper background. grid : str Hex colour for axis gridlines and background panes. text : str Hex colour for all labels, titles, and annotations. axis_line : str Hex colour for zero-axis lines and tick marks. class_colors : list of str Ordered list of hex colours assigned to distinct classes. Colours are cycled when the number of classes exceeds the list length. surface_colorscale : str Plotly-compatible named colorscale used for probability volumes and scalar-field surfaces. boundary_colorscale : str Colorscale used to shade diverging decision-boundary surfaces. marker_line_color : str Colour of the thin outline drawn around scatter markers. centroid_color : str Colour of the star-shaped class-centroid markers. annotation_color : str Colour of variance-explained and other textual annotations. """ background: str = "#0d1117" grid: str = "#161b22" text: str = "#e6edf3" axis_line: str = "#30363d" class_colors: List[str] = field( default_factory=lambda: [ "#58a6ff", # GitHub blue "#3fb950", # GitHub green "#f78166", # GitHub red-orange "#d2a8ff", # GitHub purple "#ffa657", # GitHub amber "#79c0ff", # GitHub sky "#56d364", # GitHub lime "#ff7b72", # GitHub coral ] ) surface_colorscale: str = "Plasma" boundary_colorscale: str = "RdBu" marker_line_color: str = "#0d1117" centroid_color: str = "#f0f6fc" annotation_color: str = "#8b949e"
# Rendering parameters
[docs] @dataclass class RenderConfig: """Low-level rendering and layout parameters. Parameters ---------- width : int Canvas width in pixels. height : int Canvas height in pixels. surface_opacity : float Alpha value (0–1) for decision boundary / probability isosurfaces. scatter_opacity : float Alpha value (0–1) for data-point scatter markers. marker_size : int Diameter of scatter markers in pixels. centroid_marker_size : int Diameter of class-centroid markers in pixels. ellipsoid_opacity : float Alpha value (0–1) for confidence ellipsoid surfaces. show_axes : bool Whether to display axis labels, ticks, and gridlines. show_legend : bool Whether to show the interactive legend panel. show_colorbar : bool Whether to show the colourbar for scalar-field surfaces. camera_eye : dict Plotly camera ``eye`` dict with keys ``x``, ``y``, ``z``. camera_up : dict Plotly camera ``up`` vector dict. font_family : str Font family string passed to Plotly's ``font`` specification. font_size : int Base font size in points. """ width: int = 960 height: int = 720 surface_opacity: float = 0.28 scatter_opacity: float = 0.88 marker_size: int = 5 centroid_marker_size: int = 14 ellipsoid_opacity: float = 0.15 show_axes: bool = True show_legend: bool = True show_colorbar: bool = False camera_eye: Dict[str, float] = field( default_factory=lambda: {"x": 1.55, "y": 1.55, "z": 1.15} ) camera_up: Dict[str, float] = field( default_factory=lambda: {"x": 0.0, "y": 0.0, "z": 1.0} ) font_family: str = ( "'JetBrains Mono', 'Fira Code', 'Consolas', 'Courier New', monospace" ) font_size: int = 12
# Projection / dimensionality-reduction parameters
[docs] @dataclass class ProjectionConfig: """Configuration for the dimensionality-reduction pipeline. Parameters ---------- method : {"pca", "tsne", "umap", "sensitivity"} Projection algorithm. ``"pca"`` and ``"sensitivity"`` both support inverse-transform (required for decision-surface rendering). ``"sensitivity"`` finds axes the model actually cares about using finite-difference Jacobians. ``"tsne"`` and ``"umap"`` are for latent-space visualisation only. n_components : int Target dimensionality. Should be 3 for all 3-D visualisations. whiten : bool Whether to whiten the PCA output (unit variance per component). tsne_perplexity : float Perplexity hyper-parameter for t-SNE. Should be less than n_samples. tsne_learning_rate : float Learning rate for t-SNE gradient descent. tsne_n_iter : int Maximum number of iterations for t-SNE optimisation. umap_n_neighbors : int Number of neighbours used by UMAP to build the local topology. umap_min_dist : float Minimum distance between embedded points for UMAP. random_state : int Global random seed for reproducibility across all stochastic operations. scale_input : bool Whether to standardise features (zero-mean, unit-variance) before applying the chosen projection. Strongly recommended for PCA. """ method: str = "pca" n_components: int = 3 whiten: bool = False tsne_perplexity: float = 30.0 tsne_learning_rate: float = 200.0 tsne_n_iter: int = 1000 umap_n_neighbors: int = 15 umap_min_dist: float = 0.1 random_state: int = 42 scale_input: bool = True # Sensitivity projection sensitivity_n_subsample: int = 300 sensitivity_eps: float = 1e-2
# Master configuration container
[docs] @dataclass class VisualizationConfig: """Top-level configuration container for geolatent. Combines colour, rendering, and projection sub-configurations into a single immutable-style object that can be passed to any public API function. All sub-configs carry sensible defaults so that ``VisualizationConfig()`` yields a production-ready dark-scientific theme. Parameters ---------- colors : ColorPalette Colour definitions for the entire visualisation. render : RenderConfig Rendering and canvas layout parameters. projection : ProjectionConfig Dimensionality-reduction settings applied to model inputs and embeddings. title : str, optional Plot title string. When set, overrides the auto-generated title. show_variance_annotation : bool When ``True`` and PCA is used, annotates the figure with the cumulative explained-variance ratio captured by the three principal components. Examples -------- >>> from geolatent.config.themes import VisualizationConfig, ProjectionConfig >>> cfg = VisualizationConfig() >>> cfg_tsne = cfg.with_method("tsne") >>> cfg_titled = cfg.with_title("SVM Decision Geometry — RBF Kernel") """ colors: ColorPalette = field(default_factory=ColorPalette) render: RenderConfig = field(default_factory=RenderConfig) projection: ProjectionConfig = field(default_factory=ProjectionConfig) title: Optional[str] = None show_variance_annotation: bool = True # Fluent mutation helpers (return new copies to avoid shared state)
[docs] def copy(self) -> "VisualizationConfig": """Return an independent deep copy of this configuration object.""" return copy.deepcopy(self)
[docs] def with_method(self, method: str) -> "VisualizationConfig": """Return a copy with the projection ``method`` overridden. Parameters ---------- method : {"pca", "tsne", "umap", "sensitivity"} New projection algorithm. Returns ------- VisualizationConfig """ cfg = self.copy() cfg.projection.method = method return cfg
[docs] def with_title(self, title: str) -> "VisualizationConfig": """Return a copy with the plot ``title`` overridden. Parameters ---------- title : str Returns ------- VisualizationConfig """ cfg = self.copy() cfg.title = title return cfg
[docs] def with_resolution(self, width: int, height: int) -> "VisualizationConfig": """Return a copy with canvas dimensions overridden. Parameters ---------- width : int height : int Returns ------- VisualizationConfig """ cfg = self.copy() cfg.render.width = width cfg.render.height = height return cfg
[docs] def with_opacity( self, surface: Optional[float] = None, scatter: Optional[float] = None, ellipsoid: Optional[float] = None, ) -> "VisualizationConfig": """Return a copy with opacity values selectively overridden. Parameters ---------- surface : float, optional scatter : float, optional ellipsoid : float, optional Returns ------- VisualizationConfig """ cfg = self.copy() if surface is not None: cfg.render.surface_opacity = surface if scatter is not None: cfg.render.scatter_opacity = scatter if ellipsoid is not None: cfg.render.ellipsoid_opacity = ellipsoid return cfg
# Pre-built themes #: Default dark-scientific theme shipped with geolatent. #: Colour palette inspired by GitHub Dark, Weights & Biases, and the visual #: language of high-quality ML research tooling. DARK_SCIENTIFIC: VisualizationConfig = VisualizationConfig()