-
-
Notifications
You must be signed in to change notification settings - Fork 7.6k
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
Don't check iterable()
before len()
.
#7767
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -33,7 +33,7 @@ | |
|
||
from matplotlib import rcParams | ||
from matplotlib.artist import Artist, allow_rasterization | ||
from matplotlib.cbook import is_string_like, iterable, silent_list, is_hashable | ||
from matplotlib.cbook import is_string_like, silent_list, is_hashable | ||
from matplotlib.font_manager import FontProperties | ||
from matplotlib.lines import Line2D | ||
from matplotlib.patches import Patch, Rectangle, Shadow, FancyBboxPatch | ||
|
@@ -408,17 +408,6 @@ def _set_loc(self, loc): | |
# find_offset function will be provided to _legend_box and | ||
# _legend_box will draw itself at the location of the return | ||
# value of the find_offset. | ||
self._loc_real = loc | ||
if loc == 0: | ||
_findoffset = self._findoffset_best | ||
else: | ||
_findoffset = self._findoffset_loc | ||
|
||
# def findoffset(width, height, xdescent, ydescent): | ||
# return _findoffset(width, height, xdescent, ydescent, renderer) | ||
|
||
self._legend_box.set_offset(_findoffset) | ||
|
||
self._loc_real = loc | ||
self.stale = True | ||
|
||
|
@@ -427,24 +416,20 @@ def _get_loc(self): | |
|
||
_loc = property(_get_loc, _set_loc) | ||
|
||
def _findoffset_best(self, width, height, xdescent, ydescent, renderer): | ||
"Helper function to locate the legend at its best position" | ||
ox, oy = self._find_best_position(width, height, renderer) | ||
return ox + xdescent, oy + ydescent | ||
|
||
def _findoffset_loc(self, width, height, xdescent, ydescent, renderer): | ||
"Helper function to locate the legend using the location code" | ||
def _findoffset(self, width, height, xdescent, ydescent, renderer): | ||
"Helper function to locate the legend" | ||
|
||
if iterable(self._loc) and len(self._loc) == 2: | ||
# when loc is a tuple of axes(or figure) coordinates. | ||
fx, fy = self._loc | ||
bbox = self.get_bbox_to_anchor() | ||
x, y = bbox.x0 + bbox.width * fx, bbox.y0 + bbox.height * fy | ||
else: | ||
if self._loc == 0: # "best". | ||
x, y = self._find_best_position(width, height, renderer) | ||
elif self._loc in Legend.codes.values(): # Fixed location. | ||
bbox = Bbox.from_bounds(0, 0, width, height) | ||
x, y = self._get_anchored_bbox(self._loc, bbox, | ||
self.get_bbox_to_anchor(), | ||
renderer) | ||
else: # Axes or figure coordinates. | ||
fx, fy = self._loc | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. are these changes related to the title of the PR? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The idea was to fix the line a bit below ( |
||
bbox = self.get_bbox_to_anchor() | ||
x, y = bbox.x0 + bbox.width * fx, bbox.y0 + bbox.height * fy | ||
|
||
return x + xdescent, y + ydescent | ||
|
||
|
@@ -701,6 +686,7 @@ def _init_legend_box(self, handles, labels, markerfirst=True): | |
children=[self._legend_title_box, | ||
self._legend_handle_box]) | ||
self._legend_box.set_figure(self.figure) | ||
self._legend_box.set_offset(self._findoffset) | ||
self.texts = text_list | ||
self.legendHandles = handle_list | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,8 +7,8 @@ | |
import io | ||
|
||
import numpy as np | ||
from numpy.testing import assert_array_equal, assert_array_almost_equal | ||
from numpy.testing import assert_equal | ||
from numpy.testing import ( | ||
assert_array_equal, assert_array_almost_equal, assert_equal) | ||
import pytest | ||
|
||
import matplotlib.pyplot as plt | ||
|
@@ -641,9 +641,9 @@ def test_lslw_bcast(): | |
col.set_linestyles(['-', '-']) | ||
col.set_linewidths([1, 2, 3]) | ||
|
||
assert col.get_linestyles() == [(None, None)] * 6 | ||
assert col.get_linewidths() == [1, 2, 3] * 2 | ||
assert_equal(col.get_linestyles(), [(None, None)] * 6) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. any reason you're using numpy testing over py.test asserts here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. because There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It works. See also numpy/numpy#8457.
|
||
assert_equal(col.get_linewidths(), [1, 2, 3] * 2) | ||
|
||
col.set_linestyles(['-', '-', '-']) | ||
assert col.get_linestyles() == [(None, None)] * 3 | ||
assert col.get_linewidths() == [1, 2, 3] | ||
assert_equal(col.get_linestyles(), [(None, None)] * 3) | ||
assert_equal(col.get_linewidths(), [1, 2, 3]) |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -157,11 +157,15 @@ def get_converter(self, x): | |
converter = self.get_converter(next_item) | ||
return converter | ||
|
||
if converter is None and iterable(x) and (len(x) > 0): | ||
thisx = safe_first_element(x) | ||
if classx and classx != getattr(thisx, '__class__', None): | ||
converter = self.get_converter(thisx) | ||
return converter | ||
if converter is None: | ||
try: | ||
thisx = safe_first_element(x) | ||
except (TypeError, StopIteration): | ||
pass | ||
else: | ||
if classx and classx != getattr(thisx, '__class__', None): | ||
converter = self.get_converter(thisx) | ||
return converter | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the converter is always returned at the bottom of this function (it's literally the next line) so is it worth putting here? And a general question/qualm on the multiple returns: while I know PEP8 is lenient on them, is there a good reason for them here where everything is bundled in if statements anyway? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I tried to keep the logical flow of the previous implementation as much as possible -- I think the whole thing probably needs some refactor anyways, so there isn't much in favor of a piecemeal approach. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I get...refactoring units (and adding ScalerMappable support) is on my wishlist... |
||
|
||
# DISABLED self._cached[idx] = converter | ||
return converter | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is the code set up such that if self._loc is neither 0 nor in Legend.codes.values(), then it has to be iterable of len 2?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The condition effectively is the same as before.
Previous impl:
New impl:
It is correct that the error on invalid locations would be different though. The previous implementation would raise an AssertionError (
assert loc in range(1, 11) # called only internally
in get_anchored_bbox), the current one raises a TypeError (when trying to iterate over self._loc).There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
:/ Should it be raising a
ValueError
since that's what's actually going wrong? I think I get now why the old code checked for len first...There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The previous version would raise AssertionError both for invalid single values (loc=99) and for invalid length values (loc=(1, 2, 3)). The new implementation now raises TypeError for the former and ValueError for the latter. I think the new version is better, given that most functions can indeed raise both TypeError and ValueError when given an incorrect input, so you need to catch both anyways (whereas catching AssertionError is pretty rare).