 # Triangulations and Polar Plots

Greetings.

I recently found myself in the position of needing to plot polar, irregularly spaced data. I’ve done similar using regularly spaced values with no problem. However, I’ve found that when the points become greatly scattered, the triangulation does not translate from rectangular to polar very well. Below, find a code example that shows this; though it is much “better” than my real-world case that uses simulation results. Essentially, in the translation from regular to polar axes, many of the triangles overlap others, many features of the plot are lost, and the plot looks mangled in certain regions, esp. across the theta=0 boundary. While subtle here (but MUCH worse in the results I’m trying to visualize), some of the triangles lie outside of the triangulated region. It isn’t merely that the polar plot is suffering from poor data coverage; the triangulation is not working properly in polar coordinates and the results are quantitatively different than the rectangular plot.

The obvious work-around for this problem illustrates the issue more clearly. If we convert rad, theta back to x, y and do a rectangular plot, the triangulation is much better (not only is there no issue around theta=0, but there are no overlapping triangles), all of the details of the non-polar version are maintained, and the plot looks great. This is not the best solution, as polar plots in Matplotlib are quite elegant.

Any help here would be appreciated. It could be that triangulations are just not suited for polar plots; it could be that the theta=0 issue throws things off, etc; I’m just not sure. It would be perfect if I could use the polar axes in the end.

Thanks.

-dw

#!/usr/bin/env python

‘’’

Demonstrate troubles with polar plots and triangulations.

‘’’

import numpy as np

import matplotlib.pyplot as plt

# Regular grid:

angle=np.linspace(0, 2*np.pi, 20)

x=np.tile(angle,20)

y=np.repeat(angle,20)

z=np.cos(x)*np.sin(y)

# Irregular grid:

x_ir=2np.pinp.random.random(400)

y_ir=2np.pinp.random.random(400)

z_ir=np.cos(x_ir)*np.sin(y_ir)

f=plt.figure()

a1.tricontourf(x,y,z); a1.plot(x,y, ‘k+’)

a2.tricontourf(x,y,z); a2.plot(x,y, ‘k+’)

a2.triplot(x,y)

a3.tricontourf(x_ir,y_ir,z_ir); a3.plot(x_ir,y_ir, ‘k+’)

a4.tricontourf(x_ir,y_ir,z_ir); a4.plot(x_ir,y_ir, ‘k+’)

a4.triplot(x_ir,y_ir)

# “Fix” back to rectangular.

x=y_ir*np.cos(x_ir)

y=y_ir*np.sin(x_ir)

ax.tricontourf(x,y,z_ir)

ax.triplot(x,y)

Daniel,

I can’t give you much help but I can provide some explanation. If you don’t specify a triangulation of your own, the matplotlib tri* functions use lib/matplotlib/delaunay/triangulate as a black box. You are right in saying that it is not suited to polar plots; it assumes cartesian axes. The lib/matplotlib/tri/* functions use triangulations that comprise a number of triangles with vertices ordered in an anticlockwise manner. The delaunay triangulation returns such triangles on a cartesian grid. But if you transform a cartesian triangulation to a polar grid, you invariably end up with some triangles which are ordered clockwise and hence also overlap each other. Tricontour doesn’t like this and gives the best results it can given that is has been passed an incorrect triangulation, which from your point of view means the wrong results.

In addition, as you have noticed there are other problems around theta=0. In a polar plot points near theta=0 are visible both from the low and high theta ends of the plot, whereas in a cartesian plot they are only visible from one side unless you take steps to repeat such points so the wraparound works.

The answer, unfortunately, is to specify your own triangulation using the ‘triangles’ keyword in your calls to the tri* functions. I suspect that most people who regularly use the tri* functions obtain their triangulations from elsewhere rather than using the matplotlib delaunay code.

It should be possible to pass your polar coordinates to delaunay to obtain the triangulation in polar space, then use this triangulation in your tri* polar plots. However, I’ve tried it (albeit briefly) and it appears to hang the delaunay code.

An alternative may be to take a look at griddata (there is an example in matplotlib’s pylab_examples directory). It is difficult for me to recommend such an approach, however, as I wrote the tri* functions so that I wouldn’t have to use griddata!

Ian

···

On 15 November 2011 00:18, Daniel Welling <dantwelling@…287…> wrote:

Greetings.

I recently found myself in the position of needing to plot polar, irregularly spaced data. I’ve done similar using regularly spaced values with no problem. However, I’ve found that when the points become greatly scattered, the triangulation does not translate from rectangular to polar very well. Below, find a code example that shows this; though it is much “better” than my real-world case that uses simulation results. Essentially, in the translation from regular to polar axes, many of the triangles overlap others, many features of the plot are lost, and the plot looks mangled in certain regions, esp. across the theta=0 boundary. While subtle here (but MUCH worse in the results I’m trying to visualize), some of the triangles lie outside of the triangulated region. It isn’t merely that the polar plot is suffering from poor data coverage; the triangulation is not working properly in polar coordinates and the results are quantitatively different than the rectangular plot.

The obvious work-around for this problem illustrates the issue more clearly. If we convert rad, theta back to x, y and do a rectangular plot, the triangulation is much better (not only is there no issue around theta=0, but there are no overlapping triangles), all of the details of the non-polar version are maintained, and the plot looks great. This is not the best solution, as polar plots in Matplotlib are quite elegant.

Any help here would be appreciated. It could be that triangulations are just not suited for polar plots; it could be that the theta=0 issue throws things off, etc; I’m just not sure. It would be perfect if I could use the polar axes in the end.

Thanks.

-dw