I would like to display a set of xy-data in Matplotlib in such a way as to indicate a particular path. Ideally, the linestyle would be modified to use an arrow-like patch. I have created a mock-up, shown below (using Omnigraphsketcher). It seems like I should be able to override one of the common
Here's a starting off point:
Walk along your line at fixed steps (
aspace in my example below) .
A. This involves taking steps along the line segments created by two sets of points (
y1) and (
B. If your step is longer than the line segment, shift to the next set of points.
At that point determine the angle of the line.
Draw an arrow with an inclination corresponding to the angle.
I wrote a little script to demonstrate this:
import numpy as np import matplotlib.pyplot as plt fig = plt.figure() axes = fig.add_subplot(111) # my random data scale = 10 np.random.seed(101) x = np.random.random(10)*scale y = np.random.random(10)*scale # spacing of arrows aspace = .1 # good value for scale of 1 aspace *= scale # r is the distance spanned between pairs of points r =  for i in range(1,len(x)): dx = x[i]-x[i-1] dy = y[i]-y[i-1] r.append(np.sqrt(dx*dx+dy*dy)) r = np.array(r) # rtot is a cumulative sum of r, it's used to save time rtot =  for i in range(len(r)): rtot.append(r[0:i].sum()) rtot.append(r.sum()) arrowData =  # will hold tuples of x,y,theta for each arrow arrowPos = 0 # current point on walk along data rcount = 1 while arrowPos < r.sum(): x1,x2 = x[rcount-1],x[rcount] y1,y2 = y[rcount-1],y[rcount] da = arrowPos-rtot[rcount] theta = np.arctan2((x2-x1),(y2-y1)) ax = np.sin(theta)*da+x1 ay = np.cos(theta)*da+y1 arrowData.append((ax,ay,theta)) arrowPos+=aspace while arrowPos > rtot[rcount+1]: rcount+=1 if arrowPos > rtot[-1]: break # could be done in above block if you want for ax,ay,theta in arrowData: # use aspace as a guide for size and length of things # scaling factors were chosen by experimenting a bit axes.arrow(ax,ay, np.sin(theta)*aspace/10,np.cos(theta)*aspace/10, head_width=aspace/8) axes.plot(x,y) axes.set_xlim(x.min()*.9,x.max()*1.1) axes.set_ylim(y.min()*.9,y.max()*1.1) plt.show()
This example results in this figure:
There's plenty of room for improvement here, for starters:
While looking into this, I discovered the quiver plotting method. It might be able to replace the above work, but it wasn't immediately obvious that this was guaranteed.