9

I wanted to plot using imshow in a manner similar to the second example here http://www.scipy.org/Plotting_Tutorial but to redefine the scale for the axis. I'd also like the image to stay still while I do this!

The code from the example:

from scipy import *
from pylab import *

# Creating the grid of coordinates x,y 
x,y = ogrid[-1.:1.:.01, -1.:1.:.01]

z = 3*y*(3*x**2-y**2)/4 + .5*cos(6*pi * sqrt(x**2 +y**2) + arctan2(x,y))

hold(True)
# Creating image
imshow(z, origin='lower', extent=[-1,1,-1,1])

xlabel('x')
ylabel('y')
title('A spiral !')

# Adding a line plot slicing the z matrix just for fun. 
plot(x[:], z[50, :])

show()

If I modify the extent to be wider, eg:

imshow(z, origin='lower', extent=[-4,4,-1,1])

Then the resulting image is stretched. But all I wanted to do was change the ticks to coincide with my data. I know I can use pcolor to conserve the X and Y data, though that has other ramifications to it.

I found this answer which allows me to manually redo all the ticks:

How do I convert (or scale) axis values and redefine the tick frequency in matplotlib?

But that seems a bit overkill.

Is there a way to only change the extent shown by the labels?

Community
  • 1
  • 1
ubershmekel
  • 11,864
  • 10
  • 72
  • 89

2 Answers2

11

A help(imshow) will find the aspect argument, which after a bit of experimentation seems to give what you want (a square image of the spiral but with x scale from -4 to 4 and y from -1 to 1) when used like this:

imshow(z, origin='lower', extent=[-4,4,-1,1], aspect=4)

But now your plot is still from -1 to 1, so you'd have to modify that as well...

plot(x[:]*4, z[50, :])

I think when you have several elements that would have to be modified, just using a one-line tick relabeling instead isn't overkill:

xticks(xticks()[0], [str(t*4) for t in xticks()[0]])
weronika
  • 2,561
  • 2
  • 24
  • 30
  • Aspect is a good solution for my use case as I don't have a plot there. And you fix the xticks in a more elegant solution than mine. Thank you! – ubershmekel Jun 11 '12 at 06:30
0

I would advise against using the aspect keyword for this task, unlike the accepted answer. Let the image dictate the aspect ratio of your Axes, and simply multiply the extent of the image by a scaling factor. If you don't do that, you will be forced to scale all the subsequent artists you add.

The code snippet below shows the image with the default behavior: assigning 1 data unit to 1 pixel.

image:np.ndarray = ... # We will assume that you already loaded an image.

fig, ax = plt.subplots()
fig.show()
ax.imshow(image, cmap="gray", origin="lower")
ax.autoscale(False)
fig.canvas.draw()

This snippet scales the image.

SCALE = 5e-6/105

image:np.ndarray = ... # We will assume that you already loaded an image.

fig, ax = plt.subplots()
fig.show()
image_artist = ax.imshow(image, cmap="gray", origin="lower")
image_artist.set_extent(np.array(image_artist.get_extent())*SCALE)
ax.autoscale(False)
fig.canvas.draw()

enter image description here

Guimoute
  • 4,407
  • 3
  • 12
  • 28