Repository: matplotlib/matplotlib
Pull request: Move float() casting in Rectangle patch
<!--Thank you so much for your PR! To help us review, fill out the form
to the best of your ability.  Please make use of the development guide at
https://matplotlib.org/devdocs/devel/index.html-->

<!--Provide a general summary of your changes in the title above, for
example "Raises ValueError on Non-Numeric Input to set_xlim".  Please avoid
non-descriptive titles such as "Addresses issue #8576".-->

<!--If you are able to do so, please do not create the
PR out of master, but out of a separate branch.  See
https://matplotlib.org/devel/gitwash/development_workflow.html for
instructions.-->

## PR Summary

This moves the `float()` call in Rectangle right down to the method in which uint8's are a problem. This means that (with a slight fix to the jpl_units code) the test in #5422 will work.

Fixes #5421 by making Rectangles work with units.


Problem statement:
Rectangle patch constructor fails with units
Using unit'ized inputs in Rectangle fails in the constructor:

```
    File "test_units_patches.py", line 23, in test_units_rectangle
        p = mpatches.Rectangle( ( 5*U.km, 6*U.km ), 1*U.km, 2*U.km )
    File "/home/trd/git/TD22057/matplotlib/build/lib.linux-x86_64-2.7/matplotlib/patches.py", line 639, in __init__
        self._x = float(xy[0])
    TypeError: float() argument must be a string or a number
```

This is a new problem with 1.5.

Hints from issue discussion:
Pull request #5422 adds a test case and correct image for this this failure but doesn't fix Rectangle.  This was changed for #4751 but no test case was added for that failure so there is no easy way to verify both fixes.

Sorry for the long delay here; there's a small python3 compatibility bug in `jpl_units` that needs to be fixed, but after that and once #8938 is fixed this should be good to go.

Commit message: Add uint8 test

Patch to review:
diff --git a/lib/matplotlib/patches.py b/lib/matplotlib/patches.py
index 26195999f622..6c1d5fa84a97 100644
--- a/lib/matplotlib/patches.py
+++ b/lib/matplotlib/patches.py
@@ -688,10 +688,10 @@ def __init__(self, xy, width, height, angle=0.0, **kwargs):
 
         Patch.__init__(self, **kwargs)
 
-        self._x = float(xy[0])
-        self._y = float(xy[1])
-        self._width = float(width)
-        self._height = float(height)
+        self._x = xy[0]
+        self._y = xy[1]
+        self._width = width
+        self._height = height
         self.angle = float(angle)
         # Note: This cannot be calculated until this is added to an Axes
         self._rect_transform = transforms.IdentityTransform()
diff --git a/lib/matplotlib/tests/baseline_images/test_axes/bar_uint8.png b/lib/matplotlib/tests/baseline_images/test_axes/bar_uint8.png
new file mode 100644
index 000000000000..f01b9b3e220f
Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_axes/bar_uint8.png differ
diff --git a/lib/matplotlib/tests/test_axes.py b/lib/matplotlib/tests/test_axes.py
index b58345a51184..64c2407dbc85 100644
--- a/lib/matplotlib/tests/test_axes.py
+++ b/lib/matplotlib/tests/test_axes.py
@@ -4946,6 +4946,11 @@ def test_ls_ds_conflict():
         plt.plot(range(32), linestyle='steps-pre:', drawstyle='steps-post')
 
 
+@image_comparison(baseline_images=['bar_uint8'], extensions=['png'])
+def test_bar_uint8():
+    plt.bar(np.array([0, 1, 2, 3], dtype=np.uint8), [2, 3, 4, 5])
+
+
 @image_comparison(baseline_images=['date_timezone_x'], extensions=['png'])
 def test_date_timezone_x():
     # Tests issue 5575
diff --git a/lib/matplotlib/transforms.py b/lib/matplotlib/transforms.py
index 824b65e50b4c..17b838b7c05e 100644
--- a/lib/matplotlib/transforms.py
+++ b/lib/matplotlib/transforms.py
@@ -1908,6 +1908,8 @@ def rotate_deg_around(self, x, y, degrees):
         calls to :meth:`rotate`, :meth:`rotate_deg`, :meth:`translate`
         and :meth:`scale`.
         """
+        # Cast to float to avoid wraparound issues with uint8's
+        x, y = float(x), float(y)
         return self.translate(-x, -y).rotate_deg(degrees).translate(x, y)
 
     def translate(self, tx, ty):


Code review comments:
diff_hunk: @@ -4946,6 +4946,11 @@ def test_ls_ds_conflict():
         plt.plot(range(32), linestyle='steps-pre:', drawstyle='steps-post')
 
 
+@image_comparison(baseline_images=['bar_uint8'], extensions=['png'])
path: lib/matplotlib/tests/test_axes.py
text: @user1:
Any chance this and the test below could be written in a way that allows reusing other test images in order to avoid further bloating the repo?

@author:
I've replaced the uint8 test with a numerical check that the patches end up in the right place. Can't think of an easy way to merge the rectangle with units, but could maybe just drop the image test and just check that a rectangle with units doesn't throw any errors?