Skip to content

Imshow breaks if given a unyt_array input #18077

Closed
@neutrinoceros

Description

@neutrinoceros

Bug report

Bug summary
matplotlib.pyplot.imshow doesn't seem to play nicely with unyt_arrays like other plotting functions do.

Description

This problem was originally reported on unyt (yt-project/unyt#161)
According to unyt's documentation matplotlib is "unyt_aware", but it seems that some plotting functions are not well behaved.

What I Did

Code for reproduction

import unyt
import numpy as np
from matplotlib import pyplot as plt

arr = unyt.unyt_array(np.ones((16, 16)), "g/cm**3")
plt.pcolormesh(arr) # works
plt.contourf(arr) # works
plt.imshow(arr) # breaks
>> UnitOperationError: The <ufunc 'add'> operator for unyt_arrays with units "g/cm**3" 
(dimensions "(mass)/(length)**3") and "dimensionless" (dimensions "1") is not well defined.

Actual outcome

Full trace

UnitOperationError                        Traceback (most recent call last)
<ipython-input-9-7192cbd0f805> in <module>
----> 1 plt.savefig("hello")

~/miniconda3/envs/mpl_latest/lib/python3.8/site-packages/matplotlib/pyplot.py in savefig(*args, **kwargs)
    840 def savefig(*args, **kwargs):
    841     fig = gcf()
--> 842     res = fig.savefig(*args, **kwargs)
    843     fig.canvas.draw_idle()   # need this if 'transparent=True' to reset colors
    844     return res

~/miniconda3/envs/mpl_latest/lib/python3.8/site-packages/matplotlib/figure.py in savefig(self, fname, transparent, **kwargs)
   2309                 patch.set_edgecolor('none')
   2310
-> 2311         self.canvas.print_figure(fname, **kwargs)
   2312
   2313         if transparent:

~/miniconda3/envs/mpl_latest/lib/python3.8/site-packages/matplotlib/backend_bases.py in print_figure(self, filename, dpi, facecolor, edgecolor, orientation, format, bbox_inches, pad_inches, bbox_extra_artists, backend, **kwargs)
   2208
   2209             try:
-> 2210                 result = print_method(
   2211                     filename,
   2212                     dpi=dpi,

~/miniconda3/envs/mpl_latest/lib/python3.8/site-packages/matplotlib/backend_bases.py in wrapper(*args, **kwargs)
   1637             kwargs.pop(arg)
   1638
-> 1639         return func(*args, **kwargs)
   1640
   1641     return wrapper

~/miniconda3/envs/mpl_latest/lib/python3.8/site-packages/matplotlib/backends/backend_agg.py in print_png(self, filename_or_obj, metadata, pil_kwargs, *args)
    507             *metadata*, including the default 'Software' key.
    508         """
--> 509         FigureCanvasAgg.draw(self)
    510         mpl.image.imsave(
    511             filename_or_obj, self.buffer_rgba(), format="png", origin="upper",

~/miniconda3/envs/mpl_latest/lib/python3.8/site-packages/matplotlib/backends/backend_agg.py in draw(self)
    405              (self.toolbar._wait_cursor_for_draw_cm() if self.toolbar
    406               else nullcontext()):
--> 407             self.figure.draw(self.renderer)
    408             # A GUI class may be need to update a window using this draw, so
    409             # don't forget to call the superclass.

~/miniconda3/envs/mpl_latest/lib/python3.8/site-packages/matplotlib/artist.py in draw_wrapper(artist, renderer, *args, **kwargs)
     39                 renderer.start_filter()
     40
---> 41             return draw(artist, renderer, *args, **kwargs)
     42         finally:
     43             if artist.get_agg_filter() is not None:

~/miniconda3/envs/mpl_latest/lib/python3.8/site-packages/matplotlib/figure.py in draw(self, renderer)
   1861
   1862             self.patch.draw(renderer)
-> 1863             mimage._draw_list_compositing_images(
   1864                 renderer, self, artists, self.suppressComposite)
   1865

~/miniconda3/envs/mpl_latest/lib/python3.8/site-packages/matplotlib/image.py in _draw_list_compositing_images(renderer, parent, artists, suppress_composite)
    130     if not_composite or not has_images:
    131         for a in artists:
--> 132             a.draw(renderer)
    133     else:
    134         # Composite any adjacent images together

~/miniconda3/envs/mpl_latest/lib/python3.8/site-packages/matplotlib/artist.py in draw_wrapper(artist, renderer, *args, **kwargs)
     39                 renderer.start_filter()
     40
---> 41             return draw(artist, renderer, *args, **kwargs)
     42         finally:
     43             if artist.get_agg_filter() is not None:

~/miniconda3/envs/mpl_latest/lib/python3.8/site-packages/matplotlib/cbook/deprecation.py in wrapper(*inner_args, **inner_kwargs)
    409                          else deprecation_addendum,
    410                 **kwargs)
--> 411         return func(*inner_args, **inner_kwargs)
    412
    413     return wrapper

~/miniconda3/envs/mpl_latest/lib/python3.8/site-packages/matplotlib/axes/_base.py in draw(self, renderer, inframe)
   2746             renderer.stop_rasterizing()
   2747
-> 2748         mimage._draw_list_compositing_images(renderer, self, artists)
   2749
   2750         renderer.close_group('axes')

~/miniconda3/envs/mpl_latest/lib/python3.8/site-packages/matplotlib/image.py in _draw_list_compositing_images(renderer, parent, artists, suppress_composite)
    130     if not_composite or not has_images:
    131         for a in artists:
--> 132             a.draw(renderer)
    133     else:
    134         # Composite any adjacent images together

~/miniconda3/envs/mpl_latest/lib/python3.8/site-packages/matplotlib/artist.py in draw_wrapper(artist, renderer, *args, **kwargs)
     39                 renderer.start_filter()
     40
---> 41             return draw(artist, renderer, *args, **kwargs)
     42         finally:
     43             if artist.get_agg_filter() is not None:

~/miniconda3/envs/mpl_latest/lib/python3.8/site-packages/matplotlib/image.py in draw(self, renderer, *args, **kwargs)
    636                 renderer.draw_image(gc, l, b, im, trans)
    637         else:
--> 638             im, l, b, trans = self.make_image(
    639                 renderer, renderer.get_image_magnification())
    640             if im is not None:

~/miniconda3/envs/mpl_latest/lib/python3.8/site-packages/matplotlib/image.py in make_image(self, renderer, magnification, unsampled)
    921         clip = ((self.get_clip_box() or self.axes.bbox) if self.get_clip_on()
    922                 else self.figure.bbox)
--> 923         return self._make_image(self._A, bbox, transformed_bbox, clip,
    924                                 magnification, unsampled=unsampled)
    925

~/miniconda3/envs/mpl_latest/lib/python3.8/site-packages/matplotlib/image.py in _make_image(self, A, in_bbox, out_bbox, clip_bbox, magnification, unsampled, round_to_pixel_border)
    446                 self.norm.autoscale_None(A)
    447                 dv = np.float64(self.norm.vmax) - np.float64(self.norm.vmin)
--> 448                 vmid = self.norm.vmin + dv / 2
    449                 fact = 1e7 if scaled_dtype == np.float64 else 1e4
    450                 newmin = vmid - dv * fact

~/miniconda3/envs/mpl_latest/lib/python3.8/site-packages/numpy/ma/core.py in __add__(self, other)
   4136         if self._delegate_binop(other):
   4137             return NotImplemented
-> 4138         return add(self, other)
   4139
   4140     def __radd__(self, other):

~/miniconda3/envs/mpl_latest/lib/python3.8/site-packages/numpy/ma/core.py in __call__(self, a, b, *args, **kwargs)
   1019         with np.errstate():
   1020             np.seterr(divide='ignore', invalid='ignore')
-> 1021             result = self.f(da, db, *args, **kwargs)
   1022         # Get the mask for the result
   1023         (ma, mb) = (getmask(a), getmask(b))

~/miniconda3/envs/mpl_latest/lib/python3.8/site-packages/unyt/array.py in __array_ufunc__(self, ufunc, method, *inputs, **kwargs)
   1737                                     raise UnitOperationError(ufunc, u0, u1)
   1738                         else:
-> 1739                             raise UnitOperationError(ufunc, u0, u1)
   1740                     conv, offset = u1.get_conversion_factor(u0, inp1.dtype)
   1741                     new_dtype = np.dtype("f" + str(inp1.dtype.itemsize))

UnitOperationError: The <ufunc 'add'> operator for unyt_arrays with units "g/cm**3" (dimensions "(mass)/(length)**3") and "dimensionless" (dimensions "1") is not well defined

Expected outcome
A usable figure :)

Matplotlib version

  • Operating system: MacOS
  • Matplotlib version: 3.3.0
  • Matplotlib backend (print(matplotlib.get_backend())): MacOSX
  • Python version: 3.8.3
  • Jupyter version (if applicable):
  • Other libraries: IPython 7.16.1

mpl installed via cona (Conda-forge channel)

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions