0

I have a 2-d array that I want to display as an image. The dimensions being Y x X(log tau vs arcsec).

The issue is the y axis (log tau) is not evenly sampled. The range of the y-axis is [1.17, -8], but there few points between 1.17 to -4 and more points between -4 and -8. Hence, using the directly imshow method will plot 1.17 to -4 in less (1/3 in my case) space and -4 to -8 more space (2/3).

As you can see in the below code, the y-ticks are uneven according to data. I want to plot a uniform linear scale on the y-axis as well.

I want some code suggestion here to squeeze/stretch points in the y-axis such that, y-ticks are equidistant.

My code:

## The shape of data is (log tau, arcsec) is (150, 50).
plt.imshow(data, cmap='gray', origin='lower')
plt.xticks([10, 20, 30, 40], [623.5, 623.87, 624.25, 624.63], rotation=45)
plt.yticks([50, 106, 124, 131], [-6, -4, -2, -1]) ## want some code suggestion here to squeeze / stretch points in y-axis such that, y-ticks are equidistant.
plt.gca().set_aspect(1.0 / plt.gca().get_data_ratio(), adjustable='box') ## to make square plot
plt.colorbar()
plt.show()
Harsh M
  • 625
  • 2
  • 11
  • 25

1 Answers1

0

For uneven data, you can replace imshow() with pcolor() (or pcolormesh()). pcolor() accepts arrays of x and of y-positions as parameters. These positions mark the borders of each cell. Note that in each direction there will be one border more than the number of values in the 2D data (so 51 x-positions and 151 y-positions for 150x50 data).

Here is some example code:

from matplotlib import pyplot as plt
import numpy as np

tau = np.linspace(*np.power(10, [-8, 1.17]), 151)
y = np.log(tau)
x = np.linspace(623.12, 625, 51)
data = np.random.rand(150, 50)
plt.pcolor(x, y, data, cmap='inferno')
plt.show()

Note that tau can also be used directly, with the y-axis rescaled to log-space. In any case, the ticks will be displayed as with a regular plot. Diverse locators and/or formatters can be applied.

plt.pcolor(x, tau, data, cmap='inferno')
plt.yscale('log')

uneven spacing

JohanC
  • 71,591
  • 8
  • 33
  • 66
  • Although your solution works, I am still looking for an imshow type of solution where I do not have to give extra points in X/Y. I came across a Non-Uniform image, however, after following the example given on the matplotlib page, I was not able to get it working, I have edited my question to include this code. I am grateful for your help :) – Harsh M Apr 08 '21 at 10:37
  • You might want to have a look at creating voronoi polygons around your points. Note that the code can look somewhat complex. E.g. [Colorize Voronoi Diagram](https://stackoverflow.com/questions/20515554/colorize-voronoi-diagram) and [How to color voronoi according to a color scale ?](https://stackoverflow.com/questions/41244322/how-to-color-voronoi-according-to-a-color-scale-and-the-area-of-each-cell) and the posts linked from there. – JohanC Apr 08 '21 at 10:54
  • I saw the Voronoi polygons, But I doubt my case is creating polygons, it is simply displaying image with equally spaced axes and a vertically decreasing y-axis. Do you have any suggestions regarding NonUniformImage code given above? – Harsh M Apr 08 '21 at 12:54
  • Apparently its a bug in matplotlib, Hence pcolormesh with shading=nearest is the solution I want. Thanks – Harsh M Apr 09 '21 at 07:28