Как создать гипертекстовые векторы или стрелки, которые появляются только тогда, когда пользователь наводит указатель мыши на начальную/конечную точки или рядом с ними? Для очков это выглядит так:
indices = "first second"
plot for [id in indices] "a_test.dat" index id u 1:2
replot for [i=1:words(indices)] "a_test.dat" index word( indices, i ) u 1:2:(sprintf("point = (%d, %d)", column(1), column(2))) w labels hypertext point pt 7 ps 2 lc rgb '#ff000000' notitle
Файл "a_test.dat":
# first
x1 y1
5 1
6 2
9 8
# second
x2 y2
4 5
8 2
2 7
Я использую gnuplot-qt 5.4. Как отобразить изображение с «гипертекстом»? Означает ли это создание нового графика всего с одной стрелкой? Если это сработает, будет здорово.
Продолжая мой ответ на ваш предыдущий вопрос, вот что вы можете сделать с гипертекстовым изображением:
Это снимок экрана файла svg с (желтым) курсором, находящимся над точкой (4,5). Программа просмотра svg (в данном случае мой браузер) вывела маленькое изображение с фиолетовой стрелкой из файла /tmp/fig1.png в моей системе. Возможно, это не совсем то, что вам нужно, но это лучшее, что я могу сделать с помощью gnuplot. Вот код:
set term png size 400, 400 linewidth 3
unset key
stats "a_test.dat" nooutput
array xx[STATS_records]
array yy[STATS_records]
set xrange [STATS_min_x:STATS_max_x]
set yrange [STATS_min_y:STATS_max_y]
set offsets graph 0.05, graph 0.05, graph 0.05, graph 0.05
# save all data into two arrays
i = 1
fnset(x,y) = (xx[i]=x, yy[i]=y, i=i+1)
set table $dummy
plot "" using (fnset($1,$2)) with table
unset table
numi = int((i-1)/2)
#-----create fig*.png files
do for [i=1:numi] {
set output "/tmp/fig".i.".png"
plot for [j=i:i] $dummy using (xx[j]):(yy[j]):(xx[numi+j]-xx[j]):(yy[numi+j]-yy[j]) with vectors
set output
}
#-----2nd part
set term svg size 400, 400 mouse standalone linewidth 3
set output "aaa.svg"
indices = "first second"
count=0
fncount(x,y)=(count=(count==numi?1:count+1),count)
plot for [i=1:words(indices)] "a_test.dat" \
index word( indices, i ) \
u 1:2:(sprintf("image:/tmp/fig%d.png\nfig",fncount($1,$2) )) \
w labels hypertext point pt 7 ps 2 notitle
Я не буду объяснять строки из предыдущего ответа, такие как чтение данных в 2 массива xx и yy. Чтобы сохранить тот же масштаб для всех графиков он явно установлен с помощью set xrange ... на минимум и max рассчитывается из команды статистики.
Первая часть кода использует do for для создания файлов fig1.png и так далее. on, каждый из которых показывает только одну стрелку, используя один набор из 4 элементов данных из массивов.
Вторая часть выбирает тип терминала svg с опцией mouse и standalone. Это вставляет JavaScript, необходимый для обработки всплывающего окна мыши, в выходной файл svg. Команда plot основана на вашем примере с 3-м столбцом данных, например, строка "image:/tmp/fig1.png\nfig" для первый набор данных. Функция fncount() просто увеличивается при каждом вызове, от 1 до 3 (если у вас 3 строки данных на блок), затем обратно к 1. Это повторно использует те же 3 файла изображений в начальной и конечной точках данных.
Обратите внимание, что программа просмотра svg должна иметь возможность находить файлы изображений в файловой системе.
Я думаю, что это почти возможно. Но вы бы не использовали гипертекст, вы бы использовали функцию «переключить сюжет». Я покажу полный скрипт ниже, но вот основная идея:
Нарисуйте график, который содержит (график 1) хвостовые точки (график 2) верхние точки (графики с 3 по N) отдельный график для каждой стрелки. Поскольку каждая стрелка находится на отдельном графике, ее можно включать и выключать, щелкая ее заголовок. Команды toggle в сценарии отключают стрелки для начала. Теперь мы подошли к сложной части. Вместо того, чтобы позволять заголовку автоматически помещаться в ключевое поле графика, мы явно размещаем каждый заголовок поверх его хвостовой точки. Теперь вы можете нажать на точку и вуаля, появится стрелка.
Вот сценарий
set xrange [0:10]
set yrange [0:10]
set style arrow 1 head nofill lc "black"
# Here is the data
$ARROWS << EOF
x1 y1 x2 y2
5 1 4 5
6 2 8 2
9 8 2 7
EOF
#
# This is the basic plot, with everything visible.
# In an interactive terminal (qt/wxt/x11/windows/svg) you can toggle
# the arrows on and off by clicking on the corresponding title in the key.
#
set key samplen 0.01
plot $ARROWS using 1:2 with points pt 7 ps 2 title "Click me", \
$ARROWS using 3:4 with points pt 7 ps 2 notitle, \
for [i=1:*] $ARROWS every 1::i::i using 1:2:($3-$1):($4-$2) with vectors as 1 title " "
pause -1
#
# Now we get tricky by placing the arrow titles on top of the points
# rather than in the key, and we programmatically toggle off the arrows.
# You should be able to make the arrow appear by clicking on the point
# that corresponds to the arrow tail.
#
array tx[3]
array ty[3]
do for [i=1:3] {
tx[i] = int(word($ARROWS[i+1],1))
ty[i] = int(word($ARROWS[i+1],2))
}
plot $ARROWS using 1:2 with points pt 7 ps 2 title "Click me", \
$ARROWS using 3:4 with points pt 7 ps 2 notitle, \
for [i=1:3] $ARROWS every 1::i::i using 1:2:($3-$1):($4-$2) with vectors as 1 \
title " " at first tx[i], first ty[i]
do for [plot=3:5] {toggle plot}
pause -1
Вот скрин сюжета до первого клика
А вот и скрин показа сюжета после нажатия на одну из точек
Я говорю, что это «почти» возможно, потому что мне пришлось использовать очень неуклюжий отдельный шаг для загрузки координат заголовка в массивы. Гораздо чище было бы генерировать их на лету по мере отрисовки сюжета. Я не думаю, что это возможно в настоящее время, хотя, возможно, мне не хватает какого-то хитрого трюка.
Я думаю, вы можете имитировать «гипертекстовую стрелку» с петлей while и pause mouse.
Для векторов лучше иметь начальную/конечную точки в одной строке, но это другая тема. Я подумаю над ответом на другой ваш вопрос. Здесь для простоты предполагается, что у вас есть начальная/конечная точки уже в одной строке.
Данные отображаются один раз, а затем вы входите в цикл while (отметьте help while), который можно остановить, нажав ESC.
При нажатии кнопки 1 мыши данные строится снова, но дополнительно строится линия данных с минимальным расстоянием до положения мыши (т.е. переменные MOUSE_X и MOUSE_Y) with vectors. Однако кажется, что вы не можете использовать MOUSE_X и MOUSE_Y в функции. Итак, тогда вам нужно сначала присвоить его переменным x0 и y0.
Вы, вероятно, могли бы настроить поведение появления стрелки, т.е. исчезает ли она через некоторое время или если вы двигаетесь дальше и т. д...)
Скрипт: (протестировано с gnuplot 5.4.1 и терминалами wxt и qt)
### show arrow on mouse button press (mimic hypertext arrow)
reset session
$Data <<EOD
# first # second
x1 y1 x2 y2
5 1 4 5
6 2 8 2
9 8 2 7
EOD
set offsets 1,1,1,1
set key out noautotitle
plot $Data u 1:2 w p pt 7 ps 2 lc "blue" ti "start point", \
'' u 3:4 w p pt 7 ps 2 lc "red" ti "end point"
dist(colX,colY) = sqrt((column(colX)-x0)**2 + (column(colY)-y0)**2)
continue = 1
while (continue) {
pause mouse button1,keypress
if (MOUSE_KEY == 27) { continue=0 } # press ESC to stop loop
else {
x0 = MOUSE_X
y0 = MOUSE_Y
plot dMin=NaN \
$Data u (d=dist(1,2), (dMin!=dMin || d<dMin)?(dMin=d,idxMin=$0):0,$1):2 skip 1 \
w p pt 7 ps 2 lc "blue" ti "start point", \
'' u (d=dist(3,4), d<dMin?(dMin=d,idxMin=$0):0,$3):4 w p pt 7 ps 2 lc "red" ti "end point", \
'' u 1:2:($3-$1):($4-$2) every ::idxMin::idxMin skip 1 w vec lw 2 lc black
}
}
### end of script
Снимок экрана: (из терминала wxt)
Дополнение: (оставить и убрать стрелки)
Вот версия, в которой вы оставляете несколько стрелок и можете удалить их, снова щелкнув рядом с их начальной/конечной точкой. Вы можете удалить все стрелки сразу, если щелкнете правой кнопкой мыши (в моей системе это MOUSE_BUTTON==3).
arrowIdxs
, содержащую выбранные стрелки, то есть индексы строкinList()
, которая проверяет, есть ли индекс в спискеupdateList()
, которая либо добавляет новый индекс, либо удаляет индекс, если он уже был в списке.Надеюсь, вы сможете сами разобраться, как работает скрипт в деталях. Проверьте help <keyword> следующие используемые ключевые слова: sprintf, sum, strstrt, strlen.
Скрипт:
### show/hide arrows on mouse button click
reset session
$Data <<EOD
# first # second
x1 y1 x2 y2
5 1 4 5
6 2 8 2
9 8 2 7
EOD
set offsets 1,1,1,1
set key out noautotitle
plot $Data u 1:2 w p pt 7 ps 2 lc "blue" ti "start point", \
'' u 3:4 w p pt 7 ps 2 lc "red" ti "end point"
dist(colX,colY) = sqrt((column(colX)-x0)**2 + (column(colY)-y0)**2)
arrowIdxs = ''
inList(list,n) = (_s=sprintf("%d",n), int(sum[_i=1:words(list)] word(list,_i) eq _s))
updateList(list,n) = (_s=sprintf("%d",n), inList(list,n) ? \
list[1:strstrt(list,_s)-2].list[strstrt(list,_s)+strlen(_s):] : list.' '.sprintf("%d",n))
continue = 1
while (continue) {
pause mouse button1,button3,keypress
if (MOUSE_KEY == 27) { continue=0 } # press ESC to stop loop
else {
mb=MOUSE_BUTTON
if (mb==1) {
x0 = MOUSE_X
y0 = MOUSE_Y
plot dMin=NaN \
$Data u (d=dist(1,2), (dMin!=dMin || d<dMin)?(dMin=d,idxMin=$0):0,$1):2 skip 1 \
w p pt 7 ps 2 lc "blue" ti "start point", \
'' u (d=dist(3,4), d<dMin?(dMin=d,idxMin=$0):0,$3):4 w p pt 7 ps 2 lc "red" ti "end point", \
arrowIdxs = updateList(arrowIdxs,idxMin) \
'' u (inList(arrowIdxs,$0)? $1:NaN):2:($3-$1):($4-$2) skip 1 w vec lw 2 lc black
}
if (mb==3) {
arrowIdxs = ''
plot $Data u 1:2 w p pt 7 ps 2 lc "blue" ti "start point", \
'' u 3:4 w p pt 7 ps 2 lc "red" ti "end point"
}
}
}
### end of script
Снимок экрана: (из терминала wxt)
Как убрать все стрелки при нажатии правой кнопки мыши?
@magfan что значит «все стрелки»? Скрипт рисует только одну стрелку. Возможно, вы хотите сохранить все выбранные стрелки? И очистить их все правой кнопкой мыши?
Я всегда предполагал одну стрелку, потому что думал о гипертексте и зависании. А вот маркировка нескольких стрелок — действительно очень интересный вариант.
@magfan см. измененный ответ, который, я думаю, теперь довольно универсален.
Я не думаю, что gnuplot может это сделать. Какой тип терминала вы используете? Вы можете сделать так, чтобы опция hypertext отображала изображение из файла, что может предоставить отдельно сгенерированный график с нужной стрелкой.