gnuplot matrix or palette using one line

2019-01-20 13:49发布

问题:

..Hi all.

I want to plot matrix color map (heat map), However I want plot heat map using data printed in one line. I tried,

p for[i=5:15] 'line' u (i%2):(i/2%10):i+1 w image    

So gnuplot display warning image need at least 2dimension data

My dataset is like this

0.1(node 1 value at time step 1) 0.1(node 2 "") 0.3(node 3 "") 0.2(node 4 "")   
0.5(node 1 value at time step 2) 1.2(node 2 "") 0.7(node 3 "") 0.2(node 4 "")   
0.8(node 1 value at time step 3) 2.2(node 2 "") 0.1(node 3 "") 0.1(node 4 "")   
0.1(node 1 value at time step 4) 1.2(node 2 "") 1.1(node 3 "") 0.4(node 4 "")   
0.4(node 1 value at time step 5) 1.1(node 2 "") 0.7(node 3 "") 0.6(node 4 "")   
0.3(node 1 value at time step 6) 0.4(node 2 "") 0.2(node 3 "") 0.3(node 4 "")   
0.2(node 1 value at time step 7) 0.3(node 2 "") 0.7(node 3 "") 0.2(node 4 "") 
.
.
.
.

In above data there is 4 value in the one line. Using 4 value in the one line, I want to make 2X2 color matrix And every 0.3 second I want to change line to make color changing video. I can make video but problem is, How can I make matrix using datas in one line.

And I don't want to convert in to x:y:z data to plot image. My datas are little bit long and heavy I am worrying it could decrease speed. I need to plot real-time heat-map. As value changes color also changes in real-time

I also tried palette,

p for[i=5:15] 'line' u (i%2):(i/2%10):i+1 w p pt 5 ps 23.5 palette

However, there is empty spaces(white color) between xaxis and yaxis.

So, it doesn't look nice.

How can I plot heat map using datas printed in one line?

Actually, if I can plot real-time heat-map without saving data in the file, it will be better. ( In the C code open gnuplot and pass the values to the gnuplot)

Thank you in advance

回答1:

Basically there are several ways to achieve what you want. First I show three possibilities to process the static data into an animated gif:

  1. Use an external tool (here awk) to process the data file once.

  2. (Variant of 1: Use an external tool like awk to process the data on the fly)

  3. Use gnuplot only

Variant 1: preprocessing the data

I think an appropriate data format for you is

N1T1 N2T1
N3T1 N4T1


N1T2 N2T2
N3T2 N4T2
...

Note the two newlines between the data sets. With this you can use the index keyword to select different data sets.

To preprocess your data into this file, call from gnuplot

system('if [ ! -e dataconv ]; then awk ''{ print $1 " " $2 "\n" $3 " " $4 "\n\n"}'' data > dataconv; fi')

If you want to have a fixed color range for all frames, you can either use fixed values (if you know the ranges), or extract them from the data file:

stats 'dataconv' using 1:2
timesteps = int(STATS_records/2)
cbmin = (STATS_min_x > STATS_min_y ? STATS_min_y : STATS_min_x)
cbmax = (STATS_max_x > STATS_max_y ? STATS_max_x : STATS_max_y)
set cbrange[cbmin:cbmax]

Now, to plot the data, you can finally use matrix and sequentially select all time steps with index:

set terminal gif animate delay 30
set output 'animate.gif'
unset key
set xrange[-0.5:1.5]
set yrange[-0.5:1.5]
set xtics 1
set ytics 1
do for [i=0:(timesteps-1)] {
  set title sprintf('time step % 3d', i+1)
  plot 'dataconv' matrix index i with image
}
unset output

Here, I show only the result of the first time step:

Variant 2: processing the data on the fly

You can use awk both to select the time step and reformat the data. For simplicity, here I manually set a fixed color range:

reset
set cbrange[0:3]

set terminal gif animate delay 30
set output 'animate2.gif'
unset key
set xrange[-0.5:1.5]
set yrange[-0.5:1.5]
set xtics 1
set ytics 1
timesteps = int(system('wc -l data | cut -d " " -f1'))
do for [i=0:timesteps] {
  set title sprintf('time step % 3d', i)
  plot '< awk ''{ if (FNR == '.i.') {print $1 " " $2 "\n" $3 " " $4}}'' data' matrix with image
}
unset output

Variant 3: gnuplot only

This uses only gnuplot and relies on no external tools, but is a more tedious because it requires some fiddling with the using statement. The problem is, that you have 1D data (only one line), but want to plot it as 2D, which requires special data format to work properly.

To fake the 2D input, I let gnuplot read in two lines. While it processes the first line, gnuplot remembers the values of column 3 and 4 and uses these in the second line in columns 1 and 2. The data of line 2 is discarded. This has the small disadvantage, that the last time step cannot be plotted unless a dummy last line is inserted. Also estimation of the maximum and minimum color value is a bit more verbose for 4 columns:

stats 'data' using 1:2 prefix 'A_'
stats 'data' using 3:4 prefix 'B_'
timesteps = int(A_records)
max(x, y) = x > y ? x : y
min(x, y) = x > y ? y : x
cbmin = min(min(A_min_x, A_min_y), min(B_min_x, B_min_y))
cbmax = max(max(A_max_x, A_max_y), max(B_max_x, B_max_y))
set cbrange[cbmin:cbmax]

Again, you can skip most of this part if you know the possible color range.

set terminal gif animate delay 30
set output 'animate3.gif'
unset key

A0 = 0
A1 = 0
set xrange[0.5:2.5]
set yrange[0.5:2.5]
set xtics 1
set ytics 1

do for [i=0:(timesteps-2)] {
  set title sprintf('time step % 3d', i)
  plot 'data' matrix every :::i::(i+1) \
    using (A0 = ($1 == 2 && $2 == i) ? $3 : A0, \
           A1 = ($1 == 3 && $2 == i) ? $3 : A1, $1+1):\
           ($2-i+1):\
           ($2 == i ? $3 : ($1 == 0 ? A0 : ($1 == 1 ? A1 : $3))) \
           with image
}
unset output

I hope there is one way which fits your needs.

Real time plotting

One possibility for sort of real time plotting is to have an loop in which the last line of the data file is plotted. This however is not safe against race conditions, if your program doesn't write complete lines at a time:

set cbrange[0:3]
unset key
set xrange[-0.5:1.5]
set yrange[-0.5:1.5]
set xtics 1
set ytics 1

while (1) {
  set title "time ".strftime('%T', time(0))
  plot '< tail -1 data | awk ''{print $1 " " $2 "\n" $3 " " $4}'' ' matrix with image
  pause 0.1
}

To interrupt, just press Ctrl+C.