Title Legend Helper
GitHub Link to Code.
Helper for plot title and legend management.
Provides shared utilities for consistent title wrapping, positioning, and legend creation across density and violin plots.
- class mdxplain.plots.helper.title_legend_helper.TitleLegendHelper
Helper class for plot title and legend operations.
Provides static methods for wrapping long titles, adding figure-level titles with consistent positioning, and creating unified legends for DataSelector colors.
Examples
>>> # Wrap long title >>> wrapped = TitleLegendHelper.wrap_title("Very Long Feature Name", 20) >>> print(wrapped) Very Long Feature Name
>>> # Add figure title >>> TitleLegendHelper.add_title(fig, "My Plot", title_y=0.98)
>>> # Add DataSelector legend >>> colors = {"cluster_0": "#FF0000", "cluster_1": "#00FF00"} >>> TitleLegendHelper.add_legend(fig, colors, "Clusters", None)
- static wrap_title(title: str, max_chars_per_line: int = 40) str
Wrap long titles to multiple lines.
Splits title into multiple lines if it exceeds max_chars_per_line, breaking at word boundaries to maintain readability.
Parameters
- titlestr
Original title text
- max_chars_per_lineint, default=40
Maximum characters per line before wrapping
Returns
- str
Title with line breaks inserted
Examples
>>> wrapped = TitleLegendHelper.wrap_title("Very long feature name", 20) >>> print(wrapped) Very long feature name
>>> short = TitleLegendHelper.wrap_title("Short", 20) >>> print(short) Short
Notes
Uses textwrap.wrap() which breaks at word boundaries. Empty titles return empty string.
- static format_bold_superscript_title(title: str) str
Make mathtext superscripts bold for plot titles.
Parameters
- titlestr
Title text that may contain mathtext superscripts like
$^{A.H6.54}$.
Returns
- str
Title text with superscript content wrapped in
\mathbf{...}when applicable.
- static estimate_title_height(title: str, max_chars_per_line: int = 80, fontsize: int = 18) tuple
Wrap title and estimate height in inches.
Wraps title text to multiple lines and estimates the vertical space required in inches based on number of lines and fontsize.
Parameters
- titlestr
Original title text
- max_chars_per_lineint, default=80
Maximum characters per line before wrapping
- fontsizeint, default=18
Font size in points (standard matplotlib suptitle default)
Returns
- wrapped_titlestr
Title with line breaks inserted
- height_inchesfloat
Estimated height in inches required for the wrapped title
Examples
>>> wrapped, height = TitleLegendHelper.estimate_title_height( ... "Short Title" ... ) >>> print(wrapped) Short Title >>> print(f"{height:.3f} inches") 0.200 inches
>>> wrapped, height = TitleLegendHelper.estimate_title_height( ... "Very Long Title That Will Be Wrapped Into Multiple Lines", ... max_chars_per_line=30 ... ) >>> lines = wrapped.count('\n') + 1 >>> print(f"Lines: {lines}, Height: {height:.3f} inches") Lines: 3, Height: 0.600 inches
Notes
Height calculation:
Converts fontsize from points to inches: fontsize / 72
Multiplies by 0.8 to account for line spacing factor
Total height = n_lines * (fontsize / 72) * 0.8
This is an approximation. Actual rendering may vary slightly depending on matplotlib backend and font metrics.
- static compute_title_max_chars_from_width(subplot_width_inches: float) int
Compute maximum characters per line based on subplot width.
Calculates appropriate title wrapping length based on actual measured subplot width in inches. Uses conservative estimate of character width to ensure titles fit within subplot bounds.
Parameters
- subplot_width_inchesfloat
Actual subplot width in inches (measured from GridSpec position)
Returns
- int
Maximum characters per line, clamped to range [40, 150]
Examples
>>> # Narrow subplot (5 inches wide) >>> max_chars = TitleLegendHelper.compute_title_max_chars_from_width(5.0) >>> print(max_chars) 40
>>> # Medium subplot (10 inches wide) >>> max_chars = TitleLegendHelper.compute_title_max_chars_from_width(10.0) >>> print(max_chars) 80
>>> # Wide subplot (15 inches wide) >>> max_chars = TitleLegendHelper.compute_title_max_chars_from_width(15.0) >>> print(max_chars) 120
Notes
Character width estimation:
Assumes ~8 characters per inch at typical font sizes (conservative)
Includes safety margin to prevent text overflow
Clamps result to reasonable range [40, 150] characters
This estimate works well for proportional fonts at standard matplotlib title font sizes (14-18pt).
- static add_title(fig: Figure, title: str | None, title_y: float = 0.98, default_title: str = 'Feature Importance Plot', fontsize: int = 18) None
Add figure-level title with consistent positioning.
Parameters
- figFigure
Matplotlib figure to add title to
- titlestr, optional
Custom title text. If None, uses default_title.
- title_yfloat, default=0.98
Y-position of title (relative to figure height, 0-1)
- default_titlestr, default=”Feature Importance Plot”
Fallback title when title is None
- fontsizeint, default=18
Font size for title text
Returns
- None
Modifies fig in place by adding suptitle
Examples
>>> fig = plt.figure() >>> TitleLegendHelper.add_title(fig, "My Analysis")
>>> # With default title >>> TitleLegendHelper.add_title(fig, None)
>>> # Custom positioning >>> TitleLegendHelper.add_title(fig, "Title", title_y=0.95)
Notes
Title is added using fig.suptitle() with:
fontsize (configurable, default=18)
fontweight=’bold’
y=title_y for vertical positioning
- static add_legend(fig: Figure, data_selector_colors: Dict[str, str], legend_title: str | None, legend_labels: Dict[str, str] | None, contact_threshold: float | None = None, legend_x: float = 0.98, legend_y: float = 0.94, fontsize: int = 14, title_fontsize: int = 16, additional_handles: List[Any] | None = None) None
Add figure-wide legend for DataSelectors and contact threshold.
Creates unified legend showing DataSelector names with their colors and optionally a contact threshold line. Legend is positioned in figure coordinates for consistent placement.
Parameters
- figFigure
Matplotlib figure to add legend to
- data_selector_colorsDict[str, str]
Mapping of DataSelector name to color hex code
- legend_titlestr, optional
Custom legend title. If None, uses “DataSelectors”.
- legend_labelsDict[str, str], optional
Custom display names for DataSelectors. Maps original names to display names. Example: {“cluster_0”: “Inactive”, “cluster_1”: “Active”}
- contact_thresholdfloat, optional
Contact threshold value in Angstrom. If provided, adds a dashed red line entry to legend showing the threshold.
- legend_xfloat, default=0.98
X-position of legend (in figure coordinates, 0-1)
- legend_yfloat, default=0.94
Y-position of legend (in figure coordinates, 0-1)
- fontsizeint, default=14
Font size for legend entries
- title_fontsizeint, default=16
Font size for legend title
- additional_handlesList, optional
Additional pre-built matplotlib legend handles appended to the DataSelector legend (for example vertical marker labels).
Returns
- None
Modifies fig in place by adding legend
Examples
>>> colors = {"cluster_0": "#FF0000", "cluster_1": "#00FF00"} >>> TitleLegendHelper.add_legend(fig, colors, None, None)
>>> # With custom labels and threshold >>> labels = {"cluster_0": "Active", "cluster_1": "Inactive"} >>> TitleLegendHelper.add_legend( ... fig, colors, "States", labels, ... contact_threshold=4.5 ... )
>>> # Custom positioning >>> TitleLegendHelper.add_legend( ... fig, colors, "Clusters", None, ... contact_threshold=None, ... legend_x=0.95, legend_y=0.90 ... )
Notes
Legend is created with:
Sorted DataSelector names (alphabetical)
Colored patches (alpha=0.7)
Optional contact threshold line (red, dashed)
fontsize (configurable, default=14)
title_fontsize (configurable, default=16), title in bold
framealpha=0.9 for visibility
loc=”upper left” with bbox_to_anchor for precise positioning
- static get_side_legend_anchor(fig: Figure, rightmost_ax_first_row, gap_inches: float = 0.1, y_offset: float = 0.0) Tuple[float, float]
Compute side-legend anchor from the first row’s rightmost subplot.
Parameters
- figFigure
Figure hosting the subplots.
- rightmost_ax_first_rowmatplotlib.axes.Axes
Rightmost subplot in the first row.
- gap_inchesfloat, default=0.1
Horizontal gap in inches between axes and legend.
- y_offsetfloat, default=0.0
Additional offset in figure coordinates applied to y.
Returns
- Tuple[float, float]
(legend_x, legend_y) in figure coordinates.