I'm running this script:
gnuplot -e "arg_xlabel='My X Label'" -e "arg_ylabel='My Y Label'" -e "arg_filename='my.csv'" -e "arg_columnindex=4" histogram.plt
All arguments work except for the arg_columnindex which yields:
#!/gnuplot
#
# Histogram of compression ratio distribution
#
set terminal postscript enhanced landscape
set output "histogram.ps"
set size ratio 0.5
set key top right
set xlabel arg_xlabel
set ylabel arg_ylabel
set style fill solid 1.0 border -1
set datafile separator ","
binwidth=0.02 # Adjust according to distribution of values in data file
set boxwidth binwidth * 20
bin(x,width)=width*floor(x/width) + binwidth/2
plot arg_filename using (bin($arg_columnindex,binwidth)):(1.0) smooth freq with boxes t ""
# EOF
gnuplot -e "arg_xlabel='My X Labnel'" -e "arg_ylabel='My Y Label'" -e "arg_filename='my.csv'" -e "arg_columnindex=4" histogram.plt (base)
plot arg_filename using (bin($arg_columnindex,binwidth)):(1.0) smooth freq with boxes t ""
^
"histogram.plt" line 16: Column number or datablock line expected
How can I pass the column index argument?
use column(arg_columnindex) instead of $arg_columnindex.
Besides Ethan's hint to $arg_columnindex, what is the reason that you are specifying the option -e multiple times?
The following works for me. Option -p for window persist (not necessary in your case with postscript terminal).
gnuplot -p -e "arg_xlabel='My X Label'; arg_ylabel='My Y Label'; arg_filename='SO70859921.dat'; arg_columnindex=4" SO70859921.gp
Data: SO70859921.dat
1 0 0 6
2 0 0 4
3 0 0 7
4 0 0 1
5 0 0 3
6 0 0 2
7 0 0 5
Code: SO70859921.gp
### calling the script from command line with arguments
set xlabel arg_xlabel
set ylabel arg_ylabel
plot arg_filename u 1:(column(arg_columnindex)) w lp pt 7
### end of code
Result:
Related
I am trying to plot 4d plot using splot (x y z value). I would like to have 4th column shown as heat color. Up to this point, I am fine. What I can't figure out, after searching answers online, is to have the color of the dots being transparent but with different transparency based on their value.
For example, let's say I have the following data set:
0 0 0 0.1
0 0 1 0.2
0 1 0 0.2
0 1 1 2
1 0 0 1
1 0 1 3
1 1 0 0.5
1 1 1 4
Now, I want to make the colorbar (for the 4th column) to be as such: the closer the 4th column value is to 1, the more transparent the dot/point in the figure it will be. All the places I've look can only give me uniform transparency for the entire colorbar.
I wonder if anyone has dealt with this before, or has an idea how to do this.
Thank you very much!
I did not fully understand how you want the transparency to depend on the value, so I will give a general answer, where you can substitute the transparency function for your own.
While you can specify transparency for line colors, this appears to not be possible when using palette, which would be the most straightforward way to achieve what you want. The furthest you can go with only using gnuplot is to make the colors appear transparent, as in the following script, where in.data is a file with your sample data.
#!/usr/bin/env gnuplot
set term pngcairo
in_data = "in.data"
set out "out.png"
# function to combine color and alpha channels with white background
# 0: no transparency, 1: fully transparent
make_transparent(x1, t) = (1-t)*x1 + t
# a function to decide transparency
# the input and output must be in range of [0,1]
#get_transparency(x1) = 0 # no transparency
#get_transparency(x1) = 1 # fully transparent
get_transparency(x1) = 1 - x1 # smaller values are more transparent
# convenience function to truncate values
minval(x1, x2) = x1<x2?x1:x2
maxval(x1, x2) = x1>x2?x1:x2
truncval(x1, xmin, xmax) = maxval(minval(x1, xmax), xmin)
trunc(x1) = truncval(x1, 0, 1)
# the default palette consists of rgbfunctions 7,5,15
# we redefine their transparency enabled versions here
# the input and output must be in range of [0,1]
# see other formulae with "show palette rgbformulae" command in gnuplot
f7(x1) = make_transparent(sqrt(x1) , get_transparency(x1))
f5(x1) = make_transparent(x1**3 , get_transparency(x1))
f15(x1) = make_transparent(trunc(sin(2*pi*x1)), get_transparency(x1))
set palette model RGB functions f7(gray),f5(gray),f15(gray)
splot in_data palette
This script assumes that the background is white, but can be adapted to any other solid background. It falls apart once the points start overlapping however.
To get real transparency, you would need to plot each data point as a separate line and give it a distinct line color. This could be achieved by pre-processing the data, as in the following bash script.
#!/usr/bin/env bash
set -eu
in_data="in.data"
out_png="out.png"
pi=3.141592653589793
# function to convert data value into rgba value
function value2rgba()
{
# arguments to function
local val="${1}"
local min="${2}"
local max="${3}"
# normalized value
local nval=$( bc -l <<< "(${val}-${min})/(${max}-${min})" )
#### alpha channel value ####
local alpha="$( bc -l <<< "255 * (1-${nval})" )"
# round to decimal
alpha=$( printf "%0.f" "${alpha}" )
#### red channel value ####
# rgbformulae 7 in gnuplot
local red="$( bc -l <<< "255 * sqrt(${nval})" )"
# round to decimal
red=$( printf "%0.f" "${red}" )
#### green channel value ####
# rgbformulae 5 in gnuplot
local red="$( bc -l <<< "255 * sqrt(${nval})" )"
local green="$( bc -l <<< "255 * ${nval}^3" )"
# round to decimal
green=$( printf "%0.f" "${green}" )
#### blue channel value ####
# rgbformulae 15 in gnuplot
local blue="$( bc -l <<< "255 * s(2*${pi}*${nval})" )"
# round to decimal
blue=$( printf "%0.f" "${blue}" )
# make sure blue is positive
if (( blue < 0 ))
then
blue=0
fi
### whole rgba value
local rgba="#"
rgba+="$( printf "%02x" "${alpha}" )"
rgba+="$( printf "%02x" "${red}" )"
rgba+="$( printf "%02x" "${green}" )"
rgba+="$( printf "%02x" "${blue}" )"
echo "${rgba}"
}
# data without blank lines
data="$( sed -E "/^[[:space:]]*$/d" "${in_data}" )"
# number of lines
nline=$( wc -l <<< "${data}" )
# get the minimum and maximum value of the 4-th column
min_max=( $( awk '{ print $4 }' <<< "${data}" | sort -g | sed -n '1p;$p' ) )
# array of colors for each point
colors=()
while read -r line
do
colors+=( $( value2rgba "${line}" "${min_max[#]}" ) )
done < <( awk '{ print $4 }' <<< "${data}" )
# gather coordinates into one row
coords=( $( awk '{ print $1,$2,$3 }' <<< "${data}" ) )
gnuplot << EOF
set term pngcairo
set out "${out_png}"
\$DATA << EOD
${coords[#]}
EOD
nline=${nline}
colors="${colors[#]}"
unset key
splot for [i=0:nline-1] \$DATA \
u (column(3*i+1)):(column(3*i+2)):(column(3*i+3)) \
pt 1 lc rgb word(colors, i+1)
EOF
These scripts were tested with gnuplot 5.
I have a gnuplot script (template) which looks like this (a little bit shortened):
#!/bin/bash
F1=file_1
F2=file_2
pdffile=output.pdf
#
term="terminal pdfcairo enhanced fontscale .3 lw 3"
out="output '$pdffile'"
#
gnuplot -persist << EOF
#
set $term
set $out
#
call "statistic-file.txt"
#
# ... (some formating instructions removed)
#
plot "$F1" w l lt 1 lc rgb "red" t "Graph1" ,\
"$F2" w l lt 1 lc rgb "green" t "Graph2"
EOF
okular $pdffile
F1 F2 are variables for my data files. Via "call" command i try to include "statistic-file.txt" in which the variables F1 F2 are also used. This file looks like this (also shortened):
#
stats "$F1" u 2 nooutput name "Y1_"
stats "$F1" u 1 every ::Y1_index_min::Y1_index_min nooutput
X1_min = STATS_min
stats "$F1" u 1 every ::Y1_index_max::Y1_index_max nooutput
X1_max = STATS_max
#
# etc
#
set label \
front center point pt 6 lc rgb "red" ps 1.0 \
at first X1_max,Y1_max tc rgb "red" \
sprintf("%.0f kW / %.0f°", Y1_max, X1_max)
Executing the script, i get a error message:
"statistic-file.txt", line 2: Invalid substitution $F
Pasting the content of "statistic-file.txt" into the template file, then it works. It looks as if the variables in the second file have no relation to the variables in the template file. I prefer the 2 files solution, but how to solve it? Any help?
You are mixing bash variables and gnuplot variables. $F1 is a bash variable and will be substituted by bash only within your bash script. Within "statistic-file.txt", bash substitutes nothing, and gnuplot complains about the unknown $F1.
You can try to "convert" the bash variable $F1 into a gnuplot variable datafile1 like this:
#!/bin/bash
F1="file_1"
gnuplot -persist << EOF
datafile1="$F1"
call "statistic-file.txt"
plot datafile1 w lp
EOF
with the following statistic-file.txt:
stats datafile1
Then bash replaces $F1 with the respective filename and gnuplot uses its own variable datafile1, even within the subsequently called "statistic-file.txt".
Just for completeness: The error message "Invalid substitution $F" comes from gnuplot 4, gnuplot 5 complains about "no datablock named $F1".
One solution would be probably to just move the definition of those variables into the Gnuplot template which is being generated and use them directly, i.e.,
#!/bin/bash
pdffile=output.pdf
#
term="terminal pdfcairo enhanced fontscale .3 lw 3"
out="output '$pdffile'"
#
gnuplot -persist << EOF
#
F1="file_1"
F2="file_2"
set $term
set $out
#
call "statistic-file.txt"
#
# ... (some formating instructions removed)
#
plot F1 w l lt 1 lc rgb "red" t "Graph1" ,\
F2 w l lt 1 lc rgb "green" t "Graph2"
EOF
Similar changes would be necessary also in the file statistic-file.txt, e.g., stats F1 u 2 nooutput name "Y1_" instead of stats "$F1" u 2 nooutput name "Y1_".
In the directory l250 I have a couple of files. They each start off with "l2_" the part after it is the numerical value. I want to be able to plot what is in the file last.sh for about 300 files. I want to know what will be the way I can iterate over the file and have that be $1 and have the second value be $2.
I was thinking that because the files are in the current directory I can use for. But then I am reading about awk and csv and I don't know what to do. I would like insight on what will be the better way to iterate over a large amount of files rater then putting it in main.sh and running that.
main.sh
sh last.sh l2_4 1
sh last.sh l2_5 2
sh last.sh l2_6 3
sh last.sh l2_7 4
.
.
.
last.sh
gnuplot << EOF
set terminal png
set output "finished/$1.png"
set xlabel "Angs"
set ylabel "Angs"
set title "$1 | $2 fs "
set zrange [0: 0.00001]
set pm3d map
splot "$1"
EOF
I run the following in the command line:
$sh main.sh
First you generate a list containing all file names with
list = system('ls l2_*')
which you can then iterate over with do for ... (requires gnuplot 4.6):
set terminal pngcairo
set xlabel "Angs"
set ylabel "Angs"
set zrange [0: 0.00001]
set pm3d map
list = system('ls l2_*')
i = 1
do for [file in list] {
set output sprintf('finished/%s.png', file)
set title sprintf("%s | %d fs", file, i)
splot file
i = i + 1
}
Hy guys!
I have problems with writing bash script to run 50 times my script which generates data files and then plot it to file.
I wrote smth like this, but it doesnt work
#!/bin/bash
for i in {1..50}
do
./ampl ampltst1 # generates different res.txt file each time
/usr/bin/gnuplot <<\__EOF
set xrange [-2:2]
set yrange [-2:2]
set term png
set output "image-${i}.png"
plot "res.txt" u 1:2 w lines, "res.txt" u 3:4 w lines, "res.txt" u 5:6 w li$
pause -1
__EOF
done
Please help me to fix this script!
Possibly you have problems with indentation: __EOF must be without any leading spaces:
...
/usr/bin/gnuplot <<\__EOF
set xrange [-2:2]
...
__EOF
done
Also \ symbol is not required.
Also content of HERE-IS-DOCUMENT will be indented. Is that OK for gnuplot?
If no, you must remove indentation:
for i in {1..50}
do
./ampl ampltst1 # generates different res.txt file each time
/usr/bin/gnuplot <<__EOF
set xrange [-2:2]
set yrange [-2:2]
set term png
set output "image-${i}.png"
plot "res.txt" u 1:2 w lines, "res.txt" u 3:4 w lines, "res.txt" u 5:6 w li$
pause -1
__EOF
done
Depending on various factors i may not have 1 or more data files, referenced in pre-defined gnuplot plot instructions, that don't exist. When this is the case i get "warning: Skipping unreadable file" which cancels the rest of the instructions.
Is there any way i can ask gnuplot to skip any missing data files and plot all of the existing ones?
Here is a similar solution without a helper script
file_exists(file) = system("[ -f '".file."' ] && echo '1' || echo '0'") + 0
if ( file_exists("mydatafile") ) plot "mydatafile" u 1:2 ...
the + 0 part is to convert the result from string to integer, in this way you can also use the negation
if ( ! file_exists("mydatafile") ) print "mydatafile not found."
Unfortunately, I can't seem to figure out how to do this without a simple helper script. Here's my solution with the "helper":
#!/bin/bash
#script ismissing.sh. prints 1 if the file is missing, 0 if it exists.
test -e $1
echo $?
Now, make it executable:
chmod +x ismissing.sh
Now in your gnuplot script, you can create a simple function:
is_missing(x)=system("/path/to/ismissing.sh ".x)
and then you guard your plot commands as follows:
if (! is_missing("mydatafile") ) plot "mydatafile" u 1:2 ...
EDIT
It appears that gnuplot isn't choking because your file is missing -- The actual problem arises when gnuplot tries to set the range for the plot from the missing data (I assume you're autoscaling the axis ranges). Another solution is to explicitly set the axis ranges:
set xrange [-10:10]
set yrange [-1:1]
plot "does_not_exist" u 1:2
plot sin(x) #still plots