Adding/multiplying heatmaps in gnuplot - gnuplot

Is it possible with gnuplot to perform an operation on data (adding/multiplying) from two data files to generate a heatmap with the result of the operation ?
Ex: I have two files each with 4 columns, where
Col1: X coordinate
Col2: Y coordiante
Col3: Value
Col4: Uncertainty
I want to multiply the columns 3 of each file.
I wondered if something similar exists/would work in gnuplot, like ...
splot 'first.dat' using 1:2:(v=$3), 'second.dat' using 1:2:(v*$3)
I have been able to do this with two columns from the same file
splot 'first.dat' using 1:2:($3*$4)

A very similar question has already been answered:
gnuplot plot data from two files
In your case it will look like that:
splot "<paste first.dat second.dat" u 1:2:($3*$6)
Note that all columns from both files are present, therefore you have to "skip" the ones from the second file.

The OP apparently runs Linux or MacOS. #Eldrad's nice and short solution won't work with Windows. Of course, you can install additional programs like gnuwin, awk, etc...
A platform independent and gnuplot-only (bit more complicated) solution is the following.
You load the files 1:1 into datablocks and print these datablocks into a new datablock by appending each line. Assumption is of course that the two files have the same number of lines.
Code:
### plot data from different files combined with mathematical operation
# platform independent gnuplot-only solution
reset session
Windows = GPVAL_SYSNAME[:7] eq "Windows" ? 1 : 0 # otherwise Linux or MacOS
FILE = "first.dat"
Data = "$Data1"
if (Windows) { load '< echo '.Data.' ^<^<EOD & type "'.FILE.'"' }
else { load '< echo "\'.Data.' <<EOD" & cat "'.FILE.'"' }
FILE = "second.dat"
Data = "$Data2"
if (Windows) { load '< echo '.Data.' ^<^<EOD & type "'.FILE.'"' }
else { load '< echo "\'.Data.' <<EOD" & cat "'.FILE.'"' }
set print $Data
do for [i=1:|$Data1|] {
print $Data1[i][1:strlen($Data1[i])-1]."\t".$Data2[i]
}
set print
splot $Data u 1:2:($3*$6)
### end of code

Related

using gnuplot to read in - not output - a png image, or many, in one session - as an "overlay"

I want to read multiple png files - which themselves were created with gnuplot (terminal png) - in order to achieve an "overlay" - that is, a number of functions plotted together one on top of the other, with no background. This apparently could be done with gnuplot in one session.
I found this idea from the Linux Gazette article "Plotting the spirograph equations with 'gnuplot' ", from 2006 :
https://linuxgazette.net/133/luana.html
I am stuck on a number of error messages (vide infra) :
line 0: Bad data on line 1 of file [...]
line 0: warning: using default binary record/array structure
line 0: Too many using specs for this style
Looking for solutions, I read in the help pages ( http://gnuplot.info/docs_5.5/loc7742.html ) that gnuplot can read png images :
plot 'file.png' binary filetype=png
... and I have looked into using pngcairo instead of png itself. I am using eog to view the .png images. Here is sample code which generates the error above, and more if adjusted :
set size ratio -1
set nokey
set noxtics
set noytics
set noborder
set parametric
i2p = {0,1}*2*pi
set terminal png
t0 = 0
t1 = 1
#---------------------------------------------
# plot first function in the gnuplot session :
#---------------------------------------------
test01(t) = exp(i2p*(2*t))
set output "solve_png_problem_15nov22a.png"
plot [t=t0:t1] 1*real(test01(t)),1*imag(test01(t)) lc 1
#---------------------------------------------------
# plot second function in the same gnuplot session :
#---------------------------------------------------
test02(t) = + 3*1.0**20 * exp(i2p*(-3*t+20/200. )) + 3*1.0**19 * exp(i2p* (2*t+20/200.))
set output "solve_png_problem_15nov22b.png"
plot [t=t0:t1] 1*real(test02(t)),1*imag(test02(t)) lc 2
#------------------------------------------------------------
# last plotting to apparently "overlay" the two plots above :
#------------------------------------------------------------
set terminal png size 600,600
set output "solve_png_problem_15nov22_overlay.png"
set noparametric
plot "solve_png_problem_15nov22a.png", "solve_png_problem_15nov22b.png"
.... the reduced sample code is generated from the awk script supplement to the article - see it for detail :
https://linuxgazette.net/133/misc/luana/spirolang.awk.txt
The functions are nontrivial so they were kept in tact, as the associated settings might be causing the problem. The individual images look ok, so I think the problem is in the last plot command.
I read in the help pages that gnuplot can read png images :
plot 'file.png' binary filetype=png
... and also filetype=auto, and I have looked into using pngcairo instead of png itself, with no progress ; I have read the results of Google searches for the error messages. I have read the help pages on terminal, png, image, binary, and so on. I was expecting gnuplot to simply recognize the file was a png image that gnuplot itself generated, using the png terminal. What actually results is the error"Too many using specs for this style". For this, I have tried moving the position of the "binary filetype=png" in the code, which give the error "line 0: Bad data on line 1 of file [...]". I have also tried using programs outside gnuplot, such as montage and composite (ImageMagick).
gnuplot version 5.4 patchlevel 2
Ubuntu 22.04
post-answer update:
TL;DR : use svg terminal.
I saved a lot of grief by simply using the svg terminal. The original work must have been published before gnuplot got the svg terminal. I still need to work svg into the original script - but svg will make it a lot easier.
Try this in GNUPLOT.
gnuplot<<EOF
set terminal png medium size 600,600 background rgb "white"
set size ratio -1
set nokey
set noxtics
set noytics
set noborder
set parametric
i2p = {0,1}*2*pi
t0 = 0
t1 = 1
#---------------------------------------------
# plot first function in the gnuplot session :
#---------------------------------------------
test01(t) = exp(i2p*(2*t))
set output "solve_png_problem_15nov22a.png"
plot [t=t0:t1] 1*real(test01(t)),1*imag(test01(t)) lc 1
#---------------------------------------------------
# plot second function in the same gnuplot session :
#---------------------------------------------------
test02(t) = + 3*1.0**20 * exp(i2p*(-3*t+20/200. )) + 3*1.0**19 * exp(i2p* (2*t+20/200.))
set output "solve_png_problem_15nov22b.png"
plot [t=t0:t1] 1*real(test02(t)),1*imag(test02(t)) lc 2
#------------------------------------------------------------
# last plotting to "overlay" the two plots above :
#------------------------------------------------------------
set output "solve_png_problem_15nov22_overlay.png"
plot \
[t=t0:t1] 1*real(test01(t)),1*imag(test01(t)) lc 1, \
[t=t0:t1] 1*real(test02(t)),1*imag(test02(t)) lc 2
EOF
First Result:
Second Result:
Combined Result:

Creating a command with sprintf. Is this possible?

I want to plot some data. The data is in several files and the line it is in is not always the same. Therefore I used grep and some other commandline tools to extract the line I want. I read online, that it should be possible with gnuplot to print from a string or from the result of a commandline.
I work in linux.
set terminal pdfcairo enhanced font "Garamond,10" fontscale 1.0 size 9in,9in
set nogrid
set samples 1001
set border 31 linewidth .3
set output "access/accessTimeAcrossFreq.pdf"
set xlabel "freq"
set ylabel "Time [s]"
set key right top
set size square
set autoscale y
set termoption lw 2.5
volts = "0.8"
fins = "111 122 222"
freq = "0.5G 1G 1.5G 2G 2.5G 3G"
metrics = "read1bldeltav read0bldeltav read1senseChange read0senseChange read1latchChange read0latchChange sense1speed sense0speed write1CellFlip write0CellFLip write1CellSwing write0CellSwing write1BLSwing write0BLSwing powerpertime"
runTitle = "abetraryString"
filename(fin, f, volt) = sprintf("../%s_temp27_fin%s_freq%s_vdd%s/accessTimeVolLSA/result.txt", runTitle, fin, f, volt)
data(met, file) = system(sprintf("grep -n '%s' %s | cut -d: -f 2 | awk '{$1=$1};1'", met, file))
com(met, file) = sprintf("< grep -n '%s' %s | cut -d: -f 2 | awk '{$1=$1};1'", met, file)
do for [fin in fins] {
do for [v in volts] {
do for [met in metrics] {
set title sprintf("%s VLSA across Freq, fins %s, %sV, w/o she", met, fin, v)
plot for[i=1:words(freq)] com(met, filename(fin, word(freq, i), v)) using (i):2:xtic(word(freq, i)) notitle with points lc i
}
}
}
So I was wondering if a) I can have a function that returns a string that is a command that is then run by gnuplot
b) Where the error might come from:
line 32: warning: Skipping data file with no valid points
line 32: warning: Skipping data file with no valid points
line 32: warning: Skipping data file with no valid points
line 32: warning: Skipping data file with no valid points
line 32: warning: Skipping data file with no valid points
line 32: warning: Skipping data file with no valid points
line 32: x range is invalid
I thought, maybe I need a linebreak at the end of my one-liner of data. Or because gnuplot always thinks the first line is not data... I don't know.
Today I figured it out. I used prints in the for loop to see what the command returns. Before I posted the question I tried the command in a separate terminal with success. The problem was I just tested it with the first element of metrics. The prints revealed that I forgot the metrics need to be all lower case.
To conclude. Yes, you can put a string via a function together and gnuplot will then run it as I was expecting it. See the use of com(..) in the plot line.
Second. I think the xrange error usually points out that in a plot there are no data points and gnuplot does not like a xrange of 0. To figure this out I used prints. I did a quick search if there is a verbose mode but was not successful, so prints it is.
Maybe someone can take away something like I did.

store commented value from data file in gnuplot

I have multiple data files output_k, where k is a number. The files look like
#a=1.00 b = 0.01
# mass mean std
0.2 0.0163 0.0000125
0.4 0.0275 0.0001256
Now I need to retrieve the values of a and b and to store them in a variable, so I can use them for the title or function input etc. The looping over the files in the folder works. But I need some help with reading out the the parameters a and b. This is what i have so far.
# specify the number of plots
plot_number = 100
# loop over all data files
do for [i=0:plot_number] {
a = TODO
b = TODO
#set terminal
set terminal postscript eps size 6.4,4.8 enhanced color font 'Helvetica,20' linewidth 2
set title "Measurement \n{/*0.8 A = a, B = b}"
outFile=sprintf("plot_%d.eps", i)
dataFile=sprintf("output_%d.data", i)
set output outFile
plot dataFile using 1:2:3 with errorbars lt 1 linecolor "red", f(a,b)
unset output
}
EDIT:
I am working with gnuplot for windows.
If you are on a Unixoid system, you can use system to get the output of standard command line tools, namely head and sed, which again allow to extract said values form the files:
a = system(sprintf("head -n 1 output_%i.data | sed \"s/#a=//;s/ b .*//\"", i))
b = system(sprintf("head -n 1 output_%i.data | sed \"s/.*b = //\"", i))
This assumes that the leading spaces to all lines in your question are actually a formatting mistake.
A late answer, but since you are working under Windows you either install the comparable utilities or you might be interested in a gnuplot-only solution (hence platform-independent).
you can use stats to extract information from the datablock (or file) to variables. Check help stats.
the extraction of your a and b depends on the exact structure of that line. You can split a line at spaces via word(), check help word and get substrings via substr() or indexing, check help substr.
Script: (works with gnuplot>=5.0.0)
### extract information from commented header without external tools
reset session
$Data <<EOD
#a=1.00 b = 0.01
# mass mean std
0.2 0.0163 0.0000125
0.4 0.0275 0.0001256
EOD
set datafile commentschar ''
set datafile separator "\t"
stats $Data u (myHeader=strcol(1)[2:]) every ::0::0 nooutput
set datafile commentschar # reset to default
set datafile separator # reset to default
a = real(word(myHeader,1)[3:])
b = real(word(myHeader,4))
set label 1 at graph 0.1,0.9 sprintf("a=%g\nb=%g",a,b)
plot $Data u 1:2 w lp pt 7 lc "red"
### end of script
Result:

gnuplot png unkown and pdf error

I have a shell script that performs some calculations and plot the results. I have used gnuplot for plotting the results. I'm facing two problems. I used to run the script on my cygwin and it's Okay. When I tried to run it on Ubuntu (Version 10.04-wubi-version), it couldn't recognize the png files (set terminal png unknown). I have tried to install (missing libraries that support "libgd2_2.0.36~rc1~dfsg" and update the libraries.... no luck !! then I have decided to use set terminal pdf instead since I found it supported :
here is my gnuplot version:
G N U P L O T
Version 4.4 patchlevel 0
last modified March 2010
System: Linux 2.6.35-32-generic
here is the output of terminal types:
latex LaTeX picture environment
mf Metafont plotting standard
mif Frame maker MIF 3.00 format
mp MetaPost plotting standard
nec_cp6 NEC printer CP6, Epson LQ-800 [monocrome color draft]
okidata OKIDATA 320/321 Standard
pbm Portable bitmap [small medium large] [monochrome gray color]
pcl5 HP Designjet 750C, HP Laserjet III/IV, etc. (many options)
-->pdf PDF (Portable Document File) file driver
postscript PostScript graphics, including EPSF embedded files (*.eps)
pslatex LaTeX picture environment with PostScript \specials
pstex plain TeX with PostScript \specials
Now, After I have modified the shell script to use pdf, I'm getting this error (Note: some of the pdf files are created ).
line 0: ';' expected
Again, I've added ';' to all of the lines.... and the error still appears.
Here is part of my shell script (that gives the error):
gnuplot << TOEND ;
set terminal pdf;
set output 'A.pdf';
set autoscale ;
#unset log
#unset label
set xtic auto ;
set ytic auto ;
set title "title";
set xlabel "x axis";
set ylabel "y axis";
######################################
#UPDATE: I have added double space to a void the error
######################################
plot "A1.tr" using 1:2 title "A" with lines 9, \
"A2.tr" using 1:2 title "B" with lines 11
the output (Note this part is not of the created pdf files):
line 0: invalid character \ --->pointing to 9, \
line 0: invalid command --->poiting to A2.tr
the rest of shell script produces the same error (Note: output is created)
......
......
######################################
#UPDATE: #psibar pointed that 'ls' missing
######################################
plot "results.tr" using 1:2 title "Results" with lines ls 9;
^
line 0: ';' expected---> pointing to 9 ;
After long searching, I think the problem has to do with version of UBUNTU and Gnuplot....I don't want to upgrade my version of ubuntu.....
After solving the errors. Any suggestions on how to get the "set terminal png" works on ubuntu 10.04 ??
To solve the problem I have added ls and double spaces after the 9, \.
The final answer would be :
gnuplot << TOEND ;
set terminal pdf;
set output 'A.pdf';
set autoscale ;
#unset log
#unset label
set xtic auto ;
set ytic auto ;
set title "title";
set xlabel "x axis";
set ylabel "y axis";
######################################
#UPDATE: I have added double space to a void the error
# and #psibar pointed that 'ls' was missing
######################################
plot "A1.tr" using 1:2 title "A" with lines ls 9, \
"A2.tr" using 1:2 title "B" with lines 11

Plotting arrows with gnuplot

I have data generated in a simulation. The generated data file looks something like this:
1990/01/01 99
1990/01/02 92.7
1990/01/03 100.3
1990/01/04 44.2
1990/01/05 71.23
...
2100/01/01 98.25
I can create a chart (trivially), by simply issuing the (long versioned) command:
plot "simulation.dat" using 1:2 with line
I want to add a third column which will add arrow information. The encoding for the third column would be as follows:
0 => no arrow to be drawn for that x axis value
1 => an UPWARD pointing arrow to be drawn for the x axis value
2 => a DOWNWARD arrow to be drawn for the x axis value
I am just starting to learn gnuplot, and will appreciate help in how I can use gnuplot to create the arrows on the first plot?
I dont think there is an automatic way to create all your arrows at the same time based on the third column. You will have to execute the following for each arrow that you want:
set arrow xval1,yval1 to xval2,yval2
You can also use relative arrows
set arrow xval1,yval1 rto 1,0
This will draw a horizontal arrow from xval1,yval1 to (xval1+1),yval1
There are plenty of options associated with the set arrow command:
If you didn't want the arrow head then you might try the impulses style (with impulses rather than with lines)
(If you still want the lines on top then you can plot twice).
If you really want the arrow heads then the following might help: It uses a for loop (or sorts) to add vertical arrows to a plot.
Gnuplot script, for loop within or adding to existing plot
Specifically:
create a file simloop.gp which looks like the following:
count = count+1
#save the count to count.gp
system 'echo '.count.' > count.gp'
#load the simloop shell
system "./simloop.sh"
#draw the arrow
load 'draw_arrow.gp'
if(count<max) reread
Then create a simloop.sh file that looks something like so
#!/bin/bash
#read the count
count=$(awk -F, '{print $1}' count.gp)
#read the file
xcoord=$(awk -v count=$count -F, 'BEGIN{FS=" ";}{ if(NR==count) print $1}' simulation.dat)
ycoord=$(awk -v count=$count -F, 'BEGIN{FS=" "}{ if(NR==count) print $2}' simulation.dat)
dir=$(awk -v count=$count -F, 'BEGIN{FS=" "}{ if(NR==count) print $3}' simulation.dat)
#choose the direction of the arrow
if [ \"$dir\" == \"0\" ]; then
echo '' > draw_arrow.gp
fi
if [ \"$dir\" == \"1\" ]; then
echo 'set arrow from ' $xcoord' ,0 to '$xcoord','$ycoord' head' > draw_arrow.gp
fi
if [ \"$dir\" == \"2\" ]; then
echo 'set arrow from '$xcoord',0 to '$xcoord','$ycoord' backhead' > draw_arrow.gp
fi
Then create a simulation.gp file that looks something like so:
count = 0;
max = 5;
load "simloop.gp"
set yrange[0:*]
plot "simulation.dat" u 1:2 w l
Make sure the shell file has executable permissions (chmod +wrx simloop.sh), load up gnuplot and type
load "./simulation.gp"
This worked for me with the data file
1 99 0
2 92.7 1
3 100.3 2
4 44.2 0
5 71.23 1
(For testing I got rid of the time formatting You should be able to put it back without too much trouble.)
Then I got this graph:
Which I think is more or less what you want.
Although the question is quite old, here is my answer.
One can use the vectors plotting style, which can use variable arrowstyles based on a column's value:
set style arrow 1 backhead
set style arrow 2 head
set yrange[0:*]
set xdata time
set timefmt "%Y/%m/%d"
plot "simulation.dat" using 1:2 with line,\
"" using 1:2:(0):(-$2):($3 == 0 ? 1/0 : $3) with vectors arrowstyle variable
It the value of a column is 1/0, the point is considered as undefined and is skipped.

Resources