如何在matplotlib中很好地绘制剪裁的分层艺术家?

时间:2015-11-10 03:41:05

标签: python matplotlib plot

考虑一下matplotlib图中有三位艺术家。在顶级艺术家的bbox中不显示中级艺术家同时保留整个区域中可见的低级艺术家的最简单方法是什么?

我想要实现的目标的插图:

Illustration of layered clipping

没有要求能够看到最低级别的顶层图的非透明面色就足够了。这不适用于三个级别,因为两个较低级别将被隐藏。

this IPython notebook for a solution using shapely。这是一个尚未完全实现的纯matplotlib示例,但我希望有一种更简单的方法来获得我尚未想到的相同结果。

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)

2 个答案:

答案 0 :(得分:1)

这有点像黑客,但我可能会通过两次显示图像,一次在背景中,一次在前景中使用自定义剪辑路径来完成此操作。这是一个例子:

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

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

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

# plot the box around the text
minirect = patches.Rectangle((0.4, 0.45), 0.2, 0.1, facecolor='none',
                             edgecolor='black', zorder=4)
ax.add_patch(minirect)

# duplicate image and set a clip path
im2 = ax.imshow(imdata, extent=(0, 1, 0, 1), aspect='auto',
                cmap=cm.coolwarm, zorder=3)
im2.set_clip_path(minirect)

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

enter image description here

答案 1 :(得分:1)

我提出了另一个更清洁的答案:它涉及为阴影区域创建一个剪贴蒙版,其中有一个洞,这样你就可以在它背后的背景中看到所有

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)

this