GNUPlot: Animating a plane defined by three points - gnuplot

So I need to plot planes (as in, they HAVE to be FLAT) defined by three points which all come from my equation. I can redefine the code such that there is a space between the three points. I choose not to. I just added the comments for clarity of where the points are divided. They're not really there.
# surface 1
1.000 0.000 0.000
-46.777 -0.702 -1.692
0.000 3.000 5.500
# surface 2
0.998 0.030 0.055
-46.451 -2.099 -5.068
-0.468 2.993 5.483
# surface 3
0.991 0.060 0.110
-45.804 -3.471 -8.400
-0.932 2.972 5.432
# surface 4
0.979 0.089 0.164
-44.842 -4.803 -11.659
-1.390 2.937 5.348
# surface 5
0.963 0.119 0.217
-43.574 -6.079 -14.816
-1.839 2.889 5.232
#... and so on
now I can plot just ONE surface using this code
set dgrid3d 10,10
set style data lines
set pm3d
i=0
splot '5surf' every ::i::(i+2) pal
but when I plug it in a do loop
n = 1000
unset key
set terminal gif size 800,600 crop
outtmpl = 'pic/output%07d.gif'
set dgrid3d 10,10
set style data lines
set pm3d
do for [i=0:n:3] {
set output sprintf(outtmpl, i)
splot '5surf' every ::i::(i+2) pal
print i
}
set output
I got curved surfaces with this, which is plain wrong. (pun intended)
The surface, according to my analysis, has to look a bit like it's rotating.
EDIT: I threw the dgrid3d out the window. Filledcurves didn't work. I was able to make a square with these points
1 1 4.8
-1 1 5.6
-1 -1 2.4
1 -1 1.6
1 1 4.8
using polygon, but I can't make it read from file.
last edit: If anyone stumbling across this is curious as to how I found the four points using the original set of three points, it was a matter of finding the equation of the plane containing the three points and plugging in (\pm 1, \pm 1, z) in there. Solve for z and consider all four cases. a basic calc problem, really

With the points for the square you must also insert an empty line to make pm3d work properly:
surface.dat:
-1 -1 2.4
-1 1 5.6
1 -1 1.6
1 1 4.8
Not, that the y-values are always in the same order -1, 1 for both blocks. Plot this with
set pm3d
splot 'surface.dat'
If you want to put several surfaces from one file you can now separate two surfaces with two empty lines, which you can then access with index:
surfaces.dat:
-1 -1 2.4
-1 1 5.6
1 -1 1.6
1 1 4.8
-1 -1 1.4
-1 1 4.6
1 -1 0.6
1 1 3.8
You can use stats to count the number of blocks:
stats 'surfaces.dat' nooutput
set pm3d
do for [i=0:STATS_blocks - 1] {
splot 'surfaces.dat' index i
}

Related

Gnuplot - How to splot surface and points with dgrid3d

I have a .dat file that I need to plot as a surface :
functionVisu.dat
X Y Z
0 -3.9 1.68777
0 -4 1.7568
0 -4.1 1.81828
0 -4.2 1.87158
0 -4.3 1.91617
0 -4.4 1.9516
0 -4.5 1.97753
0 -4.6 1.99369
0 -4.7 1.99992
0 -4.8 1.99616
0 -4.9 1.98245
-0.1 -3.9 1.68277
-0.1 -4 1.75181
-0.1 -4.1 1.81328
-0.1 -4.2 1.86658
-0.1 -4.3 1.91117
-0.1 -4.4 1.94661
-0.1 -4.5 1.97253
-0.1 -4.6 1.9887
-0.1 -4.7 1.99493
-0.1 -4.8 1.99117
-0.1 -4.9 1.97746
-0.2 -3.9 1.66783
-0.2 -4 1.73687
etc
But also need to plot points on this surface, the file containing the points (pointVisu.dat) is also XYZ values.
The problem is, with my actual script:
set hidden3d
set dgrid3d 50,50 qnorm 2
splot [-10:10][-10:10] "functionVisu.dat" with lines, "pointVisu.dat" with dots lw 10 lc rgb "red"
pause -1
the result I am getting is not looking as expected :
result
My points are spreaded due to the dgrid3d, but I can't manage to make them appear as wanted. Also, with the use of qnorm 2, the points are under the surface function even though they are strict images of it.
Points under the surface
I can have the result I want but without using dgrid3d, which gives me a good but not aesthetic result:
Wanted but bad result
How could I combinate the render of dgrid3d but with single points displaying properly ?
Thanks
Gnuplot version 5.4.3 (Dec 2021) introduced a keyword "nogrid" that can be added to the splot command so that points are plotted individually rather being used for a grid. So if your copy of gnuplot is new enough, the answer to one of your questions is shown below (using some other data)
set hidden3d
set dgrid3d 25,25
splot "foo.dat" with lines title "gridded", \
"foo.dat" with points nogrid pt 7 title "nogrid"
Fallback for older gnuplot versions
For older gnuplot versions that do not recognize the nogrid keyword there is a work-around. Not all plot styles can be gridded, and this includes the with labels plot style. But labels can have an associated point, so you can plot a set of non-gridded points by describing them as labels with blank text:
splot "foo.dat" using 1:2:3 with lines title "gridded", \
"foo.dat" using 1:2:3:("") with labels point pt 7 title "nogrid"

gnuplot: how to draw a set of triangles from a file?

In gnuplot, we can set object polygon to draw a polygon, including triangles, given its coordinates.
But how to do draw a set of triangles whose coordinates are stored in a file where each line is in the format <x1> <y1> <x2> <y2> <x3> <y3>?
As for rectrangles/circles, this task can be done using plot and with boxxy/with circles options, but there is no with triangles option in gnuplot.
A possible solution is to use with vectors by drawing each edge, but it is a bit complicated and this method does not support color filling.
I cannot think of a way to do this in one step; the data format does not match any of gnuplot's plotting styles.
One approach is to transform the data via a temporary file. Here is an example that works in version 5.2 and newer. If you are using a newer gnuplot then you could substitute with polygons for with filledcurves closed.
$DATA << EOD
1 1 2 2 3 1
11 11 14 14 17 11
21 21 22 22 23 21
15 5 16 6 17 5
6 6 7 7 8 6
EOD
set table "temp.dat"
plot $DATA using (sprintf("%g %g\n %g %g\n %g %g\n \n",$1,$2,$3,$4,$5,$6)) with table
unset table
unset key
set style fill solid noborder
plot "temp.dat" using 1:2 with filledcurves closed fillcolor "forest-green"
Note: I was originally going to show use of a temporary datablock rather than an intermediate temporary file, but it this doesn't work because the formatted output from with table does not translate the newline characters \n into empty datablock lines.
Edit (show variable color)
The extra data field containing a RGB color must be present in every input line of the reformatted data, but only the value from the first vertex of each polygon is used. The sprintf format in this example has been modified to reproduce the color (NB: hexadecimal integer value) from the original data file accordingly, with zeros for the dummy values in the remaining polygon vertices.
$DATA << EOD
1 1 2 2 3 1 0x00ffff
11 11 14 14 17 11 0x191970
21 21 22 22 23 21 0x2e8b57
15 5 16 6 17 5 0xffc020
6 6 7 7 8 6 0x8b000
EOD
set table "temp.dat"
plot $DATA using (sprintf("%g %g 0x%x\n %g %g 0\n %g %g 0\n \n",$1,$2,int($7),$3,$4,$5,$6)) with table
unset table
unset key
set style fill solid noborder
plot "temp.dat" using 1:2:3 with filledcurves closed fillcolor rgb variable
My suggestion would have been the same as #Ethan's. Therefore, here is an alternative approach using set object polygon.
It also requires gnuplot>=5.2 since it uses indexing of datablock lines. Hence, the data should already be in a datablock without empty or commented lines. But how to get a file into a datablock?
Either something like:
set table $Data
plot FILE u 1:2:3:4:5:6:7 w table
unset table
or alternatively see here: gnuplot: load datafile 1:1 into datablock
Script:
### draw some colored triangles from a datablock
reset session
$Data <<EOD
0 0 2 1 1 2 0xff0000
5 1 3 2 4 4 0x00ff00
3 3 2 5 1 4 0x0000ff
EOD
vx(n,t) = word($Data[n],t*2-1) # vertex x-coordinate
vy(n,t) = word($Data[n],t*2) # vertex y-coordinate
color(n) = word($Data[n],7) # triangle color
set linetype 1 lc rgb "black"
do for [n=1:|$Data|] {
set obj n polygon from vx(n,1),vy(n,1) to vx(n,2),vy(n,2) to vx(n,3),vy(n,3) to vx(n,1),vy(n,1)
set obj n fc rgb color(n) fs solid 0.5 border lt 1 lw 3
}
set size square
set xrange[0:5]
set yrange[0:5]
plot NaN notitle # or plot something else
### end of script
Result:
Addition:
Alternatively, similar to Ethan's solution, plotting triangles instead of drawing triangles, but without using a temporary file on disk (but a datablock). The result is identical to the graph above. I haven't tested whether drawing or plotting is faster and/or more efficient if you want to draw/plot thousands of triangles.
Script:
### plot some colored triangles from a datablock
reset session
$Data <<EOD
0 0 2 1 1 2 0xff0000
5 1 3 2 4 4 0x00ff00
3 3 2 5 1 4 0x0000ff
EOD
vx(n,t) = word($Data[n],t*2-1) # vertex x-coordinate
vy(n,t) = word($Data[n],t*2) # vertex y-coordinate
color(n) = word($Data[n],7) # triangle color
set print $Triangles
do for [n=1:|$Data|] {
print sprintf("%s %s %s\n%s %s 0\n%s %s 0\n%s %s 0\n\n", \
vx(n,1),vy(n,1),color(n), vx(n,2),vy(n,2), vx(n,3),vy(n,3), vx(n,1),vy(n,1))
}
set print
set size square
set xrange[0:5]
set yrange[0:5]
set linetype 1 lc rgb "black" lw 3
set style fill solid 0.5
plot $Triangles u 1:2:3 w filledcurves lc rgb var notitle
### end of script

gnuplot : using a logarithmic axis for a histogram

I have a data file that I am creating a histogram from.
The data file is :
-0.1 0 0 JANE
1 1 1 BILL
2 2 1 BILL
1 3 1 BILL
6 4 0 JANE
35 5 0 JANE
9 6 1 BILL
4 7 1 BILL
24 8 1 BILL
28 9 1 BILL
9 10 0 JANE
16 11 1 BILL
4 12 0 JANE
45 13 1 BILL
My gnuplot script is :
file='test.txt'
binwidth=10
bin(x,width)=width*floor(x/width)
set boxwidth 1
plot file using (bin($1,binwidth)):(1.0) smooth freq with boxes, \
file using (1+(bin($2,binwidth))):(1.0) smooth freq with boxes
I would like to plot this data on a logscale in y. However there are some 0 values (because some of the bins are empty) that cannot be handled by set logscale y. I get the error Warning: empty y range [1:1], adjusting to [0.99:1.01].
According to gnuplot's help, "The frequency option makes the data monotonic in x; points with the same x-value are replaced by a single point having the summed y-values."
How can I take the log10() of the summed y-values computed by smooth freq with boxes?
There are at least two things that you could do. One is to use a linear axis between 0 and 1 and then use the logarithmic one as explained in this answer. The other one is to plot to a table first and then set the log scale ignoring the points with zero value.
With a normal linear axis and your code (plus set yrange [0:11]) your data looks:
Now lets plot to a table, then set the log scale, then plot ignoring the zero values:
file='test.txt'
binwidth=10
bin(x,width)=width*floor(x/width)
set table "data"
plot file using (bin($1,binwidth)):(1.0) smooth freq, \
file using (1+(bin($2,binwidth))):(1.0) smooth freq
unset table
set boxwidth 1
set logscale y
set yrange [0.1:11]
plot "data" index 0 using ($1):($2 == 0 ? 1/0 : $2) with boxes lc 1, \
"data" index 1 using ($1):($2 == 0 ? 1/0 : $2) with boxes lc 2
set table sometimes generates some undesirable points in the plot, which you can see at x = 0. To get rid of them you can use "< grep -v u data" instead of "data".

Gnuplot: plotting points with variable point types

I have x,y values for points in the first 2 colums and a number that indicates the point type (symbol) in the 3. column, in one data file. How do I plot data points with different symbols?
Unfortunately, there isn't a way (AFAIK) to automatically set the point of the plot from a column value using vanilla GNUPLOT.
However, there is a way to get around that by setting a linestyle for each data series, and then plotting the values based on that defined style:
set style line 1 lc rgb 'red' pt 7 #Circle
set style line 2 lc rgb 'blue' pt 5 #Square
Remember that the number after pt is the point-type.
Then, all you have to do is plot (assuming that the data in "data.txt" is ordered ColX ColY Col3):
plot "data.txt" using 1:2 title 'Y Axis' with points ls 1, \
"data.txt" using 1:3 title 'Y Axis' with points ls 2
Try it here using this data (in the section titled "Data" - also note that column 3 "Symbol" is noted used, it's mainly there for illustrative purposes):
# This file is called force.dat
# Force-Deflection data for a beam and a bar
# Deflection Col-Force Symbol
0.000 0 5
0.001 104 5
0.002 202 7
0.003 298 7
And in the Plot Script Heading:
set key inside bottom right
set xlabel 'Deflection (m)'
set ylabel 'Force (kN)'
set title 'Some Data'
set style line 1 lc rgb 'red' pt 7
set style line 2 lc rgb 'blue' pt 5
plot "data.txt" using 1:2 title 'Col-Force' with points ls 1, \
"data.txt" using 1:3 title 'Beam-Force' with points ls 2
The one caveat is of course that you have have to reconfigure your data input source.
REFERENCES:
http://www.gnuplotting.org/plotting-single-points/
http://www.gnuplotting.org/plotting-data/
Here is a possible solution (which is a simple extrapolation from gnuplot conditional plotting with if), that works as long as you don't have tens of different symbols to handle.
Suppose I want to plot 2D points in a coordinate system. I have only two symbols, that I arbitrarily represented with a 0 and a 1 in the last column of my data file :
0 -0.29450470209121704 1.2279523611068726 1
1 -0.4006965458393097 1.0025811195373535 0
2 -0.7109975814819336 0.9022682905197144 1
3 -0.8540692329406738 1.0190201997756958 1
4 -0.5559651851654053 0.7677079439163208 0
5 -1.1831613779067993 1.5692367553710938 0
6 -0.24254602193832397 0.8055955171585083 0
7 -0.3412654995918274 0.6301406025886536 0
8 -0.25005266070365906 0.7788659334182739 1
9 -0.16853423416614532 0.09659398347139359 1
10 0.169997438788414 0.3473801910877228 0
11 -0.5252010226249695 -0.1398928463459015 0
12 -0.17566296458244324 0.09505800902843475 1
To achieve what I want, I just plot my file using conditionals. Using an undefined value like 1/0 results in no plotting of the given point:
# Set styles
REG_PTS = 'pointtype 7 pointsize 1.5 linecolor rgb "purple"'
NET_PTS = 'pointtype 4 pointsize 1.5 linecolor rgb "blue"'
set grid
# Plot each category with its own style
plot "data_file" u 2:($4 == 0 ? $3 : 1/0) title "regular" #REG_PTS, \
"data_file" u 2:($4 == 1 ? $3 : 1/0) title "network" #NET_PTS
Here is the result :
Hope this helps
Variable pointype (pt variable) was introduced (I guess) not until gnuplot 5.2.0 (Sept 2017) (check help points).
Just in retrospective, another (awkward) solution would be the following for those who are still using such early versions.
Data:
1 1.0 4 # empty square
2 2.0 5 # filled square
3 3.0 6 # empty circle
4 4.0 7 # filled circle
5 5.0 8 # empty triangle up
6 6.0 9 # filled triangle down
7 7.0 15 # filled pentagon (cross in gnuplot 4.6 to 5.0)
Script: (works from gnuplot>=4.6.0, March 2012; but not necessary since 5.2.0)
### variable pointtype for gnuplot>=4.6
reset
FILE = 'SO23707979.dat'
set key noautotitle
set offsets 1,1,1,1
set pointsize 4
stats FILE u 0 nooutput
N = STATS_records # get the number of rows
p0=x1=y1=NaN
plot for [n=0:N-1 ] FILE u (x0=x1, x1=$1, x0):(y0=y1, y1=$2, y0):(p0=$3) \
every ::n::n w p pt p0 lc rgb "red", \
FILE u 1:2 every ::N-1::N-1 w p pt p0 lc rgb "red"
### end of script
Result:

Arranging non uniform xtics to a uniform scale in GNUPlot

I have a data set that uses the x-scale:
0.1 0.4 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
But I need the tics to line up evenly, not have 0.1 and 0.4 scrunched up into the corner. I currently use,
set xtics 1
set xtics add (0.1)(0.4)
But that spaces 0.1 and 0.4 respective to the rest of the scale. I've attached a link to a tinypic I uploaded of my dummy data set with my current problem.
http://tinypic.com/r/2zfolxf/7
Current State
As far as I know, you can do the following in gnuplot with tics (at least what is relevant to your question):
You can specify the start, increment and end of the tics displayed.
This would make sense to you, if you wish to simply set the tics after the value of 2 like
set xtics 2, 1
The other thing you can do, is add explicit tic labels to certain values like
set xtics add ("0.1" 0, "0.4" 1)
This would introduce the labels 0.1, and 0.4 to the x scale where the actual values are 0 and 1
However you cannot modify the actual plotting of the graph. If in you data it states
0.1 100
0.4 150
1 200
2 300
then gunplot will plot it correspondingly.
Possible workaround
A workaround could look like this:
Plot the normal graph from 2 upwards.
Do some hackery stuff to the first two values with this:
plot "Data.dat" every 1::2 w l, "" every 1::1::2 using ($1<magic>):($2)
magic specifies some algebraic operation you want to do with the first column.
Everything is allowed and if your values are constant you can specify a polynomial that goes through the points 0, 1 and 2 with the inputs 0.1, 0.4 and 1 like this polynomial:
y = -1.85*x^2 + 4.26*x - 1.4
Example
Suppose you have this data file:
0.1 0.41
0.4 0.03
1 0.97
2 0.74
3 0.05
4 0.15
5 0.11
6 0.60
7 0.76
8 0.25
Then you can "rearrange" the first two entries to the x-positions -1 and 0 like this:
plot "Data.dat" every 1::2 w l, \
"" every 1::0::2 using (-1.85*$1**2 + 4.26*$1 - 1.4):($2) w l
With some tic-labeling and line style settings it should look exactly like what you are after.
I hope I understood what you are after and that you can make some use of my suggestions.
Cherio
Woltan

Resources