1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
|
"""
.. redirect-from:: /tutorials/advance/patheffects_guide
.. _patheffects_guide:
==================
Path effects guide
==================
Defining paths that objects follow on a canvas.
.. py:currentmodule:: matplotlib.patheffects
Matplotlib's :mod:`.patheffects` module provides functionality to apply a
multiple draw stage to any Artist which can be rendered via a `.path.Path`.
Artists which can have a path effect applied to them include `.patches.Patch`,
`.lines.Line2D`, `.collections.Collection` and even `.text.Text`. Each artist's
path effects can be controlled via the `.Artist.set_path_effects` method,
which takes an iterable of `AbstractPathEffect` instances.
The simplest path effect is the `Normal` effect, which simply draws the artist
without any effect:
"""
import matplotlib.pyplot as plt
import matplotlib.patheffects as path_effects
fig = plt.figure(figsize=(5, 1.5))
text = fig.text(0.5, 0.5, 'Hello path effects world!\nThis is the normal '
'path effect.\nPretty dull, huh?',
ha='center', va='center', size=20)
text.set_path_effects([path_effects.Normal()])
plt.show()
# %%
# Whilst the plot doesn't look any different to what you would expect without
# any path effects, the drawing of the text has now been changed to use the
# path effects framework, opening up the possibilities for more interesting
# examples.
#
# Adding a shadow
# ---------------
#
# A far more interesting path effect than `Normal` is the drop-shadow, which we
# can apply to any of our path based artists. The classes `SimplePatchShadow`
# and `SimpleLineShadow` do precisely this by drawing either a filled patch or
# a line patch below the original artist:
import matplotlib.patheffects as path_effects
text = plt.text(0.5, 0.5, 'Hello path effects world!',
path_effects=[path_effects.withSimplePatchShadow()])
plt.plot([0, 3, 2, 5], linewidth=5, color='blue',
path_effects=[path_effects.SimpleLineShadow(),
path_effects.Normal()])
plt.show()
# %%
# Notice the two approaches to setting the path effects in this example. The
# first uses the ``with*`` classes to include the desired functionality
# automatically followed with the "normal" effect, whereas the latter
# explicitly defines the two path effects to draw.
#
# Making an Artist stand out
# --------------------------
#
# One nice way of making artists visually stand out is to draw an outline in
# a bold color below the actual artist. The :class:`Stroke` path effect makes
# this a relatively simple task:
fig = plt.figure(figsize=(7, 1))
text = fig.text(0.5, 0.5, 'This text stands out because of\n'
'its black border.', color='white',
ha='center', va='center', size=30)
text.set_path_effects([path_effects.Stroke(linewidth=3, foreground='black'),
path_effects.Normal()])
plt.show()
# %%
# It is important to note that this effect only works because we have drawn
# the text path twice; once with a thick black line, and then once with the
# original text path on top.
#
# You may have noticed that the keywords to `Stroke` and `SimplePatchShadow`
# and `SimpleLineShadow` are not the usual Artist keywords (*facecolor*
# *edgecolor*, etc.). This is because with these path effects we are operating
# at lower level of Matplotlib. In fact, the keywords which are accepted are
# those for a `matplotlib.backend_bases.GraphicsContextBase` instance, which
# have been designed for making it easy to create new backends - and not for
# its user interface.
#
#
# Greater control of the path effect Artist
# -----------------------------------------
#
# As already mentioned, some of the path effects operate at a lower level
# than most users will be used to, meaning that setting keywords such as
# *facecolor* and *edgecolor* raise an AttributeError. Luckily there is a
# generic `PathPatchEffect` path effect which creates a `.patches.PathPatch`
# class with the original path. The keywords to this effect are identical to
# those of `.patches.PathPatch`:
fig = plt.figure(figsize=(8.5, 1))
t = fig.text(0.02, 0.5, 'Hatch shadow', fontsize=75, weight=1000, va='center')
t.set_path_effects([
path_effects.PathPatchEffect(
offset=(4, -4), hatch='xxxx', facecolor='gray'),
path_effects.PathPatchEffect(
edgecolor='white', linewidth=1.1, facecolor='black')])
plt.show()
# %%
# ..
# Headings for future consideration:
#
# Implementing a custom path effect
# ---------------------------------
#
# What is going on under the hood
# --------------------------------
|