Skip to content

Commit 51385ed

Browse files
committed
Bugfix for loc legend validation
Co-authored-by: John Paul Jepko <jpjepko@users.noreply.github.com>
1 parent 70e0ba8 commit 51385ed

File tree

2 files changed

+83
-0
lines changed

2 files changed

+83
-0
lines changed

lib/matplotlib/legend.py

+15
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323

2424
import itertools
2525
import logging
26+
import numbers
2627
import time
2728

2829
import numpy as np
@@ -518,6 +519,8 @@ def val_or_rc(val, rc_name):
518519
loc = 'upper right'
519520

520521
# handle outside legends:
522+
type_err_message = ("loc must be string, coordinate tuple or,"
523+
f" an integer 0-10, not {loc!r}")
521524
self._outside_loc = None
522525
if isinstance(loc, str):
523526
if loc.split()[0] == 'outside':
@@ -535,6 +538,18 @@ def val_or_rc(val, rc_name):
535538
loc = locs[0] + ' ' + locs[1]
536539
# check that loc is in acceptable strings
537540
loc = _api.check_getitem(self.codes, loc=loc)
541+
elif isinstance(loc, tuple):
542+
# validate the tuple represents Real coordinates
543+
if len(loc) != 2 or not (all(isinstance(e, numbers.Real)
544+
for e in loc)):
545+
raise ValueError(type_err_message)
546+
elif isinstance(loc, int):
547+
# validate the integer represents a string numeric value
548+
if (loc < 0) or (loc > 10):
549+
raise ValueError(type_err_message)
550+
else:
551+
# all other cases are invalid values of loc
552+
raise ValueError(type_err_message)
538553

539554
if self.isaxes and self._outside_loc:
540555
raise ValueError(

lib/matplotlib/tests/test_legend.py

+68
Original file line numberDiff line numberDiff line change
@@ -1219,3 +1219,71 @@ def test_ncol_ncols(fig_test, fig_ref):
12191219
ncols = 3
12201220
fig_test.legend(strings, ncol=ncols)
12211221
fig_ref.legend(strings, ncols=ncols)
1222+
1223+
1224+
def test_loc_invalid_tuple_exception():
1225+
# check that exception is raised if the loc arg
1226+
# of legend is not a 2-tuple of numbers
1227+
fig, ax = plt.subplots()
1228+
with pytest.raises(ValueError, match=('loc must be string, coordinate '
1229+
'tuple or, an integer 0-10, not \\(1.1,\\)')):
1230+
ax.legend(loc=(1.1, ))
1231+
1232+
with pytest.raises(ValueError, match=('loc must be string, coordinate '
1233+
'tuple or, an integer 0-10, not \\(0.481, 0.4227, 0.4523\\)')):
1234+
ax.legend(loc=(0.481, 0.4227, 0.4523))
1235+
1236+
with pytest.raises(ValueError, match=('loc must be string, coordinate '
1237+
'tuple or, an integer 0-10, not \\(0.481, \'go blue\'\\)')):
1238+
ax.legend(loc=(0.481, "go blue"))
1239+
1240+
1241+
def test_loc_valid_tuple():
1242+
fig, ax = plt.subplots()
1243+
ax.legend(loc=(0.481, 0.442))
1244+
ax.legend(loc=(1, 2))
1245+
1246+
1247+
def test_loc_invalid_type():
1248+
fig, ax = plt.subplots()
1249+
with pytest.raises(ValueError, match=("loc must be string, coordinate "
1250+
"tuple or, an integer 0-10, not {'not': True}")):
1251+
ax.legend(loc={'not': True})
1252+
1253+
1254+
def test_loc_validation_string_numeric_value():
1255+
fig, ax = plt.subplots()
1256+
ax.legend(loc=0)
1257+
ax.legend(loc=1)
1258+
ax.legend(loc=5)
1259+
ax.legend(loc=10)
1260+
with pytest.raises(ValueError, match=('loc must be string, coordinate '
1261+
'tuple or, an integer 0-10, not 11')):
1262+
ax.legend(loc=11)
1263+
1264+
with pytest.raises(ValueError, match=('loc must be string, coordinate '
1265+
'tuple or, an integer 0-10, not -1')):
1266+
ax.legend(loc=-1)
1267+
1268+
1269+
def test_loc_validation_string_value():
1270+
fig, ax = plt.subplots()
1271+
ax.legend(loc='best')
1272+
ax.legend(loc='upper right')
1273+
ax.legend(loc='best')
1274+
ax.legend(loc='upper right')
1275+
ax.legend(loc='upper left')
1276+
ax.legend(loc='lower left')
1277+
ax.legend(loc='lower right')
1278+
ax.legend(loc='right')
1279+
ax.legend(loc='center left')
1280+
ax.legend(loc='center right')
1281+
ax.legend(loc='lower center')
1282+
ax.legend(loc='upper center')
1283+
s = ("'wrong' is not a valid value for"
1284+
" loc; supported values are 'best', 'upper right', "
1285+
"'upper left', 'lower left', 'lower right', 'right',"
1286+
" 'center left', 'center right', 'lower center', "
1287+
"'upper center', 'center'")
1288+
with pytest.raises(ValueError, match=s):
1289+
ax.legend(loc='wrong')

0 commit comments

Comments
 (0)