1

I'm wondering if I could "scale" a image input to be plotted to a range in the plot. To be more clear, this is what I need:

I have a 400 * 400 image that is generated based on a function which interval is -1..1. So, I do a translate to save this data, like this:

x = Utils.translate(pos_x, 0, self.width, -1, 1)
y = Utils.translate(pos_y, 0, self.height, -1, 1)
data = Utils.map_position_to_function(x, y)

I.e, first I map its position to my range and then I calculate de f(x, y) based on this "new position" and save the data.

The problem is that, later, I have to represent the image contour in the function range. So, I have an image, 400 * 400, that I have to represent in a plot which range is -1..1.

This works pretty well:

import pylab as plt

im = plt.array(Image.open('Mean.png').convert('L'))
plt.figure()
plt.contour(im, origin='image')
plt.axis('equal')

But I couldn't find a way to have the x/y axes in the range -1..1

I tried this:

row = np.linspace(-1,1,0.25)
X,Y = np.meshgrid(row,row)
Z = plt.array(Image.open('Mean.png').convert('L'))
plt.contour(X,Y,Z)

But it doesn't works, and it makes senses to not work, but I don't know how could I do what I want. I have the information about the data in this image, so I also tried to do something like these two approaches:

# 1
plt.figure()
row = np.linspace(-1,1,0.25)
X,Y = np.meshgrid(row,row)
Z = ImageMedia[Utils.translate(X, 400, 400, -1, 1), Utils.translate(Y, 400, 400, -1, 1)]
plt.contour(X,Y,Z)

# 2
im = plt.array(Image.open('Mean.png').convert('L'))
plt.figure()
plt.contour(im, origin='image')
v = [-1, 1, -1, 1]
plt.axis(v)

Which don't work either.

Any help would be much appreciated. Thanks.

pceccon
  • 9,379
  • 26
  • 82
  • 158

2 Answers2

0

You can do this simpily using the extent kwarg:

im = ax.imshow(data, ..., extent=[-1, 1, -1, 1])

(doc) It will also work with contour, contourf ect.

for example:

fig, ax2 = plt.subplots(1, 1)

im = rand(400, 400)
ax2.imshow(im, interpolation='none', extent=[-1, 1, -1, 1])

enter image description here

An alternate way to deal with this is, if you really don't want to use extent and make your life easier is to hi-jack the formatter to insert a scaling factor:

from matplotlib.ticker import FuncFormatter

fig, ax2 = plt.subplots(1, 1)

im = rand(400, 400)
ax2.imshow(im, interpolation='none', origin='bottom')

nbins = 5
scale_factor = .5
form_fun = lambda x, i, scale_factor=scale_factor: '{:.3f}'.format(scale_factor * x)
ax2.get_xaxis().set_major_formatter(FuncFormatter(form_fun))
ax2.get_yaxis().set_major_formatter(FuncFormatter(form_fun))
ax2.get_xaxis().get_major_locator().set_params(nbins=nbins)
ax2.get_yaxis().get_major_locator().set_params(nbins=nbins)

enter image description here

tacaswell
  • 84,579
  • 22
  • 210
  • 199
  • Yeah, I guess I'm too noob, I coudn't figure out how to fit this in my code. I also edited my question with a last doubt in the end. Could you read it? (: Thanks a lot! – pceccon Sep 13 '13 at 19:04
  • If you have additional questions, please open a new question. – tacaswell Sep 13 '13 at 19:08
  • Now I got what did you mean! Thanks! – pceccon Sep 13 '13 at 19:19
  • Hi, @tcaswell. Sorry to come back here, but I made another similar question (http://stackoverflow.com/questions/18817110/plot-3d-contour-from-an-image-using-extent-with-matplotlib), and, as is similar, I though you could know the answer... Thanks. – pceccon Sep 15 '13 at 22:33
-1

I actually wrote a code to do something similar myself because it has implications for a lot of science apps. I happened to be tweaking that code while checking stackoverflow for something else, so it's your lucky day.... below is a function that plots an image with appropriate tick marks on the axes.

def plotmap(mapx, mapy, mymap,flipx=False, nt=4):
   '''plots a map (mymap) with specified axes (mapx, mapy) and number of ticks (nt)'''
   nx=len(mapx)
   ny=len(mapy)

   mymap=mymap[:,::-1] #flip y axis (make start from lower left, rather than upper)
   if(flipx): #flip x-axis (useful in some applications (e.g. west longitude))
     mymap=mymap[::-1,:]

   pl.imshow(mymap.transpose()) #plot an image map.. but contour could work too
   pl.colorbar()
   if(flipx):
     mapx=mapx[::-1]
   myxticks=pl.arange(mapx[0],mapx[-1], (mapx[-1]-mapx[0])/nt) #picks appropriate tick marks
   myyticks=pl.arange(mapy[-1],mapy[0], -(mapy[-1]-mapy[0])/nt)
   for i in range(nt):
     myxticks[i]=round(myxticks[i],3) #makes the ticks pretty by lopping off insignificant figures
     myyticks[i]=round(myyticks[i],3)
   pl.xticks(range(0, nx, nx/nt), myxticks) #plots ticks at corresponding coordinates
   pl.yticks(range(0, ny, ny/nt), myyticks)

This would plot an image, it would be fairly trivial for you then to use contour(im) after running this function to overlay contours on to a properly axisified map, although you have to be careful about the axis to make sure they're flipped in the ways that you want them....

Paul R
  • 319
  • 2
  • 5
  • gah, you are re-inventing the wheel(s)! – tacaswell Sep 13 '13 at 18:47
  • see `origin` kwarg for flipping the image. And you really should be using `Formatter` and `Locator` classes for setting the tick locations. The do _all_ of this work for you. – tacaswell Sep 13 '13 at 18:51
  • it's part of a larger code that does many more things, but thank you for your answer to the question and the comments. I was not aware of those parameters.... and the extent will help (origin less so, still need to transpose to get image to work like I want). – Paul R Sep 13 '13 at 19:02
  • also, your method produces a different result where the image becomes extent x extent instead of index by index, which may or may not be what people were intending. – Paul R Sep 13 '13 at 19:11
  • I don't under stand what you mean by index x index. There are some subtlies with where the center of pixels are, but that can be fixed with proper +/- delta on your limits (the extents are the location of the _edges_ not the centers) – tacaswell Sep 13 '13 at 19:13
  • So say I do `imshow(image, extent=[-1,1,-1,1])` Then the size of the image is 2x2. If done with my implementation the size of the image is 400x400. Which can be relevant depending on what else you're doing with the plot. – Paul R Sep 13 '13 at 19:21
  • If you are plotting anything else on top of this graph (where you make use of `xticks`) then that is terrifying as the connection between the data and tick labels is now arbitrary and (in my view, which is admittedly a bit extreme) bordering on falsifying data. You either transform _all_ of your data or none of it. – tacaswell Sep 13 '13 at 19:30
  • It's not arbitrary at all -- sometimes you do calculations in real coordinates, sometimes in array coordinates (indices). Your method is better for most situations (using real coordinates), as I said, but its important to understand exactly what `extent` does. – Paul R Sep 13 '13 at 19:50
  • Or, for instance, if you're plotting data that's logarithmic or in any way doesn't use regularly sized bins, you have to disconnect the two... – Paul R Sep 13 '13 at 20:01
  • `pcolormesh` can deal with un-even boxes, and if you are using logarithmic bins, you can use a logarithmic scale on the axes. – tacaswell Sep 13 '13 at 20:03
  • if you do `plot([1], [1], 'o')` you should get a point at (1, 1) on your graph, using this method that is no longer true because there is no longer a mapping, at the mpl level, between the data coordinates and the tick labels. – tacaswell Sep 13 '13 at 20:15
  • see edits to my answer that I think replicate 90% of what your code does at the mpl level. – tacaswell Sep 13 '13 at 20:40