-
-
Notifications
You must be signed in to change notification settings - Fork 7.9k
Fix RangeSlider for same init values #22686 #22926
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
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.
Thank you for opening your first PR into Matplotlib!
If you have not heard from us in a while, please feel free to ping @matplotlib/developers
or anyone who has commented on the PR. Most of our reviewers are volunteers and sometimes things fall through the cracks.
You can also join us on gitter for real-time discussion.
For details on testing, writing docs, and our review process, please see the developer guide
We strive to be a welcoming and open project. Please follow our Code of Conduct.
I took the liberty of editing your message, changing |
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.
Looking good! I have two comments for simplifying the code but the core functionality is here
lib/matplotlib/widgets.py
Outdated
verts[0] = .25, valinit[0] | ||
verts[1] = .25, valinit[1] | ||
verts[2] = .75, valinit[1] | ||
verts[3] = .75, valinit[0] | ||
verts[4] = .25, valinit[0] |
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.
Since this verts filling code is now used in multiple places (here, and in set_val
) maybe we should pull it out into 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.
Looking good! I've got a few more comments on ways you can simplify the code a bit more but none of it is critical.
nice work
lib/matplotlib/widgets.py
Outdated
verts = self._fill_verts(verts, valinit) | ||
poly = Polygon(verts, **kwargs) | ||
poly.set_transform(self.ax.get_yaxis_transform(which="grid")) |
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.
with above suggestion you can do:
verts = self._fill_verts(verts, valinit) | |
poly = Polygon(verts, **kwargs) | |
poly.set_transform(self.ax.get_yaxis_transform(which="grid")) | |
poly_transform = self.ax.get_yaxis_transform(which="grid")) |
and then create the polygon as below
lib/matplotlib/widgets.py
Outdated
def _fill_verts(self, verts, val): | ||
"""Fills the *verts* Nx2 shaped numpy array.""" |
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 suppose it's not strictly necessary because this is private - but it could be nice to have a Parameters and Returns section of the docstring so that someone in the future trying to understand has an easier time. Something like:
def _fill_verts(self, verts, val): | |
"""Fills the *verts* Nx2 shaped numpy array.""" | |
def _fill_verts(self, verts, val): | |
""" | |
Update the *verts* of the *self.poly* slider according to the current value and slider orientation | |
Parameters | |
---------------- | |
verts : (5, 2) np.ndarray | |
The vertices to fill. Note that these will be modified in place | |
val : (2,) array_like | |
The new min and max values | |
Returns | |
---------- | |
verts : np.ndarray | |
The original array with updated values | |
""" |
I'm not sure I got the docstring styling 100% correct but this should at least convey the information
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.
Looks good! Nice work @AnnaMastori and @NickolasGiannatos
The next step is that two core developers (people with write access) need to review and approve this.
But FWIW it gets the approval from me 👍
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 there some way we can test this?
What do you mean by this? Do you want us to create a specific test for the new method ? |
Yes. Easiest is probably copying this part into a new test for the case of matplotlib/lib/matplotlib/tests/test_widgets.py Lines 1119 to 1133 in 2e70254
or just adding a second line of: slider = widgets.RangeSlider(
ax=ax, label="", valmin=0.0, valmax=1.0, orientation=orientation,
valinit=[0, 0]
)
box = slider.poly.get_extents().transformed(ax.transAxes.inverted())
assert_allclose(box.get_points().flatten()[idx], [0, 0.25, 0, 0.75]) inside the current test either before or after the current slider creation |
Is it a good practice to create a test for an edge case scenario or we should enhance the existing one to cover this specific case. |
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! This is looking good and working. I've added some suggestions to make the code easier to follow.
lib/matplotlib/tests/test_widgets.py
Outdated
slider = widgets.RangeSlider( | ||
ax=ax, label="", valmin=0.0, valmax=1.0, orientation=orientation, | ||
valinit=[0.0, 0.0] | ||
) | ||
box = slider.poly.get_extents().transformed(ax.transAxes.inverted()) | ||
assert_allclose(box.get_points().flatten()[idx], [0, 0.25, 0, 0.75]) | ||
|
||
# Check initial value is set correctly | ||
assert_allclose(slider.val, (0.0, 0.0)) |
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.
@NickolasGiannatos sorry, I have overlooked your question on whether to include into the existing test or add a new test. In this case I'd go with a dedicated test because
- There's little code sharing between the tests (only the idx order, which could be written more compact as `idx = [1, 0, 3, 2] if orientation == 'vertical' else [0, 1, 2, 3]). So there's little gain.
- The existing test is already quite long and the new test would add 10 unrelated lines. This makes understanding what's happening in the existing test much harded. If it was just a 2-3 liner like the slider.reset() below, it'd maybe ok to add to the existing test.
@AnnaMastori @NickolasGiannatos congratulations on your first contribution to Matplolib! 🎉 Thank you for the PR and your patience getting through the review process. We are looking forward to seeing you back! |
PR Summary
Change the way that polygon is initilized to cover edge case of same init values. The method axhspan is no longer used and the polygon is created manually. (closes #22686 )
PR Checklist
Tests and Styling
pytest
passes).flake8-docstrings
and runflake8 --docstring-convention=all
).Documentation
doc/users/next_whats_new/
(follow instructions in README.rst there).doc/api/next_api_changes/
(follow instructions in README.rst there).