Glowing (neon) effect in gnuplot - gnuplot

I want to reproduce this effect in gnuplot:
How can I achive it? If it can't be done, what software can I use to reproduce it?

Using a 2d kernel for every pixel can be done inside gnuplot. That way, more dense accumulations get brighter than single pixels. Check show palette rgbformulae and the respective chapter in the help to change the colours.
set term wxt size 300,300 background rgb 0
set view map
set samp 140
set dgrid3d 180,180, gauss kdensity2d 0.2,0.2
set palette rgbform 4,4,3
splot "+" us 1:(sin($1/3)**2*20):(1) with pm3d notitle

Disclaimer: It can be done with gnuplot as instructed in this answer but you should probably consider a different tool to draw this particular type of plot.
There is at least one way to do it, with preprocessing of the data. The idea is to mimic the glow effect by using a Gaussian kernel to smear the data points. Consider the following data, contained in a file called data:
1 2
1 2.1
1.1 2.2
2 3
3 4
I have purposely placed the first 3 points close to each other to be able to observe the intensified glow of neighboring points. These data look like this:
Now we smear the data points using a 2D Gaussian kernel. I have written the following python code to help with this. The code has a cutoff of 4 standard deviations (sx and sy) around each point. If you want the glow to be a circle, you should choose the standard deviations so that the sx / sy ratio is the same as the ratio of the x/y axes lengths in gnuplot. Otherwise the points will look like ellipses. This is the code:
import numpy as np
import sys
filename = str(sys.argv[1])
sx = float(sys.argv[2])
sy = float(sys.argv[3])
def f(x,y,x0,y0,sx,sy):
return np.exp(-(x-x0)**2/2./sx**2 -(y-y0)**2/2./sy**2)
datafile = open(filename, 'r')
data = []
for datapoint in datafile:
a, b = datapoint.split()
data.append([float(a),float(b)])
xmin = data[0][0]
xmax = data[0][0]
ymin = data[0][1]
ymax = data[0][1]
for i in range(1, len(data)):
if(data[i][0] < xmin):
xmin = data[i][0]
if(data[i][0] > xmax):
xmax = data[i][0]
if(data[i][1] < ymin):
ymin = data[i][1]
if(data[i][1] > ymax):
ymax = data[i][1]
xmin -= 4.*sx
xmax += 4.*sx
ymin -= 4.*sy
ymax += 4.*sy
dx = (xmax - xmin) / 250.
dy = (ymax - ymin) / 250.
for i in np.arange(xmin,xmax+dx, dx):
for j in np.arange(ymin,ymax+dy, dy):
s = 0.
for k in range(0, len(data)):
d2 = (i - data[k][0])**2 + (j - data[k][1])**2
if( d2 < (4.*sx)**2 + (4.*sy)**2):
s += f(i,j,data[k][0],data[k][1],sx,sy)
print i, j, s
It is used as follows:
python script.py data sx sy
where script.py is the name of the file where the code is located, data is the name of the data file, and sx and sy are the standard deviations.
Now, back to gnuplot, we define a palette that mimics a glowing pattern. For isolated points, the summed Gaussians yield 1 at the position of the point; for overlapping points it yields values higher than 1. You must consider that when defining the palette. The following is just an example:
set cbrange [0:3]
unset colorbox
set palette defined (0 "black", 0.5 "blue", 0.75 "cyan", 1 "white", 3 "white")
plot "< python script.py data 0.05 0.05" w image
You can see that the points are actually ellipses, because the ratio of the axes lengths is not the same as that of the standard deviations along the different directions. This can be easily fixed:
plot "< python script.py data 0.05 0.06" w image

Set a black background, and then plot your dataset several time in different colours with decreasing pointsize.
set term wxt backgr rgb "black"
plot sin(x) w p pt 7 ps 2 lc rgb 0x00003f not, \
sin(x) w p pt 7 ps 1.5 lc rgb 0x00007f not, \
sin(x) w p pt 7 ps 1 lc rgb 0x0000af not, \
sin(x) w p pt 7 ps .5 lc rgb 0x0000ff
Alternatively, some combination of splot with pm3d,set dgrid3d gauss kdensity2d, and set view map, combined with a suitable palette, can be used, see my other answer.

Related

How to format x axis to a smaller scale?

So here is what I'm trying to do.
The values on x axis are from 10000, 20000, 30000, ... 100000. I'm trying to write it like this: 10, 20, 30, 40, ... 100 (only x axis)
Is there some way to do this in Gnuplot?
I have this so far:
(data.dat - example of data)
# x y
10000 +1.24241522E-04
11000 +1.28623514E-04
12000 +1.35229020E-04
13000 +1.43767741E-04
14000 +1.53409148E-04
15000 +1.63788695E-04
16000 +1.75429485E-04
17000 +1.88827813E-04
18000 +2.02984785E-04
19000 +2.20830420E-04
...
(my gnuplot script)
set term png
set out 'example.png'
U0 = 0.00732 #parameters for this particular problem
v1 = 68000
b1 = 6550
v2 = 59600
b2 = 6050
I = sqrt(-1)
A(w, w0, b) = ((w0)**2)/(((w0)**2) - ((w)**2) + 2*I*w*b)
f(x) = U0*abs(A(2*pi*x, 2*pi*v1, b1) - A(2*pi*x, 2*pi*v2, b2))
set xlabel "x"
set ylabel "y"
fit f(x) 'data.dat' u 1:2 via U0, v1, b1, v2, b2
plot 'data.dat' u 1:2 t "Title1" w p, U(x) t "Title2"
set out
But how do I do this?
I've tried this example
How to scale the axes in Gnuplot
but it doesn't work.
See below.
# I modified the things a little bit
f(x) = (.... ... ....)/1000
fit f(x) 'data.dat' u ($1/1000.):2 via U0, v1, b1, v2, b2
plot 'data.dat' u ($1/1000.):2 t "Title1" w p, f(x) t "Title2"
But now the fitted function disappears!
How can I modify x-axis without other function disappearing?
Does there exist a line command in gnuplot for this? I'm sure there has to be a more elegant way of writing this insted of dividing each function by a desired factor.
Two possible ways come to my mind:
if you want to avoid too many zeros in the xtic labels, simply set the xtic label format to engineering
set format x "%.0s%c"
This will show, e.g. 10000 and 100000 as 10k and 100k, respectively.
if you scale (in your case: divide) the x values of the data by factor of 1000, gnuplot will take this x range for plotting the function f(x). Since this is will give x values which are a factor of 1000 too small you have to scale your x values by a factor of 1000 accordingly (in your case: multiply).
Code:
### avoid too many zeros in xtic labels
reset session
# create some random test data
set print $Data
A = rand(0)*10+5
B = rand(0)*50000+25000
C = rand(0)*5000+5000
do for [i=10000:100000:500] {
print sprintf("%g %g",i,A*exp(-((real(i)-B)/C)**2))
}
set print
a=1; b=50000; c=5000 # give some reasonable starting values
f(x) = a*exp(-((x-b)/c)**2)
set fit quiet nolog
fit f(x) $Data u 1:2 via a,b,c
set multiplot layout 1,2
set format x "%.0s%c" # set xtics to engineering
plot $Data u 1:2 w p, \
f(x) w l lc "red"
set format x "%g" # set xtics to default
plot $Data u ($1/1000):2 w p, \
f(x*1000) w l lc "red"
unset multiplot
### end of code
Result:

Finding fitting range using gnuplot

I am new to Gnuplot, I have a non-linear data set and I want to fit the data within the linear range only. I normally do the fitting and specifies the fit range using the following command and redo the fitting process by changing the fit range manually until I get the optimum range for the fit:
fit [0.2:0.6]f(x) "data.txt" u 2:3:6 yerror via m1,m2
plot "<(sed -n '15,500p' data.txt)" u 2:3:6 w yerr title 'Window A',[0:.6] f(x) notitle lc rgb 'black'
Is it possible to iteratively run the fit within some data range to obtain the optimum data range for the fit in Gnuplot?
The data is typically like this one:
data
Your data (I named the file 'mas_data.txt') looks like the following (please always show/provide relevant data in your question).
Data: (how to plot with zoom-in)
### plotting data with zoom-in
reset session
FILE = 'mas_data.txt'
colX = 2
colY = 3
set key top left
set multiplot
plot FILE u colX:colY w lp pt 7 ps 0.3 lc rgb "red" ti "Data", \
set title "Zoom in"
set origin 0.45,0.1
set size 0.5, 0.6
set xrange [0:1.0]
plot FILE u colX:colY w lp pt 7 ps 0.3 lc rgb "red" ti "Data"
unset multiplot
### end of code
Regarding the "optimum" fitting range, you could try the following procedure:
find the absolute y-minimum of your data using stats (see help stats)
limit the x-range from this minimum to the maximum x-value
do a linear fit with f(x)=a*x+b and remember the standard error value for the slope (here: a_err)
reduce the x-range by a factor of 2
go back to 3. until you have reached the number of iteration (here: N=10)
find the minimum of Aerr[i] and get the corresponding x-range
The assumption is if the relative error (Aerr[i]) has a minimum then you will have the "best" fitting range for a linear fit starting from the minimum of your data.
However, I'm not sure if this procedure will be robust for all of your datasets. Maybe there are smarter procedures. Of course, you can also decrease the xrange in different steps. This procedure could be a starting point for further adaptions and optimizations.
Code:
### finding "best" fitting range
reset session
FILE = 'mas_data.txt'
colX = 2
colY = 3
stats FILE u colX:colY nooutput # do some statistics
MinY = STATS_min_y # minimum y-value
MinX = STATS_pos_min_y # x position of minimum y-value
Xmax = STATS_max_x # maximum x-value
XRangeMax = Xmax-MinX
f(x,a,b) = a*x + b
set fit quiet nolog
N = 10
array A[N]
array B[N]
array Aerr[N]
array R[N]
set print $myRange
do for [i=1:N] {
XRange = XRangeMax/2**(i-1)
R[i] = MinX+XRange
fit [MinX:R[i]] f(x,a,b) FILE u colX:colY via a,b
A[i] = a
Aerr[i] = a_err/a*100 # asymptotic standard error in %
B[i] = b
print sprintf("% 9.3g % 9.3f %g",MinX,R[i],Aerr[i])
}
set print
print $myRange
set key bottom right
set xrange [0:1.5]
plot FILE u colX:colY w lp pt 7 ps 0.3 lc rgb "red" ti "Data", \
for [i=1:N] [MinX:R[i]] f(x,A[i],B[i]) w l lc i title sprintf("%.2f%%",Aerr[i])
stats [*:*] $myRange u 2:3 nooutput
print sprintf('"Best" fitting range %.3f to %.3f', MinX, STATS_pos_min_y)
### end of code
Result:
Zoom-in xrange[0:1.0]
0.198 19.773 1.03497
0.198 9.985 1.09066
0.198 5.092 1.42902
0.198 2.645 1.53509
0.198 1.421 1.81259
0.198 0.810 0.659631
0.198 0.504 0.738046
0.198 0.351 0.895321
0.198 0.274 2.72058
0.198 0.236 8.50502
"Best" fitting range 0.198 to 0.810

Clip vectors on circle in gnuplot

I try to draw some vector fields in a circular region. Consider the following MWE
unset grid
unset tics
unset colorbox
unset border
set size square
besselj(n, x) = n > 1 ? 2*(n-1)/x*besselj(n-1,x) - besselj(n-2,x) : (n == 1 ? besj1(x) : besj0(x))
dbesselj(n, x) = n/x*besselj(n,x) - besselj(n+1,x)
rho(x,y) = sqrt(x**2+y**2)
phi(x,y) = atan2(y,x)
d = 1.0
l = 1.0
z = l/2
q = 1
set xrange [-d/2*1.1:d/2*1.1]
set yrange [-d/2*1.1:d/2*1.1]
Erho(x,y,n,ynp) = (-1/rho(x,y)) * besselj(n, (ynp*2/d)*rho(x,y)) * (-n*sin(n*phi(x,y))) * sin(q*pi*z/l)
Ephi(x,y,n,ynp) = (ynp*2/d) * dbesselj(n, (ynp*2/d)*rho(x,y)) * (cos(n*phi(x,y))) * sin(q*pi*z/l)
Ex(x,y,n,ynp) = rho(x,y) > d/2 ? NaN : cos(phi(x,y))*Erho(x,y,n,ynp) - sin(phi(x,y))*Ephi(x,y,n,ynp)
Ey(x,y,n,ynp) = rho(x,y) > d/2 ? NaN : sin(phi(x,y))*Erho(x,y,n,ynp) + cos(phi(x,y))*Ephi(x,y,n,ynp)
mag(x,y,n,ynp) = sqrt(Ex(x,y,n,ynp)**2 + Ey(x,y,n,ynp)**2)
set object circle at 0,0 size 0.5 fc black lw 3 front
set multiplot layout 1,2
set title 'TE_{01}'
set table 'tmp.dat'
set samples 16
set isosamples 16
plot '++' u 1:2:(Ex($1,$2,0,3.832)/50):(Ey($1,$2,0,3.832)/50) w vectors
unset table
set samples 250
set isosamples 250
plot '++' u 1:2:(mag($1,$2,0,3.832)) w image notitle, \
'tmp.dat' u 1:2:3:4 w vectors head filled lc black lw 1 notitle
set title 'TE_{11}'
set table 'tmp.dat'
set samples 16
set isosamples 16
plot '++' u 1:2:(Ex($1,$2,1,1.841)/20):(Ey($1,$2,1,1.841)/20) w vectors
unset table
set samples 250
set isosamples 250
plot '++' u 1:2:(mag($1,$2,1,1.841)) w image notitle, \
'tmp.dat' u 1:2:3:4 w vectors head filled lc black lw 1 notitle
unset multiplot
which plots the vector field as well as its magnitude inside the circle with diameter d. The result from this is
which is totally okay for the left image (TE01), but the right image (TE11) looks ugly because there are some vectors which are drawn outside the circle. My actually desired result is this
where I have no vectors outside of the black circle. How can I achieve that?
I know there is the clip function in gnuplot, but this does not allow to specify the shape to be used for clipping.
Here is what you can try. Define your own clip function, e.g. a circle.
First you need to check whether a data point is outside of your circle or not.
Clip(x,y) returns NaN if it is outside and 0 if it is inside.
Now, when you plot simply add the value of the clip function to your value. Your data will be clipped within a circle because something +0 remains unchanged and something +NaN will be NaN and will not be plotted. It is sufficient if you do this just for x (vector start) and x + delta x (vector end).
Code:
### clip function in circle form
reset session
set size square
# create some test data
set samples 25
Scaling = 0.5
set table $Data
plot [-5:5] '++' u 1:2:(Scaling*$1/sqrt($1**2+$2**2)): \
(Scaling*$2/sqrt($1**2+$2**2)) : (sqrt($1**2+$2**2)) with table
unset table
set palette rgb 33,13,10
CenterX = 0
CenterY = 0
Radius = 3.5
Clip(x,y) = sqrt((x-CenterX)**2 + (y-CenterY)**2) > Radius ? NaN : 0
set xrange[-6:6]
set yrange[-6:6]
set multiplot layout 1,3
plot $Data u 1:2:3:4:5 w vec lc pal not
plot $Data u ($1+Clip($1,$2)):2:($3+Clip($1+$3,$2+$4)):4:5 w vec lc pal not
CenterX = 1
CenterY = 1
plot $Data u ($1+Clip($1,$2)):2:($3+Clip($1+$3,$2+$4)):4:5 w vec lc pal not
unset multiplot
### end of code
Result:

Display a line outside the axis limits in Octave

I'd like to draw a line that extends beyond the limits of the axis. I've tried setting the clipping property to off like this:
figure
axis([0, 10, 0, 10])
hold on
set(gca,'outerPosition',[0, 0.5, 1, 0.5])
lh = line([2, 8],[8, -5]);
set(lh, 'clipping', 'off')
print('line_plot.png')
I get a figure that looks like this:
Is there a way to make the line extend beyond the x-axis? I'm using gnuplot and AquaTerm. Would this be possible in another terminal?
In gnuplot, I would recommend annotating an arrow, which can extend beyond the axis. Here's a minimal example to achieve what you outline in your question:
# define the location of your plot:
bm = 0.15
lm = 0.12
rm = 0.95
tm = 0.95
set lmargin at screen lm
set rmargin at screen rm
set bmargin at screen bm
set tmargin at screen tm
# define your axis limits:
xmax = 10.0
xmin = 0.0
ymax = 10.0
ymin = 0.0
set xrange [xmin:xmax]
set yrange [ymin:ymax]
# define you data points:
xstart = 2
ystart = 8
xend = 8
yend = -5
# convert points into screen coordinates:
dx_rel = (rm-lm)/(xmax-xmin)
dy_rel = (tm-bm)/(ymax-ymin)
xstart_rel = lm + dx_rel * xstart
ystart_rel = bm + dy_rel * ystart
xend_rel = lm + dx_rel * xend
yend_rel = bm + dy_rel * yend
# define 'arrow' without head in screen coordinates:
set arrow 1 from screen xstart_rel,ystart_rel \
to screen xend_rel,yend_rel nohead
# plot will not show when empty, include dummy plot command:
set parametric
plot xstart, ystart not
The clip option you refer to in gnuplot does not allow you to extend your plot past the axis. It is meant to remove data points close to the axis to avoid symbols overlaying with those axis.
The arrow, however, can be specified in screen coordinates (the screen in this case is the plot window) which allows you to draw outside the axis.
To match specific data-coordinates, you have to translate those into screen-coordinates. This will only work reliably when you define you plot boundaries in those screen coordinates. That way, you can calculate where each data point will be on the screen.
When seting the arrow, make sure to use screen before the coordinates to indicate the right coordinate system.
The script above will give you this plot:

Drawing a plane on a cartesian plane using gnuplot

I'm trying to reproduce a figure I've found on a linear algebra book using gnuplot. This is the original image
You can see an intersection between two planes described by the two equations:
2u + v + w = 5
4u - 6v = -2.
I suppose that in order to plot the first equation using gnuplot I have to transform it in the form:
splot 5 - 2*x - y
where u -> x; v -> y and w -> z which is the free variable. But the result is very different from what expected. Any clue?
The approach you outline makes sense, however, the results may be far from what you expect.
I propose you draw single lines, using the arrow function in gnuplot.
This example will generate a plot very similar to the one you showed (only one plane, though):
set term gif
set output "demo_plane.gif"
# define your axis limits:
xmax = 6.5
xmin = -1.5
ymax = 8.5
ymin = -1.5
zmax = 5.5
zmin = -0.5
set xrange [xmin:xmax]
set yrange [ymin:ymax]
set zrange [zmin:zmax]
# remove the original axis
unset border
unset xtics
unset ytics
unset ztics
# define you data points:
x1 = 3.0
y1 = -1.0
z1 = 0.0
x2 = -1.0
y2 = 7.0
z2 = 0.0
x3 = -3.0
y3 = 7.0
z3 = 4.0
x4 = 1.0
y4 = -1.0
z4 = 4.0
# define 'arrow' without head:
set arrow 1 from x1,y1,z1 \
to x2,y2,z2 nohead
set arrow 2 from x2,y2,z2 \
to x3,y3,z3 nohead
set arrow 3 from x3,y3,z3 \
to x4,y4,z4 nohead
set arrow 4 from x4,y4,z4 \
to x1,y1,z1 nohead
# draw new axis manually (again, using arrow):
set arrow 5 from 0,0,0 \
to 6,0,0
set arrow 6 from 0,0,0 \
to 0,6,0
set arrow 7 from 0,0,0 \
to 0,0,5
# annotate axis labels:
set label "u" at 6.25,0,0
set label "v" at 0,6.25,0
set label "w" at 0,0,5.25
# plot will not show when empty, include dummy plot command:
set parametric
splot x1, y1, z1 not
With a little rotation you will get a figure like this:

Resources