8000 Add explicit converter setting to Axis by ksunden · Pull Request #28970 · matplotlib/matplotlib · GitHub
[go: up one dir, main page]

Skip to content

Add explicit converter setting to Axis #28970

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Oct 31, 2024
Merged
Show file tree
Hide file tree
Changes from 2 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
45 changes: 42 additions & 3 deletions lib/matplotlib/axis.py
Original file line number Diff line number Diff line change
Expand Up @@ -657,6 +657,7 @@
self.clear()
else:
self.converter = None
self._converter_is_explicit = False
self.units = None

self._autoscale_on = True
Expand Down Expand Up @@ -887,6 +888,7 @@
self.reset_ticks()

self.converter = None
self._converter_is_explicit = False
self.units = None
self.stale = True

Expand Down Expand Up @@ -1741,12 +1743,16 @@
``axis.converter`` instance if necessary. Return *True*
if *data* is registered for unit conversion.
"""
converter = munits.registry.get_converter(data)
if not self._converter_is_explicit:
converter = munits.registry.get_converter(data)
else:
converter = self.converter

if converter is None:
return False

neednew = self.converter != converter
self.converter = converter
self._set_converter(converter)
default = self.converter.default_units(data, self)
if default is not None and self.units is None:
self.set_units(default)
Expand Down Expand Up @@ -1799,7 +1805,7 @@
return x

if self.converter is None:
self.converter = munits.registry.get_converter(x)
self._set_converter(munits.registry.get_converter(x))

if self.converter is None:
return x
Expand All @@ -1810,6 +1816,39 @@
f'units: {x!r}') from e
return ret

def get_converter(self):
"""
Get the unit converter for axis.

Returns
-------
`~matplotlib.units.ConversionInterface` or None
"""
return self.converter

Check warning on line 1827 in lib/matplotlib/axis.py

View check run for this annotation

Codecov / codecov/patch

lib/matplotlib/axis.py#L1827

Added line #L1827 was not covered by tests

def set_converter(self, converter):
"""
Set the unit converter for axis.

Parameters
----------
converter : `~matplotlib.dates.ConversionInterface`
"""
self._set_converter(converter)
self._converter_is_explicit = True

def _set_converter(self, converter):
if self.converter == converter:
return
if self._converter_is_explicit:
raise RuntimeError("Axis already has an explicit converter set")
elif self.converter is not None:
_api.warn_external(
"This axis already has an converter set and "
"is updating to a potentially incompatible converter"
)
self.converter = converter

def set_units(self, u):
"""
Set the units for axis.
Expand Down
3 changes: 3 additions & 0 deletions lib/matplotlib/axis.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ from matplotlib.text import Text
from matplotlib.ticker import Locator, Formatter
from matplotlib.transforms import Transform, Bbox
from matplotlib.typing import ColorType
from matplotlib.units import ConversionInterface


GRIDLINE_INTERPOLATION_STEPS: int
Expand Down Expand Up @@ -207,6 +208,8 @@ class Axis(martist.Artist):
def update_units(self, data): ...
def have_units(self) -> bool: ...
def convert_units(self, x): ...
def get_converter(self) -> ConversionInterface | None: ...
def set_converter(self, converter: ConversionInterface) -> None: ...
def set_units(self, u) -> None: ...
def get_units(self): ...
def set_label_text(
Expand Down
28 changes: 27 additions & 1 deletion lib/matplotlib/tests/test_units.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import matplotlib.pyplot as plt
from matplotlib.testing.decorators import check_figures_equal, image_comparison
import matplotlib.units as munits
from matplotlib.category import UnitData
from matplotlib.category import StrCategoryConverter, UnitData
import numpy as np
import pytest

Expand Down Expand Up @@ -236,6 +236,32 @@ def test_shared_axis_categorical():
assert "c" in ax2.xaxis.get_units()._mapping.keys()


def test_explicit_converter():
d1 = {"a": 1, "b": 2}
str_cat_converter = StrCategoryConverter()
str_cat_converter_2 = StrCategoryConverter()

# Explicit is set
fig1, ax1 = plt.subplots()
ax1.xaxis.set_converter(str_cat_converter)
assert ax1.xaxis.converter == str_cat_converter
# Explicit not overridden by implicit
ax1.plot(d1.keys(), d1.values())
assert ax1.xaxis.converter == str_cat_converter
# No error when called twice with equivalent input
ax1.xaxis.set_converter(str_cat_converter)
# Error when explicit called twice
with pytest.raises(RuntimeError):
ax1.xaxis.set_converter(str_cat_conver 652E ter_2)

# Warn when implicit overridden
fig2, ax2 = plt.subplots()
ax2.plot(d1.keys(), d1.values())

with pytest.warns():
ax2.xaxis.set_converter(str_cat_converter)


def test_empty_default_limits(quantity_converter):
munits.registry[Quantity] = quantity_converter
fig, ax1 = plt.subplots()
Expand Down
Loading
0