Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
481 views
in Technique[技术] by (71.8m points)

python - Matplotlib set_clip_path requires patch to be plotted

I've just discovered a nice way to create a Matplotlib filled contour plot clipped to an arbitrary polygonal region. The method requires calling set_clip_path(patch) on each PathCollection instance in the QuadContourSet returned by Matplotlib's contourf() function. MWE:

import matplotlib.pyplot as plt
import numpy as np
import matplotlib.patches as mpatches
import matplotlib.path as mpath

# some arbitrary data to plot
xx, yy = np.meshgrid(np.linspace(-5, 5, 20), np.linspace(-10, 10, 20), copy=False)
zz = np.sqrt(xx ** 2 + yy ** 2)

poly_verts = [
    (0, 0),
    (-4, 7),
    (-4, -7),
    (4, -7),
    (4, 7),
    (0, 0)
]
poly_codes = [mpath.Path.MOVETO] + (len(poly_verts) - 2) * [mpath.Path.LINETO] +
mpath.Path.CLOSEPOLY]

# create a Path from the polygon vertices
path = mpath.Path(poly_verts, poly_codes)

# create a Patch from the path
patch = mpatches.PathPatch(path, facecolor='none', edgecolor='k')

plt.figure()
ax = plt.gca()
cont = plt.contourf(xx, yy, zz, 50)

# add the patch to the axes
ax.add_patch(patch)  ## TRY COMMENTING THIS OUT
for col in cont.collections:
    col.set_clip_path(patch)

plt.show()

Resulting plot

I'm confused about one aspect: if I comment out the line that plots the patch, then none of the clipping works and I end up with a blank plot. I presume that when calling the set_clip_path method with a patch on the PathCollection, the patch must have been added to the axes, but I don't understand why. Setting edgecolor='none' for patch creation is a fine workaround, but where's the fun in that?

Any thoughts?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

If the patch is not added to the axes, is cannot know according to which transform it should be handled. By adding it to the axes, you implicitely set the transform to the data transformation of the axes it is added to.
I guess this necessity becomes clear if you imagine to have several axes on a figure. Then the mpatches.PathPatch could potentially be used for any of those axes.

You may indeed set the patch invisible by setting the face- and edgecolor to "none"

patch = mpatches.PathPatch(path, facecolor='none', edgecolor='none')

or turning it invisible alltogether,

patch = mpatches.PathPatch(path, visible=False)

In case you really want to get rid of adding the patch to the axes, you may set the required transform manually

patch = mpatches.PathPatch(path, transform=ax.transData)

for col in cont.collections:
    col.set_clip_path(patch)

In this case there would not be any need to add it to the axes.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...