Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/basics.py
Original file line number Diff line number Diff line change
Expand Up @@ -489,7 +489,7 @@
# <https://matplotlib.org/stable/tutorials/introductory/customizing.html>`__ and
# :ref:`ultraplot settings <ug_rcUltraPlot>`. The matplotlib-specific settings are
# stored in :func:`~ultraplot.config.rc_matplotlib` (our name for :data:`~matplotlib.rcParams`) and
# the UltraPlot-specific settings are stored in :class:`~ultraplot.config.rc_ultraplot`.
# the UltraPlot-specific settings are stored in :class:`~ultraplot.config.rc.rc_ultraplot`.
# UltraPlot also includes a :rcraw:`style` setting that can be used to
# switch between `matplotlib stylesheets
# <https://matplotlib.org/stable/gallery/style_sheets/style_sheets_reference.html>`__.
Expand Down
12 changes: 6 additions & 6 deletions docs/configuration.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ A dictionary-like object named :obj:`~ultraplot.config.rc`, belonging to the
:class:`~ultraplot.config.Configurator` class, is created when you import UltraPlot.
This is your one-stop shop for working with
`matplotlib settings <ug_rcmpl_>`_
stored in :obj:`~ultraplot.config.rc_matplotlib`
stored in :obj:`~ultraplot.config.rc.rc_matplotlib`
(our name for the :obj:`~matplotlib.rcParams` dictionary)
and :ref:`ultraplot settings <ug_rcUltraPlot>`
stored in :obj:`~ultraplot.config.rc_ultraplot`.
stored in :obj:`~ultraplot.config.rc.rc_ultraplot`.

To change global settings on-the-fly, simply update :obj:`~ultraplot.config.rc`
using either dot notation or as you would any other dictionary:
Expand Down Expand Up @@ -73,7 +73,7 @@ Matplotlib settings

Matplotlib settings are natively stored in the :obj:`~matplotlib.rcParams`
dictionary. UltraPlot makes this dictionary available in the top-level namespace as
:obj:`~ultraplot.config.rc_matplotlib`. All matplotlib settings can also be changed with
:obj:`~ultraplot.config.rc.rc_matplotlib`. All matplotlib settings can also be changed with
:obj:`~ultraplot.config.rc`. Details on the matplotlib settings can be found on
`this page <ug_rcmpl_>`_.

Expand All @@ -83,9 +83,9 @@ dictionary. UltraPlot makes this dictionary available in the top-level namespace
UltraPlot settings
----------------

UltraPlot settings are natively stored in the :obj:`~ultraplot.config.rc_ultraplot` dictionary.
UltraPlot settings are natively stored in the :obj:`~ultraplot.config.rc.rc_ultraplot` dictionary.
They should almost always be changed with :obj:`~ultraplot.config.rc` rather than
:obj:`~ultraplot.config.rc_ultraplot` to ensure that :ref:`meta-settings <ug_rcmeta>` are
:obj:`~ultraplot.config.rc.rc_ultraplot` to ensure that :ref:`meta-settings <ug_rcmeta>` are
synced. These settings are not found in :obj:`~matplotlib.rcParams` -- they either
control UltraPlot-managed features (e.g., a-b-c labels and geographic gridlines)
or they represent existing matplotlib settings with more clear or succinct names.
Expand Down Expand Up @@ -120,7 +120,7 @@ Meta-settings
Some UltraPlot settings may be more accurately described as "meta-settings",
as they change several matplotlib and UltraPlot settings at once (note that settings
are only synced when they are changed on the :obj:`~ultraplot.config.rc` object rather than
the :obj:`~ultraplot.config.rc_UltraPlot` and :obj:`~ultraplot.config.rc_matplotlib` dictionaries).
the :obj:`~ultraplot.config.rc.rc_ultraplot` and :obj:`~ultraplot.config.rc.rc_matplotlib` dictionaries).
Here's a broad overview of the "meta-settings":

* Setting :rcraw:`font.small` (or, equivalently, :rcraw:`fontsmall`) changes
Expand Down
8 changes: 4 additions & 4 deletions docs/why.rst
Original file line number Diff line number Diff line change
Expand Up @@ -815,8 +815,8 @@ Acceptable units include inches, centimeters, millimeters,
pixels, `points <https://en.wikipedia.org/wiki/Point_(typography)>`__, and `picas
<https://en.wikipedia.org/wiki/Pica_(typography)>`__ (a table of acceptable
units is found :ref:`here <units_table>`). Note the :func:`~ultraplot.utils.units` engine
also translates rc settings assigned to :func:`~ultraplot.config.rc_matplotlib` and
:obj:`~ultraplot.config.rc_UltraPlot`, e.g. :rcraw:`subplots.refwidth`,
also translates rc settings assigned to :func:`~ultraplot.config.rc.rc_matplotlib` and
:obj:`~ultraplot.config.rc.rc_ultraplot`, e.g. :rcraw:`subplots.refwidth`,
:rcraw:`legend.columnspacing`, and :rcraw:`axes.labelpad`.

Links
Expand Down Expand Up @@ -848,8 +848,8 @@ Changes
-------

In UltraPlot, you can use the :obj:`~ultraplot.config.rc` object to change both native
matplotlib settings (found in :obj:`~ultraplot.config.rc_matplotlib`) and added UltraPlot
settings (found in :obj:`~ultraplot.config.rc_UltraPlot`). Assigned settings are always
matplotlib settings (found in :obj:`~ultraplot.config.rc.rc_matplotlib`) and added UltraPlot
settings (found in :obj:`~ultraplot.config.rc.rc_ultraplot`). Assigned settings are always
validated, and "meta" settings like ``meta.edgecolor``, ``meta.linewidth``, and
``font.smallsize`` can be used to update many settings all at once. Settings can
be changed with ``uplt.rc.key = value``, ``uplt.rc[key] = value``,
Expand Down
77 changes: 6 additions & 71 deletions ultraplot/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,78 +105,13 @@ def setup(eager: Optional[bool] = None) -> None:
if eager is None:
from .config import rc

eager = bool(rc["ultraplot.eager_import"])
if eager:
_LOADER.load_all(globals())
# Validate color names now that colors are registered
# NOTE: This updates all settings with 'color' in name (harmless if it's not a color)
rcsetup.VALIDATE_REGISTERED_COLORS = True
rc.sync() # triggers validation


def _build_registry_map():
global _REGISTRY_ATTRS
if _REGISTRY_ATTRS is not None:
return
from .constructor import FORMATTERS, LOCATORS, NORMS, PROJS, SCALES

registry = {}
for src in (NORMS, LOCATORS, FORMATTERS, SCALES, PROJS):
for _, cls in src.items():
if isinstance(cls, type):
registry[cls.__name__] = cls
_REGISTRY_ATTRS = registry


def _get_registry_attr(name):
_build_registry_map()
return _REGISTRY_ATTRS.get(name) if _REGISTRY_ATTRS else None


_LOADER: LazyLoader = LazyLoader(
package=__name__,
package_path=Path(__file__).resolve().parent,
exceptions=_LAZY_LOADING_EXCEPTIONS,
setup_callback=_setup,
registry_attr_callback=_get_registry_attr,
registry_build_callback=_build_registry_map,
registry_names_callback=lambda: _REGISTRY_ATTRS,
)


def __getattr__(name):
# If the name is already in globals, return it immediately
# (Prevents re-running logic for already loaded attributes)
if name in globals():
return globals()[name]

if name == "pytest_plugins":
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")

# Priority 2: Core metadata
if name in {"__version__", "version", "name", "__all__"}:
if name == "__all__":
val = _LOADER.load_all(globals())
globals()["__all__"] = val
return val
return globals().get(name)

# Priority 3: Special handling for figure
if name == "figure":
# Special handling for figure to allow module imports
import inspect
import sys

# Check if this is a module import by looking at the call stack
frame = inspect.currentframe()
try:
caller_frame = frame.f_back
if caller_frame:
# Check if the caller is likely the import system
caller_code = caller_frame.f_code
# Check if this is a module import
is_import = (
"importlib" in caller_code.co_filename
or caller_code.co_name
in ("_handle_fromlist", "_find_and_load", "_load_unlocked")
or "_bootstrap" in caller_code.co_filename
)
from .colors import _cmap_database as colormaps
from .utils import check_for_update

# Also check if the caller is a module-level import statement
if not is_import and caller_code.co_name == "<module>":
Expand Down
Loading
Loading