在gnuplot中的两个点之间绘制弯曲的箭头 [英] Draw a bended arrow between two points in gnuplot

查看:72
本文介绍了在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.

一些解释:

    三次贝塞尔曲线的
  1. 使用4个点:p0,p1,p2,p3,其中p0p3分别是起点和终点. p1p2是控制曲率的点. p0x, p0y, ... p3x, p3y分别是xy组件.

  1. for the Cubic Bézier curves 4 points are used: p0,p1,p2,p3, where p0 and p3 are the start and end points, respectively. p1 and p2 are points which control the curvature. p0x, p0y, ... p3x, p3y are the x and y components, respectively.

的控制点p1p2的绝对值不是绝对值,而是根据p0p3以及角度a0a3以及半径r0r3.

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.

在点p0p3处的箭头角度可以为绝对值或相对于p0p3的方向.参数e指示哪一端具有相对角度,哪一端具有绝对角度. 0 =两端的相对角度,1 =起始角度相对,绝对角度,2 =起始角度绝对,相对角度,3 =两端角度绝对.对于相对角度,您首先需要计算p0p3(函数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())

控制点p1p2与点p0p3的距离以相对值r0r3相对于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 ith 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点上的箭头的角度沿从p2p3的方向,即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.

一些用法说明:

  1. 为了看到"您在$myArrows中指定的正确角度,绘图必须具有与x和y范围相同的纵横比.在下面的示例中,它是x[0:20]y[0:10],因此,将图形的纵横比设置为0.5,即在set size 0.5的开头.

  1. 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 is x[0:20] and y[0:10], hence, set the aspect ratio of the graph to 0.5, i.e. at the beginning set 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=0e=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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆