Reputation: 1007
I want to add arrow for a series of curves in gnuplot
. The question is how to put arrow in the center of a curve. My solution is to find line segment in the points sequence, and draw an arrow for this line segment. It works but the size of arrows are different.
I have write a code with python+gnuplot, it works but looks ugly
#!/bin/python
import numpy as np
import Gnuplot
def middleArrowCurve(g, x,y, percent, reverse=False):
d = Gnuplot.Data(x,y,with_='l')
index = int(len(x)*percent)
fromx,tox = x[index],x[index+1]
fromy,toy = y[index],y[index+1]
g('set style arrow 1 front head filled size screen 0.03,15 lt 1 lw 1')
if reverse:
g('set arrow from ' + str(tox) + ',' + str(toy) + ' to ' + str(fromx) + ',' + str(fromy) + ' as 1')
else :
g('set arrow from ' + str(fromx) + ',' + str(fromy) + ' to ' + str(tox) + ',' + str(toy) + ' as 1')
return d
def stableNode2():
g = Gnuplot.Gnuplot(persist=1)
g('set term png')
g('set output "stableNode2.png"')
g('unset key')
g('unset tics')
g('unset border')
g('set xrange [-1:1]')
g('set yrange [-1:1]')
data = []
reverse = False
for s in [-1,1]:
x = np.linspace(s,0,20)
data.append(middleArrowCurve(g,x,0.6*x**2,0.5,reverse))
data.append(middleArrowCurve(g,x,-0.6*x**2,0.5,reverse))
data.append(middleArrowCurve(g,x,2*x**2,0.5,reverse))
data.append(middleArrowCurve(g,x,-2*x**2,0.5,reverse))
data.append(middleArrowCurve(g,x,x*0,0.5,reverse))
data.append(middleArrowCurve(g,x*0,x,0.5,reverse))
g.plot(*data)
stableNode2()
Upvotes: 3
Views: 1538
Reputation: 1007
Use set object poly
can solve this.
#!/bin/python
import numpy as np
import Gnuplot
arrowCount = 0
def addArrow(g, x,y, dx, dy, width=0.01,angle=15):
def normal(v):
s = 1.0/np.sqrt(v[0]**2+v[1]**2)
v[0] *= s
v[1] *= s
l = [dx,dy]
n = [-dy,dx]
normal(l)
normal(n)
length = width/np.tan(angle*np.pi/360)
coords = []
coords.append((x,y))
coords.append((x+n[0]*width,y+n[1]*width))
coords.append((x+l[0]*length,y+l[1]*length))
coords.append((x-n[0]*width,y-n[1]*width))
coords.append((x,y))
coordsStr = "from "
coordsStr += " to ".join([str(c[0])+","+str(c[1]) for c in coords])
global arrowCount
arrowCount += 1
return 'set object ' + str(arrowCount) + ' polygon ' + coordsStr + ';set object ' + str(arrowCount) + ' fc rgb "red" fs solid '
def middleArrowCurve(g, x,y, percent, reverse=False):
d = Gnuplot.Data(x,y,with_='l')
index = int(len(x)*percent)
fromx,tox = x[index],x[index+1]
fromy,toy = y[index],y[index+1]
if reverse:
return d,addArrow(g, tox,toy, -tox+fromx, -toy+fromy)
else:
return d,addArrow(g, fromx,fromy, tox-fromx, toy-fromy)
def stableNode2():
g = Gnuplot.Gnuplot(persist=1)
g('set term png')
g('set output "stableNode2.png"')
g('unset key')
g('unset tics')
g('unset border')
g('set xrange [-1:1]')
g('set yrange [-1:1]')
data = []
reverse = False
for s in [-1,1]:
x = np.linspace(s,0,20)
data.append(middleArrowCurve(g,x,0.6*x**2,0.5,reverse))
data.append(middleArrowCurve(g,x,-0.6*x**2,0.5,reverse))
data.append(middleArrowCurve(g,x,2*x**2,0.5,reverse))
data.append(middleArrowCurve(g,x,-2*x**2,0.5,reverse))
data.append(middleArrowCurve(g,x,x*0,0.5,reverse))
data.append(middleArrowCurve(g,x*0,x,0.5,reverse))
for a in data:
g(a[1])
g.plot(*[d[0] for d in data])
stableNode2()
The remaining problem is why the polygon arrows are covered by line plot? If I put polygon drawing after the line plot, they are just ignored.
Upvotes: 1
Reputation: 48390
As of version 4.6 gnuplot automatically scales the arrow head if the arrow length is less than twice the head's length. In version 5.0 (almost stable, 5.0RC2 is out) an additional arrow parameter fixed
was introduced which prevents this scaling. So using the line
g('set style arrow 1 front head filled size screen 0.03,15 fixed lt 1 lw 1')
gives the result:
In version 4.6 I don't know any other workaround than increasing the length of some arrows.
Upvotes: 3