Module plottools.arrows
Drawing arrows.
Axes member functions
harrow()
: draw a horizontal arrow with annotation on the arrow.varrow()
: draw a vertical arrow with annotation on the arrow.point_to()
: text with arrow pointing to a point.
Settings
arrow_style()
: generate an arrow style.generic_arrow_styles()
: some generic arrow styles.
Display
plot_arrow_styles()
: plot names and arrows of all available arrow styles.
Install/uninstall arrows functions
You usually do not need to call these functions. Upon loading the arrows
module, install_arrows()
is called automatically.
install_arrows()
: install functions of the arrows module in matplotlib.uninstall_arrows()
: uninstall all code of the arrows module from matplotlib.
Expand source code
"""
Drawing arrows.
## Axes member functions
- `harrow()`: draw a horizontal arrow with annotation on the arrow.
- `varrow()`: draw a vertical arrow with annotation on the arrow.
- `point_to()`: text with arrow pointing to a point.
## Settings
- `arrow_style()`: generate an arrow style.
- `generic_arrow_styles()`: some generic arrow styles.
## Display
- `plot_arrow_styles()`: plot names and arrows of all available arrow styles.
## Install/uninstall arrows functions
You usually do not need to call these functions. Upon loading the arrows
module, `install_arrows()` is called automatically.
- `install_arrows()`: install functions of the arrows module in matplotlib.
- `uninstall_arrows()`: uninstall all code of the arrows module from matplotlib.
"""
import __main__
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
from matplotlib.patches import ArrowStyle
def harrow(ax, x, y, dx, heads='right', text=None, va='bottom', dist=3.0,
style='>', shrink=0, lw=1, color='k',
head_width=15, head_length=15, transform=None, **kwargs):
""" Draw a horizontal arrow with annotation on the arrow.
Parameters
----------
ax: matplotlib axes
Axes on which to draw the arrow.
x: float
X-coordinate of starting point of arrow in data coordinates.
y: float
Y-coordinate of starting point of arrow in data coordinates.
dx: float
Length of arrow in data x-coordinates.
heads: string
One of 'left', '<', 'right', '>', 'both', '<>', 'none', or '',
Specifies whether to draw the arrow head at the starting point ('left', '<'),
at the end ('right', '>'), on both ends ('both', '<>'), or none ('none', '').
text: string
Text for annotating the arrow. A formatting instruction within text (e.g. 'd=%.1fm')
is replaced by `dx`.
va: string
Place text annotation above ('top') or below ('bottom') the arrow.
dist: float
Distance of text annotation from arrow in points.
style: string
Appearance of the arrow head:
'>': line arrow, '|>': filled arrow, '>>': fancy arrow, '|': bar
shrink: float
Shrink arrow away from endpoints.
lw: float
Linewidth of line in points.
color: matplotlib color
Color of line and arrow.
head_width: float
Width of arrow head in points.
head_length: float
Length of arrow head in points.
transform: matplotlib.Transform
Defines coordinate system for `x`, `y`, and `dx`. Defaults to data coordinates.
**kwargs: key-word arguments
Formatting of the annotation text, passed on to text().
A `zorder` argument is also applied to the arrow.
See Also
--------
varrow(), point_to(), arrow_style()
"""
if transform is None:
transform = ax.transData
transcoord = 'data'
if transform is ax.transAxes:
transcoord = 'axes fraction'
if transform is ax.get_figure().transFigure:
transcoord = 'figure fraction'
zkwargs = {}
if 'zorder' in kwargs:
zkwargs.update(dict(zorder=kwargs['zorder']))
heads_d = {'leftx': 'left', '<x': 'left', 'rightx': 'right', '>x': 'right',
'bothx': 'both', '<>x': 'both', 'nonex': 'none', 'x': 'none'}
heads = heads_d[heads+'x']
if heads == 'none':
style = '>'
if style == '>>':
arrowstyle = ArrowStyle.Fancy(head_length=0.07*head_length,
head_width=0.07*head_width, tail_width=0.01)
if heads in ['right', 'both']:
ax.annotate('', (x+dx, y), (x, y),
xycoords=transcoord, textcoords=transcoord,
arrowprops=dict(arrowstyle=arrowstyle,
edgecolor='none', facecolor=color,
linewidth=lw, shrinkA=shrink, shrinkB=shrink,
clip_on=False), annotation_clip=False, **zkwargs)
if heads in ['left', 'both']:
ax.annotate('', (x, y), (x+dx, y),
xycoords=transcoord, textcoords=transcoord,
arrowprops=dict(arrowstyle=arrowstyle,
edgecolor='none', facecolor=color,
linewidth=lw, shrinkA=shrink, shrinkB=shrink,
clip_on=False), annotation_clip=False, **zkwargs)
else:
scale = head_width*2.0
if style == '|':
scale /= 4.0
bstyle = style[::-1]
if bstyle[0] == '>':
bstyle = '<' + bstyle[1:]
arrowstyle = '-'
if heads == 'right':
arrowstyle = '-' + style
elif heads == 'left':
arrowstyle = bstyle + '-'
elif heads == 'both':
arrowstyle = bstyle + '-' + style
ec = color
lww = lw
if style == '|>':
ec = 'none'
lww = 0
ax.annotate('', (x+dx, y), (x, y),
xycoords=transcoord, textcoords=transcoord,
arrowprops=dict(arrowstyle=arrowstyle, edgecolor=ec, facecolor=color,
linewidth=lww, shrinkA=shrink, shrinkB=shrink,
mutation_scale=scale, clip_on=False),
annotation_clip=False, **zkwargs)
if style in ['|>', '>>']:
pixelx = np.abs(np.diff(ax.get_window_extent().get_points()[:,0]))[0]
xmin, xmax = ax.get_xlim()
dxu = np.abs(xmax - xmin)/pixelx
ddx = 0.5*head_length*dxu
ddxr = ddx if heads in ['right', 'both'] else 0
ddxl = ddx if heads in ['left', 'both'] else 0
if dx < 0:
ddxl = -ddxl
ddxr = -ddxr
ax.plot([x+ddxl, x+dx-ddxr], [y, y], '-', lw=lw, color=color,
transform=transform, solid_capstyle='butt', clip_on=False, **zkwargs)
if text:
if '%' in text and text[-1] != '%':
text = text % dx
# ax dimensions:
ax.autoscale_view(False)
ax.autoscale(False)
pixely = np.abs(np.diff(ax.get_window_extent().get_points()[:,1]))[0]
ymin, ymax = ax.get_ylim()
dyu = np.abs(ymax - ymin)/pixely
dy = 0.5*lw + dist
if 'ha' in kwargs:
del kwargs['ha']
if va == 'top':
ax.text(x+0.5*dx, y+dy*dyu, text, ha='center', va='bottom',
transform=transform, clip_on=False, **kwargs)
else:
ax.text(x+0.5*dx, y-dy*dyu, text, ha='center', va='top',
transform=transform, clip_on=False, **kwargs)
def varrow(ax, x, y, dy, heads='right', text=None, ha='right', dist=3.0,
style='>', shrink=0, lw=1, color='k',
head_width=15, head_length=15, transform=None, **kwargs):
""" Draw a vertical arrow with annotation on the arrow.
Parameters
----------
ax: matplotlib axes
Axes on which to draw the arrow.
x: float
X-coordinate of starting point of arrow in data coordinates.
y: float
Y-coordinate of starting point of arrow in data coordinates.
dx: float
Length of arrow in data x-coordinates.
heads: string
One of 'left', '<', 'right', '>', 'both', '<>', 'none', or '',
Specifies whether to draw the arrow head at the starting point ('left', '<'),
at the end ('right', '>'), on both ends ('both', '<>'), or none ('none', '').
text: string
Text for annotating the arrow. A formatting instruction within text (e.g. 'd=%.1fm')
is replaced by `dy`.
ha: string
Place text annotation to the left ('left') or right ('right') of the arrow.
dist: float
Distance of text annotation from arrow in points.
style: string
Appearance of the arrow head:
'>': line arrow, '|>': filled arrow, '>>': fancy arrow, '|': bar
shrink: float
Shrink arrow away from endpoints.
lw: float
Linewidth of line in points.
color: matplotlib color
Color of line and arrow.
head_width: float
Width of arrow head in points.
head_length: float
Length of arrow head in points.
transform: matplotlib.Transform
Defines coordinate system for `x`, `y`, and `dx`. Defaults to data coordinates.
**kwargs: key-word arguments
Formatting of the annotation text, passed on to text().
A `zorder` argument is also applied to the arrow.
See Also
--------
harrow(), point_to(), arrow_style()
"""
if transform is None:
transform = ax.transData
transcoord = 'data'
if transform is ax.transAxes:
transcoord = 'axes fraction'
if transform is ax.get_figure().transFigure:
transcoord = 'figure fraction'
zkwargs = {}
if 'zorder' in kwargs:
zkwargs.update(dict(zorder=kwargs['zorder']))
heads_d = {'leftx': 'left', '<x': 'left', 'rightx': 'right', '>x': 'right',
'bothx': 'both', '<>x': 'both', 'nonex': 'none', 'x': 'none'}
heads = heads_d[heads+'x']
if heads == 'none':
style = '>'
if style == '>>':
arrowstyle = ArrowStyle.Fancy(head_length=0.07*head_length,
head_width=0.07*head_width, tail_width=0.01)
if heads in ['right', 'both']:
ax.annotate('', (x, y+dy), (x, y),
xycoords=transcoord, textcoords=transcoord,
arrowprops=dict(arrowstyle=arrowstyle,
edgecolor='none', facecolor=color,
linewidth=0, shrinkA=shrink, shrinkB=shrink,
clip_on=False), annotation_clip=False, **zkwargs)
if heads in ['left', 'both']:
ax.annotate('', (x, y), (x, y+dy),
xycoords=transcoord, textcoords=transcoord,
arrowprops=dict(arrowstyle=arrowstyle,
edgecolor='none', facecolor=color,
linewidth=0, shrinkA=shrink, shrinkB=shrink,
clip_on=False), annotation_clip=False, **zkwargs)
else:
scale = head_width*2.0
if style == '|':
scale /= 4.0
bstyle = style[::-1]
if bstyle[0] == '>':
bstyle = '<' + bstyle[1:]
arrowstyle = '-'
if heads == 'right':
arrowstyle = '-' + style
elif heads == 'left':
arrowstyle = bstyle + '-'
elif heads == 'both':
arrowstyle = bstyle + '-' + style
ec = color
lww = lw
if style == '|>':
ec = 'none'
lww = 0
ax.annotate('', (x, y+dy), (x, y),
xycoords=transcoord, textcoords=transcoord,
arrowprops=dict(arrowstyle=arrowstyle, edgecolor=ec, facecolor=color,
linewidth=lww, shrinkA=shrink, shrinkB=shrink,
mutation_scale=scale, clip_on=False),
annotation_clip=False, **zkwargs)
if style in ['|>', '>>']:
pixely = np.abs(np.diff(ax.get_window_extent().get_points()[:,1]))[0]
ymin, ymax = ax.get_ylim()
dyu = np.abs(ymax - ymin)/pixely
ddy = 0.5*head_length*dyu
ddyr = ddy if heads in ['right', 'both'] else 0
ddyl = ddy if heads in ['left', 'both'] else 0
if dy < 0:
ddyl = -ddyl
ddyr = -ddyr
ax.plot([x, x], [y+ddyl, y+dy-ddyr], '-', lw=lw, color=color,
transform=transform, solid_capstyle='butt', clip_on=False, **zkwargs)
if text:
if '%' in text and text[-1] != '%':
text = text % dy
# ax dimensions:
ax.autoscale_view(False)
ax.autoscale(False)
pixelx = np.abs(np.diff(ax.get_window_extent().get_points()[:,0]))[0]
xmin, xmax = ax.get_xlim()
dxu = np.abs(xmax - xmin)/pixelx
dx = 0.5*lw + dist
if 'ha' in kwargs:
del kwargs['ha']
if 'va' in kwargs:
del kwargs['va']
if ha == 'right':
ax.text(x+dx*dxu, y+0.5*dy, text, ha='left', va='center',
transform=transform, clip_on=False, **kwargs)
else:
ax.text(x-dx*dxu, y+0.5*dy, text, ha='right', va='center',
transform=transform, clip_on=False, **kwargs)
def point_to(ax, text, xyfrom, xyto, radius=0.2, relpos=(1, 0.5),
style='>', shrink=0, lw=1, color='k',
head_width=15, head_length=15, **kwargs):
""" Text with arrow pointing to a point.
Parameters
----------
ax: matplotlib axes
Axes on which to draw the text and arrow.
text: string
Text placed at `xyfrom`.
xyfrom: tuple of floats
X- and y-coordinates of text position in data coordinates.
xyto: tuple of floats
X- and y-coordinates of arrow point in data coordinates.
radius: float
Radius of arrow line. Negative curves to the right. Relative to arrow length.
relpos: tuple of floats
X- and y-coordinate of starting point of arrow on text box. Between 0 and 1.
style: string
Appearance of the arrow head:
'>': line arrow, '|>': filled arrow, '>>': fancy arrow
shrink: float
Shrink arrow away from endpoints.
lw: float
Linewidth of line in points.
color: matplotlib color
Color of line and arrow.
head_width: float
Width of arrow head in points.
head_length: float
Length of arrow head in points.
**kwargs: key-word arguments
Formatting of the text, passed on to annotate().
See Also
--------
harrow(), varrow(), arrow_style()
"""
if style == '>>':
arrowstyle = ArrowStyle.Fancy(head_length=0.09*head_length,
head_width=0.09*head_width, tail_width=0.14*lw)
arrowprops = dict(arrowstyle=arrowstyle, edgecolor='none', linewidth=0)
else:
scale = head_width*2.0
if style == '|':
scale /= 4.0
arrowprops = dict(arrowstyle='-' + style, edgecolor=color,
mutation_scale=scale, linewidth=lw)
arrowprops.update(dict(facecolor=color, relpos=relpos,
shrinkA=shrink, shrinkB=shrink, clip_on=False))
arrowprops.update(dict(connectionstyle='arc3,rad=%g' % radius))
if 'dist' in kwargs:
kwargs.pop('dist')
ax.annotate(text, xy=xyto, xytext=xyfrom, arrowprops=arrowprops,
annotation_clip=False, **kwargs)
def arrow_style(namespace, name, dist=3.0, style='>', shrink=0, lw=1,
color='k', head_width=15, head_length=15, **kwargs):
"""Generate an arrow style.
Add dictionary with name 'as'+name to `namespace` and to `ars`
Parameters
----------
namespace: class or None
Namespace to which the generated arrow style is added.
If None add arrow style to the __main__ module.
name: string
The name of the arrow style, the prefix 'as' is prepended.
dist: float
Distance of text annotation from arrow in points (for harrow()
and varrow()).
style: string
Appearance of the arrow head:
'>': line arrow, '|>': filled arrow, '>>': fancy arrow, '|': bar
shrink: float
Shrink arrow away from endpoints.
lw: float
Linewidth of line in points.
color: matplotlib color
Color of line and arrow.
head_width: float
Width of arrow head in points.
head_length: float
Length of arrow head in points.
**kwargs: key-word arguments
Formatting of the annotation text, passed on to text().
See Also
--------
harrow(), varrow(), point_to(), plot_arrow_styles(), generic_arrow_styles()
"""
if namespace is None:
namespace = __main__
if not hasattr(namespace, 'ars'):
setattr(namespace, 'ars', {})
ad = dict(dist=dist, style=style, shrink=shrink, lw=lw, color=color,
head_width=head_width, head_length=head_length, **kwargs)
setattr(namespace, 'as' + name, ad)
getattr(namespace, 'ars')[name] = ad
def generic_arrow_styles(namespace, palette, scale=1):
""" Some generic arrow styles.
- `asLine`: simple arrow
- `asFilled`: arrow with filled head
- `asPoint`: big arrow with filled head and thick line
- `asPointSmall`: arrow with filled head and thin line
- `asMarker`: arrow with filled head, annotation on a transparent background
This is just a suggestion. Copy it and adapt it to your needs!
Parameters
----------
namespace: class or None
Namespace to which the generated arrow style is added.
If None add arrow style to the __main__ module.
palette: dict
Color palette. Uses black for the arrow and white for text background.
scale: float
Scale factor for line width, head height and width.
See Also
--------
arrow_style(), plot_arrow_styles()
"""
arrow_style(namespace, 'Line', dist=3, style='>', shrink=0,
lw=0.6*scale, color=palette['black'],
head_length=4*scale, head_width=4*scale )
arrow_style(namespace, 'Filled', dist=3, style='>>', shrink=0,
lw=0.6*scale, color=palette['black'],
head_length=8*scale, head_width=5*scale )
arrow_style(namespace, 'Point', dist=3, style='>>', shrink=0,
lw=1.2*scale, color=palette['black'],
head_length=8*scale, head_width=6*scale )
arrow_style(namespace, 'PointSmall', dist=3, style='>>', shrink=0,
lw=1*scale, color=palette['black'],
head_length=5*scale, head_width=5*scale,
fontsize='small')
arrow_style(namespace, 'Marker', dist=3, style='>>', shrink=0,
lw=0.9*scale, color=palette['black'],
head_length=5*scale, head_width=5*scale,
fontsize='small', ha='center', va='center',
bbox=dict(boxstyle='round, pad=0.1, rounding_size=0.4',
facecolor=palette['white'],
edgecolor='none', alpha=0.6))
def plot_arrow_styles(ax, namespace=None):
""" Plot names and arrows of all available arrow styles.
Parameters
----------
ax: matplotlib axes
Subplot to use for plotting the arrow styles.
namespace: class or None
Namespace on which styles are defined.
If None take styles from the __main__ module.
See Also
--------
arrow_style(), generic_arrow_styles()
"""
if namespace is None:
namespace = __main__
for k, name in enumerate(namespace.ars):
ax.harrow(0.5, 0.5*k+0.5, 1.0, 'both', 'as'+name, **namespace.ars[name])
ax.set_xlim(0.0, 2.0)
ax.set_ylim(0.0, 0.5*k+1)
ax.set_title('arrow styles')
def install_arrows():
""" Install functions of the arrows module in matplotlib.
See also
--------
uninstall_arrows()
"""
if not hasattr(mpl.axes.Axes, 'harrow'):
mpl.axes.Axes.harrow = harrow
if not hasattr(mpl.axes.Axes, 'varrow'):
mpl.axes.Axes.varrow = varrow
if not hasattr(mpl.axes.Axes, 'point_to'):
mpl.axes.Axes.point_to = point_to
def uninstall_arrows():
""" Uninstall all code of the arrows module from matplotlib.
See also
--------
install_arrows()
"""
if hasattr(mpl.axes.Axes, 'harrow'):
delattr(mpl.axes.Axes, 'harrow')
if hasattr(mpl.axes.Axes, 'varrow'):
delattr(mpl.axes.Axes, 'varrow')
if hasattr(mpl.axes.Axes, 'point_to'):
delattr(mpl.axes.Axes, 'point_to')
install_arrows()
def demo():
""" Run a demonstration of the arrows module.
"""
fig, ax = plt.subplots()
fig.suptitle('plottools.arrows')
ax.set_xlim(0.0, 3.0)
ax.set_ylim(0.0, 2.0)
for y in [1.1, 1.3, 1.5, 1.7, 1.9]:
ax.plot([0.2, 1.8], [y, y], '-c', lw=15, solid_capstyle='butt')
ax.harrow(0.2, 1.9, 1.6, 'right', 'these', lw=1)
ax.harrow(0.2, 1.7, 1.6, 'both', 'are', style='|>', lw=1)
ax.harrow(0.2, 1.5, 1.6, 'left', 'all', style='>>', lw=2)
ax.harrow(0.2, 1.3, 1.6, 'both', 'arrows', style='|', va='top', lw=2)
ax.harrow(0.2, 1.1, 1.6, 'both', 'fancy', style='>>', va='top', lw=2)
for x in [0.2, 0.5, 0.8, 1.1, 1.4]:
ax.plot([x, x], [0.1, 0.8], '-c', lw=15, solid_capstyle='butt')
ax.varrow(0.2, 0.1, 0.7, '>', 'these', lw=4)
ax.varrow(0.5, 0.1, 0.7, '<>', 'are', style='|>', lw=4)
ax.varrow(0.8, 0.1, 0.7, '<', 'all', ha='left', style='>>', lw=2)
ax.varrow(1.1, 0.1, 0.7, 'both', 'arrows', style='|', lw=4, rotation=90)
ax.varrow(1.4, 0.1, 0.7, 'both', 'fancy', style='>>', lw=2, rotation='vertical')
x = 1.7
ax.plot([x, x], [0.1, 0.8], '-c', lw=25, solid_capstyle='butt')
ax.varrow(x, 0.1, 0.7, 'both', 'big fancy', style='>>', lw=5, rotation=90,
head_width=25, head_length=35)
ax.point_to('point_to', (2.0, 1.9), (2.8, 1.7), -0.3, (1, 0.5))
ax.point_to('point_to', (2.0, 1.6), (2.8, 1.4), -0.3, (1, 0.5), style='|>')
ax.point_to('point_to', (2.0, 1.3), (2.8, 1.1), -0.3, (1, 0.5), style='>>')
ax.point_to('point_to', (2.0, 1.0), (2.8, 0.8), -0.3, (1, 0.5), style='>', lw=4)
ax.point_to('point_to', (2.0, 0.7), (2.8, 0.5), -0.3, (1, 0.5), style='|>', lw=4)
ax.point_to('point_to', (2.0, 0.4), (2.8, 0.2), -0.3, (1, 0.5), style='>>', lw=4)
plt.show()
if __name__ == "__main__":
demo()
Functions
def harrow(ax, x, y, dx, heads='right', text=None, va='bottom', dist=3.0, style='>', shrink=0, lw=1, color='k', head_width=15, head_length=15, transform=None, **kwargs)
-
Draw a horizontal arrow with annotation on the arrow.
Parameters
ax
:matplotlib axes
- Axes on which to draw the arrow.
x
:float
- X-coordinate of starting point of arrow in data coordinates.
y
:float
- Y-coordinate of starting point of arrow in data coordinates.
dx
:float
- Length of arrow in data x-coordinates.
heads
:string
- One of 'left', '<', 'right', '>', 'both', '<>', 'none', or '', Specifies whether to draw the arrow head at the starting point ('left', '<'), at the end ('right', '>'), on both ends ('both', '<>'), or none ('none', '').
text
:string
- Text for annotating the arrow. A formatting instruction within text (e.g. 'd=%.1fm')
is replaced by
dx
. va
:string
- Place text annotation above ('top') or below ('bottom') the arrow.
dist
:float
- Distance of text annotation from arrow in points.
style
:string
- Appearance of the arrow head: '>': line arrow, '|>': filled arrow, '>>': fancy arrow, '|': bar
shrink
:float
- Shrink arrow away from endpoints.
lw
:float
- Linewidth of line in points.
color
:matplotlib color
- Color of line and arrow.
head_width
:float
- Width of arrow head in points.
head_length
:float
- Length of arrow head in points.
transform
:matplotlib.Transform
- Defines coordinate system for
x
,y
, anddx
. Defaults to data coordinates. **kwargs
:key-word arguments
- Formatting of the annotation text, passed on to text().
A
zorder
argument is also applied to the arrow.
See Also
Expand source code
def harrow(ax, x, y, dx, heads='right', text=None, va='bottom', dist=3.0, style='>', shrink=0, lw=1, color='k', head_width=15, head_length=15, transform=None, **kwargs): """ Draw a horizontal arrow with annotation on the arrow. Parameters ---------- ax: matplotlib axes Axes on which to draw the arrow. x: float X-coordinate of starting point of arrow in data coordinates. y: float Y-coordinate of starting point of arrow in data coordinates. dx: float Length of arrow in data x-coordinates. heads: string One of 'left', '<', 'right', '>', 'both', '<>', 'none', or '', Specifies whether to draw the arrow head at the starting point ('left', '<'), at the end ('right', '>'), on both ends ('both', '<>'), or none ('none', ''). text: string Text for annotating the arrow. A formatting instruction within text (e.g. 'd=%.1fm') is replaced by `dx`. va: string Place text annotation above ('top') or below ('bottom') the arrow. dist: float Distance of text annotation from arrow in points. style: string Appearance of the arrow head: '>': line arrow, '|>': filled arrow, '>>': fancy arrow, '|': bar shrink: float Shrink arrow away from endpoints. lw: float Linewidth of line in points. color: matplotlib color Color of line and arrow. head_width: float Width of arrow head in points. head_length: float Length of arrow head in points. transform: matplotlib.Transform Defines coordinate system for `x`, `y`, and `dx`. Defaults to data coordinates. **kwargs: key-word arguments Formatting of the annotation text, passed on to text(). A `zorder` argument is also applied to the arrow. See Also -------- varrow(), point_to(), arrow_style() """ if transform is None: transform = ax.transData transcoord = 'data' if transform is ax.transAxes: transcoord = 'axes fraction' if transform is ax.get_figure().transFigure: transcoord = 'figure fraction' zkwargs = {} if 'zorder' in kwargs: zkwargs.update(dict(zorder=kwargs['zorder'])) heads_d = {'leftx': 'left', '<x': 'left', 'rightx': 'right', '>x': 'right', 'bothx': 'both', '<>x': 'both', 'nonex': 'none', 'x': 'none'} heads = heads_d[heads+'x'] if heads == 'none': style = '>' if style == '>>': arrowstyle = ArrowStyle.Fancy(head_length=0.07*head_length, head_width=0.07*head_width, tail_width=0.01) if heads in ['right', 'both']: ax.annotate('', (x+dx, y), (x, y), xycoords=transcoord, textcoords=transcoord, arrowprops=dict(arrowstyle=arrowstyle, edgecolor='none', facecolor=color, linewidth=lw, shrinkA=shrink, shrinkB=shrink, clip_on=False), annotation_clip=False, **zkwargs) if heads in ['left', 'both']: ax.annotate('', (x, y), (x+dx, y), xycoords=transcoord, textcoords=transcoord, arrowprops=dict(arrowstyle=arrowstyle, edgecolor='none', facecolor=color, linewidth=lw, shrinkA=shrink, shrinkB=shrink, clip_on=False), annotation_clip=False, **zkwargs) else: scale = head_width*2.0 if style == '|': scale /= 4.0 bstyle = style[::-1] if bstyle[0] == '>': bstyle = '<' + bstyle[1:] arrowstyle = '-' if heads == 'right': arrowstyle = '-' + style elif heads == 'left': arrowstyle = bstyle + '-' elif heads == 'both': arrowstyle = bstyle + '-' + style ec = color lww = lw if style == '|>': ec = 'none' lww = 0 ax.annotate('', (x+dx, y), (x, y), xycoords=transcoord, textcoords=transcoord, arrowprops=dict(arrowstyle=arrowstyle, edgecolor=ec, facecolor=color, linewidth=lww, shrinkA=shrink, shrinkB=shrink, mutation_scale=scale, clip_on=False), annotation_clip=False, **zkwargs) if style in ['|>', '>>']: pixelx = np.abs(np.diff(ax.get_window_extent().get_points()[:,0]))[0] xmin, xmax = ax.get_xlim() dxu = np.abs(xmax - xmin)/pixelx ddx = 0.5*head_length*dxu ddxr = ddx if heads in ['right', 'both'] else 0 ddxl = ddx if heads in ['left', 'both'] else 0 if dx < 0: ddxl = -ddxl ddxr = -ddxr ax.plot([x+ddxl, x+dx-ddxr], [y, y], '-', lw=lw, color=color, transform=transform, solid_capstyle='butt', clip_on=False, **zkwargs) if text: if '%' in text and text[-1] != '%': text = text % dx # ax dimensions: ax.autoscale_view(False) ax.autoscale(False) pixely = np.abs(np.diff(ax.get_window_extent().get_points()[:,1]))[0] ymin, ymax = ax.get_ylim() dyu = np.abs(ymax - ymin)/pixely dy = 0.5*lw + dist if 'ha' in kwargs: del kwargs['ha'] if va == 'top': ax.text(x+0.5*dx, y+dy*dyu, text, ha='center', va='bottom', transform=transform, clip_on=False, **kwargs) else: ax.text(x+0.5*dx, y-dy*dyu, text, ha='center', va='top', transform=transform, clip_on=False, **kwargs)
def varrow(ax, x, y, dy, heads='right', text=None, ha='right', dist=3.0, style='>', shrink=0, lw=1, color='k', head_width=15, head_length=15, transform=None, **kwargs)
-
Draw a vertical arrow with annotation on the arrow.
Parameters
ax
:matplotlib axes
- Axes on which to draw the arrow.
x
:float
- X-coordinate of starting point of arrow in data coordinates.
y
:float
- Y-coordinate of starting point of arrow in data coordinates.
dx
:float
- Length of arrow in data x-coordinates.
heads
:string
- One of 'left', '<', 'right', '>', 'both', '<>', 'none', or '', Specifies whether to draw the arrow head at the starting point ('left', '<'), at the end ('right', '>'), on both ends ('both', '<>'), or none ('none', '').
text
:string
- Text for annotating the arrow. A formatting instruction within text (e.g. 'd=%.1fm')
is replaced by
dy
. ha
:string
- Place text annotation to the left ('left') or right ('right') of the arrow.
dist
:float
- Distance of text annotation from arrow in points.
style
:string
- Appearance of the arrow head: '>': line arrow, '|>': filled arrow, '>>': fancy arrow, '|': bar
shrink
:float
- Shrink arrow away from endpoints.
lw
:float
- Linewidth of line in points.
color
:matplotlib color
- Color of line and arrow.
head_width
:float
- Width of arrow head in points.
head_length
:float
- Length of arrow head in points.
transform
:matplotlib.Transform
- Defines coordinate system for
x
,y
, anddx
. Defaults to data coordinates. **kwargs
:key-word arguments
- Formatting of the annotation text, passed on to text().
A
zorder
argument is also applied to the arrow.
See Also
Expand source code
def varrow(ax, x, y, dy, heads='right', text=None, ha='right', dist=3.0, style='>', shrink=0, lw=1, color='k', head_width=15, head_length=15, transform=None, **kwargs): """ Draw a vertical arrow with annotation on the arrow. Parameters ---------- ax: matplotlib axes Axes on which to draw the arrow. x: float X-coordinate of starting point of arrow in data coordinates. y: float Y-coordinate of starting point of arrow in data coordinates. dx: float Length of arrow in data x-coordinates. heads: string One of 'left', '<', 'right', '>', 'both', '<>', 'none', or '', Specifies whether to draw the arrow head at the starting point ('left', '<'), at the end ('right', '>'), on both ends ('both', '<>'), or none ('none', ''). text: string Text for annotating the arrow. A formatting instruction within text (e.g. 'd=%.1fm') is replaced by `dy`. ha: string Place text annotation to the left ('left') or right ('right') of the arrow. dist: float Distance of text annotation from arrow in points. style: string Appearance of the arrow head: '>': line arrow, '|>': filled arrow, '>>': fancy arrow, '|': bar shrink: float Shrink arrow away from endpoints. lw: float Linewidth of line in points. color: matplotlib color Color of line and arrow. head_width: float Width of arrow head in points. head_length: float Length of arrow head in points. transform: matplotlib.Transform Defines coordinate system for `x`, `y`, and `dx`. Defaults to data coordinates. **kwargs: key-word arguments Formatting of the annotation text, passed on to text(). A `zorder` argument is also applied to the arrow. See Also -------- harrow(), point_to(), arrow_style() """ if transform is None: transform = ax.transData transcoord = 'data' if transform is ax.transAxes: transcoord = 'axes fraction' if transform is ax.get_figure().transFigure: transcoord = 'figure fraction' zkwargs = {} if 'zorder' in kwargs: zkwargs.update(dict(zorder=kwargs['zorder'])) heads_d = {'leftx': 'left', '<x': 'left', 'rightx': 'right', '>x': 'right', 'bothx': 'both', '<>x': 'both', 'nonex': 'none', 'x': 'none'} heads = heads_d[heads+'x'] if heads == 'none': style = '>' if style == '>>': arrowstyle = ArrowStyle.Fancy(head_length=0.07*head_length, head_width=0.07*head_width, tail_width=0.01) if heads in ['right', 'both']: ax.annotate('', (x, y+dy), (x, y), xycoords=transcoord, textcoords=transcoord, arrowprops=dict(arrowstyle=arrowstyle, edgecolor='none', facecolor=color, linewidth=0, shrinkA=shrink, shrinkB=shrink, clip_on=False), annotation_clip=False, **zkwargs) if heads in ['left', 'both']: ax.annotate('', (x, y), (x, y+dy), xycoords=transcoord, textcoords=transcoord, arrowprops=dict(arrowstyle=arrowstyle, edgecolor='none', facecolor=color, linewidth=0, shrinkA=shrink, shrinkB=shrink, clip_on=False), annotation_clip=False, **zkwargs) else: scale = head_width*2.0 if style == '|': scale /= 4.0 bstyle = style[::-1] if bstyle[0] == '>': bstyle = '<' + bstyle[1:] arrowstyle = '-' if heads == 'right': arrowstyle = '-' + style elif heads == 'left': arrowstyle = bstyle + '-' elif heads == 'both': arrowstyle = bstyle + '-' + style ec = color lww = lw if style == '|>': ec = 'none' lww = 0 ax.annotate('', (x, y+dy), (x, y), xycoords=transcoord, textcoords=transcoord, arrowprops=dict(arrowstyle=arrowstyle, edgecolor=ec, facecolor=color, linewidth=lww, shrinkA=shrink, shrinkB=shrink, mutation_scale=scale, clip_on=False), annotation_clip=False, **zkwargs) if style in ['|>', '>>']: pixely = np.abs(np.diff(ax.get_window_extent().get_points()[:,1]))[0] ymin, ymax = ax.get_ylim() dyu = np.abs(ymax - ymin)/pixely ddy = 0.5*head_length*dyu ddyr = ddy if heads in ['right', 'both'] else 0 ddyl = ddy if heads in ['left', 'both'] else 0 if dy < 0: ddyl = -ddyl ddyr = -ddyr ax.plot([x, x], [y+ddyl, y+dy-ddyr], '-', lw=lw, color=color, transform=transform, solid_capstyle='butt', clip_on=False, **zkwargs) if text: if '%' in text and text[-1] != '%': text = text % dy # ax dimensions: ax.autoscale_view(False) ax.autoscale(False) pixelx = np.abs(np.diff(ax.get_window_extent().get_points()[:,0]))[0] xmin, xmax = ax.get_xlim() dxu = np.abs(xmax - xmin)/pixelx dx = 0.5*lw + dist if 'ha' in kwargs: del kwargs['ha'] if 'va' in kwargs: del kwargs['va'] if ha == 'right': ax.text(x+dx*dxu, y+0.5*dy, text, ha='left', va='center', transform=transform, clip_on=False, **kwargs) else: ax.text(x-dx*dxu, y+0.5*dy, text, ha='right', va='center', transform=transform, clip_on=False, **kwargs)
def point_to(ax, text, xyfrom, xyto, radius=0.2, relpos=(1, 0.5), style='>', shrink=0, lw=1, color='k', head_width=15, head_length=15, **kwargs)
-
Text with arrow pointing to a point.
Parameters
ax
:matplotlib axes
- Axes on which to draw the text and arrow.
text
:string
- Text placed at
xyfrom
. xyfrom
:tuple
offloats
- X- and y-coordinates of text position in data coordinates.
xyto
:tuple
offloats
- X- and y-coordinates of arrow point in data coordinates.
radius
:float
- Radius of arrow line. Negative curves to the right. Relative to arrow length.
relpos
:tuple
offloats
- X- and y-coordinate of starting point of arrow on text box. Between 0 and 1.
style
:string
- Appearance of the arrow head: '>': line arrow, '|>': filled arrow, '>>': fancy arrow
shrink
:float
- Shrink arrow away from endpoints.
lw
:float
- Linewidth of line in points.
color
:matplotlib color
- Color of line and arrow.
head_width
:float
- Width of arrow head in points.
head_length
:float
- Length of arrow head in points.
**kwargs
:key-word arguments
- Formatting of the text, passed on to annotate().
See Also
Expand source code
def point_to(ax, text, xyfrom, xyto, radius=0.2, relpos=(1, 0.5), style='>', shrink=0, lw=1, color='k', head_width=15, head_length=15, **kwargs): """ Text with arrow pointing to a point. Parameters ---------- ax: matplotlib axes Axes on which to draw the text and arrow. text: string Text placed at `xyfrom`. xyfrom: tuple of floats X- and y-coordinates of text position in data coordinates. xyto: tuple of floats X- and y-coordinates of arrow point in data coordinates. radius: float Radius of arrow line. Negative curves to the right. Relative to arrow length. relpos: tuple of floats X- and y-coordinate of starting point of arrow on text box. Between 0 and 1. style: string Appearance of the arrow head: '>': line arrow, '|>': filled arrow, '>>': fancy arrow shrink: float Shrink arrow away from endpoints. lw: float Linewidth of line in points. color: matplotlib color Color of line and arrow. head_width: float Width of arrow head in points. head_length: float Length of arrow head in points. **kwargs: key-word arguments Formatting of the text, passed on to annotate(). See Also -------- harrow(), varrow(), arrow_style() """ if style == '>>': arrowstyle = ArrowStyle.Fancy(head_length=0.09*head_length, head_width=0.09*head_width, tail_width=0.14*lw) arrowprops = dict(arrowstyle=arrowstyle, edgecolor='none', linewidth=0) else: scale = head_width*2.0 if style == '|': scale /= 4.0 arrowprops = dict(arrowstyle='-' + style, edgecolor=color, mutation_scale=scale, linewidth=lw) arrowprops.update(dict(facecolor=color, relpos=relpos, shrinkA=shrink, shrinkB=shrink, clip_on=False)) arrowprops.update(dict(connectionstyle='arc3,rad=%g' % radius)) if 'dist' in kwargs: kwargs.pop('dist') ax.annotate(text, xy=xyto, xytext=xyfrom, arrowprops=arrowprops, annotation_clip=False, **kwargs)
def arrow_style(namespace, name, dist=3.0, style='>', shrink=0, lw=1, color='k', head_width=15, head_length=15, **kwargs)
-
Generate an arrow style.
Add dictionary with name 'as'+name to
namespace
and toars
Parameters
namespace
:class
orNone
- Namespace to which the generated arrow style is added. If None add arrow style to the main module.
name
:string
- The name of the arrow style, the prefix 'as' is prepended.
dist
:float
- Distance of text annotation from arrow in points (for harrow() and varrow()).
style
:string
- Appearance of the arrow head: '>': line arrow, '|>': filled arrow, '>>': fancy arrow, '|': bar
shrink
:float
- Shrink arrow away from endpoints.
lw
:float
- Linewidth of line in points.
color
:matplotlib color
- Color of line and arrow.
head_width
:float
- Width of arrow head in points.
head_length
:float
- Length of arrow head in points.
**kwargs
:key-word arguments
- Formatting of the annotation text, passed on to text().
See Also
harrow()
,varrow()
,point_to()
,plot_arrow_styles()
,generic_arrow_styles()
Expand source code
def arrow_style(namespace, name, dist=3.0, style='>', shrink=0, lw=1, color='k', head_width=15, head_length=15, **kwargs): """Generate an arrow style. Add dictionary with name 'as'+name to `namespace` and to `ars` Parameters ---------- namespace: class or None Namespace to which the generated arrow style is added. If None add arrow style to the __main__ module. name: string The name of the arrow style, the prefix 'as' is prepended. dist: float Distance of text annotation from arrow in points (for harrow() and varrow()). style: string Appearance of the arrow head: '>': line arrow, '|>': filled arrow, '>>': fancy arrow, '|': bar shrink: float Shrink arrow away from endpoints. lw: float Linewidth of line in points. color: matplotlib color Color of line and arrow. head_width: float Width of arrow head in points. head_length: float Length of arrow head in points. **kwargs: key-word arguments Formatting of the annotation text, passed on to text(). See Also -------- harrow(), varrow(), point_to(), plot_arrow_styles(), generic_arrow_styles() """ if namespace is None: namespace = __main__ if not hasattr(namespace, 'ars'): setattr(namespace, 'ars', {}) ad = dict(dist=dist, style=style, shrink=shrink, lw=lw, color=color, head_width=head_width, head_length=head_length, **kwargs) setattr(namespace, 'as' + name, ad) getattr(namespace, 'ars')[name] = ad
def generic_arrow_styles(namespace, palette, scale=1)
-
Some generic arrow styles.
asLine
: simple arrowasFilled
: arrow with filled headasPoint
: big arrow with filled head and thick lineasPointSmall
: arrow with filled head and thin lineasMarker
: arrow with filled head, annotation on a transparent background
This is just a suggestion. Copy it and adapt it to your needs!
Parameters
namespace
:class
orNone
- Namespace to which the generated arrow style is added. If None add arrow style to the main module.
palette
:dict
- Color palette. Uses black for the arrow and white for text background.
scale
:float
- Scale factor for line width, head height and width.
See Also
Expand source code
def generic_arrow_styles(namespace, palette, scale=1): """ Some generic arrow styles. - `asLine`: simple arrow - `asFilled`: arrow with filled head - `asPoint`: big arrow with filled head and thick line - `asPointSmall`: arrow with filled head and thin line - `asMarker`: arrow with filled head, annotation on a transparent background This is just a suggestion. Copy it and adapt it to your needs! Parameters ---------- namespace: class or None Namespace to which the generated arrow style is added. If None add arrow style to the __main__ module. palette: dict Color palette. Uses black for the arrow and white for text background. scale: float Scale factor for line width, head height and width. See Also -------- arrow_style(), plot_arrow_styles() """ arrow_style(namespace, 'Line', dist=3, style='>', shrink=0, lw=0.6*scale, color=palette['black'], head_length=4*scale, head_width=4*scale ) arrow_style(namespace, 'Filled', dist=3, style='>>', shrink=0, lw=0.6*scale, color=palette['black'], head_length=8*scale, head_width=5*scale ) arrow_style(namespace, 'Point', dist=3, style='>>', shrink=0, lw=1.2*scale, color=palette['black'], head_length=8*scale, head_width=6*scale ) arrow_style(namespace, 'PointSmall', dist=3, style='>>', shrink=0, lw=1*scale, color=palette['black'], head_length=5*scale, head_width=5*scale, fontsize='small') arrow_style(namespace, 'Marker', dist=3, style='>>', shrink=0, lw=0.9*scale, color=palette['black'], head_length=5*scale, head_width=5*scale, fontsize='small', ha='center', va='center', bbox=dict(boxstyle='round, pad=0.1, rounding_size=0.4', facecolor=palette['white'], edgecolor='none', alpha=0.6))
def plot_arrow_styles(ax, namespace=None)
-
Plot names and arrows of all available arrow styles.
Parameters
ax
:matplotlib axes
- Subplot to use for plotting the arrow styles.
namespace
:class
orNone
- Namespace on which styles are defined. If None take styles from the main module.
See Also
Expand source code
def plot_arrow_styles(ax, namespace=None): """ Plot names and arrows of all available arrow styles. Parameters ---------- ax: matplotlib axes Subplot to use for plotting the arrow styles. namespace: class or None Namespace on which styles are defined. If None take styles from the __main__ module. See Also -------- arrow_style(), generic_arrow_styles() """ if namespace is None: namespace = __main__ for k, name in enumerate(namespace.ars): ax.harrow(0.5, 0.5*k+0.5, 1.0, 'both', 'as'+name, **namespace.ars[name]) ax.set_xlim(0.0, 2.0) ax.set_ylim(0.0, 0.5*k+1) ax.set_title('arrow styles')
def install_arrows()
-
Expand source code
def install_arrows(): """ Install functions of the arrows module in matplotlib. See also -------- uninstall_arrows() """ if not hasattr(mpl.axes.Axes, 'harrow'): mpl.axes.Axes.harrow = harrow if not hasattr(mpl.axes.Axes, 'varrow'): mpl.axes.Axes.varrow = varrow if not hasattr(mpl.axes.Axes, 'point_to'): mpl.axes.Axes.point_to = point_to
def uninstall_arrows()
-
Expand source code
def uninstall_arrows(): """ Uninstall all code of the arrows module from matplotlib. See also -------- install_arrows() """ if hasattr(mpl.axes.Axes, 'harrow'): delattr(mpl.axes.Axes, 'harrow') if hasattr(mpl.axes.Axes, 'varrow'): delattr(mpl.axes.Axes, 'varrow') if hasattr(mpl.axes.Axes, 'point_to'): delattr(mpl.axes.Axes, 'point_to')
def demo()
-
Run a demonstration of the arrows module.
Expand source code
def demo(): """ Run a demonstration of the arrows module. """ fig, ax = plt.subplots() fig.suptitle('plottools.arrows') ax.set_xlim(0.0, 3.0) ax.set_ylim(0.0, 2.0) for y in [1.1, 1.3, 1.5, 1.7, 1.9]: ax.plot([0.2, 1.8], [y, y], '-c', lw=15, solid_capstyle='butt') ax.harrow(0.2, 1.9, 1.6, 'right', 'these', lw=1) ax.harrow(0.2, 1.7, 1.6, 'both', 'are', style='|>', lw=1) ax.harrow(0.2, 1.5, 1.6, 'left', 'all', style='>>', lw=2) ax.harrow(0.2, 1.3, 1.6, 'both', 'arrows', style='|', va='top', lw=2) ax.harrow(0.2, 1.1, 1.6, 'both', 'fancy', style='>>', va='top', lw=2) for x in [0.2, 0.5, 0.8, 1.1, 1.4]: ax.plot([x, x], [0.1, 0.8], '-c', lw=15, solid_capstyle='butt') ax.varrow(0.2, 0.1, 0.7, '>', 'these', lw=4) ax.varrow(0.5, 0.1, 0.7, '<>', 'are', style='|>', lw=4) ax.varrow(0.8, 0.1, 0.7, '<', 'all', ha='left', style='>>', lw=2) ax.varrow(1.1, 0.1, 0.7, 'both', 'arrows', style='|', lw=4, rotation=90) ax.varrow(1.4, 0.1, 0.7, 'both', 'fancy', style='>>', lw=2, rotation='vertical') x = 1.7 ax.plot([x, x], [0.1, 0.8], '-c', lw=25, solid_capstyle='butt') ax.varrow(x, 0.1, 0.7, 'both', 'big fancy', style='>>', lw=5, rotation=90, head_width=25, head_length=35) ax.point_to('point_to', (2.0, 1.9), (2.8, 1.7), -0.3, (1, 0.5)) ax.point_to('point_to', (2.0, 1.6), (2.8, 1.4), -0.3, (1, 0.5), style='|>') ax.point_to('point_to', (2.0, 1.3), (2.8, 1.1), -0.3, (1, 0.5), style='>>') ax.point_to('point_to', (2.0, 1.0), (2.8, 0.8), -0.3, (1, 0.5), style='>', lw=4) ax.point_to('point_to', (2.0, 0.7), (2.8, 0.5), -0.3, (1, 0.5), style='|>', lw=4) ax.point_to('point_to', (2.0, 0.4), (2.8, 0.2), -0.3, (1, 0.5), style='>>', lw=4) plt.show()