Repository: matplotlib/matplotlib
Pull request: Raise ValueError on negative number inputs for set_aspect 
## PR Summary
This PR fixes the issue where the function set_aspect when given a negative number as a parameter leads to infinite loop (#23847)
## PR Checklist

<!-- Please mark any checkboxes that do not apply to this PR as [N/A]. -->
**Tests and Styling**
- [N/A] Has pytest style unit tests (and `pytest` passes).
- [N/A] Is [Flake 8](https://flake8.pycqa.org/en/latest/) 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](https://matplotlib.org/devel/documenting_mpl.html#building-the-docs) without error).

<!--
Thank you so much for your PR!  To help us review your contribution, please
consider the following points:

- A development guide is available at https://matplotlib.org/devdocs/devel/index.html.

- Help with git and github is available at
  https://matplotlib.org/devel/gitwash/development_workflow.html.

- Do not create the PR out of main, but out of a separate branch.

- The PR title should summarize the changes, for example "Raise ValueError on
  non-numeric input to set_xlim".  Avoid non-descriptive titles such as
  "Addresses issue #8576".

- The summary should provide at least 1-2 sentences describing the pull request
  in detail (Why is this change required?  What problem does it solve?) and
  link to any relevant issues.

- If you are contributing fixes to docstrings, please pay attention to
  http://matplotlib.org/devel/documenting_mpl.html#formatting.  In particular,
  note the difference between using single backquotes, double backquotes, and
  asterisks in the markup.

We understand that PRs can sometimes be overwhelming, especially as the
reviews start coming in.  Please let us know if the reviews are unclear or
the recommended next step seems overly demanding, if you would like help in
addressing a reviewer's comments, or if you have been waiting too long to hear
back on your PR.
-->


Problem statement:
[Bug]: set_aspect with negative argument leads to infinite loop
### Bug summary

When calling `plt.gca().set_aspect(-1)` it leads to a infinite loop, where `ValueError: 'box_aspect' and 'fig_aspect' must be positive` repeatedly, until I terminate python.

### Code for reproduction

```python
import matplotlib.pyplot as plt
plt.plot()
plt.gca().set_aspect(-1)
```


### Actual outcome

`ValueError: 'box_aspect' and 'fig_aspect' must be positive` is thrown repeatedly

### Expected outcome

either a single Value Error, or that you get the same as if you would invert the y-axis, but with a 1:1 aspect ratio.

### Additional information

_No response_

### Operating system

iOS

### Matplotlib Version

3.5.3

### Matplotlib Backend

MacOSX

### Python version

3.10

### Jupyter version

_No response_

### Installation

pip

Hints from issue discussion:
Please provide more info: a full minimal example (the code snippet above does not raise) and the full stack trace.

---

Side note: Possibly someting in the backend/event loop. With Qt backend and an added `plt.show()` I get

```
Traceback (most recent call last):
  File "/home/tim/anaconda3/envs/mpl35/lib/python3.10/site-packages/matplotlib/backends/backend_qt.py", line 477, in _draw_idle
    self.draw()
  File "/home/tim/anaconda3/envs/mpl35/lib/python3.10/site-packages/matplotlib/backends/backend_agg.py", line 436, in draw
    self.figure.draw(self.renderer)
  File "/home/tim/anaconda3/envs/mpl35/lib/python3.10/site-packages/matplotlib/artist.py", line 73, in draw_wrapper
    result = draw(artist, renderer, *args, **kwargs)
  File "/home/tim/anaconda3/envs/mpl35/lib/python3.10/site-packages/matplotlib/artist.py", line 50, in draw_wrapper
    return draw(artist, renderer)
  File "/home/tim/anaconda3/envs/mpl35/lib/python3.10/site-packages/matplotlib/figure.py", line 2823, in draw
    artists = self._get_draw_artists(renderer)
  File "/home/tim/anaconda3/envs/mpl35/lib/python3.10/site-packages/matplotlib/figure.py", line 238, in _get_draw_artists
    ax.apply_aspect()
  File "/home/tim/anaconda3/envs/mpl35/lib/python3.10/site-packages/matplotlib/axes/_base.py", line 1895, in apply_aspect
    pb1 = pb.shrunk_to_aspect(box_aspect, pb, fig_aspect)
  File "/home/tim/anaconda3/envs/mpl35/lib/python3.10/site-packages/matplotlib/transforms.py", line 558, in shrunk_to_aspect
    raise ValueError("'box_aspect' and 'fig_aspect' must be positive")
ValueError: 'box_aspect' and 'fig_aspect' must be positive
```
and an empty but responsive figure window. As expected the interpreter is blocked while the window is open. When closing the window, the prompt returns.

Anyway, we should do input validation already on `set_aspect()`.
Steps needed:

 - add validation in `set_aspect` that will raise for negative values
 - add a test that it raises
Hello, May I work on this issue please sir/ma'am ?
@ZzN1NJ4 Go for it.
As a more general remark: Setting the aspect ratio via `set_aspect` does not work together with inverting the y axis with `invert_yaxis`. (As `invert_yaxis` does not give an equal aspect ratio, while `set_aspect(1)` leaves me with a non-inverted y axis...). 

Should I open a feature-request issue on that? 
That seems like a bug, and a yes, please open a different issue

> As a more general remark: Setting the aspect ratio via `set_aspect` does not work together with inverting the y axis with `invert_yaxis`. (As `invert_yaxis` does not give an equal aspect ratio, while `set_aspect(1)` leaves me with a non-inverted y axis...).
> 
> Should I open a feature-request issue on that?



Regarding my above comment: It turned out, that the issue was with some other part of the code I was working on, and matplotlib actually works fine there. Sorry for the confusion.
Hey, I would like to tackle this issue if you don't mind.
hi @KelsonXie, while we don't assign issues,  we'd prefer that effort not get duplicated. Can you wait a few days and see if @ZzN1NJ4  puts in a PR and then help out? https://matplotlib.org/3.6.0/devel/contributing.html#issues-for-new-contributors

Commit message: Update _base.py

Patch to review:
diff --git a/lib/matplotlib/axes/_base.py b/lib/matplotlib/axes/_base.py
index ebe1ef7911d4..d6d4d301e87e 100644
--- a/lib/matplotlib/axes/_base.py
+++ b/lib/matplotlib/axes/_base.py
@@ -1680,6 +1680,8 @@ def set_aspect(self, aspect, adjustable=None, anchor=None, share=False):
             aspect = 1
         if not cbook._str_equal(aspect, 'auto'):
             aspect = float(aspect)  # raise ValueError if necessary
+            if aspect<0:
+                raise ValueError("aspect must be positive")
 
         if share:
             axes = {sibling for name in self._axis_names


Code review comments:
diff_hunk: @@ -1680,6 +1680,8 @@ def set_aspect(self, aspect, adjustable=None, anchor=None, share=False):
             aspect = 1
         if not cbook._str_equal(aspect, 'auto'):
             aspect = float(aspect)  # raise ValueError if necessary
+            if aspect<0:
path: lib/matplotlib/axes/_base.py
text: @user1:
```suggestion
            if aspect <= 0:
```