3

An advantage of plt.pcolormesh over plt.imshow is the possibility to have unequal axis spacing.

On the other hand, plt.imshow's advantage over plt.pcolormesh is that it can display RGB-triplets.

Now, the predicament I am in is that I need to plot RGB-triplets with uneven axis spacing....

Below is a MWE:

import numpy as np
import matplotlib.pyplot as plt
from colorsys import  hsv_to_rgb

square_x_axis = np.linspace(0,1,100)**2
cube_y_axis = np.linspace(0,1,200)**3

X,Y = np.meshgrid(cube_y_axis,square_x_axis); print(f'meshgrid has shape: {X.shape}')

rgb_array = np.zeros((square_x_axis.size, cube_y_axis.size,3)); print(f'rgb_array has shape: {rgb_array.shape}')
""" Now we populate the rgb array (initially in hsv color space for clarity)"""
for i,row in enumerate(rgb_array):
    for j,col in enumerate(row):
        rgb_array[i,j,:] = np.array(hsv_to_rgb(0,square_x_axis[i],cube_y_axis[j]))

fig = plt.figure(figsize=(15,10))
imshow_ax = plt.subplot(1,2,1)
imshow_ax.imshow(rgb_array, aspect='auto', extent=[0,1,0,1])
pcolor_R_ax = plt.subplot(3,2,2)
pcolor_R_ax.pcolormesh(X,Y,rgb_array[:,:,0], cmap='Reds')
pcolor_G_ax = plt.subplot(3,2,4)
pcolor_G_ax.pcolormesh(X,Y,rgb_array[:,:,1], cmap='Greens')
pcolor_B_ax = plt.subplot(3,2,6)
pcolor_B_ax.pcolormesh(X,Y,rgb_array[:,:,2], cmap='Blues')

Which produces the following figure:

enter image description here

The problem becomes immediately obvious: imshow (on the left) is capable of representing the 3D array, but its axis are scaled wrong, leading to a distorted representation. pcolormesh (on the right), on the other hand, can not represent the 3D array (hence why I plot all three channels separately), but is capable of applying the axis correctly, leading to no distortion.

How can I combine these properties?

  • Huh, I did not know this about `pcolormesh`. Can changing the `aspect` argument (and/or figure dimensions) not do what you want? That's how I usually solve this issue. – Matt Hall Sep 12 '22 at 22:05
  • @kwinkunks: pcolormesh has no `aspect` argument. imshow accepts `aspect`, but if the two axes greatly differ in number of points, the plot becomes unfeasible when `aspect='auto'` (substitute, for example, this line: `square_x_axis = np.linspace(0,1,10)**2`). I could supply a float, but that woudl still keep the pixels the same rectangular shape, when actually the rectangles should be changing size.... – Douglas James Bock Sep 12 '22 at 22:14
  • Right, I was thinking of changing `aspect` on `imshow` though. But nevermind, because I found something that seems to work! See below. Thanks for the education. – Matt Hall Sep 12 '22 at 22:22

2 Answers2

2

I found another answer here that seems to work on your example, with a small tweak for some new pcolorbesh behaviour (the shading='auto' bit). Try this plot on your data:

fig = plt.figure(figsize=(15,10))
placeholder = rgb_array[..., 0]
colors = rgb_array.reshape(-1, 3)
mesh = plt.pcolormesh(X, Y, placeholder, facecolors=colors, shading='auto')
mesh.set_array(None)

It produces:

Output of the code

Matt Hall
  • 7,614
  • 1
  • 23
  • 36
0

@kwinkunks answer is the method that solved my problem: The original data, using imshow, looked like this, where both the x- and y-axis of the data plot and the colorbar are wrong. Of all 4 axes, only the data y-axis is linear, the 3 other axes are non-linear, and so using imshows's extent option is no good:

enter image description here

Now... taking @kwinkunks answer directly produced the following plot:

enter image description here

...where the axes tickmarks are now as they should be! Amazing!