I have a file with the coordinates (x1, y1), (x2, y2) of a double pendulum at an instant of time t. I would like to know how to animate this file.
n t x y
1. 0. 0.3435957874318018 -0.36323812418181006
2. 0. 0.3490554835456995 -0.8632083150115673
1. 0.03 0.3299928793095484 -0.3756390549516834
2. 0.03 0.34657472136383705 -0.8753640218225479
1. 0.06 0.3099940098067639 -0.3923056383534705
2. 0.06 0.3437105896402516 -0.891167535319286
This are the first three positions of the double pendulum, 'n' is the particle number
The following might be a starting point.
Since I don't have enough data for illustration, I generated some data (note: it's not "real" double pendulum data). The assumption is that the anchor point is a at 0,0. Furthermore, it might be desired to not just draw the points with points but also the bars of the pendulum with vectors. It's a bit tricky and not obvious how to draw the second bar since you have to remember the previous position of mass1. I hope you can figure out how to code works.
Code:
### animate double pendulum
reset session
# create some test data (no "real" double pendulum data, just for illustration)
set print $Data
do for [t=0:15] {
print sprintf("%d. %g %g %g", 1, t, x1=cos(t*pi/20+pi/8), y1=-sin(t*pi/20+pi/8))
print sprintf("%d. %g %g %g", 2, t, x2=x1+cos(t/10.), y2=y1-sin(t/10.))
}
set print
set size ratio -1
set xrange[-1.5:2.0]
set yrange[-2:0.1]
set term gif size 400,300 animate delay 20
set output "DoublePendulum.gif"
do for [i=0:15] {
plot $Data u (0):(0):3:4 every ::2*i::2*i w vectors lc "grey" nohead notitle, \
x2=y2=NaN '' u (x1=x2,x2=$3):(y1=y2,y2=$4):(x1-x2):(int($0)%2==0 ? NaN: y1-y2) every ::2*i::2*i+1 w vectors lc "grey" nohead notitle, \
'' u 3:4 every ::2*i::2*i w p pt 7 ps 3 lc "red" title "1", \
'' u 3:4 every ::2*i+1::2*i+1 w p pt 7 ps 2 lc "blue" title "2", \
}
set output
# just for illustration: plot all positions at the same time
set term wxt # or any other terminal
plot $Data u (0):(0):3:4 every 2 w vectors lc "grey" nohead notitle, \
x2=y2=NaN '' u (x1=x2,x2=$3):(y1=y2,y2=$4):(x1-x2):(int($0)%2==0 ? NaN: y1-y2) w vectors lc "grey" nohead notitle, \
'' u 3:4 every 2 w p pt 7 ps 3 lc "red" title "1", \
'' u 3:4 every 2::1 w p pt 7 ps 2 lc "blue" title "2", \
### end of code
Result: (no "real" double pendulum data, just for illustration)
All positions (in wxt terminal):
Related
You can rotate text labels as well as ticlabels.
However, if I have multiline labels, how can I keep alignment and line spacing with rotated labels which have a rotation angle other than 0°, 90°, 180° or 270°?
As you can see in the example below, aligment and line spacing are not kept with other than the above mentioned angles. What's going wrong there? I haven't checked yet whether this maybe depends on the aspect ratio of x- and y-axes? Any ideas how to fix this?
Script:
### how to keep alignment and line spacing with rotated labels?
reset session
$Data <<EOD
1 0 "multiline\nlabel"
2 30 "multiline\nlabel"
3 45 "multiline\nlabel"
4 60 "multiline\nlabel"
5 90 "multiline\nlabel"
EOD
set termoption font ",14"
set offset 1,1,2,2
set key noautotitle
plot $Data u 1:(1):3:2 w labels rotate var right , \
'' u 1:(2):3:2 w labels rotate var center, \
'' u 1:(3):3:2 w labels rotate var left
### end of script
Result:
Here another illustration that something does not work as expected:
I filed a bug report. Actually, 180° is not correct as well, line1 and line2 are swapped.
Here are two attempts to workaround the problem that apparently gnuplot rotates multiline labels around the anchor point for each line independently instead of a common anchor point for the whole label. Although, there are exceptions for 90° and 270° as you can see in the jumping text in the animation.
1. Attempt: split the multiline labels and plot them separately and add x- and y-offset depending on angle and line number. This seems to work for wxt terminal, but I haven't tested whether this works for all terminals and graph sizes.
Line(s,n) = ((c=strstrt(s,"\n"))==0 && n==2 ? '' : n==1 ? s[1:c-1] : s[c+1:strlen(s)] )
dx(n,a) = n==1 ? -sin(a) : sin(a)
dy(n,a) = n==1 ? 0.5*cos(a) : -0.5*cos(a)
2. Attempt: the first attempt will not work for ticlabels because you would create two shifted tics. Hence, in the second example, in addition to xtics with an offset for the first line, x2tics with an offset for the second line are used. However, depending on the graph height, you have to set the y-offset manually which is rather tedious. I haven't found yet a way to do this automatically (maybe with help of the GPVAL_ variables and a replot).
As a 3rd option, you could also play with multiplot and overlay differently shifted xtics, which I would consider a painful workaround as well.
I hope that there are (or will be) better solutions.
Script 1:
### rotated multiline labels (two lines)
reset session
set key noautotitle
set angle degrees
s = "multiline\nlabel"
dx(n,a) = n==1 ? -sin(a) : sin(a)
dy(n,a) = n==1 ? 0.5*cos(a) : -0.5*cos(a)
Line(s,n) = ((c=strstrt(s,"\n"))==0 && n==2 ? '' : n==1 ? s[1:c-1] : s[c+1:strlen(s)] )
set yzeroaxis ls 1
set term gif animate size 640,480 delay 10 font ",11"
set output "SO74000192_2.gif"
do for [a=0:355:5] {
s = sprintf("multi line:\nAngle: % 4d°",a)
set multiplot layout 1,2 ti "rotated multiline labels"
set title "as is"
plot 0, 1, 3, 5, 6, \
'+' u (0):(1):(s):(a) every ::0::0 w labels rotate var right, \
'+' u (0):(3):(s):(a) every ::0::0 w labels rotate var center, \
'+' u (0):(5):(s):(a) every ::0::0 w labels rotate var left
set title "workaround"
plot 0, 1, 3, 5, 6, \
for [j=1:2] '+' u (0):(1):(Line(s,j)):(a) every ::0::0 \
w labels rotate var right offset dx(j,a), dy(j,a), \
for [j=1:2] '+' u (0):(3):(Line(s,j)):(a) every ::0::0 \
w labels rotate var center offset dx(j,a), dy(j,a), \
for [j=1:2] '+' u (0):(5):(Line(s,j)):(a) every ::0::0 \
w labels rotate var left offset dx(j,a), dy(j,a)
unset multiplot
}
set output
### end of script
Result 1:
Script 2:
### rotated multiline xticlabels (two lines)
reset session
set angle degrees
set key noautotitle
$Data <<EOD
1 2 label
2 5 "multiple\nlines"
3 4 "another label"
4 7 "another two\nline label"
5 4 "single line again"
6 3 "multiline\nagain"
EOD
Line(s,n) = ((c=strstrt(s,"\n"))==0 && n==2 ? '' : n==1 ? s[1:c-1] : s[c+1:strlen(s)] )
dx(n,a) = n==1 ? -sin(a) : sin(a)
dy(n,a) = n==1 ? 0.5*cos(a) : -0.5*cos(a)
set boxwidth 0.8
set style fill solid 0.3
set yrange[0:]
a = 65
set xtic out nomirror rotate by a right offset -sin(a),0.5*cos(a) font ",11"
set multiplot layout 1,2 title "rotated multine labels"
set title "as is"
plot $Data u 1:2:xtic(3) w boxes
set title "workaround"
set link x2 via x inverse x
set x2tics rotate by a right font ",11" offset sin(a), graph -1.14 # manually adjust y-offset depending on graph
plot $Data u 1:2 w boxes, \
'' u 1:(-1):xtic(Line(strcol(3),1)), \
'' u 1:(-1):x2tic(Line(strcol(3),2))
unset multiplot
### end of script
Result 2:
I have the following script which is expected to produce the animations of 2 curves :
#!/bin/bash
for i in {1..397}; do
gnuplot -p <<-EOFMarker
set terminal png;
set output "pic$i.png";
set title "power spectrum";
set xlabel "scale (k)";
set ylabel "P(k)";
set key top left;
set grid;
set ytics out nomirror;
set xtics out nomirror;
set logscale x;
set logscale y;
set format x "10^{%L}";
set yrange [0:30000];
plot "CAMB-1.3.5/matter_camb$i" u 1:2 w l;
replot "EFTCAMB_v3_beta/matter_eftcamb$i" u 1:2 w l;
EOFMarker
done
# Build movie with ffmpeg
ffmpeg -start_number 1 -i pic%d.png movie.mpeg
Every works fine excepted the fact that only one curve is plotted in animation (CAMB-1.3.5) :
Here is an example of frame :
Why the "replot" command is not taken into account in the generated image ?
Just for the sake of the SO-rule "no answer in comments":
Check help plot:
Syntax:
plot {<ranges>} <plot-element> {, <plot-element>, <plot-element>}
Examples:
plot sin(x)
plot sin(x), cos(x)
plot f(x) = sin(x*a), a = .2, f(x), a = .4, f(x)
plot "datafile.1" with lines, "datafile.2" with points
plot [t=1:10] [-pi:pi*2] tan(t), \
"data.1" using (tan($2)):($3/$4) smooth csplines \
axes x1y2 notitle with lines 5
plot for [datafile in "spinach.dat broccoli.dat"] datafile
If you need to draw some graphs against x1y1 or x1y2 axes, depending on the maximum y value of each graph, what would be the proper syntax for that?
My data file has several columns. The first one contains x values, the others y1, y2 and so on.
After using the stats command, I could easily define each axis value for each graph:
stats '$data_file' u 1:2 nooutput;
y1max = STATS_max_y;
if (y1max > ymax) { y1axis = 'x1y2' } else { y1axis = 'x1y1' };
stats '$data_file' u 1:3 nooutput;
y2max = STATS_max_y;
if (y2max > ymax) { y2axis = 'x1y2' } else { y2axis = 'x1y1' };
...
After that, I can draw the graphs with this plot cmd
plot '$data_file' using 1:2 axes x1y1 notitle with lines lc rgb 'black' lw 1,\
'' using 1:3 axes x1y2 notitle with lines lc rgb 'green' lw 1;
which works, but it is not programmatically at all.
But this one doesn't works
plot '$data_file' using 1:2 axes #y1axis notitle with lines lc rgb 'black' lw 1,\
'' using 1:3 axes #y2axis notitle with lines lc rgb 'green' lw 1;
where I used the Substitution of string variables as macros (The character # is used to trigger substitution of the current value of a string variable into
the command line...) which is written in the docs.
Nor the eval command likes to work for me.
Could you please provide an example for that purpose, which is working or any a good advise. THX!
I got two errors/warnings when using the above code in a bash script as an oneliner the following way
echo "gnuplot cmds;plot ..." | gnuplot
warning: y3axis is not a string variable
axes must be x1y1, x1y2, x2y1 or x2y2
As written in the docs, the macro could not be expanded the same time as it is defined, what is the case if written on the same line.
To avoid the above mistake we have to use only
echo -e "gnuplot cmds;\nplot ..." | gnuplot
and it works like it should.
Credits to #Christoph and #Ethan who put me on the right track.
I am following this post to make a pie chart using Gnuplot. The only problem with the approach is that I can't align my percentage labels. What am I missing here?
DATA FILE:
"Others" 1.085117e-01 3.904323e-02
"D_o" 2.894902e-01 6.145359e-01
"{/Symbol b}_o" 5.760601e-01 3.760299e-01
"O_h" 5.393108e-01 1.000000e+00
"D_p" 6.743313e-01 2.284404e-01
"{/Symbol a}_p" 1.000000e+00 1.271822e-01
"{/Symbol b}_f" 4.020115e-01 2.233656e-01
"D_m" 2.389996e-01 8.577689e-02
"{/Symbol a}_m" 3.601146e-01 1.033153e-01
"{/Symbol b}_m" 5.596836e-01 1.947165e-01
CODE:
#!/usr/bin/gnuplot
# Terminal & Encoding
set terminal epscairo enhanced color dashed rounded size 8.5, 4.5
set output 'mu_piechart.eps'
set termoption enhanced
set encoding utf8
# Get Status
filename = './datafile.dat'
stats filename u 2 noout
# Get Angles & Percentages
ANG(x)=x*360.0/STATS_sum
PER(x)=x*100.0/STATS_sum
# Square Canvas
set size square
set xrange [-1:1.5]
set yrange [-1.25:1.25]
set style fill solid 1
# Remove Base Properties (Titles, Tics, Axis, Palette)
unset key
unset tics
unset border
unset colorbox
# Initial Angle, Mid Angle, Initial Color
A = 0.0; M = 0.0; i = 0;
# Palette
set palette defined (1 1 0.788 0.055, 2 0.090 0.161 0.659)
# Plot
plot for [i=0:STATS_records-1] filename u (0):(0):(1):(A):(A=A+ANG($2)):(i) every ::i::i with circle linecolor palette,\
filename u (M=A+ANG($2), A=2*M-A, M=M*pi/360.0, -0.5*cos(M)):(-0.5*sin(M)):(PER($2) > 8.00 ? sprintf('%.1f\%', PER($2)) : " ") every ::1 w labels center font ',10',\
for [i=0:STATS_records-1] filename u (1.45):(i*0.25)-1.11:($1) every ::i::i with labels left,\
for [i=0:STATS_records-1] '+' u (1.3):(i*0.25)-1.11:(i) pt 5 ps 4 lc palette
exit
OUTPUT:
The percentages positions are not correct in the figure generated by the script.
Your labels are at wrong positions, because your label plot starts at 1, i.e. you skip the first entry.
Also, what I don't understand is, why you plot the pie parts counterclockwise, and the labels clockwise.
Here is a working version of you script, without some parts which are superfluous for demonstration. Both labels and pie parts are plotted starting at an angle of A = 0 (note the second initialization between the two plots):
reset
# Get Status
filename = './datafile.dat'
stats filename u 2 noout
# Get Angles & Percentages
ANG(x)=x*360.0/STATS_sum
PER(x)=x*100.0/STATS_sum
# Y position of key point and label
YLBL(row) = 2.0 * (row - 0.5*(STATS_records - 1))/(STATS_records - 1)
# Square Canvas
set size square
set xrange [-1:1.5]
set yrange [-1.25:1.25]
set style fill solid 1
# Remove Base Properties (Titles, Tics, Axis, Palette)
unset key
unset tics
unset border
unset colorbox
# Palette
set palette defined (1 1 0.788 0.055, 2 0.090 0.161 0.659)
# Plot
A = 0.0
plot filename u (0):(0):(1):(A):(A=A+ANG($2)):0 with circle linecolor palette,\
A = 0,\
filename u (M=A+ANG($2), A=2*M-A, M=M*pi/360.0, 0.5*cos(M)):(0.5*sin(M)):(PER($2) > 8.0 ? sprintf('%.1f\%', PER($2)) : "" ) w labels center,\
filename u (1.3):(YLBL($0)):1 with labels offset char 3 left ,\
filename u (1.3):(YLBL($0)):0 pt 5 ps 4 lc palette
The script contains some other improvements:
You don't need to iterate over STATS_records
The text and point for the key are plotted at the same position, the label is shifted with the offset parameter by three character units (offset char 3). That makes fine-tuning easier.
This question is related to gnuplot histogram: How to put values on top of bars.
I have a datafile file.dat:
x y1 y2
1 2 3
2 3 4
3 4 5
and the gnuplot:
set style data histogram;
set style histogram rowstacked;
plot newhistogram 'foo', 'file.dat' u 2:xtic(1) t col, '' u 3 t col;
Now I want to place the sums of columns 2 and 3 above the bars. The obvious solution
plot newhistogram 'foo', 'file.dat' u 2:xtic(1) t col, '' u 3 t col, \
'' u ($0-1):($2+$3+0.2):($2+$3) notitle w labels font "Arial,8";
puts the labels in the correct place, but the calculated sum is wrong. That is, in ($0-1):($2+$3+0.2):($2+$3), the second $2 appears to evaluate to zero.
What's going wrong here and how do I fix it?
You must give an explicit string as label:
plot newhistogram 'foo', 'file.dat' u 2:xtic(1) t col, '' u 3 t col, \
'' u ($0-1):($2+$3):(sprintf('%.1f', $2+$3)) notitle w labels offset 0,1 font "Arial,8"
As other improvement, I would use the offset option which allows you to give an displacement in character units, which doesn't depend on the yrange.
(Side note: if a value from a column is used, then one can skip the explicit formatting of the label, like using 1:2:2 with labels, but in general one should use sprintf to format the label)