Automatic offset in gnuplot - gnuplot

I am plotting data from a datafile and the data has behaviour that after a while on the x-axis the y-axis start to monotonically decrease and ultimately go to zero (with some very small fluctuations later on).
Hence, I want to offset the y-axis so that those fluctuations are clearly visible. For that I use something like set offsets 0,0,0,0.1. But I have actually written a bash script to generate the plot for me. I just need to provide the datafile name to it. So for each plot I don't want to go into the script and manually set offset value based on the data.
I would like if the offset were determined by gnuplot automatically based on the bin-size on the axis, like the offset is 1*bin-size. So my command could look like :
set offsets 0,0,0,1*$bin_size
Is there any way to achieve this?
Edit:
This is the script I am using.
#!/bin/bash
#Requires that the script be in the same directory as the data files
#sed -n '3001,4000p' fish_data_re.dat > fish_data_re_3k_4k.dat : Can be used to extract data from specific range in data file
DATA_FILE_NAME="abc"
DATA_FILE_TYPE="dat"
#Code to generate normalised files
awk 'NR == FNR {if(max < $2) {max = $2}; next} {$2 = $2 / max; printf "%f\t%f\n", $1, $2}' $DATA_FILE_NAME.$DATA_FILE_TYPE $DATA_FILE_NAME.$DATA_FILE_TYPE > $DATA_FILE_NAME\_normed.$DATA_FILE_TYPE
DATA_FILE_NAME="$DATA_FILE_NAME\_normed"
DATA_FILE_TYPE="dat"
OUTPUT_FILE_TYPE="eps"
OUTPUT_FILE_NAME="$DATA_FILE_NAME\_plot.$OUTPUT_FILE_TYPE"
X_LABEL="Time"
Y_LABEL="Real Classical Fisher Information"
TITLE="Real Classical Fisher Information vs Time"
#Set font size for axis tics
X_TICS_SIZE="6"
Y_TICS_SIZE="6"
gnuplot <<- MULTI_LINE_CODE_TAG
set xlabel "$X_LABEL"
set ylabel "$Y_LABEL"
#Following command allows the printing of underscore from name of data file in plot
set key noenhanced
set title "$TITLE"
set xtics font ", $X_TICS_SIZE"
set ytics font ", $Y_TICS_SIZE"
set xtics nomirror
set ytics nomirror
#set ytics format "%.22g"
set ytics format "%0.s*10^{%L}"
#set xtics format "%t"
set multiplot
#------The big-plot------
set title "$TITLE"
set offsets 0,0,0,0.01
#Following plots only data from line 1 to line 100
#plot "<(sed -n '1,100p' $DATA_FILE_NAME.$DATA_FILE_TYPE)" u 1:2 notitle w l lc "red" lw 2
plot "$DATA_FILE_NAME.$DATA_FILE_TYPE" u 1:2 notitle w l lc "red" lw 2
#------The sub-plot------
unset title
unset offsets
set origin 0.25,0.3
set size 0.45,0.45
set xrange [30:60]
set yrange [-0.01:0.01]
unset xlabel
unset ylabel
#unset label
plot "$DATA_FILE_NAME.$DATA_FILE_TYPE" u 1:2 notitle w l lc "red" lw 2
unset multiplot
set term "$OUTPUT_FILE_TYPE"
set output "$OUTPUT_FILE_NAME"
replot
MULTI_LINE_CODE_TAG
exit
As you can see I need to provide the offset manually.
Here is the plot I am getting.
The y-axis here got offset by -0.002 -0.2. I want to automate this thing and want gnuplot to always use the the offset as the size of a bin (which I define as the distance between successive tics).
(If this is a trivial question I apologise in advance, I am quite new to gnuplot.)

I guess I still don't understand your exact problem. By the way, your offset it -200e-3 = -0.2 not -0.002.
Is your data always between 0 and 1?
You could set the offsets depending on the graph (check help offsets)
set offsets 0,0,0, graph 0.2
In general, why not using logarithmic scale? With this you will be able to see all small features in your data.
Code:
### linear scale vs logarithmic scale
reset session
# Gauss curve by specifing Amplitude A, position x0 and width via FWHM
GaussW(x,x0,A,FWHM) = A * exp(-(x-x0)**2/(2*(FWHM/(2*sqrt(2*log(2))))**2))
# create some test data
set xrange[0:100]
set samples 500
set table $Data
plot '+' u 1:(GaussW($1,5,1,2.5) + GaussW($1,40,7e-3,2) + GaussW($1,47,8e-4,5) + 2e-4) w table
unset table
set multiplot layout 1,2
set offset 0,0,0, graph 0.2
set yrange[-0.02:1]
plot $Data u 1:2 w l title "linear y-scale"
set logscale y
set yrange[1e-4:1]
plot $Data u 1:2 w l title "logarithmic y-scale"
unset multiplot
### end of code
Result:

Related

Place tics at values stored in variables

I have used the stats command to store the x-postion of absolute maxima in my plot of seven datasets in seven variables, grN_pos_max_y with N that goes from 1 to 7. Can I place the tics in the x-axis at the positions specified by these variables?
I tried using
$maxima << EOD
gr1_pos_max_y
gr2_pos_max_y
gr3_pos_max_y
gr4_pos_max_y
gr5_pos_max_y
gr6_pos_max_y
gr7_pos_max_y
EOD
and then
plot ..., \
$maxima u 1:(NaN):xticlabel(1) notitle
but I don't know how to read variables into a data block (if I replace the variable names by their values, however, it works).
Edit: This is what I want (I plotted it using Ethan's answer)
I'm not entirely sure I understand what you want, but this may get you partway there:
set xtics add (gr1_pos_max_y, gr2_pos_max_y, gr3_pos_max_y, gr4_pos_max_y, gr5_pos_max_y, gr6_pos_max_y, gr7_pos_max_y)
plot 'whatever'
That will get you plain (unlabeled) tic marks in addition to whatever tic marks and labels are being generated automatically.
If you want only these marks and no auto-generated marks, remove the keyword add.
If you want to place labels to go with these new tics, change it to:
set xtics add ( "Max 1" gr1_pos_maxy, "Max 2" gr2_pos_maxy, ...
This is all assuming you want these tics to label a plot that contains something other than the tics themselves. If you want only a plot of these y values, perhaps as impulses?, please re-phrase the question or show a sketch of what you want it to look like.
There is no need for awk, you can do it all in gnuplot.
put stats into a loop and write the STATS values into a datablock $Maxima
plot your data and $Maxima as Ethan suggested with impulses
you can also plot the maxima y-value as labels in the graph
The script needs to be adapted depending on your file naming scheme.
Script:
### extract maxima from several files
reset session
N = 7
myFile(n) = sprintf("SO72750257_%d.dat",n)
# create some "random" test data
do for [n=1:N] {
set table myFile(n)
f(x) = -a*(x-x0)**2 +y0
x0 = (n-1)*10./N + rand(0)*10./N
a = rand(0)*50+10
y0 = rand(0)*80+20
plot [0:10] '+' u 1:(f(x))
unset table
}
# extract maxima
set print $Maxima
do for [n=1:N] {
stats myFile(n) u 1:2 nooutput
print sprintf("%.1f %.1f", STATS_pos_max_y, STATS_max_y)
}
set print
set yrange[0:]
set offsets graph 0.05, graph 0.05, graph 0.1, 0
set xtics () # remove all xtics
set key out noautotitle
plot for [i=1:N] myFile(i) u 1:2 w l ti sprintf("Set %d",i), \
$Maxima u 1:2:($0+1):xtic(1) w impulses lc var dt 2, \
$Maxima u 1:2:2 w labels offset 0, char 1
### end of script
Result:

In gnuplot show only the maxmimum point of the graph and highlight it

In Gnuplot I write below code:
set xlabel "Time in Seconds"
set ylabel "Resistance in Ohms"
while(1){
set multiplot layout 2, 1 title " " font ",12"
set tmargin 1.5
set title "MQ7 Gas Sensor Data"
unset key
plot 'putty2.log' using 0:1 with lines ,'' using 0:2:2 with labels center boxed bs 1 notitle column
set title "MQ9 Gas Sensor Data"
unset key
plot 'putty2.log' using 0:3 with lines
pause 1;
reread;
}
This code is described by drawing the multiplot of the data file 'putty.log' in Gnuplot. After doing this I got this:
but I want to show only the maximum point in the 1st multigraph.
Any help will be appreciated.
As starting point, the following script is a simple way to identify maxima in noisy curves. Actually, the random test data generation takes almost more lines than the maxima extraction.
On the smoothened curve you simply check if the 3 consecutive y-values y0,y1,y2 fulfil y0<y1 && y1>y2, then you have a maximum at y1.
The smoothing via smooth bezier might not be suitable for all type of data. Maybe some averaging together with smoothing might lead to better results.
For example, in the example below the human eye would also detect maxima at 35 and 42.
Futhermore, if you also want to display the y-values of the maxima, the Bezier smoothing probably will mostly return too low values compared to what averaging would give.
I hope you can optimize the script for your data and special needs.
Script:
### find maxima on smoothened data
reset session
# create some random test data
set table $Backbone
set samples 30
plot [0:100] '+' u 1:(rand(0)*10+10) w table
set table $CSpline
set samples 1000
plot $Backbone u 1:2 smooth cspline
set table $Data
noise(h) = (rand(0)*2-1)*h
spike(p,h) = rand(0) < p ? (rand(0)*2-1)*h : 0
plot $CSpline u 1:($2 + noise(1) + spike(0.2,3)) w table
unset table
# smooth the data to facilitate identification of maxima
set table $Smooth
set samples 200
plot $Data u 1:2 smooth bezier
unset table
# simple maxima extraction
set table $Maxima
plot x2=x1=y2=y1=NaN $Smooth u (x0=x1,x1=x2,x2=$1,y0=y1,y1=y2,y2=$2, y0<y1 && y1>y2 ? x1 : NaN):(y1) w table
unset table
set yrange[0:]
set key noautotitle
plot $Data u 1:2 w l lc "red", \
$Smooth u 1:2 w l lc "blue", \
$Maxima u 1:2 w impulses lc "black", \
'' u 1:(0):(sprintf("%.2f",$1)) w labels left offset 1,0.5 rotate by 90 tc "blue"
### end of script
Result:

Gnuplot: oscilloscope-like line style?

Is it possible in Gnuplot to emulate the drawing style of an analogue oscilloscope, meaning thinner+dimmisher lines on larger amplitudes, like this:?
The effect you see in the oscilloscope trace is not due to amplitude, it is due to the rate of change as the trace is drawn. If you know that rate of change and can feed it to gnuplot as a third column of values, then you could use it to modulate the line color as it is drawn:
plot 'data' using 1:2:3 with lines linecolor palette z
I don't know what color palette would work best for your purpose, but here is an approximation using a function with an obvious, known, derivative.
set palette gray
set samples 1000
plot '+' using ($1):(sin($1)):(abs(cos($1))) with lines linecolor palette
For thickness variations, you could shift the curve slightly up and down, and fill the area between them.
f(x) = sin(2*x) * sin(30*x)
dy = 0.02
plot '+' u 1:(f(x)+dy):(f(x)-dy) w filledcurves ls 1 notitle
This does not allow variable colour, but the visual effect is similar.
Another approach:
As #Ethan already stated, the intensity is somehow proportional to the speed of movement, i.e. the derivative. If you have sin(x) as waveform, the derivative is cos(x). But what if you have given data? Then you have to calculate the derivative numerically.
Furthermore, depending on the background the line should fade from white (minimal derivative) to fully transparent (maximum derivative), i.e. you should change the transparency with the derivative.
Code:
### oscilloscope "imitation"
reset session
set term wxt size 500,400 butt # option butt, otherwise you will get overlap points
set size ratio 4./5
set samples 1000
set xrange[-5:5]
# create some test data
f(x) = 1.5*sin(15*x)*(cos(1.4*x)+1.5)
set table $Data
plot '+' u 1:(f($1)) w table
unset table
set xtics axis 1 format ""
set mxtics 5
set grid xtics ls -1
set yrange[-4:4]
set ytics axis 1 format ""
set mytics 5
set grid ytics ls -1
ColorScreen = 0x28a7e0
set obj 1 rect from screen 0,0 to screen 1,1 behind
set obj 1 fill solid 1.0 fc rgb ColorScreen
x0=y0=NaN
Derivative(x,y) = (dx=x-x0,x0=x,x-dx/2,dy=y-y0,y0=y,dy/dx) # approx. derivative
# get min/max derivative
set table $Dummy
plot n=0 $Data u (d=abs(Derivative($1,$2)),n=n+1,n<=2? (dmin=dmax=d) : \
(dmin>d ? dmin=d:dmin), (dmax<d?dmax=d:dmax)) w table
unset table
myColor(x,y) = (int((abs(Derivative(column(x),column(y)))-dmin)/(dmax-dmin)*0xff)<<24) +0xffffff
plot $Data u 1:2:(myColor(1,2)) w l lw 1.5 lc rgb var not
### end of code
Result:

Fit histogram in gnuplot

I'm trying to fit data (histogram) in gnuplot. I tried various functions, and by looking at my histogram, I suppose the best fit is lognormal or gamma distribution, but I am not able to do this fit in gnuplot (Im rather new user of gnuplot).
Here is picture of histogram with gaussian distribution:
Also here is code in gnuplot:
reset
n=100 #number of intervals
max=15. #max value
min=0. #min value
width=(max-min)/n #interval width
#function used to map a value to the intervals
hist(x,width)=width*floor(x/width)
set term png #output terminal and file
set output "histogram.png"
set xrange [min:max]
set yrange [0:]
#to put an empty boundary around the
#data inside an autoscaled graph.
set offset graph 0.05,0.05,0.05,0.0
set xtics min,(max-min)/5,max
set boxwidth width*0.9
set style fill solid 0.5 #fillstyle
set tics out nomirror
set xlabel "Diameter"
set ylabel "Frequency"
#count and plot
#fac(x) = (int(x)==0) ? 1.0 : int(x) * fac(int(x)-1.0)
gauss(x)=a/(sqrt(2*pi)*sigma)*exp(-(x-mean)**2/(2*sigma**2))
fit gauss(x) 'hist.temp' u 1:2 via a, sigma, mean
plot 'data.list' u (hist($8, width)):(1.0) smooth freq w boxes lc rgb "green" notitle, \
gauss(x) w lines ls 2 lw 2
In file hist.temp is tabular output ( see this link )

Set definition area for output of splot

What I want to create is a efficiency map in gnuplot. Therefore I have values (x y z) with z as the efficiency in a datafile named efficiency_cloud.dat.
I plot some data with splot. I want to show that in a 2D diagramm with the third dimension as contours. That works, but gnuplot extrapolates. I don't want to show the extrapolated part because therefore are no values in my datafile and it would physically no sense.
Here is my code up to now:
view map
unset surface
set dgrid3d 25,25,2.5
set contours
set cntrparam levels incr 16,1,35
splot "efficiency_cloud.dat" using 1:2:3 with lines, "efficiency_cloud.dat" using 1:2:3 with labels
That makes a picture like the following where i added the pink line manually afterwards. It's just an example y= -1.5*x+250
Result with manually added graph as example for a border:
Is there an option to show just the part that lies under the graph?
EDIT :
As suggested in a comment by #Christoph, you need to store to a file the contours and then filter those points you don't want
reset
set view map
unset key
unset surface
set dgrid3d 25,25,2.5
set contour
set cntrparam levels incr 16,1,35
set table "contours.dat"
splot "efficieny_cloud.txt" u 1:2:3 with lines
unset table
unset dgrid
unset contour
set surface
f(x)=-1.5*x+250
splot 'contours.dat' u 1:2:(f($1)<$2?0/0:0) w l
or
plot "contours.dat" u 1:(f($1) > $2 ? $2: 0/0) with lines
or
stats'efficieny_cloud.txt'
g(x)=STATS_max_y
plot "contours.dat" u 1:2 w l, "+" u 1:(f(x)):(g(x)) w filledcur
Apparently you loose the possibility of adding the labels as it would mean to mix contour/non-contour, dgrid/non-dgrid and surface/nonsurface.
And saving in a table the plot with only labels, doesn't just save the labal-points (you can request gnuplot-devs to implement such a thing, it shouldn't be so difficult to do)
After some hours I found a solution: We first need to use set table and splotthe contours. To make sure they are only visible in a certain area we create two functions (upper and lower limit) with fit in combination with many parameters, so our functions fits really well.
So now we plot with conditions as #bibi already sayed. So solve the problem with the labels we use the little parameter every.
So here it is:
unset key
unset xtics
unset ytics
set view map
unset surface
set dgrid3d 15,15,2.5
# create contours
set contours
set cntrparam cubicspline
set cntrparam levels discrete 20, 24, 26, 28, 29, 30, 32, 33, 34, 35
# create file
set table 'contours_eta'
splot [0:100] "data_efficiency.dat" using 1:2:3 with lines
unset table
unset dgrid3d
# define styles
set style line 1 lt 1 lc rgb 'black'
set style textbox opaque margins 0.5, 0.5 noborder
set style line 2 lt 0 lc rgb '#0025ad' dt 11 lw 1
# upper limit
f0(x) = at0 + bt0*x + ct0*x**2 + dt0*x**3 + et0*x**5 + ft0*x**6 + gt0*x**7
fit [0:100] f0(x) "file_with_points_for_upper_limit.dat" using 1:2 \
via at0,bt0,ct0,dt0,et0,ft0,gt0
# lower limit
g0(x) = ab0 + bb0*x + cb0*x**2 + db0*x**3 + eb0*x**5 + fb0*x**6 + gb0*x**7
fit [0:100] g0(x) "file_with_points_for_lower_limit.dat" using 1:2 \
via ab0,bb0,cb0,db0,eb0,fb0,gb0
# variable for the density of the labels
incr = 40
plot [0:80] [0:250] "file_with_points_for_upper_limit.dat" w l ls 1,\
"file_with_points_for_lower_limit.dat" w l ls 1,\
for [n=0:20] 'contours_eta' index (n) u 1:((f0($1) > $2) && (g0($1) < $2)) ? $2 : 0/0 ls 2 w l,\
'contours_eta' index 0:20 every incr u 1:(((f0($1) > $2) && (g0($1) < $2)) ? $2 : 0/0):(((f0($1) > $2) && (g0($1) < $2)) ? $3 : 0/0) w labels center boxed
Thanks for your help!

Resources