Search code examples
pythonmatplotlibcoordinate-transformationpolar-coordinates

Python - Coordinate transformation with polar scatter plot in matplotlib


I have to associate an HTML clickable map on some polar plots generated with matplotlib, so I need a method to convert the Data coordinates to the pixel coordinates of the figure.

The code, adapted from How to get pixel coordinates for Matplotlib-generated scatterplot?, is:

# Creates 6 points on a ray of the polar plot
fig, ax = plt.subplots(subplot_kw=dict(projection='polar'))
points, = ax.plot([1,1,1,1,1,1],[0,1,2,3,4,5], 'ro')
ax.set_rmax(5)

x, y = points.get_data()
xy_pixels = ax.transData.transform(np.vstack([x,y]).T)
xpix, ypix = xy_pixels.T
width, height = fig.canvas.get_width_height()
ypix = height - ypix

for xp, yp in zip(xpix, ypix):
    print('{x:0.2f}\t{y:0.2f}'.format(x=xp, y=yp))

which gives

328.00  240.00
354.80  207.69
381.60  175.38
408.40  143.06
435.20  110.75
461.99  78.44

Only the first point, placed in the center of the graph, is correct. The other ones appear to be shifted, as if the figure were stretched horizontally. This figure represents the points as drawn by matplotlib (red) and the ones I drew following the coordinates:

Difference between the plotted points and the Figure coordinates I get

What could be going on? Thanks for your help!

Update 03 Aug 2017

The "stretching" is even weirder: I tried to plot an octahedron inscribed in a circle of radius 3 with this command:

points, = ax.plot([math.pi/4,math.pi/2,3*math.pi/4,math.pi,5*math.pi/4,3*math.pi/2,7*math.pi/4,2*math.pi],[3,3,3,3,3,3,3,3], 'ro')

and the same routine gave as a result

495.01  110.70
328.00  57.14
160.99  110.70
91.81   240.00
160.99  369.30
328.00  422.86
495.01  369.30
564.19  240.00

While the 4 points along the x and y axes are placed correctly, the other 4 corresponding to i*pi/2 + pi/4 angles (where i=0,1,2,3) suffer from the "stretching". Indeed this can be seen even by looking at their coordinates: for i=0,2,4,6 it should be true that |x[(i+4)%8]-x[i]| = |y[(i+4)%8]-y[i]|, while this does not appear to be the case.


Solution

  • This is a very tricky problem, turns out it's already been solved here:

    Inconsistent figure coordinates in matplotlib with equal aspect ratio

    The problem is that when setting the aspect to equal the dimensions and positions of the axes can only be determined by matplotlib once something is drawn onto the canvas. Before plotting the data, it cannot know where the axes would reside in the final figure.

    The easiest solution is to call

    fig.canvas.draw()
    

    right after the plot command but before doing any transformation works. In this way, the figure gets drawn to the canvas, applying the equal aspect; and from this point on, the correct transformations are available.