| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
|
If you want a simpler PR at first, you can make one that deprecates the public AxesStack and "just" creates the private one. We can go from there in simplifing the API. I'd wait on having the deprecation of the AxesStack vetted by others before moving forward. I think make AxesStack private is a good idea: it is only used in the figure object right now, in a private attribute, and probably aimed at being private from the start. |
Sorry, something went wrong.
| return a in self.as_list() | ||
|
|
||
|
|
||
| class _AxesStack: |
There was a problem hiding this comment.
needs to inherit from (object) (for now).
Sorry, something went wrong.
There was a problem hiding this comment.
fixed
Sorry, something went wrong.
|
👍 in principle but we should try to support as much of the old API as possible. I know I have written SO answers which reached in and touched the AxesStack.... The balance against making everything private is that if you do not give users enough public knobs to get done what they need to get done, they will find the private knobs and just do it. Once enough user are using a private API it become defacto public and we are as bad off or worse than we would have been other wise. |
Sorry, something went wrong.
|
@NelleV Hopefully everything should be fixed now (I didn't realize that I need to keep track both of the axes stack and of the order in which the axes were created). @tacaswell The only reference to AxesStack I could find on SO is http://stackoverflow.com/questions/24104990/how-to-get-a-list-of-axes-for-a-figure-in-pyplot which somehow ironically ends with your comment
In any case this PR literally doesn't change any public API -- the old AxesStack class is still there, it's just used nowhere :-) (and 1. the AxesStack object instantiated by the Figure class was a private attribute, so it's fair game to change it and 2. in fact, the new private AxesStack implements (nearly) the same API as the old one...). Honestly if we start having to worry about modifying private APIs then I don't know what's left to do other than adding features over features and never fixing old stuff because, well, it may always break someone else who is playing with the internals (that person should have asked for a public API, or known better). Again, I'm not removing AxesStack for now; if someone complains that they were actually using it, we can always consider undeprecating it. |
Sorry, something went wrong.
|
The code looks good to me. |
Sorry, something went wrong.
| return next((ax for _, k, ax in self._items if k == key), None) | ||
|
|
||
| def current_key_axes(self): | ||
| """Return the topmost key, axes pair, or `None, None` if empty. |
There was a problem hiding this comment.
topmost? Is that a word I don't know?
Sorry, something went wrong.
There was a problem hiding this comment.
Sorry, something went wrong.
There was a problem hiding this comment.
Should add some parentheses because right now it can read as either "a key" or "an axes pair" or None, None, but it's really "(key, axes) pair" or None, None.
Sorry, something went wrong.
There was a problem hiding this comment.
good point, fixed
Sorry, something went wrong.
There was a problem hiding this comment.
Maybe a silly question, but is the only difference between this and an OrderedDict that it can do operations based on the value instead of the key? A comment/doc to that effect would be useful for the future.
Sorry, something went wrong.
| return key, ax | ||
|
|
||
| def add(self, key, ax): | ||
| """Append a key, axes pair, unless the axes are already present. |
There was a problem hiding this comment.
Add parentheses on this one too.
Sorry, something went wrong.
There was a problem hiding this comment.
done
Sorry, something went wrong.
| def as_list(self): | ||
| """Copy of the list of axes, in the order of insertion. | ||
| """ | ||
| return [ax for _, _, ax in sorted(self._items)] |
There was a problem hiding this comment.
I know it's originally sorted this way, but I wonder if that's even necessary...
Sorry, something went wrong.
There was a problem hiding this comment.
The "keep creation order" behavior is mandated by the tests right now, and I don't see a reason to get rid of it.
Sorry, something went wrong.
|
@QuLogic also because keys may not be hashable. Added a comment to that effect. |
Sorry, something went wrong.
|
@anntzer It as always fun when 2.5 year old comments come back at me ;) |
Sorry, something went wrong.
|
This PR clearly supersedes #7335, thought I think the latter is 2.0 safe while this one isn't. |
Sorry, something went wrong.
| def get(self, key): | ||
| """Find the axes corresponding to a key; defaults to `None`. | ||
| """ | ||
| return next((ax for _, k, ax in self._items if k == key), None) |
There was a problem hiding this comment.
@anntzer I consistently learn new python details from your code.
Sorry, something went wrong.
| """ | ||
| # Skipping existing Axes is needed to support calling `add_axes` with | ||
| # an already existing Axes. | ||
| if not any(a == ax for _, _, a in self._items): |
There was a problem hiding this comment.
This probably needs to handle the duplicate key case?
Sorry, something went wrong.
There was a problem hiding this comment.
Each call to add is actually preceded by a call to get, so technically we can rely on the caller code to never try to add in a duplicate key. Also I worded the docstring carefully: the pair is not appended if the axes is already present but there's no check on whether the key is :-)
In practice I could make the behavior (no checking for duplicate key) clearer in the docstring, or add a check and error out if the key is already there; either is fine with me. Please let me know your preference.
Sorry, something went wrong.
|
👍 One small concern about the duplicate key, other wise LGTM I strongly prefer to not backport this for 2.0. |
Sorry, something went wrong.
|
We should never have duplicate keys, so what should be the expected behaviour? Raise an error? |
Sorry, something went wrong.
|
Lets go with raise (and keep the raise / API change in #7335). |
Sorry, something went wrong.
|
Hmm, so I just thought of something that the key function actually handles that isn't here, namely, that elements of args and kwargs may be mutable, which may not be something you want in the key. For example: rect = np.array([0.2, 0.2, 0.2, 0.2])
ax1 = fig.add_axes(rect, ...)
rect[:2] += 0.2
ax2 = fig.add_axes(rect, ...)ax2 should be new, but I think it will return ax1 with this class. |
Sorry, something went wrong.
|
In fact I just realized there's a much bigger issue here: you can't use == to compare arrays for full equality, so something as simple as plt.axes(np.array(...)); plt.axes(np.array(...)) will fail with ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all() I guess there's no way around having some variant of make_key :-( |
Sorry, something went wrong.
|
do we need to support mutable/non-hashable keys? |
Sorry, something went wrong.
|
On 2016/11/11 8:23 AM, Antony Lee wrote:
I suspect we all agree on this. I think it is the result of starting |
Sorry, something went wrong.
|
If you're willing to break backcompatibility here, the good thing is that's there's an obvious deprecation path:
By the way I assume(?) it is possible to change the rectangle where an axes sit, in which case that provides another way to break the current implementation (create an axes, move it somewhere else, and either try to create another axes where the first one was, or try to create another axes where the first one is currently). In fact even MATLAB doesn't provide that behavior: >> axes('Position', [.1 .1 .7 .7]); axes('Position', [.1, .1, .7, .7]); get(gcf, 'children')
ans =
2×1 Axes array:
Axes
Axes
|
Sorry, something went wrong.
| return self._axstack.as_list() | ||
|
|
||
| axes = property(fget=_get_axes, doc="Read-only: list of axes in Figure") | ||
| axes = property(lambda self: self._axstack.as_list(), |
There was a problem hiding this comment.
Can't this be
@property
def axes(self):
"""Read-only: list of axes in Figure"""
return self._axstack.as_list()
Sorry, something went wrong.
There was a problem hiding this comment.
I don't think one is more readable that the other?
Sorry, something went wrong.
|
Is there any interest in pushing this forward? |
Sorry, something went wrong.
|
Why not :-) |
Sorry, something went wrong.
Current coverage is 62.01% (diff: 97.05%)@@ master #7377 diff @@
==========================================
Files 174 174
Lines 56065 56068 +3
Methods 0 0
Messages 0 0
Branches 0 0
==========================================
- Hits 34820 34770 -50
- Misses 21245 21298 +53
Partials 0 0
|
Sorry, something went wrong.
There was a problem hiding this comment.
I think this looks good. I'd rather merge this sooner than later, if something is terribly wrong, we might pick it up before the 2.1 release.
Sorry, something went wrong.
|
Actually, see the discussion starting at #7377 (comment). I think the issue mentioned by @QuLogic cannot really be fixed with the current implementation so perhaps we should instead follow the path mentioned in #7377 (comment) (see comment by @efiring re: backcompatibility, too). |
Sorry, something went wrong.
|
This needs a rebase. |
Sorry, something went wrong.
The current implementation of AxesStack subclasses cbook.Stack, which requires hashable keys, which leads to additional complexity on the caller's side (`_make_key`). Instead, switch to using two lists (keys and axes) and relying on `list.index`, which makes the implementation much simpler. Also make the new class private and deprecate the previous one.
|
done |
Sorry, something went wrong.
|
Are we not worried about #7377 (comment)? |
Sorry, something went wrong.
|
@QuLogic I missed that when I was re-reading the comments last night, sorry. |
Sorry, something went wrong.
| Back | FazBrowse Home | New Git URL |
attn @NelleV
The current implementation of AxesStack subclasses cbook.Stack, which
requires hashable keys, which leads to additional complexity on the
caller's side (_make_key).
Instead, switch to using two lists (keys and axes) and relying on
list.index, which makes the implementation much simpler.
Also make the new class private and deprecate the previous one.
(The original idea was to make AxesStack private to avoid having to deal with issues such as #7194. I originally thought that we could just replace it by an OrderedDict, which is still an option, but you need a really need a two-way dict to implement remove-by-value (instead of by key), so I ended up dropping that idea -- the benefit of dropping _make_key looked more enticing.)