Skip to content

check_plot_environment

Print and return GRADIEND plot rendering environment status.

When apply_style=True, calls :func:configure_plot_style with :meth:PlotStyleConfig.from_env.

Source code in gradiend/visualizer/plot_style.py
def check_plot_environment(*, print_status: bool = True, apply_style: bool = True) -> Dict[str, Any]:
    """Print and return GRADIEND plot rendering environment status.

    When ``apply_style=True``, calls :func:`configure_plot_style` with
    :meth:`PlotStyleConfig.from_env`.
    """
    env_config: PlotStyleConfig
    latex_preference_error = None
    try:
        env_config = PlotStyleConfig.from_env()
    except ValueError as exc:
        env_config = PlotStyleConfig()
        latex_preference_error = str(exc)

    command_paths = _latex_command_paths()
    latex_on_path = any(path for path in command_paths.values())
    latex_usable = _latex_usable() if latex_on_path else False
    resolved_usetex = _resolve_use_latex(env_config) if latex_preference_error is None else False

    font_status = _check_configured_font(env_config.font_path)

    matplotlib_status: Dict[str, Any] = {
        "available": False,
        "version": None,
        "current_text_usetex": None,
        "style_configured": _CONFIGURED,
        "current_font_family": None,
        "current_font_sans_serif": None,
        "error": None,
    }

    def _refresh_matplotlib_status() -> None:
        try:
            import matplotlib as mpl

            matplotlib_status.update(
                {
                    "available": True,
                    "version": getattr(mpl, "__version__", None),
                    "current_text_usetex": bool(mpl.rcParams.get("text.usetex")),
                    "style_configured": _CONFIGURED,
                    "current_font_family": mpl.rcParams.get("font.family"),
                    "current_font_sans_serif": mpl.rcParams.get("font.sans-serif"),
                    "error": None,
                }
            )
        except Exception as exc:
            matplotlib_status["error"] = str(exc)

    _refresh_matplotlib_status()

    style_status: Optional[PlotStyleStatus] = None
    if apply_style and matplotlib_status["available"] and latex_preference_error is None:
        try:
            style_status = configure_plot_style(env_config, force=False)
            _refresh_matplotlib_status()
        except Exception as exc:
            font_status["usable"] = False
            font_status["error"] = str(exc)
            _refresh_matplotlib_status()

    current_font_status = _check_current_font() if matplotlib_status["available"] else {
        "family": None,
        "available": False,
        "resolved_path": None,
        "error": "matplotlib is not available.",
    }
    font_status["current"] = current_font_status
    pref = env_config.use_latex
    forced_latex_but_unusable = pref is True and not latex_usable
    active_usetex = matplotlib_status["current_text_usetex"]
    usetex_mismatch = matplotlib_status["available"] and active_usetex != resolved_usetex
    active_family = current_font_status.get("family")
    configured_font_name = font_status.get("font_name")
    font_style_not_applied = bool(
        font_status["usable"]
        and configured_font_name
        and not apply_style
        and not matplotlib_status["style_configured"]
    )
    expected_font_missing = bool(
        font_status["usable"]
        and configured_font_name
        and matplotlib_status["style_configured"]
        and configured_font_name not in (
            active_family if isinstance(active_family, (list, tuple)) else [active_family]
        )
    )
    font_unavailable = matplotlib_status["available"] and not current_font_status["available"]
    ok = (
        latex_preference_error is None
        and matplotlib_status["available"]
        and font_status["usable"]
        and not font_unavailable
        and not expected_font_missing
        and not forced_latex_but_unusable
        and not (usetex_mismatch and apply_style)
    )
    warnings_list = []
    info = []
    if latex_preference_error is not None:
        warnings_list.append(latex_preference_error)
    if forced_latex_but_unusable:
        warnings_list.append(f"{ENV_USE_LATEX}=true but LaTeX is not usable by matplotlib.")
    if env_config.font_path and str(env_config.font_path).strip() and not font_status["usable"]:
        warnings_list.append(str(font_status["error"]))
    if font_unavailable:
        warnings_list.append(
            "Matplotlib cannot resolve the current font.family "
            f"({_font_family_text(current_font_status['family'])}): {current_font_status['error']}"
        )
    if font_style_not_applied:
        info.append(
            "GRADIEND style has not been applied in this process yet; "
            f"plots will register {ENV_FONT_PATH} when rendering."
        )
    if expected_font_missing:
        warnings_list.append(
            f"{ENV_FONT_PATH} resolved to {configured_font_name!r}, but matplotlib is currently "
            f"using {_font_family_text(active_family)!r}."
        )
    if not matplotlib_status["available"]:
        warnings_list.append(f"matplotlib is not available: {matplotlib_status['error']}")
    if usetex_mismatch:
        if not apply_style and not matplotlib_status["style_configured"]:
            info.append(
                "GRADIEND style has not been applied in this process yet; "
                f"plots will set text.usetex={resolved_usetex} when rendering."
            )
        else:
            warnings_list.append(
                "Matplotlib text.usetex does not match the GRADIEND LaTeX preference "
                f"(current={active_usetex}, resolved={resolved_usetex})."
            )

    latex_pref_label = (
        "force_on"
        if pref is True
        else "force_off"
        if pref is False
        else "auto"
    )

    status = {
        "ok": ok,
        "warnings": warnings_list,
        "info": info,
        "style": {
            "transition_arrows": env_config.transition_arrows,
            "font_family": env_config.font_family,
            "font_family_env_var": ENV_FONT_FAMILY,
            "font_family_env_value": os.environ.get(ENV_FONT_FAMILY),
            "latex_preamble_extra": bool((env_config.latex_preamble_extra or "").strip()),
            "configured": style_status.configured if style_status else _CONFIGURED,
            "text_usetex": style_status.text_usetex if style_status else active_usetex,
        },
        "latex": {
            "env_var": ENV_USE_LATEX,
            "env_value": os.environ.get(ENV_USE_LATEX),
            "preference": latex_pref_label,
            "preference_error": latex_preference_error,
            "commands": command_paths,
            "on_path": latex_on_path,
            "usable": latex_usable,
            "resolved_text_usetex": resolved_usetex,
        },
        "font": {
            "env_var": ENV_FONT_PATH,
            "family_env_var": ENV_FONT_FAMILY,
            "family_env_value": os.environ.get(ENV_FONT_FAMILY),
            **font_status,
        },
        "matplotlib": matplotlib_status,
    }
    if print_status:
        print(_format_plot_environment_status(status))
    return status