I'm having trouble getting a "time friendly" X-axis layout in Gnuplot.
I need to present some data referring to a period within one day; the time X data is represented in decimal form, e.g. X=20.75 meaning 20 hours and 45 mins, the range is generally [0 : 24], but normally a subset, such as [2.25 : 8.75].
The default Gnuplot x-axis layout will be something like the range [0 : 25] with major tics at 0,5,10,15,..., which is nice for normal decimal data, but I would like it to choose something more "time friendly" in the usual clock manner, I mean major ticks at hours 1,2,3 or 6 and minor ticks at 1,5,15 or 30 minutes, suitably chosen depending on the range.
Does anybody know how to do that?
How about this?
set xtics 1, 0.25
Unfortunately, according to the manual:
Minor tics can be used only with uniformly spaced major tics. Since major tics can be placed arbitrarily by set {x|x2|y|y2|z}tics, minor tics cannot be used if major tics are explicitly set.
Using gnuplot 4.6 patchlevel 0
I ended up with this shell script that can be called followed by the desired output name:
save this as makeChart.sh
path='/home/you/yourdir/dat2.txt'
echo "
set terminal unknown
plot '$path' u 1:2
min = (GPVAL_Y_MIN-1)
max = (GPVAL_Y_MAX+1)
set terminal pngcairo size 1400,600 enhanced font 'Helvetica,12'
set timefmt '%H:%M'
set ylabel 'Temperature'
set xlabel 'Time'
unset key
set grid
set title 'Temperature Sensor 1'
set xtics rotate right
set xtics 0,1800,96000
set xdata time
set mxtics 2
set format x '%H:%M'
set format y '%.2f'
set yrange [min:max]
set output '/var/www/somefolder/$1'
plot '$path' u 1:2 index 0 with lines" | gnuplot
Some sample data from dat2.txt:
A temperature reading every 5 minutes over one day.
00:05 74.75
00:10 74.85
00:15 74.85
.
.
.
23:30 75.65
23:35 75.65
23:40 75.52
23:45 75.65
23:50 75.65
23:55 75.75
run it like this:
you#yourpc $sudo ./makeChart.sh chartx.png
Kept playing with the xtics range until I had 30 minute intervals.
You can specify the tics at which gnuplot prints labels with xtics.
An example of placing the xtics would look like this:
set xtics (1, 2, 3, 6)
set xtics add 2
set grid
plot [0:24] sqrt(x)
The script above will place tics at the positions 1, 2, 3 and 6 and then will repeat the tics at an interval of 2. That will be at 8, 10, 12, ...
set grid enables a grid. The documentation can be found here.
To maybe further improve your plots you might want to check out the time/date data functionalities of gnuplot here.
Try using the command set xdata time to indicate that the X axis data are time values. You can then use something like set timefmt '%H' to tell gnuplot how to parse the time values.
For example, to plot the following data with the first column being X values in hours and the second column being the Y axis values:
2.25 1
2.50 2
3.00 3
5.25 4
Use something like:
set xdata time
set timefmt '%H'
plot 'myfile.dat' using 1:2
gnuplot should then properly set the x tics to regular time intervals.
Related
A datafile contains three columns with the first and second representing the x & y position of a circle at a time (in seconds) given by the third column. For example, the first two lines in "data.txt" give the position of two circles at time=0, followed by two blank lines then the position of the two circles at time=0.1 sec and so forth. The first few lines of data.txt are:
0 0 0
-1 -1 0
1 1.0 0.1
-1 -0.5 0.1
1.2 1.25 0.2
-0.5 -0.25 0.2
...
The Gnuplot code producing a series of frames (a movie) with the position of the two circles in time is:
set terminal gif size 1200,1200 animate delay 500
set output "movie.gif"
stats "data.txt" u 1:2 name "A"
set style circle radius graph 0.025; set style fill solid
set xrange [A_min_x*1.1:A_max_x*1.1]
set yrange [A_min_y*1.1:A_max_y*1.1]
do for [i=0:A_blocks-2] {
plot "data.txt" index i u 1:2 w circle
}
I'm trying to add a label or textbox of the form "Time=?" to each frame where the question mark is replaced by the number from the third column. Any suggestions on how to do it?
This answer requires the current version of gnuplot (5.4)
Assuming that all the column 3 entries in a given data block are the same, it should be sufficient to say
plot "data.txt" index i u 1:(FOO=strcol(3),column(2)) w circle title sprintf("Time = %s",FOO)
This updates the value of FOO for each line used. The title uses whatever the final update was for that plot. If you must specifically choose the column 3 value from a particular line within the block, or calculate something like an average, that's a harder problem. In that case please clarify.
Edit:
The reason this requires 5.4 is that earlier versions evaluated the title before reading the data for that plot. Version 5.4 evaluates the title after reading the data.
The first (not too obvious) solution which comes to my mind: plot your data in a loop and assign the value of the 3rd column to a variable, e.g. t. Use keyenty to print the legend with your time re-using the variable t. In order to avoid a symbol in the legend use plotting style with points and a point with pointsize 0.
Code:
### animation with time label
reset session
$Data <<EOD
0 0 0
-1 -1 0
1 1.0 0.1
-1 -0.5 0.1
1.2 1.25 0.2
-0.5 -0.25 0.2
EOD
set terminal gif size 400,400 animate delay 100
set output "SO70474478.gif"
stats $Data u 1:2 name "A" nooutput
set style circle radius graph 0.025; set style fill solid
set xrange [A_min_x*1.1:A_max_x*1.1]
set yrange [A_min_y*1.1:A_max_y*1.1]
set key top left
do for [i=0:A_blocks-1] {
plot $Data index i u 1:(t=$3,$2) w circle notitle, \
keyentry w points ps 0 ti sprintf("Time: %.1f",t)
}
set output
### end of code
Result:
I have trouble with xrange. When I put 'set autoscale xfix' image is ok but information axis not. When i put xrange [-1:1] i get info ok but images is damage. Second trouble is flip image. In my data stored in file upper left corner is -1 on image is +1, why?
my data is:
-0.999770 -0.998743 0.946455 0.999678 0.999777
-0.699447 -0.999784 -0.999565 -0.076214 0.999467
0.999921 -0.717181 -0.999790 -0.999734 -0.959481
0.999943 0.999920 -0.733798 -0.999793 -0.999786
0.999943 0.999943 0.999920 -0.749453 -0.999794
my code is:
set terminal png transparent enhanced font "arial,10" fontscale 1.0 size 600, 400
set output 'out.png'
set xtics 0.25
set ytics 0.25
set xrange [-1:1]
set yrange [-1:1]
set cbrange [-1:1]
plot 'data.txt' matrix with image
My image is -1 to 1 step 0.5
if I add set xrange [-1:1] and set yrange [-1:1] I get
$ gnuplot -V
gnuplot 5.0 patchlevel 3
the thing is that your data file is interpreted as a uniform matrix. In this case:
gnuplot> help matrix
Gnuplot can interpret matrix data input in two different ways.
The first of these assumes a uniform grid of x and y coordinates and assigns
each value in the input matrix to one element M[i,j] of this uniform grid.
The assigned x coordinates are the integers [0:NCOLS-1].
The assigned y coordinates are the integers [0:NROWS-1].
So this means that the datapoints in the first row of your file will have y-coordinate set to 0, second row 1, etc. However, since the y-axis by default points upwards, the resulting image is therefore flipped. Also, these points define the centers of the elementary color squares/boxes in the plot. So that's way the "effective x/y-range" is in your case [-0.5:4.5].
To "fix" the y-axis, you could use
set yr [] reverse
Here, [] specifies that the axis is still autoscaled.
Finally, to rescale your image from [0,4] into the [-1,1] range, you could use:
fn(x) = x/2. - 1
plot 'data.txt' matrix u (fn($1)):(fn($2)):3 w image
So in total:
set terminal png transparent enhanced font "arial,10" fontscale 1.0 size 600, 400
set output 'out.png'
set xtics 0.25
set ytics 0.25
set xrange [-1:1]
set yrange [-1:1] reverse
set cbrange [-1:1]
fn(x)=x/2-1
plot 'data.txt' matrix u (fn($1)):(fn($2)):3 w image
EDIT:
One could also adapt the script above to deal with a matrix of a priori unknown size:
set terminal png transparent enhanced font "arial,10" fontscale 1.0 size 600, 400
set output 'out.png'
set xrange [-1:1]
set yrange [-1:1] reverse
set cbrange [-1:1]
fName = 'data.txt'
stats fName nooutput
N = STATS_records - 1
set xtics 1./N
set ytics 1./N
fn(x)=(2*x/N)-1
plot fName matrix u (fn($1)):(fn($2)):3 w image
Here, the stats command first scans the file and stores the number of records into a special variable STATS_records. The function fn then rescales the range [0:STATS_records-1] on [-1:1]. Also, the x/y-tics are adapted automatically.
My question about how to automate placing labels at the edge of a plot for data points that exceed the range of plot. This would be done for points that are outliers that, if plotted, skew the scale of the plot such that the plot is no longer useful, but still need to be noted.
For example, let's say I've got a data file called 'mydata.dat' that looks like this:
1 2
3 3
7 4
8 6
50 8
If I plot the data using
set yrange [0:10]
set xrange [0:10]
plot 'mydata.dat' w lp pt 1
then the last point (50,8) will not be plotted. To acknowledge, however, that there is a point outside the plotted range, a label and point would be placed at the edge (i.e., at 10,8) of the plot using
set label "" at 10,8 point pt 1
set label "50" at 9.75,8 right
Is there a way to automate this process? A way to have GNUplot read the entire data file and set points and labels at the edge of the plot?
To plot all point which are outside of the specified range, you'll need a second plot command using the labels plotting style.
In the using statement you can then check for the point being outside the range. If it is, you place a point with a corresponding label, otherwise you skip the point (using 1/0 as value):
set xrange [0:10]
set yrange [0:10]
set linetype 1 pt 7
plot 'mydata.dat' w lp lt 1, \
'' using ($1 > 10 ? 10 : 1/0):2:(sprintf('%d', $1)) with labels right offset -2,-0.25 point lt 1 notitle
Here, I check only for the x-value being larger than the specified maximum x-value. Maybe you need to adapt it in order to catch also outliers in y-direction or those smaller than 0.
I'm plotting data using the command files discussed here:
gnuplot contour line color: set style line and set linetype not working
I want to provide different output options. PNG works well, as does the wxt terminal, however, these have fixed resolution, e.g. when I "zoom in" on the plot it gets grainier.
If I use pdf or pdfcairo for the terminal, the resulting file has a Moire pattern. The region in the image over which the Moire pattern is observed can be reduced by using increasing amounts of interpolation in the pm3d command. There are lots of points in the data set in the radial direction, but not many angular sets of data, so I need to interpolate more in that "direction". Using no interpolation results in a very grainy pm3d image, so I have been trying 0,20 to 20,20 or even 20,40. Unfortunately even lots of interpolation does not completely get rid of the Moire pattern, makes the file size HUGE (e.g. the PNG file is around 250kB but the pdf file is over 11MB) and as a result it renders very slowly. I've tried viewing these with Adobe Acrobat Reader 10.1.8 and GSview and the result is the same.
I am interested in using the pdf format because it is ubiquitous and can be zoomed in without excessive loss of detail (unlike PNG).
Below are a couple of screen shots that I captured of the pattern in the resulting pdf output at different levels of interpolation. The first image is the png file for reference as it shows no Moire pattern, 250kB file size.
Next, the pdf output without pm3d interpolation, 72kB file size:
Next, the pdf output using set pm3d map interpolate 0,20, file size 1861kB:
Next, the pdf output using set pm3d map interpolate 10,20, file size 5942kB:
Finally, the pdf output using set pm3d map interpolate 20,20, file size 11515kB:
Why are these Moire patterns generated for the pdf outputs? Is there away around this, that would allow me to still have a vector format that can be zoomed in without (much) loss of resolution?
This is not supposed to be a solution, but rather an explanation and a possible, although ugly workaround.
From time to time there are reports to the gnuplot mailinglists about this issue, but it seems to be related to the viewers. It has to do with the way gnuplot creates the surfaces plots. These are drawn as polygons, which are stitched together. The Moiré patterns you are showing come from wrong rendering between two polygons. That depends on the viewer, the viewer settings and the zoom factor.
The easiest example, to show that effect is the following Postscript file:
%!PS-Adobe-2.0
50 50 moveto 50 0 rlineto 0 50 rlineto -50 0 rlineto closepath 0 setgray fill
100 50 moveto 50 0 rlineto 0 50 rlineto -50 0 rlineto closepath 0 setgray fill
Save this file e.g. as moire.ps and view it, or convert it with ps2pdf and view it. With the Acrobat reader 9.5.1 I see the following:
The Acrobat Reader has a setting Preferences -> Page Display -> Enhance thin lines which can prevent this problem, but causes problems on other parts.
On my system (Debian), all viewers show this patterns, mupdf, firefox, ghostscript, pdftocairo, libpoppler` etc.
So, what to do? For myself I use the following workaround. I splot to a png with high resolution, and reread that file later with plot ... with rgbimage. Then you get your heatmap as bitmap, and the rest is vectorial. In most cases this is no problem, because in any way you have some measurement data with limited resolution, which you interpolate.
Based on the question gnuplot contour line color: set style line and set linetype not working, here is how you can implement it:
reset
set lmargin at screen 0.05
set rmargin at screen 0.85
set bmargin at screen 0.1
set tmargin at screen 0.9
set pm3d map interpolate 20,20
unset key
set cntrparam bspline
set cntrparam points 10
set cntrparam levels increment -6,-6,-24
set contour surface
set linetype 1 lc rgb "blue" lw 2
set linetype 2 lc rgb "blue"
set linetype 3 lc rgb "black"
set linetype 4 lc rgb "orange"
set linetype 5 lc rgb "yellow"
set palette rgb 33,13,10 #rainbow (blue-green-yellow-red)
set cbrange [-18:0]
unset border
unset xtics
unset ytics
set angles degree
r = 3.31
set xrange[-r:r]
set yrange[-r:r]
set colorbox user origin 0.9,0.1 size 0.03,0.8
##################### start changes ##############
set autoscale fix
RES_X = 2000
RES_Y = 2000
save('settings.tmp')
set lmargin at screen 0
set rmargin at screen 1
set bmargin at screen 0
set tmargin at screen 1
unset colorbox
set terminal pngcairo size RES_X, RES_Y
set output '3d-polar-inc.png'
splot 'new_test.dat' nocontour
unset output
load('settings.tmp')
# mapping of the coordinates for the png plotting later
X0 = GPVAL_X_MIN
Y0 = GPVAL_Y_MIN
DX = (GPVAL_X_MAX - GPVAL_X_MIN)/real(RES_X)
DY = (GPVAL_Y_MAX - GPVAL_Y_MIN)/real(RES_Y)
C0 = GPVAL_CB_MIN
DC = GPVAL_CB_MAX - GPVAL_CB_MIN
C(x) = (x/255.0) * DC + C0
# now plot the png
#set terminal pdfcairo size 10cm,10cm
#set output '3d-polar.pdf'
set terminal postscript eps color level3 size 10cm,10cm solid
set output '3d-polar-eps.eps'
set multiplot
set cbrange[GPVAL_CB_MIN:GPVAL_CB_MAX]
plot '3d-polar-inc.png' binary filetype=png \
origin=(X0, Y0) dx=DX dy=DY \
using (C($1)):(C($2)):(C($3)) \
with rgbimage, \
NaN with image t '' # hack for getting the colorbox
# plot the contours
unset surface
unset pm3d
splot 'new_test.dat' w l
###################### end changes #################
# now plot the polar grid only
set style line 11 lc rgb 'black' lw 2 lt 0
set grid polar ls 11
set polar
set logscale r 10
set rrange[10:20000]
unset raxis
set rtics format '' scale 0
#set rtics axis scale
set rtics (20,50,100,200,500,1000,2000,5000,10000,20000)
do for [i=-150:180:30] {
dum = r+0.15+0.05*int(abs(i/100))+0.05*int(abs(i/140))-0.05/abs(i+1)
set label i/30+6 at first dum*cos(i), first dum*sin(i) center sprintf('%d', i)
}
set label 20 at first 0, first -(log(20)/log(10)-1) center "20"
set label 100 at first 0, first -(log(100)/log(10)-1) center "100"
set label 200 at first 0, first -(log(200)/log(10)-1) center "200"
set label 1000 at first 0, first -(log(1000)/log(10)-1) center "1k"
set label 2000 at first 0, first -(log(2000)/log(10)-1) center "2k"
set label 10000 at first 0, first -(log(10000)/log(10)-1) center "10k"
set label 20000 at first 0, first -(log(20000)/log(10)-1) center "20k"
plot NaN w l
unset multiplot
unset output
With pdfcairo this gives a 1.7 MB pdf file, with epslatex level3 (this option is available in the 4.7 development version only) you get a 1.5 MB eps file, which can be converted with epstopdf to a 136 KB pdf file.
See also my answer to Big data surface plots: Call gnuplot from tikz to generate bitmap and include automatically? on TeX.SX.
I'm plotting a 600px*600px image in gnuplot, and I would like to have the xtics correspond to a different coordinate system than the pixel system. as it is, the xtics go 0, 100, 200, ..., 500, 600. I would like to make them be at the same place, but have different values. Is there a way to make it so that the tics are uniformly modified, like, xtic[i] = (xtic[i]*c1) + c2?
EDIT: Here's my code. Also, I should clarify that what I'm trying to do is have the xtics and ytics correspond to longitude and latitude specifically. So for instance, I would like to add in a transformation such that xtic=0 -> xtic=$minlat, and xtic=$maxx -> xtic=$maxlat.
#!/bin/sh
inputfilename=$1
outputfilename=$2
minlat=$3
maxlat=$4
minlon=$5
maxlon=$6
imagexsize=$7
imageysize=$8
maxx=$(($imagexsize - 1))
maxy=$(($imageysize - 1))
windowxsize=$(($imagexsize+5+5))
windowysize=$(($imageysize+5+5))
imagename=${inputfilename%.*}
gnuplot <<EOF
set terminal png size $windowxsize,$windowysize
unset key
unset colorbox
set output "$outputfilename"
set lmargin 5
set bmargin 5
set rmargin 5
set tmargin 5
set size square
set xrange [0:${maxx}]
set yrange [0:${maxy}]
set palette grey
set label "$imagename" at screen 0.3,0.95
plot "$inputfilename" binary array=${imagexsize}x${imageysize} format='%ushort' with image
EOF
You can accomplish this quite easily by adding a 'using' argument to your 'plot' command.
Here's an example with an added offset of 10 & scale of 0.5:
plot '-' using (($1+10)/2):(($2+10)/2) with linespoints
1 2
3 4
5 6
e