python4oceanographers

Turning ripples into waves

Simulating Matlab's compass with mpl

Matlab's compass is a very handy function to plot arrows emanating from an origin. As far as I know matplotlib does not have an equivalent function. However, matplotlib is so versatile that we can build a compass like function very quickly.

We will need a function to convert from Cartesian coordinates to Polar coordinates.

In [2]:
import numpy as np


def cart2pol(x, y):
    """Convert from Cartesian to polar coordinates.

    Example
    -------
    >>> theta, radius = pol2cart(x, y)
    """
    radius = np.hypot(x, y)
    theta = np.arctan2(y, x)
    return theta, radius

Now we need a way to plot the arrows from the origin in the Polar coordinates. My first guess was to use arrow, but then I found this and realized it is not a good idea to use arrows. Then I thought about quiver... But before I even tried quiver I found this and I realized that arrow annotations was the way to go for simple, good looking graphs.

From the docs:

An arrow connecting two point (xy & xytext) can be optionally
drawn by specifying the arrowprops argument. To draw only an
arrow, use empty string as the first argument.
In [3]:
import matplotlib.pyplot as plt

def compass(u, v, arrowprops=None):
    """
    Compass draws a graph that displays the vectors with
    components `u` and `v` as arrows from the origin.

    Examples
    --------
    >>> import numpy as np
    >>> u = [+0, +0.5, -0.50, -0.90]
    >>> v = [+1, +0.5, -0.45, +0.85]
    >>> compass(u, v)
    """

    angles, radii = cart2pol(u, v)

    fig, ax = plt.subplots(subplot_kw=dict(polar=True))

    kw = dict(arrowstyle="->", color='k')
    if arrowprops:
        kw.update(arrowprops)
    [ax.annotate("", xy=(angle, radius), xytext=(0, 0),
                 arrowprops=kw) for
     angle, radius in zip(angles, radii)]

    ax.set_ylim(0, np.max(radii))

    return fig, ax

Now let's plot it,

In [4]:
u = [+0, -0.5, -0.50, +0.90]
v = [+1, +0.5, -0.45, -0.85]

fig, ax = compass(u, v)

and customize the arrows:

In [5]:
arrowprops = dict(color='darkorange', linewidth=2)

fig, ax = compass(u, v, arrowprops=arrowprops)
In [6]:
HTML(html)
Out[6]:

This post was written as an IPython notebook. It is available for download or as a static html.

Creative Commons License
python4oceanographers by Filipe Fernandes is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.
Based on a work at https://ocefpaf.github.io/.

Comments