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
815 views
in Technique[技术] by (71.8m points)

python - How to nicely plot clipped layered artists in matplotlib?

Consider that you have three artists in a matplotlib plot. What is the easiest way to not show the intermediate-level artist in the bbox of the top-level artist while retaining the low-level artist visible throughout the whole area?

Illustration of what I want to achieve:

Illustration of layered clipping

It there was no requirement of being able to see the lowest level a non-transparent facecolor of the toplevel plot would be enough. This does not work with the three levels as then the both of the lower levels would be concealed.

See this IPython notebook for a solution using shapely. Here is a not yet completely functional pure matplotlib example, but I'm hoping there is a simpler way of getting the same result that I have not thought of yet.

import numpy as np
import matplotlib.pyplot as plt
from matplotlib import patches, cm
from matplotlib.path import Path
fig, ax = plt.subplots()
imdata = np.random.randn(10, 10)
ax.imshow(imdata, extent=(0, 1, 0, 1), aspect='auto', cmap=cm.coolwarm)
text = ax.text(0.5, 0.5, 'Text', fontsize='xx-large', fontweight='bold',
               color='k', ha='center', va='center')
renderer = fig.canvas.get_renderer()
bbox = text.get_window_extent(renderer).transformed(ax.transData.inverted())
bboxrect = patches.Rectangle((bbox.x0, bbox.y0), bbox.width, bbox.height)
bbpath = bboxrect.get_path().transformed(bboxrect.get_patch_transform())
patch = patches.Rectangle((0.3, 0.3), 0.4, 0.4)
path = patch.get_path().transformed(patch.get_patch_transform())
path = Path.make_compound_path(path, bbpath)
patch = patches.PathPatch(path, facecolor='none', hatch=r'//')
ax.add_patch(patch)
See Question&Answers more detail:os

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

1 Reply

0 votes
by (71.8m points)

I came up with another answer that's a bit cleaner: it involves creating a clip mask for the hatched region that has a hole in it, so that you can see everything in the background behind it.

from matplotlib.path import Path
from matplotlib.patches import PathPatch

def DoubleRect(xy1, width1, height1,
               xy2, width2, height2, **kwargs):
    base = np.array([(0, 0), (0, 1), (1, 1), (1, 0), (0, 0)])
    verts = np.vstack([xy1 + (width1, height1) * base,
                       xy2 + (width2, height2) * base[::-1],
                       xy1])
    codes = 2 * ([Path.MOVETO] + 4 * [Path.LINETO]) + [Path.CLOSEPOLY]
    return PathPatch(Path(verts, codes), **kwargs)

fig, ax = plt.subplots()
imdata = np.random.randn(10, 10)

# plot the image
im = ax.imshow(imdata, extent=(0, 1, 0, 1), aspect='auto',
               cmap='coolwarm', interpolation='nearest')

# plot the hatched rectangle
patch = plt.Rectangle((0.3, 0.3), 0.4, 0.4, facecolor='none',
                      hatch=r'//')
ax.add_patch(patch)

# add the text
text = ax.text(0.5, 0.5, 'Text', fontsize='xx-large', fontweight='bold',
               color='k', ha='center', va='center')

# create a mask for the hatched rectangle
mask = DoubleRect((0, 0), 1, 1, (0.4, 0.45), 0.2, 0.1,
                  facecolor='none', edgecolor='black')
ax.add_patch(mask)
patch.set_clip_path(mask)

enter image description here


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

...