Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit ea082aa

Browse files
committed
Clipping for OffsetBoxes
- Child `Artists` of `DrawingArea` can now get clipped to the bounds of the parent
1 parent fce2a6d commit ea082aa

File tree

10 files changed

+328
-4
lines changed

10 files changed

+328
-4
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
'OffsetBox.DrawingArea' respects the 'clip' keyword argument
2+
````````````````````````````````````````````````````````````
3+
4+
The call signature was `OffsetBox.DrawingArea(..., clip=True)` but nothing
5+
was done with the `clip` argument. The object did not do any clipping
6+
regardless of that parameter. Now the object can and does clip the child `Artists` if they are set to be clipped.
7+
8+
You can turn off the clipping on a per-child basis using `child.set_clip_on(False)`.

doc/users/whats_new/offsetbox.rst

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
OffsetBoxes now support clipping
2+
````````````````````````````````
3+
4+
`Artists` draw onto objects of type :class:`~OffsetBox`
5+
through :class:`~OffsetBox.DrawingArea` and :class:`~OffsetBox.TextArea`.
6+
The `TextArea` calculates the required space for the text and so the
7+
text is always within the bounds, for this nothing has changed.
8+
9+
However, `DrawingArea` acts as a parent for zero or more `Artists` that
10+
draw on it and may do so beyond the bounds. Now child `Artists` can be
11+
clipped to the bounds of the `DrawingArea`.

examples/pylab_examples/anchored_artists.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ class AnchoredDrawingArea(AnchoredOffsetbox):
6363
def __init__(self, width, height, xdescent, ydescent,
6464
loc, pad=0.4, borderpad=0.5, prop=None, frameon=True):
6565

66-
self.da = DrawingArea(width, height, xdescent, ydescent, clip=True)
66+
self.da = DrawingArea(width, height, xdescent, ydescent)
6767

6868
super(AnchoredDrawingArea, self).__init__(loc, pad=pad, borderpad=borderpad,
6969
child=self.da,

lib/matplotlib/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1416,6 +1416,7 @@ def tk_window_focus():
14161416
'matplotlib.tests.test_lines',
14171417
'matplotlib.tests.test_mathtext',
14181418
'matplotlib.tests.test_mlab',
1419+
'matplotlib.tests.test_offsetbox',
14191420
'matplotlib.tests.test_patches',
14201421
'matplotlib.tests.test_path',
14211422
'matplotlib.tests.test_patheffects',

lib/matplotlib/offsetbox.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import matplotlib.transforms as mtransforms
2525
import matplotlib.artist as martist
2626
import matplotlib.text as mtext
27+
import matplotlib.path as mpath
2728
import numpy as np
2829
from matplotlib.transforms import Bbox, BboxBase, TransformedBbox
2930

@@ -569,14 +570,16 @@ class DrawingArea(OffsetBox):
569570
"""
570571
The DrawingArea can contain any Artist as a child. The DrawingArea
571572
has a fixed width and height. The position of children relative to
572-
the parent is fixed.
573+
the parent is fixed. The children can be clipped at the
574+
boundaries of the parent.
573575
"""
574576

575577
def __init__(self, width, height, xdescent=0.,
576-
ydescent=0., clip=True):
578+
ydescent=0., clip=False):
577579
"""
578580
*width*, *height* : width and height of the container box.
579581
*xdescent*, *ydescent* : descent of the box in x- and y-direction.
582+
*clip* : Whether to clip the children
580583
"""
581584

582585
super(DrawingArea, self).__init__()
@@ -585,6 +588,7 @@ def __init__(self, width, height, xdescent=0.,
585588
self.height = height
586589
self.xdescent = xdescent
587590
self.ydescent = ydescent
591+
self._clip_children = clip
588592

589593
self.offset_transform = mtransforms.Affine2D()
590594
self.offset_transform.clear()
@@ -656,7 +660,17 @@ def draw(self, renderer):
656660
self.dpi_transform.clear()
657661
self.dpi_transform.scale(dpi_cor, dpi_cor)
658662

663+
# At this point the DrawingArea has a transform
664+
# to the display space so the path created is
665+
# good for clipping children
666+
tpath = mtransforms.TransformedPath(
667+
mpath.Path([[0, 0], [0, self.height],
668+
[self.width, self.height],
669+
[self.width, 0]]),
670+
self.get_transform())
659671
for c in self._children:
672+
if self._clip_children and not (c.clipbox or c._clippath):
673+
c.set_clip_path(tpath)
660674
c.draw(renderer)
661675

662676
bbox_artist(self, renderer, fill=False, props=dict(pad=0.))
Binary file not shown.
Lines changed: 241 additions & 0 deletions
Loading
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
from __future__ import (absolute_import, division, print_function,
2+
unicode_literals)
3+
4+
import nose
5+
6+
from matplotlib.testing.decorators import image_comparison
7+
import matplotlib.pyplot as plt
8+
import matplotlib.patches as mpatches
9+
import matplotlib.lines as mlines
10+
from matplotlib.offsetbox import AnchoredOffsetbox, DrawingArea
11+
12+
13+
@image_comparison(baseline_images=['offsetbox_clipping'], remove_text=True)
14+
def test_offsetbox_clipping():
15+
# - create a plot
16+
# - put an AnchoredOffsetbox with a child DrawingArea
17+
# at the center of the axes
18+
# - give the DrawingArea a gray background
19+
# - put a black line across the bounds of the DrawingArea
20+
# - see that the black line is clipped to the edges of
21+
# the DrawingArea.
22+
fig, ax = plt.subplots()
23+
size = 100
24+
da = DrawingArea(size, size, clip=True)
25+
bg = mpatches.Rectangle((0, 0), size, size,
26+
facecolor='#CCCCCC',
27+
edgecolor='None',
28+
linewidth=0)
29+
line = mlines.Line2D([-size*.5, size*1.5], [size/2, size/2],
30+
color='black',
31+
linewidth=10)
32+
anchored_box = AnchoredOffsetbox(
33+
loc=10,
34+
child=da,
35+
pad=0.,
36+
frameon=False,
37+
bbox_to_anchor=(.5, .5),
38+
bbox_transform=ax.transAxes,
39+
borderpad=0.)
40+
41+
da.add_artist(bg)
42+
da.add_artist(line)
43+
ax.add_artist(anchored_box)
44+
ax.set_xlim((0, 1))
45+
ax.set_ylim((0, 1))
46+
47+
48+
if __name__ == '__main__':
49+
nose.runmodule(argv=['-s', '--with-doctest'], exit=False)

lib/mpl_toolkits/axes_grid1/anchored_artists.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ def __init__(self, width, height, xdescent, ydescent,
2424
*prop* : font property. This is only used for scaling the paddings.
2525
"""
2626

27-
self.da = DrawingArea(width, height, xdescent, ydescent, clip=True)
27+
self.da = DrawingArea(width, height, xdescent, ydescent)
2828
self.drawing_area = self.da
2929

3030
super(AnchoredDrawingArea, self).__init__(loc, pad=pad, borderpad=borderpad,

0 commit comments

Comments
 (0)