Skip to content

[Bug]: pcolormesh writing to input mask #26093

Closed
@rcomer

Description

@rcomer

Bug summary

When pcolormesh receives a masked array, it seems to be writing back to the mask. Since numpy 1.24 this now causes pcolormesh to fail if the mask is read-only.

Code for reproduction

import matplotlib.pyplot as plt
import numpy as np

data = np.arange(6).reshape(2, 3)
mask = np.broadcast_to([False, True, False], data.shape)  # read-only array

masked_data = np.ma.array(data, mask=mask)

plt.pcolormesh(masked_data)

Actual outcome

Traceback (most recent call last):
  File "pcolormesh_read_only_mask.py", line 9, in <module>
    plt.pcolormesh(masked_data)
  File "[conda-env-path]/lib/python3.11/site-packages/matplotlib/pyplot.py", line 2773, in pcolormesh
    __ret = gca().pcolormesh(
            ^^^^^^^^^^^^^^^^^
  File "[conda-env-path]/lib/python3.11/site-packages/matplotlib/__init__.py", line 1442, in inner
    return func(ax, *map(sanitize_sequence, args), **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "[conda-env-path]/lib/python3.11/site-packages/matplotlib/axes/_axes.py", line 6220, in pcolormesh
    X, Y, C, shading = self._pcolorargs('pcolormesh', *args,
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "[conda-env-path]/lib/python3.11/site-packages/matplotlib/axes/_axes.py", line 5704, in _pcolorargs
    C = cbook.safe_masked_invalid(C)
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "[conda-env-path]/lib/python3.11/site-packages/matplotlib/cbook/__init__.py", line 715, in safe_masked_invalid
    xm = np.ma.masked_invalid(x, copy=False)
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "[conda-env-path]/lib/python3.11/site-packages/numpy/ma/core.py", line 2360, in masked_invalid
    res = masked_where(~(np.isfinite(a)), a, copy=copy)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "[conda-env-path]/lib/python3.11/site-packages/numpy/ma/core.py", line 1942, in masked_where
    result.mask = _shrink_mask(cond)
    ^^^^^^^^^^^
  File "[conda-env-path]/lib/python3.11/site-packages/numpy/ma/core.py", line 3516, in mask
    self.__setmask__(value)
  File "[conda-env-path]/lib/python3.11/site-packages/numpy/ma/core.py", line 3462, in __setmask__
    current_mask.flat = mask
    ^^^^^^^^^^^^^^^^^
ValueError: array is read-only

Expected outcome

No error

Additional information

The code above runs fine with numpy v1.23, although the output from broadcast_to was already read-only at that version. From numpy release notes, this looks like the likely reason for the change:
https://numpy.org/doc/stable/release/1.24.0-notes.html#masked-invalid-now-modifies-the-mask-in-place

Aside from the new error, if a user passes a masked array that has nans or infs at the unmasked points, we are modifying their input array with the call to masked_invalid.

I guess we just need to take a copy somewhere?

Operating system

RHEL7

Matplotlib Version

3.7.1

Matplotlib Backend

QtAgg

Python version

3.11.3

Jupyter version

N/A

Installation

conda

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions