Join GitHub today
GitHub is home to over 20 million developers working together to host and review code, manage projects, and build software together.
Cleanup transforms.py. #7394
Conversation
| def get_points(self): | ||
| - return NotImplementedError() | ||
| + raise NotImplementedError |
anntzer
Nov 3, 2016
Contributor
https://docs.python.org/3/reference/simple_stmts.html#the-raise-statement:
Otherwise, raise evaluates the first expression as the exception object. It must be either a subclass or an instance of BaseException. If it is a class, the exception instance will be obtained when needed by instantiating the class with no arguments.
anntzer
Nov 3, 2016
Contributor
raise ValueError is pretty common? (if you're too lazy (hem hem) to write a proper error message)
tacaswell
added this to the
2.1 (next point release)
milestone
Nov 3, 2016
| + """ | ||
| + (property) :attr:`xmin` is the left edge of the bounding box. | ||
| + """ | ||
| + return np.min(self.get_points()[:, 0]) |
anntzer
Nov 3, 2016
Contributor
So that nan passes through -- which is probably the right thing to do? (min(np.nan, 1) is 1, np.min(np.nan, 1) is np.nan.) (and in fact needed for the various new implementations of the contains/overlaps methods)
|
I know you're not touching this, but is all the |
|
I am a tad concerned about performance regressions on this. attn @mdboom as you last touched / wrote this code in 2008. |
|
@story645 There's a bunch of |
|
git grep says the problem isn't so bad...bunch of .cpp and backend files |
| - return self.get_points()[:, 1] | ||
| - intervaly = property(_get_intervaly, None, None, """ | ||
| + @property | ||
| + def intervaly(self): |
anntzer
Nov 5, 2016
Contributor
You bet I would be extra careful not to add any public API :-)
intervaly was a public property; it is still a public property when set like this. (And in both cases the function that implements the getter is available as Bbox.invervaly.fget; it used to also be available as Bbox._get_intervaly but this PR removes that.)
| - return ((x0 < x1 | ||
| - and (x >= x0 and x <= x1)) | ||
| - or (x >= x1 and x <= x0)) | ||
| + return self.xmin <= x <= self.xmax |
NelleV
changed the title from
Cleanup transforms.py. to [MRG+1] Cleanup transforms.py.
Nov 5, 2016
| @@ -955,62 +897,62 @@ def update_from_data_xy(self, xy, ignore=None, updatex=True, updatey=True): | ||
| def _set_x0(self, val): | ||
| self._points[0, 0] = val | ||
| self.invalidate() | ||
| - x0 = property(BboxBase._get_x0, _set_x0) | ||
| + x0 = property(BboxBase.x0.fget, _set_x0) |
QuLogic
Nov 5, 2016
Member
You could write this in the decorator form as:
@BboxBase.x0.setter
def x0(self, val):
self._points[0, 0] = val
self.invalidate()or at least, it seems to work for me...
anntzer
Nov 5, 2016
Contributor
No, because this would update the setter of BboxBase too. I could write
@partial(property, BboxBase.x0.fget)
def x0(self, val): ...
but that hardly seems like an improvement in readability...
Kojoley
Nov 8, 2016
•
Member
It does not rewrite the setter of base class for me (on both 2.7 and 3.5).
class A(object):
def __init__(self):
self._z = None
@property
def z(self):
return self._z
@z.setter
def z(self, val):
print('A')
self._z = val
class B(A):
@A.z.setter
def z(self, val):
print('B')
self._z = val
a = A()
a.z = 123
print(a.z)
b = B()
b.z = 456
print(b.z)
class C(object):
def __init__(self):
self._z = None
@property
def z(self):
return self._z
class D(A):
@C.z.setter
def z(self, val):
print('D')
self._z = val
try:
c = C()
c.z = 123
print('Error')
except AttributeError:
print('Pass')
d = D()
d.z = 456
print(d.z)A
123
B
456
Pass
D
456
anntzer
Nov 8, 2016
Contributor
Oh, indeed prop.setter returns a new property, leaving the previous one untouched. The docs actually explicitly say that:
A property object has getter, setter, and deleter methods usable as decorators that create a copy of the property with the corresponding accessor function set to the decorated function.
(emphasis mine)
One new thing I learned today... and I'll update the PR accordngly.
|
@tacaswell I think your concerns about performance are very valid. For example
is three times slower. |
QuLogic
changed the title from
[MRG+1] Cleanup transforms.py. to Cleanup transforms.py.
Nov 5, 2016
|
I tried adding a Now the question is, does this actually matter? It would be nice to have some actual performance tests (on "real" plots) to check that. |
|
@anntzer If I understand you correctly you are talking about fast onepass minmax algorithm. While it makes 25% less comparisons ( |
|
The point is that
will be faster than anything that goes through a function (/ property) call. |
|
Ah, so you worry about added function call/property access overhead? class Base(object):
intervalx = 123, 456
class A(Base):
def fully_containsx(self, x):
x0, x1 = self.intervalx
return ((x0 < x1
and (x > x0 and x < x1))
or (x > x1 and x < x0))
class B(Base):
@property
def xmin(self):
return min(self.intervalx)
@property
def xmax(self):
return max(self.intervalx)
def fully_containsx(self, x):
return self.xmin < x < self.xmax
|
|
That's basically the difference I measured, yes. |
codecov-io
commented
Dec 2, 2016
Current coverage is 61.86% (diff: 90.62%)@@ master #7394 diff @@
==========================================
Files 109 173 +64
Lines 46780 56092 +9312
Methods 0 0
Messages 0 0
Branches 0 0
==========================================
+ Hits 31075 34702 +3627
- Misses 15705 21390 +5685
Partials 0 0
|
NelleV
dismissed
their
review
Dec 19, 2016
!!
|
Any updates? Needs a rebase. |
|
Given the reasonable performance concerns I don't think this can go forward unless we somehow add performance regression tests and show that there won't be a significant slowdown. |
|
I wouldn't add a performance regression tests, but I think it is reasonable to benchmark the two options implementations. |
|
But this is so much down the stack that it could literally affect anything, so I don't think a microbenchmark really makes sense. I have no idea, for example, whether it would make plotting a lot of artists much slower because it may be doing a bunch of bbox comparisons... or perhaps not. |
|
@tacaswell I restored a fast(?) implementation of |
| - y1 = max(y1, np.max(ys)) | ||
| - | ||
| - return Bbox.from_extents(x0, y0, x1, y1) | ||
| + x0 = min(bbox.xmin for bbox in bboxes) |
anntzer
Feb 21, 2017
Contributor
I guess I should use np.min everywhere (which passes nan through, whereas builtin min drops them). (At least this would be consistent with bbox.xmin.)
anntzer commentedNov 3, 2016
Simplify the implementation of the various
contains-like methods.Switch to modern property declarations. Cleanup some docstrings.