Я создал (по крайней мере, на мой взгляд) «улучшенную» версию ответа @ theozh , которая позволяет в некоторой степени контролировать форму стрелки.
Идея состоит в том, чтобы использовать кривую Безье , чтобы нарисовать изогнутую стрелку. head
рисуется как в ответе @ theozh, т. Е. С использованием vectors
. Начальная (xi,yi
) и конечная точки (xy,yf
), а также контрольные точки (xc1,yc1
и xc2,yc2
) передаются в функцию с помощью команды call
. Функция создает файл данных, используя id
, как tag
в стандартном arrow
, определенном пользователем, и связывает имя переменной (например, BentArrow_id
) с таким файлом данных. Каждый созданный файл данных содержит:
- контрольные точки
- точки данных для создания
arrow
и - точки данных создают
head
как три индексируемых блока данных (0
, 1
и 2
соответственно), например:
# Block index 0 (control points)
1.000000e+00 -1.250000e+00
1.250000e+00 0.000000e+00
2.800000e+00 -5.000000e-01
3.000000e+00 -7.500000e-01
# Block index 1 (arrow)
1.000000e+00 -1.250000e+00
1.016539e+00 -1.177084e+00
1.036070e+00 -1.108272e+00
1.058468e+00 -1.043468e+00
... ...
2.927437e+00 -6.862240e-01
2.949992e+00 -7.027320e-01
2.969690e+00 -7.189280e-01
2.986401e+00 -7.347160e-01
3.000000e+00 -7.500000e-01
# Block index 2 (head)
2.986401e+00 -7.347160e-01 1.359880e-02 -1.528400e-02
3.000000e+00 -7.500000e-01 0.000000e+00 0.000000e+00
Чтобы нарисовать изогнутую стрелку, команда plot
должна быть состоит из трех частей:
plot \
...
BentArrow_id i 0 u 1:2 w lp ...,\
BentArrow_id i 1 u 1:2 w lines ...,\
BentArrow_id i 2 u 1:2:3:4 w vectors ...,\
...
Каждая часть соответствует куску стрелки (контрольные точки, сама стрелка и головка соответственно).
Чтобы лучше показать сценарий ( называется BentArrow.fct
) работает, рассмотрим пример.
reset
set terminal wxt size 500,500
set size ratio -1
set grid ls -1 lc "gray"
unset key
set tics out nomirror
set xrange [-0.25:9.25]
set yrange [-0.25:9.25]
set style arrow 1 head size 0.25,15,45 fixed filled lc "red"
BentArrow(id,xi,yi,x1,y1,x2,y2,xf,yf) = \
sprintf("call 'BentArrow.fct' '%g' '%f' '%f' '%f' '%f' '%f' '%f' '%f' '%f'", \
id, xi,yi, x1,y1, x2,y2, xf,yf )
# id, xi,yi , xc1,yc1, xc2,yc2, xf,yf
eval BentArrow(1, 1.0,1.0, 2.0,2.0, 3.0,0.0, 4.0,1.0)
eval BentArrow(2, 5.0,1.0, 6.0,0.0, 7.0,2.0, 8.0,1.0)
eval BentArrow(3, 1.0,4.0, 2.0,3.0, 3.0,3.0, 4.0,4.0)
eval BentArrow(4, 5.0,4.0, 6.0,5.0, 7.0,5.0, 8.0,4.0)
eval BentArrow(5, 1.0,7.0, 5.0,5.0, 0.0,5.0, 4.0,7.0)
eval BentArrow(6, 5.0,7.0, 5.0,9.0, 6.0,7.0, 8.0,7.0)
CtrlPoints = "w lp ls -1 pt 6 ps 1 pi -1"
StyleArrow = "w lines lc 'red' lw 2"
StyleHead = "w vec as 1"
plot \
BentArrow_1 i 0 u 1:2 @CtrlPoints ,\
BentArrow_1 i 1 u 1:2 @StyleArrow ,\
BentArrow_1 i 2 u 1:2:3:4 @StyleHead ,\
BentArrow_2 i 0 u 1:2 @CtrlPoints ,\
BentArrow_2 i 1 u 1:2 @StyleArrow ,\
BentArrow_2 i 2 u 1:2:3:4 @StyleHead ,\
BentArrow_3 i 0 u 1:2 @CtrlPoints ,\
BentArrow_3 i 1 u 1:2 @StyleArrow ,\
BentArrow_3 i 2 u 1:2:3:4 @StyleHead ,\
BentArrow_4 i 0 u 1:2 @CtrlPoints ,\
BentArrow_4 i 1 u 1:2 @StyleArrow ,\
BentArrow_4 i 2 u 1:2:3:4 @StyleHead ,\
BentArrow_5 i 0 u 1:2 @CtrlPoints ,\
BentArrow_5 i 1 u 1:2 @StyleArrow ,\
BentArrow_5 i 2 u 1:2:3:4 @StyleHead ,\
BentArrow_6 i 0 u 1:2 @CtrlPoints ,\
BentArrow_6 i 1 u 1:2 @StyleArrow ,\
BentArrow_6 i 2 u 1:2:3:4 @StyleHead
Результаты
Применение сценария к вашему примеру, результат выглядит следующим образом
Конечно, контрольные точки полезны только для определения каждой стрелки.
Переменная showCtrlPoints = "False" (default "True")
определена для позволяет скрыть контрольные точки на конечном графике.
Сценарий до последнего примера:
reset
# The data
$levels<<EOD
1 0.5 -1.25
2 0.5 -1.00
3 0.5 -0.75
4 0.5 -0.50
5 0.5 -0.25
6 0.5 -1.25
7 0.5 -1.00
8 0.5 -0.75
9 0.5 -0.50
10 0.5 -0.25
EOD
# Cubic Bézier function
BentArrow(id,xi,yi,x1,y1,x2,y2,xf,yf) = \
sprintf("call 'BentArrow.fct' '%g' '%f' '%f' '%f' '%f' '%f' '%f' '%f' '%f'", \
id, xi,yi, x1,y1, x2,y2, xf,yf )
# Arrow styles
set style arrow 1 head size 0.2,15,45 fixed filled lc "red"
set style arrow 2 head size 0.2,15,45 fixed filled lc "web-green"
set style arrow 3 head size 0.2,15,45 fixed filled lc "blue"
# To levels
set errorbars small
unset key
# Options to drawing the bent arrows
showCtrlPoints = "False"
ArrowPoints = 50
# Calling the function
eval BentArrow(1, 1.00,-1.25, 1.25, 0.00, 2.80,-0.50, 3.00,-0.75)
eval BentArrow(2, 8.00, 0.50, 8.00, 0.00, 5.00, 0.25, 5.00,-0.25)
eval BentArrow(3, 1.00, 0.50, 2.00,-0.25, 9.00, 0.50, 10.0,-0.25)
# Macros
Points = "w p ls -1 pt 7 ps 2"
Levels = "w xerrorbars ls -1 lw 2"
CtrlPoints = "w lp ls -1 pt 6 ps 1 pi -1"
StyleArrow = "w lines lw 2"
StyleHead = "w vectors"
# Allow to toggle between show/hide the control points
CP(n) = showCtrlPoints eq "True" ? n : NaN
plot \
$levels u 1:2 @Points ,\
"" u 1:3:(0.35) @Levels ,\
BentArrow_1 i 0 u 1:(CP($2)) @CtrlPoints ,\
BentArrow_1 i 1 u 1:2 @StyleArrow lc "red" ,\
BentArrow_1 i 2 u 1:2:3:4 @StyleHead as 1 ,\
BentArrow_2 i 0 u 1:(CP($2)) @CtrlPoints ,\
BentArrow_2 i 1 u 1:2 @StyleArrow lc "web-green" ,\
BentArrow_2 i 2 u 1:2:3:4 @StyleHead as 2 ,\
BentArrow_3 i 0 u 1:(CP($2)) @CtrlPoints ,\
BentArrow_3 i 1 u 1:2 @StyleArrow lc "blue" ,\
BentArrow_3 i 2 u 1:2:3:4 @StyleHead as 3
Файл BentArrow.fct
содержит:
# Implements a bent arrow using Cubic Bézier curves (https://en.wikipedia.org/wiki/Bézier_curve)
#
# Usage: call 'BentArrow.fct' tag xi yi yc1 yc1 xc2 yc2 xf yf
# where
# xi,yi = start point
# xc1,yc1 = control point #1
# xc2,yc2 = control point #2
# xf,yf = final point
#
# The algorithm creates
# 1) a variable named BentArrow_id with 'id' as a integer number,
# defined by user like a standart arrow, and
# 2) a datafile (e.g BentArrow_id.bentarrow) containing
# i) the control points,
# ii) the datapoints to create the curve, and
# iii) the datapoints do ceate head
# as indexable datablocks (0, 1 and 2, respectively).
# The number of datapoint (samples) used on bent arrow construction
# are defined by 'ArrowPoints' (default 50)
# Receiving the arguments from 'call' command
tag = int(ARG1)
x_i = real(ARG2)
y_i = real(ARG3)
x_1 = real(ARG4)
y_1 = real(ARG5)
x_2 = real(ARG6)
y_2 = real(ARG7)
x_f = real(ARG8)
y_f = real(ARG9)
# Defining the variable to filename, based on 'tag', and creating the datafile
eval sprintf( "%s_%g = %s", 'BentArrow', tag, sprintf("'BentArrow_%g.bentarrow'", tag) )
# Checking if 'ArrowPoints' is defined
if ( !exists("ArrowPoints") ) {
ArrowPoints = 50
}
# Quadratic Bézier function
DrawArrow(t,p0,p1,p2,p3) = (1-t)**3*p0 + 3*(1-t)**2*t*p1 + 3*(1-t)*t**2*p2 + t**3*p3 # 0 <= t <= 1
# Creating the datafile containing the datapoints to bent arrow
set print sprintf('BentArrow_%g.bentarrow', tag)
# ----- ControlPoints -----------------------
print "# Block index 0 (control points)"
print sprintf("% e\t% e", x_i, y_i)
print sprintf("% e\t% e", x_1, y_1)
print ""
print sprintf("% e\t% e", x_2, y_2)
print sprintf("% e\t% e", x_f, y_f)
print ""
print ""
# ----- ArrowData -----------------------
print "# Block index 1 (arrow)"
do for [i=0:int(ArrowPoints):1] {
t = i/real(ArrowPoints)
print sprintf("% e\t% e", DrawArrow(t,x_i,x_1,x_2,x_f), DrawArrow(t,y_i,y_1,y_2,y_f))
}
print ""
print ""
# ----- ArrowHead -----------------------
print "# Block index 2 (head)"
do for [i=int(ArrowPoints)-1:int(ArrowPoints):1] {
t = i/real(ArrowPoints)
x_head = x_f - DrawArrow(t,x_i,x_1,x_2,x_f)
y_head = y_f - DrawArrow(t,y_i,y_1,y_2,y_f)
print sprintf("% e\t% e\t% e\t% e", DrawArrow(t,x_i,x_1,x_2,x_f), DrawArrow(t,y_i,y_1,y_2,y_f), x_head, y_head)
}
unset print
Улучшения будут хорошо приняты!