Visualise#

Block 6 — charts. See the guide. Requires pip install chem-tactics[viz].

Benchmark comparison (Altair)#

class TACTICS.library_analysis.visualization.TS_Benchmarks(no_of_cycles, methods_list, TS_runs_data, reference_data=None, top_n=100, sort_type='minimize', top_ns=None)[source]#

A class to generate visualizations of TS results. The goal here is to compare different cycles of TS runs with the same search strategy. This is mainly used to compare different search strategies to ground truth values. Each search strategy is used a no of times equal to the number of cycles. It is recommended that random baseline data and brute-force (exhaustive search) data be included for comparison. Reference data is optional, but is required for generating the barplots. A strip plot can be generated without reference data for comparison of methods.

All required data (TS runs data, bar plot data, line plot data, and grouped statistics) is automatically generated during initialization. After creating an instance, you can directly call the plotting methods without additional data generation steps.

gen_TS_runs_data(top_n=100, sort_type='minimize')[source]#

Generates a single dataframe with all the TS runs data. This is a concatenated polars dataframe for each method

Parameters:#

top_n: int

Number of top products to consider for each method

sort_type: str

Type of sorting to perform on the data “minimize” - sorts the data in ascending order “maximize” - sorts the data in descending order

stripplot_TS_results(width=None, height=None, save_path=None, show_plot=True, legend_position='right')[source]#

Generate a stripplot for TS results using altair. This visualizes the distribution of scores across cycles and methods. Data is automatically generated during class initialization.

Parameters:#

width: Optional[int]

Width of the plot

height: Optional[int]

Height of the plot

save_path: Optional[str]

Path to save the plot

show_plot: bool

If True, shows the plot in Jupyter

legend_position: str

Position of the legend. “right” (default) or “bottom” for horizontal legend below plot.

Returns:#

altair.Chart or None

The altair chart if show_plot is True, None otherwise

get_barplot_TS_results_data(top_n=100)[source]#

Generate data for bar plot, for checking the number of hits recovered by each search strategy. To use this plot, you must have the reference compounds that serve as the ground truth. This shows what fraction of the top N reference compounds each method finds.

Parameters:

top_n (int) – Number of top reference products to count as hits. Use the same top_n for every method.

Returns:

Hits found by each method in each cycle against the reference set.

Return type:

polars.DataFrame

plot_barplot_TS_results(width=None, height=None, save_path=None, show_plot=True, legend_position='right', dark_mode=False)[source]#

Generate a barplot for TS results using altair. This visualizes the number of reference hits recovered by each search strategy. Data is automatically generated during class initialization.

Parameters:#

widthOptional[int]

Width of the plot in pixels

heightOptional[int]

Height of the plot in pixels

save_pathOptional[str]

Path to save the plot

show_plotbool

If True, shows the plot in Jupyter

legend_positionstr

Position of the legend. “right” (default) or “bottom” for horizontal legend below plot.

dark_modebool

If True, uses white text for bar labels (for dark backgrounds). Default is False (black text).

Returns:#

altair.Chart or None

The altair chart if show_plot is True, None otherwise

gen_line_plot_performance_data(top_ns=None)[source]#

Generate data for line plot, for checking the performance of each method. The plot looks at how the performance of the methods changes with comparison to the top N compounds found by the reference method. Efficiently calculates fraction of hits found for each top_n cutoff.

Parameters:#

top_nsList[int], optional

List of top N values to test (e.g., [50, 100, 200, 300, 400, 500]) If None, defaults to [50, 100, 200, 300, 400, 500]

Returns:#

line_plot_dfpolars DataFrame

DataFrame with columns: [‘cycle’, ‘top_n’, ‘method’, ‘frac_top_n’]

plot_line_performance_with_error_bars(width=None, height=None, save_path=None, show_plot=True, legend_position='right')[source]#

Generate a line plot with error bars for method performance using altair. Shows mean fraction of reference compounds found across cycles with standard deviation error bars. Data and grouped statistics are automatically generated during class initialization.

Parameters:#

widthOptional[int]

Width of the plot in pixels

heightOptional[int]

Height of the plot in pixels

save_pathOptional[str]

Path to save the plot

show_plotbool

If True, shows the plot in Jupyter

legend_positionstr

Position of the legend. “right” (default) or “bottom” for horizontal legend below plot.

Returns:#

altair.Chart or None

The altair chart if show_plot is True, None otherwise

Diagnostic plots (matplotlib)#

Matplotlib plotting functions for CATS diagnostics.

All functions accept Polars DataFrames and return matplotlib.figure.Figure objects so callers can save, show, or compose them freely.

TACTICS.library_analysis.diagnostic_plots.plot_criticality_trajectory(diagnostics_df, figsize=(10, 4))[source]#

Plot per-component criticality over cycles.

A horizontal band at criticality <= 0.3 is shaded as the “diffuse” zone.

Parameters:
  • diagnostics_df (pl.DataFrame) – DataFrame from sampler.get_diagnostics().

  • figsize (tuple) – Figure size.

Returns:

Matplotlib Figure.

Return type:

Figure

TACTICS.library_analysis.diagnostic_plots.plot_snr_trajectory(diagnostics_df, figsize=(10, 4))[source]#

Plot SNR evolution with a threshold line at SNR = 1.

Requires enhanced diagnostics (snr column).

Parameters:
  • diagnostics_df (pl.DataFrame) – Enhanced diagnostics DataFrame.

  • figsize (tuple) – Figure size.

Returns:

Matplotlib Figure.

Return type:

Figure

TACTICS.library_analysis.diagnostic_plots.plot_temperature_decomposition(diagnostics_df, component_idx, figsize=(10, 6))[source]#

Plot full temperature pipeline decomposition for one component.

Shows base_temp, cats_multiplier, criticality_weight, effective_multiplier, and final_temperature on separate subplots.

Requires enhanced diagnostics.

Parameters:
  • diagnostics_df (pl.DataFrame) – Enhanced diagnostics DataFrame.

  • component_idx (int) – Which component to plot.

  • figsize (tuple) – Figure size.

Returns:

Matplotlib Figure.

Return type:

Figure

TACTICS.library_analysis.diagnostic_plots.plot_rws_diagnostic(diagnostics_df, title='', figsize=(12, 5))[source]#

RWS diagnostic: GMIC + CATS multiplier + divergence gate.

Dual y-axis plot averaged across replicates with 95 % confidence interval bands. Vertical background shading indicates batches where the divergence gate blocks GMIC modulation (diversity mode).

  • Left y-axis: GMIC per component (solid lines with CI bands).

  • Right y-axis: CATS multiplier per component (dashed lines). Shows the GMIC-driven temperature modulation directly, without the noisy heated/cooled oscillation that final_temperature has. Values > 1 amplify exploration, < 1 amplify exploitation, = 1 is the base temperature.

  • Background: light pink shading with red boundary lines when any component is in diversity mode in > 30 % of replicates.

Parameters:
  • diagnostics_df (pl.DataFrame) – RWS diagnostics for a single query, all replicates. Works with any number of components.

  • title (str) – Plot title (e.g. “rxn206 — query_008”).

  • figsize (tuple) – Figure size.

Returns:

Matplotlib Figure.

Return type:

Figure

TACTICS.library_analysis.diagnostic_plots.plot_ttts_diagnostic(diagnostics_df, title='', figsize=(12, 5))[source]#

TT-TS diagnostic: disagreement EMA + heated_scale.

Dual y-axis plot averaged across replicates with 95 % confidence interval bands.

Left y-axis: disagreement EMA per component (solid lines). Right y-axis: heated_scale per component (dashed lines). Horizontal bands mark the adaptive thresholds (0.3 and 0.8).

Works with any number of components.

Parameters:
  • diagnostics_df (pl.DataFrame) – TT-TS diagnostics for a single query, all replicates.

  • title (str) – Plot title.

  • figsize (tuple) – Figure size.

Returns:

Matplotlib Figure.

Return type:

Figure

TACTICS.library_analysis.diagnostic_plots.plot_reagent_usage_action_panel(search_df, diag_df, reagent_files, batch_size=100, replicate=None, aggregate_window=1, normalize='library', auto_trim=True, max_batches=None, component_names=None, title='', figsize=(14, 5.5), heated_label='Heated')[source]#

Two-panel reagent usage diagnostic: heating timeline + new-reagent lines.

Top panel (action strip). A thin categorical timeline showing which component was marked is_heated at each batch — one coloured block per batch, coloured by the component’s palette entry. Reads left-to-right like a sequence diagram. Batches with no heated record appear white. The strip’s y-label is set by heated_label so the figure can use method-appropriate terminology (e.g. "Heated" for RWS, "Explore" for TT-TS).

Bottom panel (lines). Per-component lines showing the fraction of that component’s reagents first-seen in this batch (new_count / n_reagents_per_component) — always library-normalized so the scree-plot decay reads the same across components. Uses the same component palette as the heating strip, so the reader can match each line to the heated-block colours in the strip above. Interpretation: the decay rate summarizes when the algorithm has exhausted the informative reagents per component.

Note: the normalize parameter is retained for API compatibility but no longer affects the plot (the bar panel it controlled has been replaced by the heating strip). The value is still validated so stale callers passing unknown strings still raise.

Parameters:
  • search_df (pl.DataFrame) – Search-phase rows for a single trial (library, query, method, replicate), in evaluation order. Must have Name (underscore-joined reagent IDs) and phase columns. If replicate is None the DataFrame must already be filtered to a single replicate.

  • diag_df (pl.DataFrame) – Per-cycle diagnostics for the same trial. Must have component_idx, current_cycle, is_heated.

  • reagent_files (list[Path]) – Ordered list of .smi file paths, one per component. Used to count total reagents (for library normalization) and to correctly parse product names where reagent IDs themselves may contain underscores (e.g. adenine’s isocyanide_db_511).

  • batch_size (int) – Evaluations per batch (default 100).

  • replicate (Optional[int]) – If provided, filter both DataFrames to this replicate.

  • aggregate_window (int) – If >1, bin every aggregate_window batches into a single bar. Useful for long searches (e.g., 1000+ batches on docking libraries). Diversity is averaged across batches in the bin; new is recomputed against all prior bins; heated component is the majority within the bin.

  • auto_trim (bool) – If True (default), automatically crop to the active region of the search — batches where the mechanism is still switching heated components or discovering new reagents. Trailing exploitation-only batches (same component heated for many batches with no new reagents) are dropped and a note is annotated on the figure.

  • max_batches (Optional[int]) – Hard upper limit on the number of batches shown. Takes precedence over auto_trim if smaller.

  • component_names (Optional[list[str]]) – Optional list of display names (one per component) to use in the legend instead of “Component N”. If None, names are inferred from the common prefix of each component’s reagent IDs (e.g., adenine automatically becomes [“Amidine”, “Isocyanide”, “Aldehyde”]). Components with purely numeric reagent IDs fall back to “Component N”.

  • normalize (str) – "library" (default) normalizes by total reagents in each component — interpretation: fraction of the library sampled this batch. "batch" normalizes by min(batch_size, n_reagents) — interpretation: fraction of the maximum achievable diversity. "share" normalizes each batch’s per-component count by the batch’s total unique-reagent count across components, producing a stacked-to-1 view. Use "share" on imbalanced libraries where components differ in size by many-fold, so small components don’t disappear visually when heated.

  • title (str) – Plot title.

  • figsize (tuple) – Figure size.

  • heated_label (str) – Y-axis label for the action strip. Use "Heated" for RWS-family methods (default) and "Explore" for TT-TS, where the strip marks the exploring component each batch (cooled / exploit components are the unfilled cells).

Returns:

Matplotlib Figure.

Return type:

Figure

TACTICS.library_analysis.diagnostic_plots.plot_gmic_directed_exploration(search_df, diag_df, reagent_files, methods, *, method_labels=None, replicate=None, batch_size=100, component_names=None, component_colors=None, gmic_ref=1.0, title=None, figsize=None)[source]#

Layer 1: how GMIC directs WHICH component to explore (signal -> decision -> result).

One column per method; three stacked rows sharing the search-cycle x-axis:

SIGNAL – per-component GMIC (criticality). High = the component’s reagent

means are well separated relative to noise (resolved -> exploit); low = unresolved (explore).

DECISION – the per-component “explored” strip (is_heated): which component

the GMIC-weighted rotation sends exploration to each cycle.

RESULT – cumulative per-component reagent coverage (fraction of that

component’s reagents discovered), each normalised to its own size.

On an imbalanced library (thrombin: 130 acids x 3844 dipeptides) the small component resolves immediately (high GMIC -> exploited -> coverage saturates to 100%) while the large one stays unresolved (low GMIC -> explored -> coverage climbs), making the GMIC-directed explore/exploit reallocation visible end to end.

Parameters:
  • search_df (DataFrame) – Per-evaluation search log (Name, method, replicate, phase); only phase == "search" rows are used.

  • diag_df (DataFrame) – Per-cycle diagnostics (method, replicate, current_cycle, component_idx, gmic, is_heated).

  • reagent_files (list[Path]) – One .smi per component (defines each component’s reagent IDs).

  • methods (list[str]) – Method names to show as columns (e.g. the RWS and TT-TS labels).

  • method_labels – Optional {method: display label} for the column titles.

  • replicate – Replicate to plot; defaults to the smallest in diag_df.

  • batch_size (int) – Evaluations per cycle/batch (default 100).

  • component_names – Display names per component; inferred from reagent-ID prefixes when None.

  • component_colors – Line colours per component.

  • gmic_ref (float) – Reference line on the GMIC row (default 1.0 = critical/flexible boundary).

  • title – Figure suptitle.

  • figsize – Defaults to (7.5 * n_methods, 9.2).

Returns:

Matplotlib Figure.

TACTICS.library_analysis.diagnostic_plots.plot_adaptive_intensity(search_df, diag_df, reagent_files, methods, *, method_labels=None, replicate=None, batch_size=100, component_names=None, component_colors=None, smooth_window=9, show_decision=True, result='new', title=None, figsize=None)[source]#

Layer 2: how each method tunes exploration within a component.

Where plot_gmic_directed_exploration() (layer 1) shows WHICH component GMIC sends exploration to, this shows HOW HARD each method explores the chosen component, and what that yields in reagent discovery. One column per method; rows share the search-cycle x-axis:

INTENSITY – the per-component within-component knob, smoothed. Both knobs

are reported as dimensionless multipliers centred on 1.0 (1.0 = no adjustment; >1 = amplify exploration), so the two methods read on a common interpretation: RWS modulates the CATS temperature multiplier (cats_multiplier, ×base temperature – the GMIC-driven factor); TT-TS modulates the σ-inflation multiplier (heated_scale, ×posterior σ – the disagreement-driven factor). Note the asymmetry the knobs reveal: RWS’s multiplier is GMIC-driven, so it amplifies above 1.0 on the unresolved (low-GMIC) component; TT-TS’s heated_scale is disagreement-driven, and because two-sample disagreement saturates (>0.8) on both components of a large library it decays toward 1.0 – most on the highest-disagreement (unresolved) component – i.e. the TT-TS adaptation is largely one-directional and cannot manufacture exploration beyond what the raw posteriors already provide.

DECISION – per-component heating probability (rolling fraction of

cycles in which the component was the explored/heated one). Omitted when show_decision=False (leaving INTENSITY + RESULT, i.e. “just the temperature”).

RESULT – per-component within-component discovery. result="new"

(default) plots new reagents discovered per batch (the per-batch rate – the discrete increment of coverage); result="coverage" plots cumulative coverage (% of the component’s reagents seen at least once – the running total, identical to the layer-1 RESULT row). New-per-batch is the derivative of coverage: it falls toward zero as the reagent pool is exhausted even while coverage is still rising.

On thrombin (130 acids × 3844 dipeptides) both methods keep discovering new dipeptides long after the small acid component is exhausted – the same reallocation, reached through two different within-component mechanisms.

Parameters:
  • search_df (DataFrame) – Per-evaluation search log (Name, method, replicate, phase); only phase == "search" rows are used.

  • diag_df (DataFrame) – Per-cycle diagnostics (method, replicate, current_cycle, component_idx, is_heated plus the method-specific intensity column cats_multiplier for RWS or heated_scale for TT-TS).

  • reagent_files (list[Path]) – One .smi per component (defines each component’s reagent IDs).

  • methods (list[str]) – Method names to show as columns.

  • method_labels – Optional {method: display label} for column titles.

  • replicate – Replicate to plot; defaults to the smallest in diag_df.

  • batch_size (int) – Evaluations per cycle/batch (default 100).

  • component_names – Display names per component; inferred from reagent-ID prefixes when None.

  • component_colors – Line colours per component.

  • smooth_window (int) – Centred (edge-shrinking) rolling-mean window (cycles) applied to every row so the per-cycle heated/cooled square-wave reads as an effective average (default 9).

  • show_decision (bool) – Include the heating-probability row (default True).

  • result (str) – "new" (new reagents per batch, default) or "coverage" (cumulative % coverage, as in layer 1).

  • title – Figure suptitle.

  • figsize – Defaults to (7.5 * n_methods, 9.2 or 7.0).

Returns:

Matplotlib Figure.