How to plot a function of functions - gnuplot

I would like to get a plot like this
which is generated in Gnuplot but plotting from a file.
The Gnuplot scrip that contains all the functions is the following:
set encoding iso_8859_1
set key right top font "Helvetica,17"
set ylabel "Received power, P_t (dBm)" font "Helvetica,18"
set xlabel "Separation distance, r (m)" font "Helvetica,18"
set xtics font "Helvetica,16"
set ytics font "Helvetica,16"
set size 1, 1.2
set terminal postscript color eps enhanced
set grid xtics ytics
set key spacing 1.5
set key box linestyle 1 width 3
set logscale x
set grid xtics mxtics
set output "link-up-test.eps"
h1=1.85
h2=0.5
r(x) = sqrt((h1 - h2)**2 + x**2 )
lmb = 300/865.7
H(x) = sqrt( 1- (4*h1*h2)/(x**2 + (h1 + h2)**2 ) )
theta(x) = 2*pi/lmb*( sqrt((h1 + h2)**2+x**2 ) - sqrt((h1 - h2)**2+ x**2) )
q_e(x) = H(x)**2*(sin(theta(x)))**2 + (1 - H(x)*cos(theta(x)))**2
P_x_G = 4
sigma = 1.94
invsqrt2pi = 0.398942280401433
normal(x,mu,sigma)=sigma<=0?1/0:invsqrt2pi/sigma*exp(-0.5*((x-mu)/sigma)**2)
rnd(x) = 10**(-normal(x,0,sigma)/10)
pot_t(x) = 10*log10( 1000*(P_x_G*1.622*((300/lmb)**2) *0.5*1) / (((4*pi*r(x))**2) *1.2*1)*q_e(x)*rnd(x) )
plot [1:12][] pot_t(x) t "up" w lines ls 1
With this script, I get the following plot
which is has similar form but it does not have the randomness os the function rnd(x) and it does not have the same levels in the y-axis.
I am missing something but I have checked several times the functions several times. I would like to know why is not the same figure.
Regards

I would like to give my solution to this question.
I have used the Box-Muller method to generate Gaussian samples.
h1=1.85
h2=0.5
r(x) = sqrt((h1 - h2)**2 + x**2 )
lmb = 300/865.7
H(x) = sqrt( 1- (4*h1*h2)/(x**2 + (h1 + h2)**2 ) )
theta(x) = 2*pi/lmb*( sqrt((h1 + h2)**2+x**2 ) - sqrt((h1 - h2)**2 + x**2) )
q_e(x) = H(x)**2*(sin(theta(x)))**2 + (1 - H(x)*cos(theta(x)))**2
P_G = 4
sigma = 1.94
normal(x,mu,sigma) = sqrt(-2.0 * log(rand(0))) * cos(2*pi * rand(0)) * sigma + mu
rnd(x) = 10**(-normal(x,0,sigma)/10)
pot_t(x) = 10*log10( 1000*(P_G*1.622*((lmb)**2) *0.5*1) / (((4*pi*r(x))**2) *1.2*1)*q_e(x)*rnd(x) )
set samples 1000
plot [1:12][] pot_t(x) t "up" w lines ls 1
Which creates this plot:
The samples are generated with the function normal(x, mu, sigma).
There is only an issue with this solution
When I plot with set logscale x the plot of points should be denser when the x-axis are more concentrated (see first plot above), but it seems that Gnuplot first makes the logscale of the x-axis and after that takes equidistant samples in figure dealing the log scale as a linear scale. I would appreciate if anyone could answer this or improve the solution.
Regards

There is nothing random about your rnd(x) function. Just plot rnd(x) and you can see that. Why are you not using gnuplot's rand() function in conjunction with your normal distribution?

Related

Smoothing the boundary of graph - gnuplot

In gnuplot, given f and g two functions from plane to real line, I am going to plot f as g gets positive values. I have this code:
set xrange [-2:2]
set yrange [-2:2]
set isosamples 100,100
unset grid
unset key
set view map
f(x,y) = x*x*exp(-x*x)*y*y*exp(-y*y)
g(x,y) = x**2 - y**2
h(x,y) = g(x,y)> 0 ? f(x,y) : 1/0
splot h(x,y) with pm3d
I obtain this:
I would like to smooth the boundary of this image.
Thanks in advance
I assume it should read g(x,y) = x**2 - y**2. Play with the parameters samples and isosamples. Check help samples and help isosamples.
For example:
set samples 300
set isosamples 300
Result:

Plotting piecewise linear functions with gnuplot inaccurately

I have a problem when plotting a piecewise linear function h(x) = max(0, 1-|x|) (hat function) with gnuplot. My goal is to showcase the interpolation of a polynomial employing these hat functions as basis functions. Thus I need to shift and scale them to different grid points.
My code looks like this:
set key inside bottom right
set xrange [0:1]
set yrange [0:6]
set grid xtics
set style line 1 linecolor rgb '#0060ad' linetype 1 linewidth 2
set ytics 1
set xtics 2**(-3)
set key right top
s(x) = (3.0 * x - 1)
a0 = 2
a1 = -6
a2 = 5
a3 = 5
a4 = -5
a5 = 1
f(x) = a0 + a1*s(x) + a2*(s(x)**2) + a3*(s(x)**3) + a4*(s(x)**4) + a5*(s(x)**5)
max(x, y) = (x > y) ? x:y
h(x) = max(0, 1 - abs(x))
nodal(x, i)=h(2**(3)*x - i) * f(i * 2**(-3))
plot f(x) title "f(x)", nodal(x, 1)
The output however looks like this:
Obviously towards the point where the nodal basis function is not differentiable it fails to nicely plot the function, which looks bad. As I want to include this a thesis I have to submit, it is not something that I could include. Is there any solution for this problem?

Gnuplot: triangle in log-log axes

I want to plot a right triangle with hypothenuse parallel to the slope of a curve in loglog scale. However, gnuplot behaves funky:
set terminal postscript eps enhanced "Helvetica" 22
a1 = 64459.7;
a2 = -1.90748;
func(x) = a1*x**a2
X1 = 1e+4;
Y1 = 1e-4;
X2 = 2e+4;
Y2 = Y1 + func(X1) - func(X2)
set logscale xy
set format x "10^{%T}"
set format y "10^{%T}"
set key top right
set output 'temp.eps'
set object 1 poly from X1,Y1 to X2,Y1 to X1,Y2 to X1,Y1 fs empty border 1
set xrange [0.8e+4:1e+5]
plot func(x) title sprintf("a line with slope %1.2f",a2)
unset object 1
and outputs
Perhaps in log-log scale the command set object behaves differently when in log-log scale, otherwise i have no idea...
the right answer is:
Y2 = Y1 * 10**(a2 * log10(X1 / X2) );
p.s. moderators, feel free to delete the question

Logarithmic y with zero in GnuPlot

My goal is to display 0 values on a logarithmic scale a little bit under 1.
I managed to plot my own simple histogram (with boxes) with logarithmic Y scale. My Y values are non-negative integers up to 25000. I cannot differentiate the 0 and 1 values as the Y scale begins at 1. Which is mathematically correct, but I want to hack a zero just under the one.
If I were to write a program that plots my graph, I would add 1 to all of my data, and remove 1 from the Y labels. Is there any tricks that would do something like that for me?
gnuplot> set xrange [0:2]
gnuplot> set log y
gnuplot> set yrange [0.1:100]
gnuplot> set ytics ("0" 0.1, "1" 1, "10" 10)
gnuplot> plot cosh(x)
gnuplot>
I think the best option would be to plot your histogram using a modified function:
plot 'data' using 1:($2 < 1 ? $2 : log10($2)+1) with boxes
The above command plots the log10()+1 of your data if it is above or equal to 1, otherwise it plots simply your data. Then, you can modify your y axis so that it's linear between 0 and 1 and logarithmic between 1 and the highest value:
ymax = 10000
set yrange [0:log10(ymax)]
unset ytics
set ytics 1 add ("0" 0, "1" 1)
set for [i=2:log10(ymax)] ytics add (sprintf("%g",10**(i-1)) i) # Add major tics
set for [i=1:log10(ymax)] for [j=2:9] ytics add ("" log10(10**i*j) 1) # Add minor tics
set for [j=1:9] ytics add ("" j/10. 1) # Add minor tics between 0 and 1
plot 'data' using 1:($2 < 1 ? $2 : log10($2)+1) with boxes
The 1 after the tic position is to adjust the minor tics' length (thanks to #Christoph). Anyway, this looks like the following figure for a test case x^2, where you can see how the y axis is linear up to 1 and logarithmic beyond:
I hope this can help you. this is not just a "hack", but a real way to have a linear-log y axis on gnuplot:
reset
set terminal wxt 0 enhanced font 'Sans,13'
#%%% SIZE SETTINGS (whole figure)
tm = 0.90; bm = 0.2
lm = 0.12; rm = 0.885
size = 0.8
#%%% RANGE SETTINGS
y1 = 0.; y2 = 1.; #(lin interval)
y3 = 1.; y4 = 1000.; #(log interval)
x1 = -8.0; x2 = 8.0
set xrange [x1:x2];
#%%% SIZE SETTINGS (single plots)
I_1 = abs(y2-y1)
I_2 = abs(log10(y4)-log10(y3))
denom = I_1 + I_2
T_m_1 = lm + size * (I_1/denom)
T_m_2 = lm + size * ((I_1+I_2))/denom)
f(x) = (15.*sin(x)/x)**2
#%%% BEGIN MULTIPLOT
set multiplot
# Left and Right margins
set lmargin at screen lm
set rmargin at screen rm
# X-axis settings:
set xlabel "X [ux]"; set format x "%2.1f";
set xtics 2 nomirror; set mxtics 4
do for [i=(x1+1):(x2-1):2] {
set xtics add ("" i) }
set samples 10000;
# Y-axis label
set label 'Y [uy]' \
at screen 0.03,bm + 0.5*size \
offset 0,-strlen("X [ux]")/4.0 \
rotate by 90
#%% First plot, first interval
set border 1+2+8
set bmargin at screen bm
set tmargin at screen T_m_1
set yrange [y1:y2]
set format y "%1.0f";
set ytics 1; set mytics 5;
plot f(x) lw 2 \
lc rgb "navy" notitle
#%% End first plot
unset xlabel; unset xtics
#%% Second (and last) plot
set border 2+4+8
set bmargin at screen T_m_1
set tmargin at screen T_m_2
# showing mirror xtics via a x2 axis
set link x via x inverse x
set format x2 "";
set x2tics nomirror; set mx2tics 4;
do for [i=(x1+1):(x2-1):2] {
set x2tics add ("" i) }
set logscale y;
set ytics autofreq; set mytics autofreq;
set format y "10^{%L}";
set ytics add ("" 1.0);
set yrange [y3:y4]
plot f(x) lw 2 \
lc rgb "navy" notitle
#%% End second plot
unset multiplot
#%%% END MULTIPLOT
Result:
image
Practical guide to the code:
start by modifying the "RANGE SETTINGS" to adapt them to your plot
then choose the "X-axis settings" and "Y-axis label" you prefer
comment the two lines specifying the ytics and yformat in the "first plot" part (aka let Gnuplot set those for you, for now)
modify "first" plot command to plot (between y1 and y2) your function/datafile
adapt the part under "showing mirror xtics via a x2 axis" to your X axis setting (if you want specular tics)
modify "second" plot command to plot (between y3 and y4) your function/datafile
see the result and fix minor details, like labels, formats, tics, mtics, and so on.

how to calculate or set size of gnuplot margins + labels + legend

We have a large spectrogram that needs to be pixel perfect (1 row = 100ms of data, 1 column = 1 frequency bin of a fft). I use the below code to calculate the size of the plot:
set terminal unknown
sedcmd="<(sed -n '1p;" .rowstart. "," .rowend. "p' " .filename. ".csv)"
plot sedcmd nonuniform matrix using 2:1:3 notitle with image
xspan = GPVAL_DATA_X_MAX - GPVAL_DATA_X_MIN
yspan = GPVAL_DATA_Y_MAX - GPVAL_DATA_Y_MIN
set terminal png size (rowend-rowstart),yspan
sedcmd="<(sed -n '1p;" .rowstart. "," .rowend. "p' " .filename. ".csv)"
plot sedcmd nonuniform matrix using 2:1:3 notitle with image
rowstart and rowend are variables passed in to gnuplot which represent the frequency bins. This works fine with one exception, it doesn't account for the space needed for the legend and labels. How can I either calculate, or set the pixels so that:
[ylabels][ PLOT ][LEGEND]
[ xlabels ]
PLOT will be the exact size I specify (ie: 1000x1000)
EDIT: final calculation code for the plotsize and margins:
# margins and plotsize
rowstart = 2457 # rowstart/end represent the fft bins
rowend = 5734 # plot is actually rotated 90deg (rows are cols)
cols = 6970 # number of ms in plot (plotted rows)
plotwidth = (rowend - rowstart) +1
plotheight = cols
lm = 1200.00
rm = 600
tbmargin = 200.00
width = plotwidth + (lm + rm)
height = plotheight + (tbmargin * 2)
set lmargin at screen lm / width
set rmargin at screen 1 - (rm / width)
set tmargin at screen tbmargin / height
set bmargin at screen 1 - (tbmargin / height)
show margin
If you know the exact size of the plot you want it helps a lot. If you want a 1000x1000 plot, you can start with:
s = 1250 # size of plot
set terminal pngcairo size 1250,1250
set output 'spectrogram.png'
# difference between l/r and t/b margins = (0.9-0.1)*1250 = 1000 px
set lmargin at screen 0.1
set rmargin at screen 0.9
set bmargin at screen 0.1
set tmargin at screen 0.9
plot ...
I find that doing some basic algebra and using the *margin commands is very helpful when fiddling with pixel-perfect plot shapes (examples here and here).
There may be a 1 px difference or so--I am not sure if the axes are drawn from 0 to 1 px or -1 to 0 as far as the plot edges are concerned.

Resources