I am currently working on a project to plot the development of humidity and temperature at my place. Therefore I am using a raspberry pi 2 with Raspbian Jessie and a DHT-22.
In the end it comes down to a file per day, that stores the measurements all 30 seconds. The file is named like this; 2016-01-30_Temp_Hum_data and contains the following data
2016-01-30-19:30:03 22.0 50.2
2016-01-30-19:30:34 22.0 50.2
2016-01-30-19:31:04 22.0 50.3
2016-01-30-19:31:35 22.0 50.3
2016-01-30-19:32:05 22.0 50.2
whereas the first part is the timestamp, the second value separated by a space is the temperature, followed by the humidity.
Now I plot this with the following script that is called by a for-loop in a bash file that iterates over all data files that I described above.
!/usr/bin/gnuplot
reset
# This command works for a linux computer. In linux, you need to specify the exact location of
# the font you want to use
set terminal png notransparent rounded giant font "/usr/share/fonts/msttcore/arial.ttf" 24 \
size 2600,960
# nomirror means do not put tics on the opposite side of the plot
set xtics nomirror
set ytics nomirror
# Line style for axes
# Define a line style (we're calling it 80) and set
# lt = linetype to 0 (dashed line)
# lc = linecolor to a gray defined by that number
set style line 80 lt 0 lc rgb "#808080"
# Line style for lines
set style line 1 lt 1 lc rgb "#A00000" lw 4
set style line 2 lt 1 lc rgb "#00A000" lw 4
# Add line at 70
# Draw a line from the right end of the graph to the left end of the graph at
# the y value of 70
# The line should not have an arrowhead
# Linewidth = 4
# Linecolor = black
# It should be in front of anything else drawn
set arrow from graph 0,first 70 to graph 1, first 70 nohead lw 2 lc rgb "#500000" front
set arrow from graph 0,first 50 to graph 1, first 50 nohead lw 2 lc rgb "#005000" front
set arrow from graph 0,first 20 to graph 1, first 20 nohead lw 2 lc rgb "#005000" front
# Put a label 80% hum at 80% the width of the graph and y = -2 (it will be just above the line drawn)
set label "70%" at graph 0.8, first 72
set label "50%" at graph 0.8, first 48
set label "20°C" at graph 0.8, first 22
# Define data
set xdata time
set timefmt "%Y-%m-%d-%H:%M:%S"
set format x "%H"
set xlabel "time"
set ylabel "values"
set yrange [10:80]
heading="Kueche Temperatur und Luftfeuchtigkeit " . timestamp
set title heading
set key reverse Left outside
set grid
set style data lines
plot datafile using 1:2 ls 1 title "",datafile using 1:3 ls 2 title ""
It is working quite well like this, but now I made a node everytime I start cooking or the washing machine and made a file like this:
2016-01-30-15:00:00 cooking
2016-01-22-19:00:00 washing machine
2016-01-23-12:30:00 washing machine
Now I would like to add the following functionality. If there is an entry in the cooking/washing file that falls into the x range of the plot, I want a vertical line from the bottom to the top of the plot with a note that says "cooking" or "washing machine.
Unfortunately I don't even get a vertical line at some point. I tried
set arrow from 15,0 to 15,100 nohead lw 2 lc rgb "#500000" front
and
set arrow from 2016-01-30-19:00:00,0 to 2016-01-30-19:00:00,100 no head lw 2 lc rgb "#500000" front
as well as several other examples I found online, but nothing worked.
Can someone help me in finding a way to
At least draw a vertical line on my time series plot
Or even better, tell me how I can automatically detect if there is a point in the additional file that falls into the x range of the actual plot and add vertical lines according to that file?
Thanks in advance!!
I am not going to reproduce your entire script here, but focus on the part that you are asking about - adding the vertical lines.
I will add the labels at the top of the graph, and doing this will require adding an little bit of extra top margin to make them fit. If you place them in the graph itself, you don't need this extra top margin. Additionally, drawing the vertical lines is made much easier as you have fixed the yrange. We could still make this work without doing that, but we would either need to create a plot, figure out the yrange it used, and then draw the new plot using that computed yrange, or use the stats command to figure it out (we actually will need the stats command later to figure out the xrange). We avoid this by having the fixed yrange.
The minimal set-up that I'll need to demonstrate this is the following:
set xdata time
set timefmt "%Y-%m-%d-%H:%M:%S"
set format x "%m/%d"
set yrange [10:80]
set tmargin at screen .9
unset key
When you weave this into your full script, you can add the additional details (title, axis labels, etc). I also changed the x-axis labels to make it clear that the lines are drawn in the correct place (you will use your original labels). You may need to adjust the offset of the title to avoid a collision between the line labels and the title.
Finally, we can plot the vertical lines and labels with (you'll want to combine this with your existing plot command)
plot datafile u 1:(10):(0):(70) with vectors nohead,\
"" u 1:(80):2 with labels offset 0,char 1.1 rotate by 45
We use the vectors style (help vectors) which expects four values: x, y, x_delta, and y_delta. As we want vertical lines, we set x_delta to 0 and as we range from the bottom (y=10) to the top (y=80) we can set y to 10 and y_delta to 70 (80-10).
The labels are, of course, much simpler. Here we place the label at the top of the graph (moved up by 1.1 characters to place it above the graph) and rotated to avoid overlapping labels.
Unfortunately, there is a problem here. The range from your vertical line file may mess up the range determined from the original file. This can be fixed by using the stats command and then fixing the range. The stats command does not like time series data, but we can manually parse the time series as the first step (before set xdata time).
If we put the following two commands at the very top of the script
stats datafile u (strptime("%Y-%m-%d-%H:%M:%S",strcol(1))) nooutput
set xrange[STATS_min:STATS_max]
it will fix the xrange according to the range in datafile, so we don't have this problem.
Your original example data does not have any overlap with the data you provided for drawing the vertical lines. In order to demonstrate this, I added one extra line to the beginning of your data file,
2016-01-30-12:30:03 30.0 70.2
to force there to be an overlap. Thus taking your original script, adding these extra commands (stats and xrange) at the beginning, and adding the two new plot commands to your existing plot command (which now reads
plot datafile1 using 1:2 ls 1 title "",\
"" using 1:3 ls 2 title "", \
datafile2 u 1:(10):(0):(70) with vectors nohead title "",\
"" u 1:(80):2 with labels offset 0,char 1.1 rotate by 45 title ""
), we obtain
I did not use your set terminal command here, so fonts may look different. You will probably have to do some adjustments of sizes and offsets to produce a final plot that you are happy with, but this adds your original requirements. I also did not add the extra margin here, as the title automatically did that. However, if you need to move the title up to avoid the labels (which I didn't in this example), you will probably have to add some extra margin.
Related
I came across the gif terminal in gnuplot. I read that it keeps track of each plot command until the second set out command is encountered.
Recently, the need for an animated multiplot came up - is there any way of achieving this with the gif terminal?
What I need essentially is a matrix of three plots, each one animated, in some grid I can specify.
In a normal single plot environment each plot command creates a new frame. In a multiplot environment each set multiplot - unset multiplot pair creates a new frame which can contain several plot commands like this example:
set terminal gif animate delay 100
set output "multiplot_animated.gif"
n = 50
dphi = 2*pi/n
do for [i=0:(n-1)] {
phi = i*dphi
set multiplot layout 2,1
plot sin(x+phi)
plot cos(x+phi)
unset multiplot
}
This is the result. Skip the delay 100 (or change the number) to change the animation speed.
I have a matrix of data, which is an output of automatic music transcription program. I want to plot it using gnuplot, assigning appropriate labels. Here's my dropbox with some data, where Intensity.dat is actual data, example.stn is a column of string values, some of which are to be displayed on y axis and example.all is just a result of paste example.stn Intensity.dat > example.all Script:
reset
set title "Intensity detection"
set palette negative grayscale
set cbrange [0.01:1]
set xlabel "Time [s]"
set ylabel "Musical note"
set terminal qt font "Verdana,16"
set logscale cb
xincr=0.04644
yincr=1
plot 'example.all' u (($1+0.5)*xincr):($2*yincr):3 matrix with image
produces
plot produced by script 1. Everything's OK, now just tic labels...
After I change the last line to plot 'example.all' u (($1+0.5)*xincr):($2*yincr):3 matrix rowheaders with image, the y-axis becomes too densly populated (It's plot2.jpg from my dropbox, link on top. Sorry guys, I'm new and it doesn't allow me to post more than 2 links).
What I want is a way to present only the labels I want (or hide others, whatever), not all at a time (because it looks unreadable). I'd also like to be able to quickly change them to the others when I need to do so. Supposingly, I want to display every 12th label, but still keep entire matrix with all rows plotted. Or every 12th starting from 2nd label AND every 12th starting from 6th. I've already tried many ways but I'm stuck. Functions like :ytics() or :yticlabels() can't make it, at least for me. And yes, I need this Verdana 16, and removing labels completely is out of question.
I'll be extra grateful if the method applies also for x-axis, as I have an analogical problem with x-axis in other plot, but I generally appreciate any help.
You can separate plotting the image from plotting the ytics like this:
condition(n) = (ceil(n)%12-2 == 0) || (ceil(n)%12-6 == 0)
plot 'Intensity.dat' u (($1+0.5)*xincr):($2*yincr):3 matrix with image ,\
'example.stn' u (NaN):0:ytic(condition($0) ? strcol(1) : "") notitle
The function condition checks whether the label should be plotted or not. I have used ceil to convert from a real number to an integer which is required by the modulo operator (%). The condition function is called with the linenumber $0. The NaN while plotting 'example.stn' avoids plotting data points while keeping the chance for setting the labels. If the condition is met (12th label starting from 2nd or 12th starting from 6th), we use the actual label, else an empty string is used.
In gnuplot I've using set term postscript enhanced eps color as well as lw 5 and lt 1, 2 and 3 , for three different graphs.
Due to the width of the graphs the line types don't look so different for the three cases.
If I decrease the value of lw to 2 stuffs start getting better, but I'd like to keep using the lw 5 and at the same time be able to use the different line types. Am I missing something?
EDIT
Follow two graphs. Using set term postscript enhanced eps color dashed,
and set term epscairo color dashed:
In both cases I've used lw 4.
The version with epscairo looks better, but still the dashed-dot-dot-dashed, looks awful, close to f(x)=1 for sin(2x)
I think this is a general problem of dashed lines with the postscript terminal: For some internal reasons, the points aren't drawn as one continuous line, but every 100 points the line is interrupted by a moveto operation. This can lead to very strange results for dashed lines.
A pathological example is
set terminal postscript eps mono dashed dl 10 lw 5
set samples 200
set output 'test.eps'
plot x lt 2
As you can see, the center dash is much longer than the others. Try using the epscairo terminal and see if this works better.
When you set the terminal you can specify the dash length with the dl option, this will also increase the separation between dashes:
set term postscript enhanced eps color dl 4
plot sin(x) lw 5 lt 2, cos(x) lw 5 lt 3
You can also add points to better distinguish your graph:
set term postscript enhanced eps color
plot "+" u ($1):(sin($1)) w lp lw 5 lt 2 ps 2 pt 7
As written in the manual of Gnuplot at page 136,
Because the pm3d algorithm does not extend the colored surface outside
the range of the input data points, the 'c' coloring options will
result in pixels along two edges of the grid not contributing to the
color of any quadrangle. For example, applying the pm3d algorithm to
the 4x4 grid of data points in script demo/pm3d.dem (please have a
look) produces only (4-1)x(4-1)=9 colored rectangles.
So if I would like to plot a 4x4 pixel sized image, I can't do it in this way without missing the 4th column and row. (I would like not to modify the file.) Is there an efficent workaround for this problem?
To plot a 4x4 image which shows exactly the color rectangles specified in the data file, the splot ... with pm3d is not suited. For this one can use the image plotting style. The pm3d mode must be used e.g when the grid points are not equidistant, or for a 3D representation.
Taking the following file data.dat
1 6 8 3
2 5 4 4
9 1 1 2
5 4 3 8
a more or less minimal script would be
set autoscale fix
set xtics 1 out
set ytics 1 out
plot 'data.dat' matrix with image t ''
The result for set terminal pngcairo is:
The terminal must support plotting with image, this is the case for the most, but not for all (e.g. pstricks does not). In that case one would need to use with image failsafe.
I have a file that contains the map between the two entities. I have to plot the x and and Y axis in a graph using linux. The X axis is Time like (12:35:07) and the Y axis will have some integer numbers range (1-14). I need to plot the x and the Y axis using some method that should be called from linux shell script. X axis will have totally around 500 to 800 samples. say (from 12:14:00 to 12:30:00). Can anyone please help me out. I tried using GNUplot, but the graph is not proper. Sample input is given below
12:34:58 5
12:35:06 9
12:35:07 14
12:35:07 13
12:35:08 4
12:35:08 5
12:35:17 9
12:35:17 13
12:35:18 14
12:35:19 4
12:35:19 5
This is what I have written
1 set terminal png
2 set output 'test.png'
3 set xdata time
4 set timefmt "%H:%M:%S"
5 set yrange [1:15]
6 plot "Graph1" using 1:2 title 'data A'
The problem I have is since the image has large number of samples (around 700 intervals, I am not able to see each value properly. Also the Y axis is not proper. I need to restrict the Y axis to onlyh 10 values (1-10). Also I need to draw 4 similar graphs and place each graph in each corner (subplot). I have not done the subplot yet in GNUplot.
It seems that you have three main issues right now. For some of them the issue is not totally clear, so it would help if you could update your question (or make a comment) to clarify, and I can update my response.
1) Not able to see each of ~700 values properly.
Here I need a bit of clarification. I'm assuming you don't want to see each of 700 data points individually, rather you want to be able to get rid of clutter on the x axis which happens when plotting time values. For this you can use the command
set xtics X
where X is the interval between tics you want, in this case a number of seconds. Is this what you want?
You can also use
set format x '%M:%S'
(or something) if you want to control how the x values are displayed on the axis.
2) y axis needs to be restricted to 10 values.
Here also it's not totally clear what you are looking for. Do you want to scale everything down to be between 1 and 10? The range of your data presented is 4 to 14, so by subtracting four you can get things between 0 and 10 like this:
plot "Graph1" using 1:($2-4) title 'data A'
If you want to constrict an arbitrary y data set to be between 1 and 10, that's a little more tricky:
stats "Graph1"
plot "Graph1" using 1:(($2-STATS_min_y)*9/(STATS_max_y-STATS_min_y)+1) title 'data A'
The stats command gets statistics about a file before you plot it. The convoluted plot command should scale everything to be between 1 and 10 on the y axis.
3) You want to have 4 subplots.
This one is pretty easy. Before your first plot command, use the command
set multiplot layout 2,2
This will create a 2x2 grid for your plots. Every plot command will plot on a new subplot. Type help set multiplot at the gnuplot command line for details on changing the sequence of subplots used.