Skip to content

[MNT] Typing: Use Literal for set_loglevel #30301

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

Closed
Closed
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
4 changes: 3 additions & 1 deletion lib/matplotlib/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,10 @@ import contextlib
from packaging.version import Version

from matplotlib._api import MatplotlibDeprecationWarning
from matplotlib.typing import LogLevel
from typing import Any, Literal, NamedTuple, overload


class _VersionInfo(NamedTuple):
major: int
minor: int
Expand All @@ -52,7 +54,7 @@ __bibtex__: str
__version__: str
__version_info__: _VersionInfo

def set_loglevel(level: str) -> None: ...
def set_loglevel(level: LogLevel) -> None: ...

class _ExecInfo(NamedTuple):
executable: str
Expand Down
45 changes: 28 additions & 17 deletions lib/matplotlib/legend.py
Original file line number Diff line number Diff line change
Expand Up @@ -576,7 +576,7 @@ def __init__(
# set the text color

color_getters = { # getter function depends on line or patch
'linecolor': ['get_color', 'get_facecolor'],
'linecolor': ['get_facecolor', 'get_edgecolor', 'get_color'],
'markerfacecolor': ['get_markerfacecolor', 'get_facecolor'],
'mfc': ['get_markerfacecolor', 'get_facecolor'],
'markeredgecolor': ['get_markeredgecolor', 'get_edgecolor'],
Expand All @@ -592,32 +592,43 @@ def __init__(
continue
except AttributeError:
pass

for getter_name in getter_names:
try:
color = getattr(handle, getter_name)()

if isinstance(color, np.ndarray):
if (
color.shape[0] == 1
or np.isclose(color, color[0]).all()
):
text.set_color(color[0])
if color.size == 0:
continue
if color.shape[0] == 1 or np.isclose(color, color[0]).all():
rgba = color[0]
else:
pass
continue # Gradient or ambiguous color
else:
text.set_color(color)
rgba = color

# Skip if fully transparent (invisible legend text)
if (
hasattr(rgba, '__getitem__')
and len(rgba) == 4 and rgba[3] == 0
):
continue

text.set_color(rgba)
break
except AttributeError:
pass
elif cbook._str_equal(labelcolor, 'none'):
for text in self.texts:
text.set_color(labelcolor)
elif np.iterable(labelcolor):
for text, color in zip(self.texts,
itertools.cycle(
colors.to_rgba_array(labelcolor))):
text.set_color(color)
else:
raise ValueError(f"Invalid labelcolor: {labelcolor!r}")
if cbook._str_equal(labelcolor, 'none'):
for text in self.texts:
text.set_color(labelcolor)
elif np.iterable(labelcolor):
for text, color in zip(self.texts,
itertools.cycle(colors.to_rgba_array(labelcolor))):
text.set_color(color)
else:
for text in self.texts:
text.set_color(labelcolor)

def _set_artist_props(self, a):
"""
Expand Down
3 changes: 2 additions & 1 deletion lib/matplotlib/pyplot.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@
MouseEventType,
PickEventType,
ResizeEventType,
LogLevel
)
from matplotlib.widgets import SubplotTool

Expand Down Expand Up @@ -351,7 +352,7 @@ def uninstall_repl_displayhook() -> None:

# Ensure this appears in the pyplot docs.
@_copy_docstring_and_deprecators(matplotlib.set_loglevel)
def set_loglevel(level: str) -> None:
def set_loglevel(level: LogLevel) -> None:
return matplotlib.set_loglevel(level)


Expand Down
31 changes: 31 additions & 0 deletions lib/matplotlib/tests/test_legend.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@
import matplotlib.legend as mlegend
from matplotlib import rc_context
from matplotlib.font_manager import FontProperties
import matplotlib.colors as mcolors




def test_legend_ordereddict():
Expand Down Expand Up @@ -1472,3 +1475,31 @@ def test_boxplot_legend_labels():
bp4 = axs[3].boxplot(data, label='box A')
assert bp4['medians'][0].get_label() == 'box A'
assert all(x.get_label().startswith("_") for x in bp4['medians'][1:])


def test_legend_labelcolor_linecolor_default_artists():
fig, axes = plt.subplots(2, 2)
x = np.random.randn(1000)
y = np.random.randn(1000)

# Top Left: Filled Histogram (default color C0)
axes[0, 0].hist(x, histtype='bar', label="spam")
leg00 = axes[0, 0].legend(labelcolor='linecolor')
assert np.allclose(leg00.get_texts()[0].get_color()[:3], mcolors.to_rgb('C0'))

# Top Right: Step Histogram (default color C0)
axes[0, 1].hist(x, histtype='step', label="spam")
leg01 = axes[0, 1].legend(labelcolor='linecolor')
assert np.allclose(leg01.get_texts()[0].get_color()[:3], mcolors.to_rgb('C0'))

# Bottom Left: Scatter (filled, default color C0)
axes[1, 0].scatter(x, y, label="spam")
leg10 = axes[1, 0].legend(labelcolor='linecolor')
assert np.allclose(leg10.get_texts()[0].get_color()[:3], mcolors.to_rgb('C0'))

# Bottom Right: Scatter (outline, default edge color C0)
axes[1, 1].scatter(x, y, label="spam")
leg11 = axes[1, 1].legend(labelcolor='linecolor')
assert np.allclose(leg11.get_texts()[0].get_color()[:3], mcolors.to_rgb('C0'))

plt.close(fig)
4 changes: 4 additions & 0 deletions lib/matplotlib/typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,10 @@
FillStyleType: TypeAlias = Literal["full", "left", "right", "bottom", "top", "none"]
"""Marker fill styles. See :doc:`/gallery/lines_bars_and_markers/marker_reference`."""

LogLevel: TypeAlias = Literal["notset", "debug", "info", "warning", "error", "critical"]
"""Valid string values for logging levels used in `set_loglevel`."""


JoinStyleType: TypeAlias = JoinStyle | Literal["miter", "round", "bevel"]
"""Line join styles. See :doc:`/gallery/lines_bars_and_markers/joinstyle`."""

Expand Down
Loading