GIF term animation in gnuplot with multiplot - animation

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.

Related

Gnuplot: Making a gif of a map generated with matrix?

I generated a .dat file with 100 matrix 15x15, now I want to create a gif which shows the evolution from the first to the last matrix. They are all matrix with 1 or -1, so if I want to represent the inicial matrix I can copy and paste it in another file and I put this in gnuplot:
plot 'firstmatrix.dat' matrix with image
It represents the 1, -1 matrix with yellow and black.
To create the gif I'm trying to do this in gnuplot:
set terminal gif animate delay 20
set output 'evolution.gif'
set xrange [0:15]
set yrange [0:15]
N=15
nframes=5
do for [i=1:int(nframes)] {
plot 'evolution.dat' every ::(i-1)*N+1::i*N matrix with image
}
I intend to read from the first line of the file to the 15th line, then from the 16th to the 30th and so on.
I put only 5 frames to see better the result, and I obtain that the gif shows the first matrix in the first frame and nothing more, only white frames.
The error message is four times this one:
warning: Skipping data file with no valid points
So the data for the first frame, the first matrix, is well processed but not the rest. So here is my problem, I don't know why it process good the first one and no more.
Thanks in advance.
It shows only the first matrix in the first frame
You've been pretty close. But it took me also some iterations and testing...
Apparently, slicing a block of rows from a matrix requires every :::rowFirst::rowLast (mind the 3 colons at the beginning). And then gnuplot apparently takes the row index of the whole matrix as y-coordinate. Since you want to have it "on top of each other" you need the modulo operator % (check help operators binary). It might have been a bit easier if your matrices were separated by one or two empty lines.
Code:
### animated matrix data
reset session
### create some random data
set print $Data
do for [n=1:20] {
do for [y=1:15] {
Line = ''
do for [x=1:15] {
Line=Line.sprintf("% 3g",int(rand(0)*2)*2-1)
}
print Line
}
}
set print
set terminal gif animate delay 30
set output "tbMatrixAnimated.gif"
unset key
N=15
do for [i=1:20] {
plot $Data u 1:(int($2)%N):3 matrix every :::N*(i-1)::N*i-1 with image
}
set output
### end of code
Result: (only 20 matrices)

gnuplot matrix increased pixel size

I am having trouble visualizing a large matrix in gnuplot, seemingly due to pixel sizes. As a minimal working example, I try to plot a 5000 x 5000 identity matrix with the following commands:
set term pngcairo enh col
set out "plot.png"
unset key
set datafile commentschars "%#"
set xrange [0:5000]
set yrange [5000:0] reverse
plot 'A' matrix w image
Data is here. The resulting plot looks like this:
You can see some of the diagonal elements but it looks quite bad and much of the diagonal is missing. When I go to 10000 x 10000, none of the diagonal is visible. It seems the pixels sizes aren't large enough. In contrast, the following matlab code produces a nice figure:
A = eye(5000,5000);
imagesc(A);
The figure looks like this:
Here we can see a nice diagonal in the image. How can I make gnuplot produce a similar figure?
Option 1: Make your plot resolution big enough that it can actually represent 5000 pixels per side. If the resulting image file is too large for your purpose you can shrink it with an external tool such as ImageMagick. A likely problem is that the diagonal line is so thin that it will become invisible when you shrink the figure.
set size square
unset key
set datafile commentschars "%#"
set xrange [0:5000]
set yrange [5000:0] reverse
set term pngcairo size 6000,6000 fontscale 10.
set output 'bigplot.png'
plot 'A' matrix w image
unset output
Option 2: Down-sample the matrix so that it fits in a smaller plot resolution. E.g.
set size square
unset key
set datafile commentschars "%#"
set xrange [0:5000]
set yrange [5000:0] reverse
set term pngcairo size 600,600
set output 'smallplot.png'
plot 'A' matrix every 10:10 with image
Shown below is the output from option 2

How to decimate / decrease number of tic labels in gnuplot matrix

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.

vertical lines from data in file in time series plot using gnuplot

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.

Drawing a graph in linux

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.

Resources