Drawing arrows in Matplotlib

This is a fun one. A colleague of mine spent a while this afternoon trying to get arrows to work in Matplotlib, so that he could draw upper-limit points on a graph (similar to this). All to no avail – the arrow() function would happily draw lines, but without an arrow head. He came to ask about it, and we spent a little while digging into the documentation to see what was up.

As it turns out, the documentation was what’s up. The function reference for arrow() is missing information about some rather important keyword arguments, the ones that control arrow head presentation. Even worse, in the versions of Matplotlib we’re using, the default option seems to be to display no arrow head at all! This is clearly broken – arrows should look like arrows by default.

Fortunately, there were a couple of code examples available on the Matplotlib website. Unfortunately, one was rather complicated (312 lines of code!), and the other wasn’t really what he was looking for (fancy arrows in LaTeX). We ended up trying to reverse-engineer the first example, which is when we stumbled upon the extra, undocumented, keyword arguments that would make everything work in a nice, easy way. These are head_length and head_width, which need to be set to non-zero float values to display an arrow head.

I’ve included a minimal example below – it just draws a black arrow with a sensibly-proportioned arrow head. There are other arrow style keywords that you can use too; look at the ArrowStyle documentation to see them listed.

import pylab as P
# P.arrow( x, y, dx, dy, **kwargs )
P.arrow( 0.5, 0.8, 0.0, -0.2, fc="k", ec="k",
head_width=0.05, head_length=0.1 )

Drawing an arrow in Matplotlib


About Phil Bull

I'm a theoretical cosmologist, currently working as a NASA NPP fellow at JPL/Caltech in Pasadena, CA. My research focuses on the effects of inhomogeneities on the evolution of the Universe and how we measure it. I'm also keen on stochastic processes, scientific computing, the philosophy of science, and open source stuff. View all posts by Phil Bull

12 responses to “Drawing arrows in Matplotlib

  • Gilmour

    Ugg, I’d been wondering about this…thanks for clearing it up

  • Phil Marshall (@drphilmarshall)

    In a log-log plot it turns out you have to make a whole new axis, with linear scales, and draw the arrow there. StackOverflow has the details:


  • Bennett B

    How did you stumble on a keyword? Saw it on the Web in a posting? Looked at the source code for the module?

    • Phil Bull

      I saw an example on the Matplotlib website that was doing something much more complicated (i.e. it wasn’t just drawing a simple arrow, but arrows were involved), and dug through the code to investigate. And there, lo and behold, were the undocumented/broken keywords in the call to arrow(). If I’d suspected the problem was missing keywords before, I’d have simply looked through the source code, but that idea didn’t occur to me until I actually saw the damn things!

  • Ben

    I was looking for an answer to this question, and found a useful solution! You can specify any “mathtext” character (matplotlib’s version of LaTeX) as a marker. Try: plt.plot(x,y, ‘ko’, marker=r’$\downarrow$’, markersize=20)

    This will plot a downward pointing, black arrow at position (x,y) that looks good on any plot (even log-log). See: matplotlib.org/users/mathtext.html#mathtext-tutorial for more symbols you can use.


    I figured out the keywords by myself (this documentation
    was particularly useful), but when I use them, I get a flat arrow, not a pointed one.

    If I use an annotation, I can get a pointy arrow, but I want one text annotation to point to two things, and I can’t figure out how to get that to work without drawing a raw arrow and not an annotation.

    Even the arrow example from the page that you linked to seems to just use annotations as an example. I might use the -[ style to encompass two locations with the text and move on, but this is very annoying…


      Ok so to reply to my own comment, you need to scale the width and height depending on the values in your plot. In my case, the x_lim was fairly small, but the y_lim was large (in the thousands). So the arrow looked flat – the height was very small at the yscale. I scaled everything (head_length=20,head_width=0.5) and it worked.

  • nangomusic

    thank your very much, that was helpful!

  • AL

    According to the code in this example, the desired arrow length is 0.2. But the figure shows an arrow that has a length of about 0.3… What is that supposed to mean ?? It seems the head is added to the vector, thus adding to the total length. That is a pretty inconvenient behaviour in any applications I can think of in science… It means one has to define dx and dy as the desired length minus the head length. Is there a keyword to modify this behaviour ?

  • AL

    Found my answer (length_includes_head=True) – sorry for the hassle.

  • Eduardo Zamora

    OMG Hi Phil!
    I came across this article while writing a program to create streamplots for my differential equations class.
    Thanks for the article, and hope all is well at UC Berkeley!
    – Eduardo Zamora

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: