gnuplot: arrows between circles

半腔热情 提交于 2021-02-11 14:21:53

问题


How can I draw arrows between circles where

  1. the arrows point to the centers of the circles,
  2. but have reduced length such that they only touch the circumference,
  3. independent of the terminal size ratio?

Sounds easy, but I haven't found a shorter solution than the example below. You need to to some coordinate transformations between axes coordinates and terminal coordinates. For this, you need to know the terminal size of the plot and you'll get these values into the GPVAL_... variables only after plotting you have to do a dummy plot first and then replot. If I overlooked some obvious and simpler procedure, please let me know.

Code:

### arrows touching circles
reset session

# Factor between axes and terminal coordinates
FactorX(n) = real(GPVAL_X_MAX-GPVAL_X_MIN)/(GPVAL_TERM_XMAX-GPVAL_TERM_XMIN)
FactorY(n) = real(GPVAL_Y_MAX-GPVAL_Y_MIN)/(GPVAL_TERM_YMAX-GPVAL_TERM_YMIN)

# Axis coordinates to terminal coordinates
AxisToTermX(x) = (x-GPVAL_X_MIN)/FactorX(0)+GPVAL_TERM_XMIN
AxisToTermY(y) = (y-GPVAL_Y_MIN)/FactorY(0)+GPVAL_TERM_YMIN

xt(x) = AxisToTermX(x)
yt(y) = AxisToTermY(y)
rt(r) = r/FactorX(0)
Lt(x1,y1,x2,y2) = sqrt((xt(x2)-xt(x1))**2 + (yt(y2)-yt(y1))**2)

# terminal coordinates reduced by radii
x1tr(x1,y1,r1,x2,y2,r2) = rt(r1)*(xt(x2)-xt(x1))/Lt(x1,y1,x2,y2)+xt(x1)
y1tr(x1,y1,r1,x2,y2,r2) = rt(r1)*(yt(y2)-yt(y1))/Lt(x1,y1,x2,y2)+yt(y1)
x2tr(x1,y1,r1,x2,y2,r2) = (Lt(x1,y1,x2,y2)-rt(r2))*(xt(x2)-xt(x1))/Lt(x1,y1,x2,y2) + xt(x1)
y2tr(x1,y1,r1,x2,y2,r2) = (Lt(x1,y1,x2,y2)-rt(r2))*(yt(y2)-yt(y1))/Lt(x1,y1,x2,y2) + yt(y1)

# Terminal coordinates to axis coordinates
TermToAxisX(xt) = real(xt-GPVAL_TERM_XMIN)*FactorX(0)+GPVAL_X_MIN
TermToAxisY(yt) = real(yt-GPVAL_TERM_YMIN)*FactorY(0)+GPVAL_Y_MIN

# axis coordinates reduced by radii
x1r(x1,y1,r1,x2,y2,r2) = TermToAxisX(x1tr(x1,y1,r1,x2,y2,r2))
y1r(x1,y1,r1,x2,y2,r2) = TermToAxisY(y1tr(x1,y1,r1,x2,y2,r2))
x2r(x1,y1,r1,x2,y2,r2) = TermToAxisX(x2tr(x1,y1,r1,x2,y2,r2))
y2r(x1,y1,r1,x2,y2,r2) = TermToAxisY(y2tr(x1,y1,r1,x2,y2,r2))

# dummy plot
set xrange [-10:10]
set yrange [-10:10]
plot NaN notitle

$Data <<EOD
0   0   1.0
-6  2   3.0
0   5   0.75
7   -8  2.0
5    8  1.5
EOD

N = |$Data|   # length of datablock

# draw N circles
do for [i=0:N-1] {
    set obj i+1 circle at word($Data[i+1],1),word($Data[i+1],2) size word($Data[i+1],3) fc "blue"
}

# draw N arrows
do for [i=0:N-1] {
    x1 = word($Data[i+1],1)
    y1 = word($Data[i+1],2)
    r1 = word($Data[i+1],3)
    x2 = word($Data[(i+1)%N+1],1)
    y2 = word($Data[(i+1)%N+1],2)
    r2 = word($Data[(i+1)%N+1],3)
    set arrow i+1 from x1r(x1,y1,r1,x2,y2,r2), y1r(x1,y1,r1,x2,y2,r2) \
                  to x2r(x1,y1,r1,x2,y2,r2), y2r(x1,y1,r1,x2,y2,r2) heads lc "red"
}

replot
### end of code

Result: (wxt size 600,600)

The same code with (wxt size 700,300)

来源:https://stackoverflow.com/questions/65097645/gnuplot-arrows-between-circles

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!