2

I have a RGBA array (img) with 2D x and y like this:

import numpy as np
import matplotlib.pyplot as plt

np.random.seed(100)

x = np.arange(10, 20)
y = np.arange(0, 10)
x, y = np.meshgrid(x, y)

img = np.random.randint(low=0, high=255, size=(10, 10, 4))

According to this question, we can pass any array to plot and set the color using img:

fig, axs = plt.subplots()
axs.pcolormesh(x, y, img[:, :,0], color=img.reshape((img.shape[0]*img.shape[1]), 4)/255)

However, it just changed the edgecolors.

edge_color

I want to show it like axs.imshow(img)

imshow

zxdawn
  • 825
  • 1
  • 9
  • 19
  • I don’t think you can specify rgba with pcolormesh. Is there a reason you don’t want to use imshow? Perhaps consider using the extent kwargs. . – Jody Klymak Dec 31 '21 at 11:26
  • @JodyKlymak It seems the extent for `imshow` only supports `xmin, xmax, ymin, and ymax`. If the space of x and y isn't equal, it will not work. – zxdawn Dec 31 '21 at 12:38

2 Answers2

4

Update: here is the completed example code given the trick you found to impede the assignment of the colormapped colors.

import numpy as np
import matplotlib.pyplot as plt

np.random.seed(100)

x = np.arange(10, 21)
y = np.arange(0, 11)
x, y = np.meshgrid(x, y)

img = np.random.randint(low=0, high=255, size=(10, 10, 4))

fig, ax = plt.subplots()
mesh = ax.pcolormesh(x, y, img[:, :,0], facecolors=img.reshape(-1, 4)/255)
# This is necessary to let the `color` argument determine the color
mesh.set_array(None)
plt.show()

pcolormesh with changed colors

PS: Also note that img.reshape(-1, 4) is a shortcut (and more maintainable) version of img.reshape(img.shape[0]*img.shape[1], 4).

Also note that the x and y refer to the borders between the cells, and there need to be one value more than the number of cells in each dimension. Therefore, I incremented np.arange(10, 20) to np.arange(10, 21), but if you want 10..19 as centers, you need to subtract 0.5 for the position of the border (as e.g. np.arange(10, 21) - 0.5).

As commented by Jody Klymak, it's recommended not to use color which refers to both facecolor and edgecolor. As the edges are overlapping with their neighbors, some strange effects are visible when transparency comes into play.

JohanC
  • 71,591
  • 8
  • 33
  • 66
  • @JohanC Strange. What's the version of your matplotlib? It doesn't work for 3.5.0 which still shows the viridis color. Or do I have to use some specific backend of matplotlib? – zxdawn Dec 31 '21 at 12:43
  • I'm running in an interactive PyCharm environment with matplotlib 3.4.3 – JohanC Dec 31 '21 at 12:49
  • Thanks. I have tested the same version with Qt5Agg and TkAgg in Linux terminal. I still got the viridis image ... @JodyKlymak any idea? – zxdawn Dec 31 '21 at 12:56
  • 1
    I find another method. See [here](https://stackoverflow.com/a/49630831/7347925). `m.set_array(None)` can show the correct image. – zxdawn Dec 31 '21 at 21:18
  • 1
    This definitely works. Future readers should be aware that this seems to be undefined behaviour though, and could change in future versions. Probably the best bet is to open a feature request on GitHub to have a proper API for this. – Jody Klymak Jan 02 '22 at 08:07
  • 2
    As of 3.7 this workaround is no longer needed. See [below](https://stackoverflow.com/a/75950850/3394386) – Jody Klymak Jun 16 '23 at 16:42
2

Since Matplotlib v3.7, the RGB(A) array can be passed directly. https://matplotlib.org/stable/users/prev_whats_new/whats_new_3.7.0.html#pcolormesh-accepts-rgb-a-colors

import numpy as np
import matplotlib.pyplot as plt

np.random.seed(100)

x = np.arange(10, 20)
y = np.arange(0, 10)
x, y = np.meshgrid(x, y)

img = np.random.randint(low=0, high=255, size=(10, 10, 4)) / 255

fig, axs = plt.subplots()
axs.pcolormesh(x, y, img)
plt.show()

Edit: note I converted the img array to float, as the original array gave me

ValueError: Image RGB array must be uint8 or floating point; found int64

enter image description here

RuthC
  • 1,269
  • 1
  • 10
  • 21