-
-
Notifications
You must be signed in to change notification settings - Fork 7.9k
Clear() methods to Radio and CheckButtons and other improvements #10924
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
Conversation
for some reason, my latest commit to address the PEP test fails is not getting reflected here |
The commit you've linked is on the master branch, not on radio_checkbox_clear. |
thanks @timhoffm - I suspected that, but was apparently confused by my IDE's presentation of the VCS log :) |
lib/matplotlib/widgets.py
Outdated
|
||
return [l.get_text() for l, box_checked in | ||
zip(self.labels, self.get_status()) | ||
if box_checked ] |
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.
if box_checked ]
needs to become if box_checked]
That's the last PEP error. You're almost there... 🎉
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.
thanks, need to configure my IDE better, to not have to go through this so many times :)
lib/matplotlib/tests/test_widgets.py
Outdated
@@ -255,11 +255,26 @@ def test_CheckButtons(): | |||
assert check.get_status() == [True, False, True] | |||
check.set_active(0) | |||
assert check.get_status() == [False, False, True] | |||
assert check.get_checked() == ['c'] | |||
check.clear() | |||
assert not(any(check.get_status())) |
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.
assert not any(...)
There is no need for the extra parentheses. not
is not a function.
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.
good point - will update it.
def get_status(self): | ||
""" | ||
returns a tuple of the status (True/False) of all of the check buttons | ||
""" | ||
return [l1.get_visible() for (l1, l2) in self.lines] | ||
|
||
def get_checked(self): | ||
"""Returns a list of labels currently checked by user.""" |
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.
Not sure how universally useful this method is. Generally, the labels are a user-facing string aimed at readability and not to identify a state. Only the latter use-case would need this method. This is not something usually found in GUI frameworks, because you tie the state to the displayed string; i.e. when changing the displayed string, you would also have to change your code logic.
I tend not to include this in our public API. However, if other reviewers are ok with it, I'd follow along.
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.
I didn't mean this to be a state indicator - which is clearly and explicitly covered by get_status()
with status
in its name, but as a result once the user is done checking all the applicable boxes. I am using it in visualqc and there is a clear need for this.
I am not dogmatic about the name, we could improve the name if needed.
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.
Still, you are using the labels as identifiers for the checked elements. This works well for simple cases, and I agree that it's simpler to use than get_status()
. However, in general labels don't qualify as identifiers. E.g. among other things labels don't have to be unique.
A more universal solution would associate each check box with a unique identifier and only use the label for the visual text. We don't have this at the moment, but current changes should not make it more difficult to implement.
I would be ok to rename this to get_checked_labels()
.
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.
Interesting.
Yes, current implementation allows duplicate labels, as python list allows it. But index into the list sufficiently unique for this purpose. Using ‘set’ would make the implementation more complicated.
What do you mean by “you are using the labels as identifiers for the checked elements”?
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.
AFAICS the use case it that you want to know which of the boxes is checked. You want something that describes (identifies) the checked boxes. You are probably thinking of something like
btns = CheckButtons(ax, labels=['a', 'b', 'c'])
...
if 'a' in btns.get_checked():
You use 'a' as an identifier for the first check box, which has label 'a'. This works in the simple example.
However, in general you cannot infer/identify the checked boxes from the associated labels because labels don't have to be unique.
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.
I see what you mean now. At a high level, "labels don't have to be unique" is a design decision that has been made already. Using python lists as the underlying data structure is a fine decision too. Discussion on whether to impose uniqueness (representing them with a set
perhaps) would be interesting, and is especially well-suited for RadioButtons. Such a decision might require additional logic to maintain valid instantiation of these widgets.
It seems that What's more of a general concern with those methods (this is not really part of this PR but once we're at it...):
|
I think its really helpful for novice users, who would other write a for loop (for lack of expertise in writing that complex expression you put out). Even expert programmers would find it convenient to have it already, so they don't have to write it every time.
I see your point - how about
I had that same uneasy feeling when I first looked into the implementation. My guess is that the original dev might have made this decsion to ensure what is shown is what is represented inside (WYSIWYG).. Other options are maintaining separate boolean list that the visibility is synced to, not sure if that would be any more reliable. Getting back to this PR, is it all good to merge? Entries to README or API Changes is not warranted I suppose? |
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 widgets could use attention in many aspects (naming, functionality, logic, implementation, docs). But that's beyond this PR.
I've expressed my concern on get_checked_labels()
. But given the current code base, this is a helpful function and preferable to np.array(btns.labels)[btns.get_status()]
. index_selected
is a reasonable name. Also, the set_active()
extension and the clear()
methods are an improvement. The changes don't complicate future rewrites/improvements.
By me, this is ready to go in. Probably one should sqash the commits.
Thanks Tim. Again, I think set_active should really be renamed to just set, with 2/3 deprecation cycles.. |
Talking about CheckButtons: If we touch the existing API with a deprecation, then we should spit Actually, adding |
Out of the scope for that PR, but in case someone wants to rationalize a bit the widgets API (#10924 (review)) I would suggest doing a comparison with the APIs provided by major GUI toolkits (e.g. http://doc.qt.io/qt-5/qbuttongroup.html in this case). We don't have to strictly copy their APIs (which are after all designed for C/C++), but they're probably not completely stupid either. |
ping @raamana |
thanks Jody - I had some trouble setting up the mpl dev environment on my macbook (some issues with gcc, compiling mpl locally etc), so couldn't investigate why tests were failing. Let me try it again now (although Apple seems to be not making it any easier). |
You don’t teally need to trigger the tests locally (though it helps). You’d see where ci fails and copy the relevant test to a file and debug as a script. |
that's a good idea - although I suspect I need to be able to install matplotlib locally in editable/develop mode, before I can run any of the test_* files locally, don't you think? Appreciate your help in seeing this through. |
On a side note, it would be great if someone made a more "robust" installer script (dev mode) for potential contributors who are good with python but not env management etc. Anyways I am stuck here:
|
?? What are you doing? Maybe take to the Gitter channel... |
You need Xcode, most likely. |
This is replaced by #13401. |
PR Summary
Closes #10922
I'm unable to set up test environment on my laptop yet, so will use CI tests here.
Not sure if this deserves entries into What's New and API changes.
PR Checklist