How to use set_clip_path() with multiple polygons?

Viewed 192

I'm trying to clip a cloud of points by several polygons, but I don't know if this is possible with plt.axis.set_clip_path().

Since set_clip_path() requires a Path or a Patch as arguments, how could you create a geometry formed by several Polygons? It would be something like a plt.MultiPolygon(), but that doesn't exist. I've tried to create a matplotlib.PatchCollection with all the Polygons, but that does not work.

Here is the desired goal (from upper to lower figure): enter image description here

Here is how I'd like the code to look like:

import matplotlib.pyplot as plt
from matplotlib.collections import PatchCollection
import numpy as np

fig, ax = plt.subplots()

points = np.array([np.random.random(100)*400,
                    np.random.random(100)*100]).T

A = plt.Polygon( np.array([( 0,   0),(50,100),(100,  0)]), color='w', ec='k' )
B = plt.Polygon( np.array([(120 ,  0),(170 , 100), (220,  0)]), color='w', ec='k'  )
C = plt.Polygon( np.array([(240 ,  0),(290 , 100), (340,  0)]), color='w', ec='k'  )

[ax.add_patch(i) for i in (A,B,C)]

ax.scatter(points[:,0], points[:,1], zorder=3).set_clip_path([A,B,C])
1 Answers

You can concatenate the vertices and the codes of all polygons, and use them to create a "compound path". Matplotlib's path tutorial contains an example creating a histogram from just one compound path.

import matplotlib.pyplot as plt
from matplotlib.path import Path
from matplotlib.patches import PathPatch
import numpy as np

points = np.array([np.random.random(100) * 400,
                   np.random.random(100) * 100]).T
A = plt.Polygon(np.array([(0, 0), (50, 100), (100, 0)]), color='w', ec='k')
B = plt.Polygon(np.array([(120, 0), (170, 100), (220, 0)]), color='w', ec='k')
C = plt.Polygon(np.array([(240, 0), (290, 100), (340, 0)]), color='w', ec='k')

fig, ax = plt.subplots()
all_polys = [A, B, C]
[ax.add_patch(i) for i in all_polys]
vertices = np.concatenate([i.get_path().vertices for i in all_polys])
codes = np.concatenate([i.get_path().codes for i in all_polys])

dots = ax.scatter(points[:, 0], points[:, 1], zorder=3)
dots.set_clip_path(PathPatch(Path(vertices, codes), transform=ax.transData))
plt.show()

clipping by multiple polygons

Related