Clipping Contours

I'm interested in clipping the result of plt.contour (and
plt.contourf) to a patch. However, QuadContourSet does not have a
set_clip_path() method. Is there a way to do this?

Here is an example plot that I have generated.

   http://imgur.com/pybIf

For the curious, it plots contours of a function on the 2-simplex.
The way I've gone about computing this is, unfortunately, convoluted.
I generate a regular grid in 2D and treat each point as a projection
of a 3D probability vector into 2D. Then, I invert the projection so
that I have "distributions" and then compute the Z value for each
point. The contours are then calculated, but now, I need to clip
everything outside the triangle, as only points within the triangle
correspond to actual distributions.

Is there a more direct way to calculate contours on a restricted set?

Thanks.

The contour functions support masked regions. I think that might be
what you're looking for. Since the region you want to mask is a
triangle, maybe even use a masked triangulated contour plot? Here's
the call signature:
http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.tricontour

Does that help?

···

On Tue, Oct 16, 2012 at 8:04 AM, T J <tjhnson@...287...> wrote:

I'm interested in clipping the result of plt.contour (and
plt.contourf) to a patch. However, QuadContourSet does not have a
set_clip_path() method. Is there a way to do this?

Here is an example plot that I have generated.

   http://imgur.com/pybIf

For the curious, it plots contours of a function on the 2-simplex.
The way I've gone about computing this is, unfortunately, convoluted.
I generate a regular grid in 2D and treat each point as a projection
of a 3D probability vector into 2D. Then, I invert the projection so
that I have "distributions" and then compute the Z value for each
point. The contours are then calculated, but now, I need to clip
everything outside the triangle, as only points within the triangle
correspond to actual distributions.

Is there a more direct way to calculate contours on a restricted set?

Thanks.

--
Damon McDougall
http://www.damon-is-a-geek.com
B2.39
Mathematics Institute
University of Warwick
Coventry
West Midlands
CV4 7AL
United Kingdom

Yes, that looks to be exactly what I am looking for. Note, the mask
kwarg is barely mentioned in that docstring, but I think I get it.
However, I am having some trouble. tricontour seems to fail when
computing the Triangulation() object. Here is my code:

http://codepad.org/cVB7YP9r

This is a set of 152 points on a triangle. delaunay is mentioned to
have problems for some pathological cases. Is a complete triangular
grid considered as such a case?

Code is shown below as well.

···

On Tue, Oct 16, 2012 at 2:34 AM, Damon McDougall <damon.mcdougall@...287...> wrote:

On Tue, Oct 16, 2012 at 8:04 AM, T J <tjhnson@...287...> wrote:

I'm interested in clipping the result of plt.contour (and
plt.contourf) to a patch. However, QuadContourSet does not have a
set_clip_path() method. Is there a way to do this?

Here is an example plot that I have generated.

   http://imgur.com/pybIf

For the curious, it plots contours of a function on the 2-simplex.
The way I've gone about computing this is, unfortunately, convoluted.
I generate a regular grid in 2D and treat each point as a projection
of a 3D probability vector into 2D. Then, I invert the projection so
that I have "distributions" and then compute the Z value for each
point. The contours are then calculated, but now, I need to clip
everything outside the triangle, as only points within the triangle
correspond to actual distributions.

Is there a more direct way to calculate contours on a restricted set?

Thanks.

The contour functions support masked regions. I think that might be
what you're looking for. Since the region you want to mask is a
triangle, maybe even use a masked triangulated contour plot? Here's
the call signature:
http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.tricontour

Does that help?

------------

import numpy as np
import matplotlib.pyplot as plt

points = np.array([
[0.8660254037844384, -0.5000000000000004],
[0.7577722283113836, -0.5000000000000004],
[0.6495190528383288, -0.5000000000000003],
[0.5412658773652739, -0.5000000000000003],
[0.4330127018922191, -0.5000000000000002],
[0.3247595264191642, -0.5000000000000002],
[0.21650635094610943, -0.5000000000000002],
[0.10825317547305463, -0.5000000000000001],
[-2.220446049250313e-16, -0.5000000000000001],
[-0.10825317547305507, -0.5],
[-0.21650635094610993, -0.5],
[-0.32475952641916467, -0.5],
[-0.4330127018922195, -0.4999999999999999],
[-0.5412658773652743, -0.4999999999999999],
[-0.6495190528383291, -0.49999999999999983],
[-0.7577722283113839, -0.4999999999999998],
[-0.8660254037844388, -0.4999999999999997],
[0.811898816047911, -0.40625000000000044],
[0.7036456405748561, -0.4062500000000004],
[0.5953924651018013, -0.40625000000000033],
[0.48713928962874653, -0.4062500000000003],
[0.3788861141556917, -0.4062500000000002],
[0.2706329386826369, -0.4062500000000002],
[0.16237976320958203, -0.4062500000000001],
[0.05412658773652723, -0.4062500000000001],
[-0.05412658773652762, -0.40625000000000006],
[-0.16237976320958242, -0.40625],
[-0.2706329386826372, -0.40625],
[-0.37888611415569207, -0.40624999999999994],
[-0.4871392896287469, -0.4062499999999999],
[-0.5953924651018018, -0.40624999999999983],
[-0.7036456405748566, -0.4062499999999998],
[-0.8118988160479114, -0.4062499999999997],
[0.7577722283113836, -0.3125000000000004],
[0.6495190528383288, -0.31250000000000033],
[0.541265877365274, -0.31250000000000033],
[0.4330127018922191, -0.3125000000000002],
[0.3247595264191643, -0.3125000000000002],
[0.21650635094610948, -0.31250000000000017],
[0.10825317547305463, -0.3125000000000001],
[-1.6653345369377348e-16, -0.31250000000000006],
[-0.10825317547305502, -0.3125],
[-0.21650635094610982, -0.3125],
[-0.3247595264191646, -0.31249999999999994],
[-0.43301270189221946, -0.3124999999999999],
[-0.5412658773652743, -0.31249999999999983],
[-0.6495190528383292, -0.3124999999999998],
[-0.7577722283113839, -0.3124999999999998],
[0.7036456405748562, -0.21875000000000036],
[0.5953924651018013, -0.2187500000000003],
[0.48713928962874653, -0.21875000000000028],
[0.37888611415569173, -0.21875000000000022],
[0.2706329386826369, -0.21875000000000017],
[0.16237976320958208, -0.21875000000000014],
[0.05412658773652723, -0.21875000000000008],
[-0.054126587736527565, -0.21875000000000006],
[-0.16237976320958242, -0.21875],
[-0.2706329386826372, -0.21874999999999994],
[-0.378886114155692, -0.21874999999999992],
[-0.48713928962874686, -0.21874999999999986],
[-0.5953924651018017, -0.2187499999999998],
[-0.7036456405748566, -0.21874999999999978],
[0.6495190528383288, -0.12500000000000033],
[0.541265877365274, -0.12500000000000028],
[0.43301270189221913, -0.12500000000000025],
[0.32475952641916433, -0.1250000000000002],
[0.2165063509461095, -0.12500000000000017],
[0.10825317547305469, -0.1250000000000001],
[-1.6653345369377348e-16, -0.12500000000000006],
[-0.10825317547305496, -0.125],
[-0.21650635094610982, -0.12499999999999997],
[-0.3247595264191646, -0.12499999999999993],
[-0.4330127018922194, -0.12499999999999989],
[-0.5412658773652743, -0.12499999999999983],
[-0.6495190528383291, -0.12499999999999979],
[0.5953924651018014, -0.031250000000000305],
[0.4871392896287466, -0.03125000000000028],
[0.37888611415569173, -0.031250000000000194],
[0.27063293868263694, -0.03125000000000017],
[0.1623797632095821, -0.03125000000000014],
[0.05412658773652729, -0.03125000000000008],
[-0.054126587736527565, -0.03125000000000003],
[-0.16237976320958236, -0.031249999999999986],
[-0.2706329386826372, -0.031249999999999944],
[-0.378886114155692, -0.031249999999999903],
[-0.4871392896287468, -0.031249999999999854],
[-0.5953924651018017, -0.03124999999999981],
[0.541265877365274, 0.06249999999999972],
[0.4330127018922192, 0.06249999999999975],
[0.3247595264191644, 0.06249999999999983],
[0.21650635094610954, 0.06249999999999986],
[0.10825317547305471, 0.06249999999999989],
[-1.1102230246251565e-16, 0.062499999999999944],
[-0.10825317547305496, 0.0625],
[-0.21650635094610976, 0.06250000000000003],
[-0.3247595264191646, 0.06250000000000008],
[-0.4330127018922194, 0.06250000000000012],
[-0.5412658773652742, 0.06250000000000017],
[0.4871392896287466, 0.15624999999999975],
[0.3788861141556918, 0.15624999999999978],
[0.27063293868263694, 0.15624999999999986],
[0.16237976320958214, 0.1562499999999999],
[0.054126587736527315, 0.15624999999999992],
[-0.05412658773652751, 0.15625],
[-0.16237976320958236, 0.15625000000000003],
[-0.27063293868263716, 0.15625000000000006],
[-0.378886114155692, 0.1562500000000001],
[-0.4871392896287468, 0.15625000000000017],
[0.43301270189221924, 0.24999999999999978],
[0.3247595264191644, 0.2499999999999998],
[0.21650635094610957, 0.2499999999999999],
[0.10825317547305474, 0.24999999999999992],
[-8.326672684688674e-17, 0.24999999999999994],
[-0.10825317547305491, 0.25],
[-0.2165063509461097, 0.25000000000000006],
[-0.32475952641916456, 0.2500000000000001],
[-0.43301270189221935, 0.2500000000000001],
[0.37888611415569184, 0.3437499999999998],
[0.270632938682637, 0.34374999999999983],
[0.16237976320958217, 0.3437499999999999],
[0.05412658773652734, 0.34374999999999994],
[-0.05412658773652748, 0.34375],
[-0.1623797632095823, 0.34375000000000006],
[-0.2706329386826371, 0.3437500000000001],
[-0.37888611415569196, 0.3437500000000001],
[0.32475952641916445, 0.43749999999999983],
[0.2165063509461096, 0.4374999999999999],
[0.10825317547305478, 0.4374999999999999],
[-5.551115123125783e-17, 0.4374999999999999],
[-0.10825317547305488, 0.43750000000000006],
[-0.2165063509461097, 0.4375000000000001],
[-0.3247595264191645, 0.4375000000000001],
[0.27063293868263705, 0.5312499999999999],
[0.1623797632095822, 0.5312499999999999],
[0.054126587736527385, 0.5312499999999999],
[-0.054126587736527426, 0.53125],
[-0.16237976320958225, 0.5312500000000001],
[-0.2706329386826371, 0.5312500000000001],
[0.21650635094610965, 0.6249999999999999],
[0.10825317547305482, 0.6249999999999999],
[-1.3877787807814457e-17, 0.625],
[-0.10825317547305482, 0.625],
[-0.21650635094610965, 0.6250000000000001],
[0.16237976320958225, 0.7187499999999999],
[0.05412658773652742, 0.71875],
[-0.0541265877365274, 0.71875],
[-0.16237976320958222, 0.71875],
[0.10825317547305485, 0.8125],
[2.7755575615628914e-17, 0.8125],
[-0.1082531754730548, 0.8125],
[0.054126587736527454, 0.90625],
[-0.05412658773652737, 0.90625],
[6.123233995736766e-17, 1.0]])

def test1(x=None):
    # Failure for x > 23
    slc = slice(None,x,None)
    plt.scatter(points[slc,0], points[slc,1])
    matplotlib.delaunay.Triangulation(points[slc,0], points[slc,1])

def test2(x=None):
    # Randomizing the rows seems to have no effect
    # Failure for x > 23
    slc = slice(None,x,None)
    idx = np.arange(points.shape[0])
    np.random.shuffle(idx)
    points2 = np.array([points[i] for i in idx])
    plt.scatter(points2[slc,0], points2[slc,1])
    matplotlib.delaunay.Triangulation(points[slc,0], points[slc,1])

if __name__ == '__main__':
    test2()
    #test2(22)

Yes, under certain circumstances! delaunay is not ‘geometrically robust’, meaning it doesn’t take into account machine precision errors when deciding if a point is on one side of a line or not or inside a circle or not, which can result in errors leading to the algorithm failing. It sounds like this should be an easy problem to solve but it isn’t.

In your example the y-values that presumably should be in a straight line about y=-0.5 feature variations at about the 16th decimal place that are causing the algorithm to fail. If these variations were much larger or much smaller, the algorithm would probably work. The first time the failure occurs is at the 20th point, which you can see if you add a call to something like

plt.tripcolor(x, y, np.zeros_like(x), alpha=0.5)

The darker blue colour shows two triangles overlapping, which shouldn’t happen.

You have a number of options:

  1. Round your x and y values to a smaller number of decimal places, e.g.

    x = x.round(8)
    y = y.round(8)
    On my machine 8 decimal places is good, 10 isn’t.

  2. Add extra noise to your point positions, which is the classic way to get around this delaunay limitation, e.g.

    x = x + 1e-6*np.random.rand(len(x))

    y = y + 1e-6*np.random.rand(len(x))

  3. Specify the triangulation yourself, which is usually pretty easy for regular cases like yours. See tricontour_demo.py for an example of how to specify a triangulation in your tri* function calls.

I hope this helps,

Ian

···

On 16 October 2012 18:44, T J <tjhnson@…1896…> wrote:

This is a set of 152 points on a triangle. delaunay is mentioned to

have problems for some pathological cases. Is a complete triangular

grid considered as such a case?

QuadContourSet does not (I think it should), but LineCollection
instances in QuadContourSet.collections does. Below is a quick
example.

import matplotlib.pyplot as plt
import numpy as np

x = np.arange(100)-50
arr = (x**2 + x[:,np.newaxis]**2)**.5
cont = plt.contour(arr)
col1 = cont.collections[3] # contour line to clip with.
clip_path = col1.get_paths()[0] # Note that col1 may have multiple paths.
for col in cont.collections:
    col.set_clip_path(clip_path, col1.get_transform()) # set clip_path
for individual LineCollection instances.

plt.show()

···

On Tue, Oct 16, 2012 at 4:04 PM, T J <tjhnson@...287...> wrote:

I'm interested in clipping the result of plt.contour (and
plt.contourf) to a patch. However, QuadContourSet does not have a
set_clip_path() method. Is there a way to do this?