在gnuplot中的两个点之间绘制弯曲的箭头 [英] Draw a bended arrow between two points in gnuplot
问题描述
我正在使用以下gnuplot代码制作下图.我想从头部标记 l = 0 到 l = 1 的点绘制一条弯曲的箭头.
I am producing the figure below using the following gnuplot code. I want to draw a bended arrow from the point labeled l=0 to l=1 with head.
代码
reset session
# Ranges
set xrange [-1:6]
set yrange [-2:1]
# Term options
set terminal postscript eps
set termoption font "Times, 30"
# set termoption
set style line 1 lc rgb 'black' lw 3 lt 1 pt 7 ps 2
# Data points
$DATA<<EOD
0 0
1 0
2 0
3 0
4 0
5 0
6 0
EOD
set output "Anderson_lattice.eps"
# set arrow
set arrow 1 from -0.5, -1.5 to 5.5, -1.5 lc rgb 'black' lw 5
set arrow 2 from -0.5, -1.5 to -0.5, -0.5 lc rgb 'black' lw 5
set label 1 "{/Times-Italic=30 {/Symbol e}_{l}}" at -0.75, -0.3 tc rgb "black"
set arrow 3 from -0.25, -1.0 to 0.25, -1.0 ls 1 nohead
set arrow 5 from 1 - 0.25, -0.75 to 1 + 0.25, -0.75 ls 1 nohead
set arrow 6 from 2 - 0.25, -0.5 to 2 + 0.25, -0.5 ls 1 nohead
set arrow 7 from 3 - 0.25, -1.35 to 3 + 0.25, -1.35 ls 1 nohead
set arrow 8 from 4 - 0.25, -1.0 to 4 + 0.25, -1 ls 1 nohead
set arrow 9 from 5 - 0.25, -0.85 to 4 + 0.25, -0.85 ls 1 nohead
set arrow 10 from 6 - 0.25, -1.25 to 6 + 0.25, -1.25 ls 1 nohead
set label 2 "{/Times-Italic=30 sites}" at 5.5, -1.65 tc 'black'
set label 3 "{/Times-Italic=30 l=0}" at 2.7, -0.25 tc 'black'
set label 4 "{/Times-Italic=30 l=1}" at 1 + 2.7, -0.25 tc 'black'
unset xtics; unset ytics; unset border
plot $DATA using 1:2 with p ls 1 notitle
unset output
结果
我该怎么做?
推荐答案
我不知道gnuplot提供了直接绘制弯曲箭头的功能.
I'm not aware that gnuplot offers a feature for directly drawing a bent arrow.
修改: (我删除了最初的方法,因为它没有使用CubicBézier的优势.并且为第二种方法增加了更多的灵活性.)
我完全同意@GRSousaJr的观点,即三次Bézier曲线在绘制弯曲的箭头时具有更大的灵活性.同时,您还可以绘制直线箭头.
I completely agree with @GRSousaJr that Cubic Bézier curves give much more flexibility in drawing bent arrows. At the same time you can also draw straight arrows.
基于@GRSousaJr的方法,我的建议如下:
而不是输入控制点的绝对值,我更喜欢相对或绝对角度以及相对距离.这样的好处是您不必关心绝对数字,尤其是当两个箭头的比例相同但绝对起点/终点不同时.
箭头的所有参数都在数据块$myArrows
中.
Based on @GRSousaJr's approach, my suggestions would be the following:
instead of entering absolute values for the control points, I would prefer relative or absolute angles and relative distances. This has the advantage that you don't have to care about absolute numbers, especially when two arrows should have the same proportions but have different absolute start/endpoints.
All parameters for the arrows are in the datablock $myArrows
.
一些解释:
-
三次贝塞尔曲线的
-
使用4个点:
p0,p1,p2,p3
,其中p0
和p3
分别是起点和终点.p1
和p2
是控制曲率的点.p0x, p0y, ... p3x, p3y
分别是x
和y
组件.
for the Cubic Bézier curves 4 points are used:
p0,p1,p2,p3
, wherep0
andp3
are the start and end points, respectively.p1
andp2
are points which control the curvature.p0x, p0y, ... p3x, p3y
are thex
andy
components, respectively.
的控制点p1
和p2
的绝对值不是绝对值,而是根据p0
和p3
以及角度a0
和a3
以及半径r0
和r3
.
in contrast to @GRSousaJr's solution the control points p1
and p2
are not given in absolute values but calculated from p0
and p3
and the angles a0
and a3
and the radii r0
and r3
.
在点p0
和p3
处的箭头角度可以为绝对值或相对于p0
至p3
的方向.参数e
指示哪一端具有相对角度,哪一端具有绝对角度. 0 =两端的相对角度,1 =起始角度相对,绝对角度,2 =起始角度绝对,相对角度,3 =两端角度绝对.对于相对角度,您首先需要计算p0
和p3
(函数AngleP0P3()
)
the angles of the arrow at the points p0
and p3
can be given absolute or relative to the direction of p0
to p3
. The parameter e
tells which end has relative angle and which end absolute angle. 0=angles at both ends relative, 1=start angle relative, end angle absolute, 2=start angle absolute, end angle relative, 3=angles at both ends absolute. For the relative angle you first need to calculate the angle between p0
and p3
(function AngleP0P3()
)
控制点p1
和p2
与点p0
和p3
的距离以相对值r0
和r3
相对于p0
之间的距离给出和p3
.这就是为什么有功能Length()
的原因. 0.5
首先是一个很好的价值.
the distance of the control points p1
and p2
from the points p0
and p3
are given in relative values r0
and r3
with respect to the distance between p0
and p3
. That's why there is the function Length()
. 0.5
is a good value to start with.
请注意,函数AngleP0P3(n)
和Length(n)
实际上不依赖于n
.那只是为了缩短代码.这些函数使用参数p1x, ..., p3y
,并且在调用AngleP0P3(0)
时,该函数将采用p1x, ..., p3y
的当前值.这比例如Angle(p0x,p0y,p3x,p3y)
.
note that the functions AngleP0P3(n)
and Length(n)
actually do not depend on n
. That is just to shorten the code. These functions use the parameters p1x, ..., p3y
, and when calling AngleP0P3(0)
the function will take the current values of p1x, ..., p3y
. This is shorter than e.g. Angle(p0x,p0y,p3x,p3y)
.
函数ArrowInit(i)
用于从数据块$myArrows
的第i
行收集或初始化p1x, ..., p3y
的值.
the function ArrowInit(i)
is to collect or initialize the values for p1x, ..., p3y
from the i
th row of datablock $myArrows
.
在t
中,范围为t[0:1]
的参数函数中的箭头线只是简单地绘制在for循环中.对于绘图命令中的每个i
,都会调用ArrowInit(i)
来从数据块$myArrows
中获取相应的参数.
the line of the arrows are simply plotted in a for loop as parametric function in t
with the range t[0:1]
. For every i
in the plot command ArrowInit(i)
is called to get the corresponding parameters from the datablock $myArrows
.
在p3
点上的箭头的角度沿从p2
到p3
的方向,即Bézier曲线在点p3
上的切线.但是,您不需要线条,而只需要箭头.到目前为止,我没有比绘制从箭头路径的99%到箭头路径的100%的短向量更好的方法.
The angle of the arrow in point p3
is in the direction from p2
to p3
, i.e. the tangent of the Bézier curve in point p3
. However you don't want the line, but just the arrow. So far, I don't have a better approach than plotting a short vector from 99% of the arrow path to 100% of the arrow path.
一些用法说明:
-
为了看到"您在
$myArrows
中指定的正确角度,绘图必须具有与x和y范围相同的纵横比.在下面的示例中,它是x[0:20]
和y[0:10]
,因此,将图形的纵横比设置为0.5
,即在set size 0.5
的开头.
in order to "see" the correct angles you specify in
$myArrows
, your plot has to have the same aspect ratio as your x and y ranges. In the below examples it isx[0:20]
andy[0:10]
, hence, set the aspect ratio of the graph to0.5
, i.e. at the beginningset size 0.5
.
箭头的方向是点p3
上的切线.如果p3
处的曲率较大,则箭头可能看起来不好",尽管箭头的角度正确.在这种情况下,请稍微增加长度r3
.
the direction of the arrow head is the tangent in point p3
. If you have a strong curvature at p3
, the arrow head might look "bad", although the arrow head is in the correct angle. In such cases, increase the length r3
a little.
您还可以绘制直线箭头,请参见Arrow1.只需设置a0=0,a3=0
和e=0
.
You can also draw straight arrows, see Arrow1. Just set a0=0,a3=0
and e=0
.
使用gnuplot 5.2.8测试
Tested with gnuplot 5.2.8
代码:
### workaround for bent arrows
reset session
set size ratio 0.5
# p0x p0y a0 r0 p3x p3y a3 r3 e color
$myArrows <<EOD
1 1.00 1.00 0 0.5 3.00 3.00 0 0.5 0 0xff0000
2 3.00 1.00 0 0.5 5.00 3.00 0 0.5 1 0x00c000
3 5.00 1.00 0 0.5 7.00 3.00 0 0.5 2 0x0000ff
4 7.00 1.00 0 0.5 9.00 3.00 0 0.5 3 0xff00ff
5 1.00 4.00 0 0.5 3.00 6.00 90 0.5 0 0xff0000
6 3.00 4.00 0 0.5 5.00 6.00 90 0.5 1 0x00c000
7 5.00 4.00 0 0.5 7.00 6.00 90 0.5 2 0x0000ff
8 7.00 4.00 0 0.5 9.00 6.00 90 0.5 3 0xff00ff
9 1.00 7.00 90 0.5 3.00 9.00 0 0.5 0 0xff0000
10 3.00 7.00 90 0.5 5.00 9.00 0 0.5 1 0x00c000
11 5.00 7.00 90 0.5 7.00 9.00 0 0.5 2 0x0000ff
12 7.00 7.00 90 0.5 9.00 9.00 0 0.5 3 0xff00ff
13 11.00 1.00 45 0.5 13.00 3.00 -45 0.5 0 0xff0000
14 13.00 1.00 45 0.5 15.00 3.00 -45 0.5 1 0x00c000
15 15.00 1.00 45 0.5 17.00 3.00 -45 0.5 2 0x0000ff
16 17.00 1.00 45 0.5 19.00 3.00 -45 0.5 3 0xff00ff
17 11.00 4.00 -45 0.5 13.00 6.00 -45 0.5 0 0xff0000
18 13.00 4.00 -45 0.5 15.00 6.00 -45 0.5 1 0x00c000
19 15.00 4.00 -45 0.5 17.00 6.00 -45 0.5 2 0x0000ff
20 17.00 4.00 -45 0.5 19.00 6.00 -45 0.5 3 0xff00ff
21 11.00 7.00 0 0.5 15.00 9.00 90 0.5 1 0x00c000
22 15.00 7.00 0 0.5 19.00 9.00 0 0.5 1 0x00c000
EOD
set angle degrees
# Angle between p0 and p3 (range: -90° <= angle < 270°), NaN if dx=dy=0
AngleP0P3(n) = (dy=p3y-p0y,dx=p3x-p0x)==0 ? (dy==0 ? NaN : sgn(dy)*90) : \
(dx<0 ? 180 : 0) + atan(dy/dx)
# Parameter e: determines which ends have relative or absolute angles
# 0: both ends relative
# 1: start relative, end absolute,
# 2: start absolute, end relative
# 3: both ends absolute
AngleAbs(i) = int(word($myArrows[i],10)) # to set all arrows equal, use: AngleAbs(i) = 0,1,2, or 3
Angle(i,p) = word($myArrows[i],p) + \
((p==4 && AngleAbs(i)&2) || (p==8 && AngleAbs(i)&1) ? 0 : AngleP0P3(0))
Length(n) = sqrt((p3x-p0x)**2 + (p3y-p0y)**2)
Color(i) = word($myArrows[i],11)
ArrowInit(i) = (p0x=word($myArrows[i],2),p0y=word($myArrows[i],3), \
p3x=word($myArrows[i],6),p3y=word($myArrows[i],7), \
p1x=p0x+Length(0)*word($myArrows[i],5)*cos(Angle(i,4)), \
p1y=p0y+Length(0)*word($myArrows[i],5)*sin(Angle(i,4)), \
p2x=p3x-Length(0)*word($myArrows[i],9)*cos(Angle(i,8)), \
p2y=p3y-Length(0)*word($myArrows[i],9)*sin(Angle(i,8)))
# Cubic Bézier curves function with t[0:1] as parameter
# p0: start point, p1: 1st control point, p2: 2nd control point, p3: endpoint
px(t) = (-p0x + 3*p1x - 3*p2x + p3x)*t**3 + (3*p0x - 6*p1x + 3*p2x)*t**2 + (-3*p0x + 3*p1x)*t + p0x
py(t) = (-p0y + 3*p1y - 3*p2y + p3y)*t**3 + (3*p0y - 6*p1y + 3*p2y)*t**2 + (-3*p0y + 3*p1y)*t + p0y
# set linestyles and arrowstyles
do for [i=1:|$myArrows|] {
set style line i lw 2 lc rgb Color(i)
set style arrow i head size 0.20,15,45 fixed filled ls i
}
set key out noautotitle below
set xrange [0:20]
set xtics 1
set format x ""
set grid xtics ls -1 lc rgb "gray"
set yrange [0:10]
set ytics 1
set format y ""
set grid ytics ls -1 lc rgb "gray"
plot for [i=1:|$myArrows|] [0:1] '+' u (ArrowInit(i),px($1)):(py($1)) w l ls i, \
for [i=1:|$myArrows|] [0:1] '+' u (ArrowInit(i),px(0.99)):(py(0.99)): \
(px(1)-px(0.99)):(py(1)-py(0.99)) every ::0::0 w vec as i, \
$myArrows u 2:3:1 w labels offset 0,-0.7, \
keyentry w l ls 1 ti "both ends relative angles", \
keyentry w l ls 2 ti "start relative, end absolute angle", \
keyentry w l ls 3 ti "start absolute, end relative angle", \
keyentry w l ls 4 ti "both ends absolute angles"
### end of code
exit
结果:
这篇关于在gnuplot中的两个点之间绘制弯曲的箭头的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!