Source code for gleplot

"""
gleplot - Matplotlib-like plotting library for GLE

A Python library for creating scientific plots using matplotlib-like syntax
that compiles directly to GLE (Graphics Layout Engine) format for publication-
quality vector graphics.

Features
--------
- Matplotlib-compatible API (plot, scatter, bar, fill_between, errorbar)
- Text annotations in data coordinates (text)
- Subplots with flexible grid layouts (subplots, add_subplot)
- Native vector graphics output (PDF, PNG, EPS)
- Inline display in Jupyter notebooks (view)
- Support for line styles, markers, and colors
- Error bars (symmetric, asymmetric, horizontal)
- Logarithmic scales
- Legend and axis labels
- Semantic per-series data file naming (data_name) and figure-level prefixes (data_prefix)
- Direct GLE script generation

Usage
-----
    import gleplot as glp

    fig = glp.figure(figsize=(8, 6))
    ax = fig.add_subplot(111)

    ax.plot([1, 2, 3], [1, 4, 9], 'b-', label='quadratic')
    ax.scatter([1, 2, 3], [1, 2, 3], color='red', label='points')

    ax.set_xlabel('X axis')
    ax.set_ylabel('Y axis')
    ax.set_title('Example Plot')
    ax.legend()

    fig.savefig('output.pdf')  # Saves as PDF
    fig.savefig('output.gle')  # Saves as GLE script only
    fig.view()  # Display inline in Jupyter notebook

Classes
-------
Figure
    Matplotlib-like figure container
Axes
    Matplotlib-like axes for plotting

Functions
---------
figure(figsize=(8, 6), dpi=100)
    Create a new figure
"""

__version__ = "2.8.1"
__author__ = "gleplot contributors"

from .figure import Figure
from .axes import Axes, validate_tick_format
from .brokenaxes import BrokenAxes
from .colors import rgb_to_gle, get_color_palette
from .markers import get_gle_marker
from .mathtext import mathtext_to_gle
from .compiler import GLECompiler
from .config import (
    GLEStyleConfig,
    GLEGraphConfig,
    GLEMarkerConfig,
    GlobalConfig,
)

# Series data sources: where a series' numbers come from. The scripting API
# always produces InlineData (baked arrays) and never needs these; they are
# the API an embedding application uses to point series at its own tables.
from .sources import (
    ColumnRef,
    DanglingSourceRef,
    DanglingSourceWarning,
    DataProvider,
    DataSource,
    DictDataProvider,
    GridRef,
    InlineData,
    TableData,
)

# Module-level convenience functions (for matplotlib compatibility)

_current_figure = None


def open_gle(path, *, base_dir=None) -> Figure:
    """Open a ``.gle`` file (or GLE source text) as a gleplot :class:`Figure`.

    Convenience wrapper around
    :func:`gleplot.parser.recognizer.parse_gle_figure` that returns just the
    reconstructed figure (discarding recovery warnings). Use
    ``parse_gle_figure`` directly when you need the warnings list.

    Parameters
    ----------
    path : str or pathlib.Path
        Path to a ``.gle`` file, or raw GLE source text.
    base_dir : str or pathlib.Path, optional
        Directory for resolving relative ``data`` references when ``path`` is
        raw source text.

    Returns
    -------
    Figure
    """
    from .parser.recognizer import parse_gle_figure

    return parse_gle_figure(path, base_dir=base_dir).figure


[docs] def figure( figsize=(8, 6), dpi=100, style=None, graph=None, marker=None, data_prefix=None, height_ratios=None, width_ratios=None, ) -> Figure: """ Create a new figure. Parameters ---------- figsize : tuple, optional Figure size (width, height) in inches. Default: (8, 6) dpi : int, optional Dots per inch. Default: 100 style : GLEStyleConfig, optional Style configuration. If None, uses global default. graph : GLEGraphConfig, optional Graph configuration. If None, uses global default. marker : GLEMarkerConfig, optional Marker configuration. If None, uses global default. data_prefix : str, optional Custom prefix for data file names (e.g., 'test9' creates 'test9_0.dat', 'test9_1.dat'). If None, uses global counter with ``data_`` prefix. Used verbatim, so it must be usable as a GLE data filename: whitespace, control characters and any of ``! " + / \\`` raise ``ValueError``. height_ratios : sequence of float, optional Relative height of each subplot ROW for the grid built with subsequent :meth:`Figure.add_subplot` calls, matplotlib-``gridspec`` style. ``None`` (default) keeps every row the same height. See :class:`gleplot.figure.Figure` for full semantics (validated against the actual row count at GLE-generation time, once every ``add_subplot`` has been made). width_ratios : sequence of float, optional Relative width of each subplot COLUMN. Same semantics as ``height_ratios``, for columns. Returns ------- Figure New figure object Examples -------- Create a figure with default settings: >>> fig = glp.figure() Create a figure with custom style: >>> style = glp.GLEStyleConfig(font='helvetica', fontsize=12) >>> fig = glp.figure(style=style) Or modify global defaults: >>> glp.GlobalConfig.style.font = 'helvetica' >>> fig = glp.figure() # Will use helvetica font A 5-row grid built with add_subplot, with a short 4th "separator" row: >>> fig = glp.figure(figsize=(3.4, 5.2), height_ratios=[3, 3, 3, 1, 4]) >>> axes = [fig.add_subplot(5, 1, i) for i in range(1, 6)] """ global _current_figure _current_figure = Figure( figsize=figsize, dpi=dpi, style=style, graph=graph, marker=marker, data_prefix=data_prefix, height_ratios=height_ratios, width_ratios=width_ratios, ) return _current_figure
[docs] def gca(): """Get current axes.""" if _current_figure is None: figure() return _current_figure.gca()
[docs] def gcf(): """Get current figure.""" if _current_figure is None: figure() return _current_figure
[docs] def plot(*args, **kwargs): """Plot on current axes.""" return gca().plot(*args, **kwargs)
[docs] def scatter(*args, **kwargs): """Scatter on current axes.""" return gca().scatter(*args, **kwargs)
[docs] def bar(*args, **kwargs): """Bar chart on current axes.""" return gca().bar(*args, **kwargs)
[docs] def fill_between(*args, **kwargs): """Fill between on current axes.""" return gca().fill_between(*args, **kwargs)
[docs] def errorbar(*args, **kwargs): """Error bar plot on current axes.""" return gca().errorbar(*args, **kwargs)
[docs] def text(*args, **kwargs): """Add text annotation on current axes.""" return gca().text(*args, **kwargs)
def axvline(*args, **kwargs): """Vertical reference line on current axes.""" return gca().axvline(*args, **kwargs) def axhline(*args, **kwargs): """Horizontal reference line on current axes.""" return gca().axhline(*args, **kwargs) def axvspan(*args, **kwargs): """Shaded vertical band on current axes.""" return gca().axvspan(*args, **kwargs) def axhspan(*args, **kwargs): """Shaded horizontal band on current axes.""" return gca().axhspan(*args, **kwargs)
[docs] def imshow(*args, **kwargs): """Display gridded data as a heatmap on current axes.""" return gca().imshow(*args, **kwargs)
[docs] def contour(*args, **kwargs): """Draw contour lines on current axes.""" return gca().contour(*args, **kwargs)
[docs] def tripcolor(*args, **kwargs): """Scattered-data heatmap on current axes.""" return gca().tripcolor(*args, **kwargs)
[docs] def tricontour(*args, **kwargs): """Scattered-data contour lines on current axes.""" return gca().tricontour(*args, **kwargs)
[docs] def colorbar(*args, **kwargs): """Attach a colorbar to the current figure's heatmap axes.""" return gcf().colorbar(*args, **kwargs)
[docs] def subplots( nrows: int = 1, ncols: int = 1, figsize=None, dpi=100, style=None, graph=None, marker=None, sharex: bool = False, sharey: bool = False, data_prefix=None, height_ratios=None, width_ratios=None, ): """ Create a figure and a set of subplots. Convenience function matching ``matplotlib.pyplot.subplots()``. Parameters ---------- nrows : int, optional Number of rows of subplots. Default: 1 ncols : int, optional Number of columns of subplots. Default: 1 figsize : tuple, optional Figure size (width, height) in inches. If None, auto-scales based on grid size (6 inches per column, 4 inches per row). dpi : int, optional Dots per inch. Default: 100 style : GLEStyleConfig, optional Style configuration. graph : GLEGraphConfig, optional Graph configuration. marker : GLEMarkerConfig, optional Marker configuration. sharex : bool, optional If True, all subplots share the same x-axis. Only the bottom row will show x-axis labels and ticks. Default: False sharey : bool, optional If True, all subplots share the same y-axis. Only the leftmost column will show y-axis labels and ticks. Default: False data_prefix : str, optional Custom prefix for data file names (e.g., 'test9' creates 'test9_0.dat', 'test9_1.dat'). If None, uses global counter with ``data_`` prefix. Used verbatim, so it must be usable as a GLE data filename: whitespace, control characters and any of ``! " + / \\`` raise ``ValueError``. height_ratios : sequence of float, optional Relative height of each of the ``nrows`` subplot rows, matplotlib- ``gridspec`` style (e.g. ``[3, 3, 3, 1, 4]`` for 5 rows whose 4th is thin). Must have length ``nrows`` if given. ``None`` (default) keeps every row the same height -- the historical behaviour, byte- identical output. See :class:`gleplot.figure.Figure` for full semantics (validated against the actual row count at GLE-generation time). width_ratios : sequence of float, optional Relative width of each of the ``ncols`` subplot columns. Same semantics as ``height_ratios``, for columns; must have length ``ncols`` if given. Returns ------- fig : Figure The figure object. axes : Axes or list of Axes A single Axes if nrows*ncols == 1, otherwise a list of Axes arranged in row-major order. Examples -------- Single plot: >>> fig, ax = glp.subplots() >>> ax.plot(x, y) 2x2 grid: >>> fig, axes = glp.subplots(2, 2, figsize=(12, 10)) >>> axes[0].plot(x, y1) # top-left >>> axes[1].scatter(x, y2) # top-right >>> axes[2].bar(x, y3) # bottom-left >>> axes[3].plot(x, y4) # bottom-right Shared x-axis (stacked plots): >>> fig, axes = glp.subplots(3, 1, sharex=True, figsize=(8, 12)) >>> # Only bottom subplot shows x-axis label and ticks Stacked panels with a short separator row (unequal row heights): >>> fig, axes = glp.subplots(3, 1, sharex=True, figsize=(3.4, 4), ... height_ratios=[3, 3, 1]) >>> # axes[2] gets 1/7 of the plotting height, axes[0]/axes[1] get 3/7 each """ global _current_figure if figsize is None: figsize = (max(6, 6 * ncols), max(4, 4 * nrows)) fig = Figure( figsize=figsize, dpi=dpi, style=style, graph=graph, marker=marker, sharex=sharex, sharey=sharey, data_prefix=data_prefix, height_ratios=height_ratios, width_ratios=width_ratios, ) _current_figure = fig axes_list = [] for idx in range(1, nrows * ncols + 1): ax = fig.add_subplot(nrows, ncols, idx) axes_list.append(ax) if len(axes_list) == 1: return fig, axes_list[0] return fig, axes_list
[docs] def xlabel(label: str): """Set x label on current axes.""" return gca().set_xlabel(label)
[docs] def ylabel(label: str): """Set y label on current axes.""" return gca().set_ylabel(label)
[docs] def title(label: str): """Set title on current axes.""" return gca().set_title(label)
[docs] def legend(**kwargs): """Add legend to current axes.""" return gca().legend(**kwargs)
[docs] def savefig(filepath: str, **kwargs): """Save current figure.""" return gcf().savefig(filepath, **kwargs)
[docs] def show(): """Show current figure (placeholder).""" print(f"Figure saved to {gcf().figsize}")
[docs] def view(dpi=None, format="png"): """Display current figure inline (in Jupyter notebooks). Parameters ---------- dpi : int, optional Resolution in dots per inch. If None, uses figure's dpi setting. format : {'png', 'pdf'}, optional Output format. Default is 'png' for inline display. Returns ------- Path or None Path to the generated file, or None when displayed inline in Jupyter. Examples -------- >>> import gleplot as glp >>> fig = glp.figure() >>> ax = fig.add_subplot(111) >>> ax.plot([1, 2, 3], [1, 4, 9]) >>> glp.view() # Display in notebook """ return gcf().view(dpi=dpi, format=format)
[docs] def close(fig=None): """Close figure.""" global _current_figure if fig is None: if _current_figure: _current_figure.close() _current_figure = None else: fig.close()
__all__ = [ "Figure", "Axes", # Light validation of a GLE tick-label number format string ("fix 1", # "sci 2 10", ...), for callers building one interactively. "validate_tick_format", "BrokenAxes", "figure", "gca", "gcf", "plot", "scatter", "bar", "fill_between", "errorbar", "text", "axvline", "axhline", "axvspan", "axhspan", "imshow", "contour", "tripcolor", "tricontour", "colorbar", "subplots", "xlabel", "ylabel", "title", "legend", "savefig", "view", "show", "close", "rgb_to_gle", "get_color_palette", "get_gle_marker", "mathtext_to_gle", "GLECompiler", "GLEStyleConfig", "GLEGraphConfig", "GLEMarkerConfig", "GlobalConfig", "open_gle", "DataSource", "InlineData", "ColumnRef", "GridRef", "DataProvider", "TableData", "DictDataProvider", "DanglingSourceRef", "DanglingSourceWarning", ]