3
votes

My problem, following from my previous question, goes like this now: I have a particle moving in a plane, and now I want a sort of box at the side which says the particle's position in XY and its velocity. I tried using labels, but they end up overlapping each other.

Here's a really crude "sketch" of what I want to see:

    +------------------------------------------+
    |         +-----------+                    |
    |         |           |       t = 2        |
    |         | PLOT HERE |  x = 0    y = 1    |
    |         |           |  vx = 2   vy = 3   |
    |         +-----------+                    |
    +------------------------------------------+

where those numbers would be changing at each frame. I've been able to animate a title, but a label seems different.

My current code looks very much like the answer in here GNUPlot - Plot 2D datapoints as MPEG but with some minor stylistic modifications, and that I removed the title. I can produce data that are just the XY coordinates, which is what I use right now.

I can also produce something like (these are random points, just for the sake of illustration)

 #X      Y      t       vx     vy
  0.00   1.00   0.0     0.0   6.28
  0.01   0.01   0.01    1.0   6.00

for the animating labels.

1

1 Answers

2
votes

A nice way for placing labels from a data file is with the labels plotting style. However, there are some difficulties for placing labels outside of the actual plotting area, since these points and labels usually are clipped.

Since you are using stats anyway to fix the x- and yrange, here is how I would do this:

  • Set a fixed right margin with e.g. set rmargin 20. This uses a right margin of 20 character widths. You could also use absolute coordinates like set rmargin at screen 0.8, but since you need the margin to place labels, character units seem appropriate.

  • Use the upper right corner of your plot area as reference point (STATS_max_x, STATS_max_y) and shift the labels using the offset parameter and shifting again by some character widths.

So, a complete script might look as follows:

# calculate the number of points
stats 'file.txt' using 1:2 nooutput

# if you want to have a fixed range for all plots
set xrange [STATS_min_x:STATS_max_x]
set yrange [STATS_min_y:STATS_max_y]

set terminal pngcairo size 800,400
outtmpl = 'output%07d.png'

v_label(x, y) = sprintf('vx = %.2f  vy = %.2f', x, y)
c_label(x, y) = sprintf('x = %d  y = %d', x, y)
t_label(t) = sprintf('t = %.2f', t)

set rmargin 20

do for [i=0:STATS_records-1] {
    set output sprintf(outtmpl, i)
    plot 'file.txt' every ::::i with lines title sprintf('n = %d', i),\
         '' every ::i::i using (STATS_max_x):(STATS_max_y):(t_label($3)) with labels offset char 11,-5 notitle,\
         '' every ::i::i using (STATS_max_x):(STATS_max_y):(c_label($1, $2)) with labels offset char 11,-6.5 notitle,\
         '' every ::i::i using (STATS_max_x):(STATS_max_y):(v_label($4, $5)) with labels offset char 11,-8 notitle
}

set output

Script output for t=0.01

Note, that the rmargin and offset settings depend on the terminal, terminal size, font and font size. For nicer labels placement you might consider placing the vx and vy labels separately and maybe changing their alignment.

Alternatively, in each iteration you can extract the current line from your data file and set the labels manually. This however requires you to use an external tool to extract the line:

do for [i=0:STATS_records-1] {
    line = system(sprintf("sed -n %dp file.txt", i+2))
    set label 1 at screen 0.9, screen 0.9 sprintf("t = %.2f", real(word(line, 3)))
    set label 2 at screen 0.9, screen 0.88 sprintf("x = %.2f y = %.2f", real(word(line, 1)), real(word(line, 2)))
    plot 'file.txt' every ::::i with lines title sprintf('n = %d', i)
}

I don't know which variant fits you better. I used i+2 as line number to skip the commented header line, which isn't detected automatically. By using tag for the label (set label 1) you make sure, that old labels are overwritten.