Skip to content

Fixed colorbar bug when yscaled length is 1 #23984

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

Closed
wants to merge 7 commits into from

Conversation

Andes0113
Copy link

@Andes0113 Andes0113 commented Sep 22, 2022

PR Summary

This pull request aims to solve issue #23817 in which an error would be thrown in the event that yscaled's length was 1. To fix this, I added a check to see if yscaled's length was 1, and if so, to set automin and automax to yscaled's only value. I also moved the declaration of automin and automax inside the if statement where extendlength is declared as suggested by @oscargus , since they are unused otherwise.

PR Checklist

Tests and Styling

  • Has pytest style unit tests (and pytest passes).
  • Is Flake 8 compliant (install flake8-docstrings and run flake8 --docstring-convention=all).

Documentation

  • [N/A] New features are documented, with examples if plot related.
  • [N/A] New features have an entry in doc/users/next_whats_new/ (follow instructions in README.rst there).
  • [N/A] API changes documented in doc/api/next_api_changes/ (follow instructions in README.rst there).
  • [N/A] Documentation is sphinx and numpydoc compliant (the docs should build without error).

Copy link

@github-actions github-actions bot left a 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.

@jklymak
Copy link
Member

jklymak commented Sep 22, 2022

Can you add a test that doesn't work on main, but is fixed by this PR? Probably in tests/test_colorbar.py.

@oscargus
Copy link
Member

oscargus commented Sep 29, 2022

As there is now a warning, which is clearly better than an error, you will need to take that intro consideration in the test.

Something like:

with pytest.warns(UserWarning) as record:
    ax.contour([[1, 1], [1, 1]])
assert len(record) == 1

should do. Also, please add a comment like:

# Smoke test for gh#23817

at the beginning of the test (so that it is clear what is tested as there is "no assert" (the assert above is really not crucial for the test purpose)).

Edit: the warning was probably always there, but earlier "hidden" by the error, so the first sentence is not completely correct...

@Andes0113
Copy link
Author

Thanks for the help! I've added the changes, and I'll circle back later to see if all these tests pass.

@oscargus
Copy link
Member

oscargus commented Oct 2, 2022

It seems like there is a divide by zero(?) elsewhere in the code now:

lib/matplotlib/tests/test_colorbar.py:251: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
lib/matplotlib/figure.py:1276: in colorbar
    cb = cbar.Colorbar(cax, mappable, **cb_kw)
lib/matplotlib/_api/deprecation.py:384: in wrapper
    return func(*inner_args, **inner_kwargs)
lib/matplotlib/colorbar.py:396: in __init__
    self._draw_all()
lib/matplotlib/colorbar.py:535: in _draw_all
    X, Y = self._mesh()
lib/matplotlib/colorbar.py:1110: in _mesh
    y, _ = self._proportional_y()

here

y = (self._boundaries - self._boundaries[self._inside][0])
y = y / (self._boundaries[self._inside][-1] -
self._boundaries[self._inside][0])

One should probably check something there as well? I do not know if the length of _boundaries[self._inside] is one or the first and last element is the same.

@timhoffm timhoffm mentioned this pull request Oct 2, 2022
6 tasks
@Andes0113
Copy link
Author

Andes0113 commented Oct 2, 2022

One should probably check something there as well? I do not know if the length of _boundaries[self._inside] is one or the first and last element is the same.

We could probably just put in a check like this:
y = (self._boundaries - self._boundaries[self._inside][0])
if self._boundaries[self._inside][-1] != self._boundaries[self._inside][0]:
` y = y / (self._boundaries[self._inside][-1] - self._boundaries[self._inside][0])
And it would work for both cases. I am a little worried about this causing unexpected behavior though, but it would likely be only in this case anyway.

Another idea:

The boundaries are set in _process_values(), here:

def _process_values(self):
"""
Set `_boundaries` and `_values` based on the self.boundaries and
self.values if not None, or based on the size of the colormap and
the vmin/vmax of the norm.
"""

Not sure which section of this function we're setting the boundaries in for this case though.

I imagine it would be here:

if self.values is not None:
# set self._boundaries from the values...
self._values = np.array(self.values)
if self.boundaries is None:
# bracket values by 1/2 dv:
b = np.zeros(len(self.values) + 1)
b[1:-1] = 0.5 * (self._values[:-1] + self._values[1:])
b[0] = 2.0 * b[1] - b[2]
b[-1] = 2.0 * b[-2] - b[-3]
self._boundaries = b
return
self._boundaries = np.array(self.boundaries)
return
though, since the catch for checking if self.boundaries is None would not catch the case where it would have length 1. In that case, maybe we should add a check there instead of when dividing the y by the ends of the boundaries? That way we would still have valid boundaries for later calculations.

I'll try the change that you mentioned for now, though.

@melissawm
Copy link
Member

Hi @Andes0113 - is this ready for a second round of reviews?

@Andes0113
Copy link
Author

@melissawm Think this PR is ready to be closed since there are branching PRs that attempt to do the same thing and are further along in the process. I'd take a look at the more recent related PRs #24656 and #24698 because I've stopped working on this issue.

@melissawm
Copy link
Member

Thanks for the update @Andes0113 - hope to see you again around Matplotlib!

@melissawm melissawm closed this Jan 23, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Development

Successfully merging this pull request may close these issues.

[Bug]: Error showing colorbar when contouring a uniform field
4 participants