Numpy: assignment destination is read-only - broadcast

wouterdobbels picture wouterdobbels · Apr 5, 2018 · Viewed 9.7k times · Source

I start with a 2D array and want to broadcast it to a 3D array (eg. from greyscale image to rgb image). This is the code I use.

>>> img_grey = np.random.randn(4, 4)
>>> img_rgb = np.broadcast_to(np.expand_dims(img_grey, axis=-1), (4, 4, 3))

This creates an array img_rgb that works as expected: 3 colored channels (last dimension), each slice being equal to the original greyscale image. However, if I do

>>> img_rgb[0, 0, 0] = 0.
ValueError: assignment destination is read-only

I can't change the rgb image!

Answer

wouterdobbels picture wouterdobbels · Apr 5, 2018

The reason is that broadcast_to does not create a new array in memory. Instead, you just get a view of the original data. This can be seen by inspecting the flags.

>>> img_rg.flags
C_CONTIGUOUS : False
F_CONTIGUOUS : False
OWNDATA : False
WRITEABLE : False
ALIGNED : True
UPDATEIFCOPY : False

In particular, the OWNDATA flag is set to False (which means the array borrows the memory from another object), as well as the WRITEABLE flag being False (this is why you can't change the object). See the numpy flags documentation.

The workaround is to create a copy of the array.

>>> img_rgb = np.broadcast_to(np.expand_dims(img_grey, axis=-1), (4, 4, 3)).copy()
>>> img_rgb[0, 0, 0] = 0.  # works!

This gives the rgb image its own memory space, which can be changed without altering the greyscale image. The OWNDATA and WRITEABLE flags are thus also set to True.