I would like to know how to manipulate parametric 1-D functions. For instance I want to plot the gaussian for differente values of the parameter a:
f(x)=exp(-a*(x-1)**2)
I know that I can create different functions f(x) for many values of a, but I wonder if there is a way to plot this function for a=1,2,3, etc.
Thanks.
Yes, just define your function so that it takes the variable parameter as input:
f(x,a)=exp(-a*(x-1)**2)
And then loop over it. It can be done in a sequence ("a from 1 to 3 at intervals of 1"):
plot for [a=1:3:1] f(x,a) t "a = ".a
Or using a list of values:
plot for [a in "1 2 3"] f(x,a) t "a = ".a
Using the following commands
gnuplot> f(x) = a*x
gnuplot> plot for [a = 1:3:1] f(x) title sprintf("a=%d",a)
I get the following plot
You may want to read the descriptions you can get by the following commands
gnuplot> help for
The `plot`, `splot`, `set` and `unset` commands may optionally contain an
iteration for clause. This has the effect of [...]
and
gnuplot> help sprintf
`sprintf("format",var1,var2,...)` applies standard C-language format specifiers
to multiple arguments and returns the resulting string. If you want to
use gnuplot's own format specifiers, you must instead call `gprintf()`.
For information on sprintf format specifiers, please see standard C-language
documentation or the unix sprintf man page.
HTH
Related
I'm making a c++ code which prints commands for gnuplot, in order to plot different things faster. The code plots the data already as the data fit as well, but now I'm adding some labels, and I want to print the fit equation, I mean something with this form
f(x) = (a +/- Δa)*x + (b +/- Δb)
I have the following line for printing it
set label 1 at screen 0.22, screen 0.75 sprintf('f(x) = %3.4f*x + %3.4f', a, b)
But, as you can see, there is only a and b values with no errors, I was thinking something like put there in the sprintf function any error related variables (FIT_something) and then have something like
set label 1 at screen 0.22, screen 0.75 sprintf('f(x) = (%3.4f +/- %3.4f)*x + (%3.4f + %3.4f)', a, deltaa, b, deltab)
But I can't find those, my answers are: does those exists? and if the answer is no, is there any way to print the variable errors further just writing it explicitly on the line?
Thanks for your help
Please read the statistical overview section of the gnuplot documentation (help statistical_overview). Keeping in mind the caveats described there, see also the documentation for set fit errorvariables, which I extract below:
If the `errorvariables` option is turned on, the error of each fitted
parameter computed by `fit` will be copied to a user-defined variable
whose name is formed by appending "_err" to the name of the parameter
itself. This is useful mainly to put the parameter and its error onto
a plot of the data and the fitted function, for reference, as in:
set fit errorvariables
fit f(x) 'datafile' using 1:2 via a, b
print "error of a is:", a_err
set label 1 sprintf("a=%6.2f +/- %6.2f", a, a_err)
plot 'datafile' using 1:2, f(x)
If the `errorscaling` option is specified, which is the default, the
calculated parameter errors are scaled with the reduced chi square. This is
equivalent to providing data errors equal to the calculated standard
deviation of the fit (FIT_STDFIT) resulting in a reduced chi square of one.
I just stumbled across the following:
According to the gnuplot manual a plot element may contain a definition.
Syntax:
plot {<ranges>} <plot-element> {, <plot-element>, <plot-element>}
Each plot element consists of a definition, a function, or a data source
together with optional properties or modifiers:
plot-element:
{<iteration>}
<definition> | {sampling-range} <function> | <data source>
| keyentry
{axes <axes>} {<title-spec>}
{with <style>}
Check the following example:
For the first graph y=x+1 is plotted because a=1 was defined earlier. As expected.
For the second graph and the first plot command it should be the same but y=2*x+1 is plotted instead (twice).
In the third graph when a=1 is explicitely specified it is plotted as expected.
Why is gnuplot ignoring a=1 for the second graph?
Have I misunderstood something?
Code:
### definitions in plot command
reset session
a = 1
b = 1
f(x) = a*x + b
set yrange[-40:40]
set multiplot layout 1,3
plot f(x)
plot f(x), a=2 f(x), a=3 f(x)
plot a=1 f(x), a=2 f(x), a=3 f(x)
unset multiplot
### end of code
Result:
Your diagnosis is slightly off. In the second panel the first, purple plot is superimposed with the a=3 plot rather than the a=2 plot.
Why? Because gnuplot accumulates all elements of the full plot before actually drawing any of them. This involves making two passes over the command line. One pass to parse and load data from any data sources mentioned (needed for example for autoscaling), then a second pass to evaluate any functions over the range (which might have determined by autoscaling). During the first pass here, a gets set to 2 and then to 3. At the start of the second pass a is still 3 and in the absence of an initial definition to change it that is what is used when f(x) is evaluated.
I was trying to plot the following
plot for [h=0:2:0.1] sin(h*x)
But it gives the following error
gnuplot> plot for [h=0:2:0.1] sin(x*h)
^
Expecting iterator for [<var> = <start> : <end> {: <incr>}]
or for [<var> in "string of words"]
But the following line works just fine
plot for [h=0:2:1.1] sin(x*h)
Is this a bug or it is supposed to work this way? I mean, why it is not accepting increments smaller than 1?
I'm using the following version of gnuplot
G N U P L O T
Version 5.0 patchlevel 1 last modified 2015-06-07
Gnuplot supports iterations only with integer values (see documentation section "For loops in plot command", p 98). Values smaller then 1 are casted as integer to 0, which is not allowed. Using e.g.
plot for [h=0:3:1.5] sin(x*h) title sprintf('%.1f', h)
plots four curves with h having the values 0, 1, 2, 3. To use smaller values you must scale the iteration value later:
plot for [h=0:20:1] sin(0.1*h*x)
In addition to Christoph's answer, another way to do arbitrary increment loops without the need to do the scaling within the function is to define a list of values that contains all the elements to loop through. This can easily be done with a system call to seq:
list(start,end,increment)=system(sprintf("seq %g %g %g", start, increment, end))
plot for [i in list(0.,1.,0.1)] sin(i*x)
An equivalent gnuplot-only solution (proposed by Karl in the comments) that will work also if seq is not available is the following:
start=0.; end=1.; inc=0.1
list = ""; a=start-inc; while (a<end) {list=list.sprintf(" %.3f",a=a+inc)}
plot for [i in list] sin(i*x)
Note that while loops are only available since gnuplot 4.6.
I have a large set of data points from x = 1 to x = 10e13 (step size is fixed to about 3e8).
When I try to plot them using a logscale I certainly get an incredible huge point-density towards the end. Of course this affects my output plots since postscript and svg files (holding each and every data point) are getting really big.
Is there a way to tell gnuplot to decrease the data density dynamically?
Sample data here. Shows a straight line using logarithmic x-axis.
Usually, for this kind of plots, one can use a filter function which selects the desired points and discards all others (sets their value to 1/0:
Something like:
plot 'sample.dat' using (filter($1) ? $1 : 1/0):2
Now you must define an appropriate filter function to change the data density. Here is a proposal, with pseudo-data, although you might for sure find a better one, which doesn't show this typical logarithmic pattern:
set logscale x
reduce(x) = x/(10**(floor(log10(x))))
filterfunc(x) = abs(log10(sc)+(log10(x) - floor(log10(x))) - log10(floor(sc*reduce(x))))
filter(x) = filterfunc(x) < 1e-5 ? x : 1/0
set multiplot layout 1,2
sc = 1
plot 'sample.data' using (filter($1)):2 notitle
sc = 10
replot
The variable sc allows to change the density. The result is (with 4.6.5) is:
I did some work inspired by Christoph's answer and able to get equal spacing in log scale. I made a filtering, if you have numbers in the sequence you can simply use Greatest integer function and then find the nearest to it in log scale by comparing the fraction part. Precision is tuned by precision_parameter here.
precision_parameter=100
function(x)=(-floor(precision_parameter*log10(x))+(precision_parameter*log10(x)))
Now filter by using the filter function defined below
density_parameter = 3.5
filter(x)=(function(x) < 1/(log10(x))**density_parameter & function(x-1) > 1/(log10(x))**density_parameter ) ? x : 1/0
set datafile missing "NaN"
Last line helps in plotting with line point. I used x and x-1 assuming the xdata is in arithmetic progression with 1 as common difference, change it accordingly with your data. Just replace x by filter(x) in the plot command.
plot 'sample_data.dat' u (filter($1)):2 w lp
I know to fit 2D data has z value between [-1:4] in gnuplot is
f(x)=a*x+b
fit [][-1:4] f(x) "data"
but for 3D data , if I only want to fit data when f(x) has value between [-1:4]
f(x)=a*x+b*y+c
fit [][-1:4] f(x) "data"
fit [][][-1:4] f(x) "data"
are both wrong. why ?
I am not sure, if the range behaviour you describe with the 2D fit is actually intended, because it does not work with the gnuplot development version. And according to the documentation, the range specifications for the fit command apply only to the dummy variables (i.e. x and y). So it might be, that your first fit command works only because of a bug, which is a feature for you.
To limit the z-range, you can set all values outside the desired range to 1/0, which results in an undefined data point which is then ignored:
f(x, y) = a*x + b*y + c
zmin = -1
zmax = 4
fit f(x, y) "data" using 1:2:($3 < zmin || $3 > zmax ? 1/0 : $3):(1) via a,b,c
Note, that your function must be defined for two dummy variables x and y, and you must have the via statement, which is missing in all of your examples.
To fit a function with two independent variables, z=f(x,y), the required
format is using with four items, x:y:z:s. The complete format must be
given---no default columns are assumed for a missing token. Weights for
each data point are evaluated from 's' as above. If error estimates are
not available, a constant value can be specified as a constant expression
(see plot datafile using), e.g., using 1:2:3:(1).
This plots a plane in 3D, not a line. I was confused until I zoomed out and realized. Try the below dataset of 4 points. 'Set autoscale' to make sure you see the whole image. Or just read the fit.log file and realize the errors are high indicating a poor fit.
377.4202 -345.5518 2.1142
377.4201 -345.5505 2.5078
377.4206 -345.556 2.8359
377.4288 -345.5555 3.2109