Source code for httk.graphics.matplotlib.arrowplot
#
# The high-throughput toolkit (httk)
# Copyright (C) 2012-2015 Rickard Armiento
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# Uses parts from 'Pedro M Duarte',
# http://stackoverflow.com/questions/8247973/how-do-i-specify-an-arrow-like-linestyle-in-matplotlib
[docs]
def arrowplot(axes, x, y, narrs=10, dspace=0.5, aspace=0.1, direc='pos',
hl=0.025, hw=2.5, c='black'):
''' narrs : Number of arrows that will be drawn along the curve
dspace : Shift the position of the arrows along the curve.
Should be between 0. and 1.
direc : can be 'pos' or 'neg' to select direction of the arrows
hl : length of the arrow head
hw : width of the arrow head
c : color of the edge and face of the arrow head
'''
from httk.external.numpy_ext import numpy as np
x = np.array(x)[::-1]
y = np.array(y)[::-1]
# r is the distance spanned between pairs of points
r = [0]
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())
# based on narrs set the arrow spacing
#aspace = r.sum() / narrs
narrs = r.sum()/aspace
if direc == 'neg':
dspace = -1.*abs(dspace)
else:
dspace = abs(dspace)
arrowData = [] # will hold tuples of x,y,theta for each arrow
arrowPos = aspace*(dspace) # current point on walk along data
# could set arrowPos to 0 if you want
# an arrow at the beginning of the curve
ndrawn = 0
rcount = 1
while arrowPos < r.sum() and ndrawn < narrs:
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))
ndrawn += 1
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
dx0 = np.sin(theta)*hl/2. + ax
dy0 = np.cos(theta)*hl/2. + ay
dx1 = -1.*np.sin(theta)*hl/2. + ax
dy1 = -1.*np.cos(theta)*hl/2. + ay
if direc == 'neg':
ax0 = dx0
ay0 = dy0
ax1 = dx1
ay1 = dy1
else:
ax0 = dx1
ay0 = dy1
ax1 = dx0
ay1 = dy0
axes.annotate('', xy=(ax0, ay0), xycoords='data',
xytext=(ax1, ay1), textcoords='data',
arrowprops=dict(headwidth=hw, headlength=10, ec=c, fc=c))
axes.plot(x, y, color=c)
#axes.set_xlim(x.min()*.9,x.max()*1.1)
#axes.set_ylim(y.min()*.9,y.max()*1.1)
if __name__ == '__main__':
from httk.external.matplotlib_ext import matplotlib
from matplotlib import pyplot as plt
from httk.external.numpy_ext import numpy as np
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
x = [0, 1]
y = [0, 1]
arrowplot(axes, x, y)
plt.show(block=False)
plt.pause(3)
plt.close()