From a function in C++ I get in a file the coordinates of the centers of a chain of spheres (of constant radius r). I would like to plot this chain with gnuplot. How can I represent the spheres with the true radius? This solution actually does not work, since the unit of pointsize is not the same as that of the axis (and is also changing with the axis limits).
This a slightly dirty solution which uses parametric (and some commands from Unix). For each line of the following data, we will plot a sphere with radius r, and centered at (x,y,z):
# points.dat :
# x y z radius
0 0 0 0.5
1 2 2 1.0
3 4 5 0.7
2 5 7 1.0
1 3 4 0.75
2 0 1 1.5
In other words, we will run commands with the form:
splot x1+r1*cos(v)*cos(u), y1+r1*cos(v)*sin(u), z1+r1*sin(v) title "line 1",\
x2+r2*cos(v)*cos(u), y2+r2*cos(v)*sin(u), z2+r2*sin(v) title "line 2", ...
The following code will do the trick (comments through the script):
set view equal xyz # to scale the axes of the plot
set hidden3d front # draw opaque spheres
set parametric # enable parametric mode with angles (u,v)
set urange [0:2*pi]
set vrange [-pi/2.0:pi/2.0]
filename = 'spheres.dat'
# get number of data-lines in filename
nlines = system(sprintf('grep -v ^# %s | wc -l', filename))
# this will save the plot commands
commands = 'splot '
do for [i=1:nlines] {
# get the i-th line
line = system( sprintf('grep -v ^# %s | awk "NR == %i {print; exit}" ', filename, i) )
# extract the data
x = word(line,1)
y = word(line,2)
z = word(line,3)
r = word(line,4)
# and save the instructions to plot the corresponding sphere
commands = commands . sprintf('%s + %s*cos(v)*cos(u), %s + %s*cos(v)*sin(u), %s + %s*sin(v) t "line %i"', x, r, y, r, z, r, i)
# if not EOF, add a comma to commands
if(i<nlines) { commands = commands . ', ' }
}
# commands is a string. We can run it into the command line through macros
set macros
#commands
This is the output I obtain:
Related
I've been trying to compute numerically the derivative using gnuplot, using the scripts in this other discussion, even with the same data file. However I keep getting this error:
gnuplot> d(y) = ($0 == 0) ? (y1 = y, 1/0) : (y2 = y1, y1 = y, y1-y2)
^
"prova.g", line 7: ')' expected
I don't know what to do here. Any help?
Here is an example for numerical derivatives from my collection. Requires gnuplot >=5.0 and with the use of files instead of datablocks (and probably with some tweaking with gnuplot>=4.4.0).
Script: (works with gnuplot>=5.0.0, Jan. 2015)
### numerical derivatives
reset session
# create some data
MyFunction = "sin(x)/x"
set table $Data
set samples 150
plot [-10:10] '+' u 1:(#MyFunction) w table
unset table
DerivX(colX) = (x0=x1,x1=column(colX),(x0+x1)/2.)
DerivY(colY) = (y0=y1,y1=column(colY),(y1-y0)/(x1-x0))
set table $Deriv1
plot x1=y1=NaN $Data u (DerivX(1)):(DerivY(2)) w table
unset table
set table $Deriv2
plot x1=y1=NaN $Deriv1 u (DerivX(1)):(DerivY(2)) w table
unset table
set table $Deriv3
plot x1=y1=NaN $Deriv2 u (DerivX(1)):(DerivY(2)) w table
unset table
plot $Data u 1:2 w l lc rgb "red" ti MyFunction, \
$Deriv1 u 1:2 w l lc rgb "web-green" ti "1st Derivative", \
$Deriv2 u 1:2 w l lc rgb "blue" ti "2nd Derivative", \
$Deriv3 u 1:2 w l lc rgb "magenta" ti "3rd Derivative"
### end of script
Result:
Addition: (version for gnuplot 4.2.6, Sept. 2009)
gnuplot 4.2.6 doesn't have datablocks and serial evaluation, but here is a cumbersome workaround without these features.
for illustration, the script creates a data file SO68198576.dat (you already have your input file)
plot the data file into another file TEMP1 skipping the first data line
merge the files line by line into another file TEMP2 using the system command paste (either on Linux already on the system or on Windows you have to install, e.g. CoreUtils from GnuWin).
now you can calculate dx and dy between two successive datapoints from column 1 and 4 and column 2 and 5, respectively.
since the files have different length, the last line(s) should be skipped. This can be done by the system command head -n -2.
That's how TEMP2 looks like:
#Curve 0 of 1, 150 points #Curve 0 of 1, 150 points
#x y type #x y type
-10 -0.0544021 i -9.86577 -0.0432646 i
-9.86577 -0.0432646 i -9.73154 -0.0310307 i
-9.73154 -0.0310307 i -9.59732 -0.0178886 i
...
Script: (works with gnuplot 4.2.6, requires system commands paste and head)
### numerical derivative for gnuplot 4.2.6
reset
FILE = "SO68198576.dat"
set table FILE
set samples 150
plot sin(x)/x
unset table
TEMP1 = FILE.'1'
TEMP2 = FILE.'2'
set table TEMP1
plot FILE u 1:2 every ::1
unset table
system(sprintf('paste %s %s > %s', FILE, TEMP1, TEMP2))
system(sprintf('head -n -2 %s > %s',TEMP2, TEMP1))
x0(col) = (column(col)+column(col+3))/2.
dx(col) = (column(col+3)-column(col))/2.
dy(col) = (column(col+3)-column(col))/2.
plot FILE u 1:2 w lp pt 7 title "Data", \
TEMP1 u (x0(1)):(dy(2)/dx(1)) w lp pt 7 title "1st Derivative"
### end of script
Result: (screenshot gnuplot 4.2.6)
I want to use gnuplot to plot relations rather than the exact coordinates.
Something like Igraph in R where I can do A->B without specifying the coordinates in space. I am using a gnuplot script specified on other SO answers inside the system call.
I want to integrate it with my ocaml compiler inside LLVM. If there are any suggestions on that as well, please let me know.
Thank you so much.
Optimizing graphs is a large and interesting field. And as #eush77 mentioned, Graphviz is a dedicated tool for this type of task.
Although, you could do something with gnuplot. There is a relatively simple algorithm which is based on attracting and repelling forces between vertices. Details can be found e.g. here and here.
First, the script places the vertices at random coordinates and then iterates to a final state (however, which is not always optimal).
You need to play with the constants c1,c2,c3,c4.
The example below used the gif terminal to visualize the iterations. If you are only interested in the final result, use another terminal and move the replot after the loop.
The script below is a starting point and can certainly be improved. Suggestions and comments are welcome.
Script: (works with gnuplot>=5.2.0, because of the use of arrays)
### plotting optimized graph
reset session
$Data <<EOD
# ID PointColor
1 0xffaaaa
2 0xaaffaa
3 0xaaaaff
4 0xffaaff
5 0xffffaa
6 0xaaffff
73 0xcccccc
A 0xcccccc
XY 0xcccccc
0 0xffffff
G 0xffffff
# ID1 ID2 LineColor
1 4 0x0000ff
2 4 0x000000
3 4 0x00ff00
5 4 0x000000
6 5 0xff0000
73 3 0xcccccc
73 4 0xcccccc
73 5 0xcccccc
A 2 0xcccccc
A 3 0xcccccc
2 1 0xcccccc
XY 4 0xcccccc
XY 6 0xcccccc
0 2 0xcccccc
0 XY 0xcccccc
G 0 0xcccccc
G A 0xcccccc
EOD
stats $Data u (column(-2)==0?Nv=int($0+1):Ne=int($0+1)) nooutput # get number of vertices and edges
array Vx[Nv]
array Vy[Nv]
array Vt[Nv]
array Vc[Nv]
stats $Data index 0 u (i=int($0)+1, Vt[i]=strcol(1), Vx[i]=rand(0)*10, Vy[i]=rand(0)*10, \
Vc[i]=int($2)) nooutput # random placement of vertices
Vidx(s) = sum[_i=1:|Vx|] ( Vt[_i] eq s ? _i : 0) # get index via lookup of vertex "name"
array E0[Ne]
array E1[Ne]
array Ec[Ne]
stats $Data index 1 u (i=int($0)+1, E0[i]=Vidx(strcol(1)), E1[i]=Vidx(strcol(2)), \
Ec[i]=int($3) ) nooutput # get edge point indices
set size ratio 1
set key noautotitle
set offsets 0.25,0.25,0.25,0.25
unset border
unset tics
set term gif animate delay 20
set output "SO43843240.gif"
plot E0 u (i=int($0+1), x0=Vx[E0[i]]):(y0=Vy[E0[i]]):(Vx[E1[i]]-x0):(Vy[E1[i]]-y0): \
(Ec[i]) w vec lw 2 lc rgb var nohead, \
Vx u (i=int($0+1),Vx[i]):(Vy[i]):(Vc[i]) w p pt 7 ps 6 lc rgb var, \
'' u (i=int($0+1),Vx[i]):(Vy[i]) w p pt 6 ps 6 lc rgb "black", \
'' u (i=int($0+1),Vx[i]):(Vy[i]):(Vt[i]) w labels
# parameters for force
c1 = 2
c2 = 1
c3 = 1
c4 = 0.2
fs(d) = c1*log(d/c2) # force spring attracting/repelling
fr(d) = c3/d # force repelling
dV(i,j) = sqrt((Vx[j]-Vx[i])**2 + (Vy[j]-Vy[i])**2)
set angle degrees
a(i,j) = atan2(Vy[j]-Vy[i], Vx[j]-Vx[i])
array Fx[Nv] # force in x
array Fy[Nv] # force in y
do for [n=1:500] {
set label 1 at screen 1.0,0.97 sprintf("Iteration: % 4d",n) right
# repelling forces
do for [i=1:Nv] {
Fx[i] = Fy[i] = 0 # initialize
do for [j=1:Nv] {
if (i!=j) {
f0 = fr(dV(i,j))
a0 = a(i,j)
Fx[i] = Fx[i] - f0*cos(a0)
Fy[i] = Fy[i] - f0*sin(a0)
}
}
}
# spring forces
do for [n=1:Ne] {
i = E0[n]
j = E1[n]
f0 = fs(dV(i,j))
a0 = a(i,j)
Fx[i]=Fx[i]+f0*cos(a0)
Fy[i]=Fy[i]+f0*sin(a0)
Fx[j]=Fx[j]-f0*cos(a0)
Fy[j]=Fy[j]-f0*sin(a0)
}
# add displacement
do for [i=1:Nv] {
Vx[i] = Vx[i] + c4*Fx[i]
Vy[i] = Vy[i] + c4*Fy[i]
}
stats Fy u 2 nooutput # get maximum change y
if (abs(c4*STATS_max)<0.005) { break } # exit loop when max. y-displacement below threshold
replot
}
set output
### end of script
Result: (animation from gif terminal)
I have a file which from which I'd like to extract two values (Time, C_F[6]) highlighted below. Its in a CentOS 7 environment so can use bash or gnuplot or r. I'm not even sure how to google that (e.g. extract values from file bash doesn't really come up with solutions). Is it possile?
I'd like to be able to:
plot Time vs C_F[6]
Average C_F[6]
EDIT 1:
I think this might be on the lines, but it reproduces the whole file
sed 's/^.*C_F[6]=//' C_F.pressure > outputfile
EDIT 2:
Extract of the file:
/*---------------------------------------------------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: 3.0.0 |
| \\ / A nd | Web: www.OpenFOAM.org |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
Build : 3.0.0-6abec57f5449
Exec : patchAverage p C_F -parallel
Date : Apr 15 2017
Time : 15:01:20
Host : "login2.jjj.uk"
PID : 59764
Case : /nobackup/jjjj/Silsoe/Solid/solid_0_LES/motorBikeLES
nProcs : 8
Slaves :
7
(
"login2.jjjj.59765"
"login2.jjjj.59766"
"login2.jjjj.59767"
"login2.jjjj.59768"
"login2.jjjj.59769"
"login2.jjjj.59770"
"login2.jjjj.59771"
)
Pstream initialized with:
floatTransfer : 0
nProcsSimpleSum : 0
commsType : nonBlocking
polling iterations : 0
sigFpe : Enabling floating point exception trapping (FOAM_SIGFPE).
fileModificationChecking : Monitoring run-time modified files using timeStampMaster
allowSystemOperations : Allowing user-supplied system call operations
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
Create time
Create mesh for time = 0.18
Time = 0.18
Reading volScalarField p
Average of volScalarField over patch C_F[6] = -18.3176
Time = 0.19
Reading volScalarField p
Average of volScalarField over patch C_F[6] = -18.299
Time = 0.2
Reading volScalarField p
Average of volScalarField over patch C_F[6] = -18.2704
Time = 0.21
Reading volScalarField p
Average of volScalarField over patch C_F[6] = -18.2349
Here's a crude way to do things:
# extract text from file line by line; will be indexed by line
sample <- readLines("D:\\tempFiles/example.txt")
# index the lines contaning "Time = "
timeI <- grep(x = sample, pattern = "Time = ")
# index the lines contaning "C_F[6]"; note that \\ is escape for [ and ]
C_FI <- grep(x = sample, pattern = "C_F\\[6\\]")
# extract lines and clean them
# note that these lines only contain "Time = values"; so just remove the "Time = "
timeval <-as.numeric(gsub(x = sample[timeI], pattern = "Time = ", replacement = ""))
# extract lines and clean them
# note that gsub removes all characters from te start (^) until "= "
C_FIval <- as.numeric(gsub(x = sample[C_FI], pattern = "^.*= ", ""))
# plot timve vs CF[6]
plot(y = timeval, x = C_FIval )
# get the mean
mean(C_FIval)
There are more elegant ways for the regex, but I'm still finding my way through that. This should be a basic way.
Since the OP tagged also gnuplot, here is a platform independent gnuplot-only solution.
How it's done:
standard datafile separator is whitespace
the function getTime() will check if the first string column is equal to "Time" and at the same time the second stringcolumn must be '=' (because you have Time in the first column in the header as well). If this is true then column 3 is the time and you memorize this value in the variable t0.
the function getValue() will check if the first string column is equal to "Average" and at the same time the 6th stringcolumn must be "C_F[6]". If this is true then column 8 is the value and memorize this value in y0, sum it up in ySum and increase the counter c by 1. If it is false, the function's return value will be NaN and nothing will be plotted. Note, the function has to check the first column because in case there is no 6th column the check will fail.
calculate the average by yAvg=ySum/c and plot and print it into the graph.
You might notice that the plotted datapoints in the first plot are not connected although the plotting style with linespoints was used. The reason is that there are empty lines in the input file and gnuplot will interrupt curves at empty lines.
Hence, in case you want connected lines you have to remove these empty lines which you can do by plotting the file each line as a whole (set datafile separator "\n") into a datablock table (with table). This requires gnuplot>=5.2.0. Furthermore, by using set datafile missing NaN gnuplot will not interrupt lines at NaN values.
This extraction can easily be adapted to any other input data format.
Data: Save the OP's data example as SO43427046.dat
Script: (the first solution works with gnuplot>4.4.4, Nov. 2011 and the second solution with gnuplot>=5.2.0, Sept. 2017)
### extract specific data from a file
reset
FILE = "SO/SO43427046.dat"
getTime(col1,col2,col3) = strcol(col1) eq "Time" && strcol(col2) eq "=" ? t0=column(col3) : t0
getValue(col1,col2,col3) = strcol(col1) eq "Average" && strcol(col2) eq "C_F[6]" ? \
(y0=column(col3),ySum=ySum+y0,c=c+1,y0) : NaN
set key top left
set ytics 0.02
set multiplot layout 2,1
ySum = c = 0
t0 = y0 = NaN
plot FILE u (getTime(1,2,3)):(getValue(1,6,8)) \
w lp pt 7 lc rgb "red" ti "unconnected points", \
(yAvg=ySum/c) w l lc rgb "blue" ti sprintf("Average: %g",yAvg)
set table $Data
set datafile separator "\n"
plot FILE u (strcol(1)) w table
set datafile separator whitespace
unset table
set datafile missing NaN
ySum = c = 0
t0 = y0 = NaN
plot $Data u (getTime(1,2,3)):(getValue(1,6,8)) w lp pt 7 lc rgb "red" ti "linespoints", \
(yAvg=ySum/c) w l lc rgb "blue" ti sprintf("Average: %g",yAvg)
unset multiplot
### end of script
Result:
Say, I have two points (x1,y1) and (x2,y2) on the same line . The midpoint of joining this two points is (x,y). Is it possible to draw a perpendicular bisector through (x,y) in gnuplot? How will I draw it?
It's simple math:
your line slope: slope = (y2 - y1) / (x2 - x1)
your line equation: line(x) = slope * (x - x1) + y1
the middle point (calling it xm,ym because x,y are reserved):
xm=(x1+x2)/2.0
ym=(y1+y2)/2.0
the perpendicular line equation: line_perp(x) = -(x-xm)/slope + ym
plot both: plot line(x), line_perp(x)
In case y2==y1 or x2==x1 i.e the two points are in horizontal/vertical line you can fix the script using an arrow:
if (y2==y1 || x2==x1) {
set arrow from xm, graph 0 to xm, graph 1 nohead
plot ym
} else {
plot line(x), line_perp(x)
}
Instead of going via y = a*x + b as in #bibi's and #user4489658's answers, where a could be infinite, I would go via the angle (check help atan2).
This covers vertical lines without extra treatment.
Make sure to use set size ratio -1 (check help size) that the perpendicular bisector really looks perpendicular in the graph.
Script:
### drawing perpendicular bisectors
reset session
$Data <<EOD
# x1 y1 x2 y2
10 20 15 20
10 10 20 20
20 10 20 15
12 10 18 12
10 12 12 18
EOD
set key out
set offset 1,1,1,1
set angle degrees
set size ratio -1
colX1 = 1
colY1 = 2
colX2 = 3
colY2 = 4
dx(n) = column(colX2)-column(colX1)
dy(n) = column(colY2)-column(colY1)
a0(n) = atan2(dy(n),dx(n)) + 90
xm(n) = (column(colX1)+column(colX2))*0.5
ym(n) = (column(colY1)+column(colY2))*0.5
Scaling = 0.2
L0(n) = Scaling*sqrt(dx(n)**2 + dy(n)**2)
getParams(n) = (dx0=L0(0)*cos(a0(0)), dy0=L0(0)*sin(a0(0)), x0=xm(0)-dx0, y0=ym(0)-dy0)
plot $Data u colX1:colY1 w p pt 7 lc "blue" ti "Start", \
'' u colX2:colY2 w p pt 7 lc "red" ti "End", \
'' u colX1:colY1:(dx(0)):(dy(0)) w vec lc "web-green" filled ti "Vector", \
'' u (getParams(0),x0):(y0):(2*dx0):(2*dy0) w vec lc "black" dt 3 nohead ti "\nperpendicular\nbisector"
### end of script
Result:
Equation of your line is
y=ax+b
a=(y2-y1)/(x2-x1)
b=(x2*y1-y2*x1)/(x2-x1)
Midpoint:
x3=(x1+x2)/2.;y3=(y1+y2)/2.
Equation of perpendicular line:
y-y3=-1./a*(x-x3)
y=-1./a*x+x3/a+y3
a2=-1./a
b2=x3/a+y3
gnuplot script:
x1=1.;y1=3.;x2=10.;y2=15.
a=(y2-y1)/(x2-x1)
b=(x2*y1-y2*x1)/(x2-x1)
x3=(x2+x1)/2.;y3=(y2+y1)/2.
a2=-1./a
b2=x3/a+y3
set arrow 1 from x1,y1 to x2,y2 nohead
plot [0:15][0:22] a2*x+b2
I am using gnuplot for the following. I have n equations which I want to plot based on the xaxis value. Here is a sample
set xrange[0:25]
f1(x) = x
f2(x) = 3*x
f3(x) = 10*x
plot (x>0)&&(x<10)?f1(x):(x<20)?f2(x):f3(x)
I know that we can set the color of the line easily by using the below. But it changes the whole color
set style line 1 lt 1 lw 3 pt 3 lc rgb "blue"
But what I want is to make the connecting lines a different color. ie if you plot the above graph you will 5 lines. 3 original lines (from the function) and 2 lines (the almost vertical lines) connecting them. I want to change the color of the connecting lines.
Note 1: These functions are automatically generated by a program, and the number of functions could be large. Even the exact plot command is automatically generated
Note 2: I want a way to differentiate my original lines with the interpolated lines which joins my original lines.
Any help is appreciated
What you actually have is one line defined piecewise, and there isn't an easy way to define colors for line segments within a piecewise line in gnuplot.
Easy way (plot a data file)
I would recommend making a data file looking like this:
# x y color
0 0 0
10 10 0
10 10 1
10 30 1
10 30 0
20 60 0
20 60 1
20 200 1
20 200 0
25 250 0
Notice the double points at x=10 and x=20. This is so the line segments meet at the transitions.
Now plot it with linecolor variable:
#!/usr/bin/env gnuplot
reset
set terminal pdfcairo enhanced color dashed rounded lw 5 size 3,2 font 'Arial,14'
set output 'output2.pdf'
set style data lines
set key top left
set tics scale 0.5 out nomirror
plot 'data.dat' u 1:2:3 lc variable
It looks like this:
You can change the palette (set palette) to determine the colors, and you can have more than 2 color values in the data file if you want.
Harder way (only OK for few segments)
You could define 2n-1 separate lines and connect them:
#!/usr/bin/env gnuplot
reset
set terminal pdfcairo enhanced color dashed rounded lw 5 size 3,2 font 'Arial,14'
set output 'output.pdf'
set style data lines
set key top left
set tics scale 0.5 out nomirror
# points every 0.001 units in the range 0:25
set samples 25001
# main lines
f1(x) = (x <= 9.999) ? x : 1/0
f3(x) = (x >= 10.001) && (x <= 19.999) ? 3*x : 1/0
f5(x) = (x >= 20.001) ? 10*x : 1/0
# define slopes and y-offsets of connecting lines
m2 = (f3(10.001)-f1(9.999))/0.002
b2 = (30.0-10.0)/2.0 + 10.0
m4 = (f5(20.001)-f3(19.999))/0.002
b4 = (200.0-60.0)/2.0 + 60.0
# connecting functions
f2(x) = (x >= 9.999) && (x <= 10.001) ? m2*(x-10) + b2 : 1/0
f4(x) = (x >= 19.999) && (x <= 20.001) ? m4*(x-20) + b4 : 1/0
plot [0:25] f1(x), f2(x), f3(x), f4(x), f5(x)
Which looks like this:
You can define a secondary function to define the breakpoints of your function, which is automatically coloring the right linepiece. The below code is easy to extend to different functions and breakpoints (i.e., you can just change x1 or x2). Adding multiple points is also straightforward.
xmin=0.
xmax=25.
x0=0.
x1=10.
x2=20.
nsample=200.
dx=(xmax-xmin)/nsample
print dx
set xrange[xmin:xmax]
set sample nsample
f1(x) = x
f2(x) = 3*x
f3(x) = 10*x
f4(x) = (x>x0)&&(x<x1)?f1(x):(x<x2)?f2(x):f3(x)
f5(x) = x
f5(x) = ( (x>x1&&x<=x1+dx) || (x>x2&&x<=x2+dx) )?1:0
set cbrange [0:1]
unset key
plot '+' using 1:(f4($1)):(f5($1)) lc variable with lines
Not that I have use the special filename '+', which just constructs a data file with equally space datapoints (following nsample).
If it is ok to skip the connecting lines, then you can use a simplified version of #andyras second variant. Just define all functions to be 1/0 when outside a specified range:
set style data lines
unset key
f1(x) = (x > 0) && (x < 10) ? x : 1/0
f2(x) = (x > 10) && (x < 20) ? 3*x : 1/0
f3(x) = (x > 20) ? 10*x : 1/0
plot [0:25] f1(x), f2(x), f3(x)
Following yet another possibility. This assumes, that you can select a sampling high enough, so that the "jumps" which connect the functions are always greater than inside a function:
set style data lines
unset key
set xrange[0:25]
f1(x) = x
f2(x) = 3*x
f3(x) = 10*x
f(x) = ( (x>0)&&(x<10)?f1(x):(x<20)?f2(x):f3(x) )
set samples 1000
curr = 0
prev = 0
lim = 1
plot '+' using (prev = curr, curr=f($1), $1):(f($1)):(abs(curr-prev) < lim ? 0 : 1) lc var