How to draw rowstacked histogram in gnuplot with value labels in each bar - label

I want to draw a rowstacked histogram. The following is what I have so far .
I have used the code below
reset
set bmargin 10
set lmargin 20
set rmargin 16
set tmargin 7
show margin
set title "" font "Verdana,27"
show title
set grid
set xlabel offset 0,-5 font "Verdana,25"
set xlabel "Number of Cores"
show xlabel
set xtics font "Verdana,18"
set ylabel offset -4,0 font "Verdana,25"
set ylabel "Time (%)"
show ylabel
set yrange [0:130]
set ytics font "Verdana,18"
set ytics (0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100)
set style data histogram
set style histogram rowstacked title offset 0,3
set style fill solid border lt -1
set boxwidth 0.9
set key right
set key font "Verdana,17"
set key autotitle columnheader horizontal
plot newhistogram '{/=22 1-Core}', \
for [i=2:5] 'base_vs_FHA_speedup_1core.dat' using i:xtic(1), \
newhistogram '{/=22 2-Cores}' lt 1, \
for [i=2:5] 'base_vs_FHA_speedup_2core.dat' using i:xtic(1) notitle, \
newhistogram '{/=22 4-Cores}' lt 1, \
for [i=2:5] 'base_vs_FHA_speedup_4core.dat' using i:xtic(1) notitle, \
newhistogram '{/=22 8-Cores}' lt 1, \
for [i=2:5] 'base_vs_FHA_speedup_8core.dat' using i:xtic(1) notitle
I have 4 different data files with sample data like this
base_vs_FHA_1core.dat
Configuration col1 col2 col3 col4 col5
Base 5 50 40.5 4.5
FHA 5 16 38 5 1.54x
base_vs_FHA_2core.dat
Base 9.3 47 37.3 6.3
FHA 9.3 15 34.3 6.3 1.54x
base_vs_FHA_4core.dat
Base 18 41 33.9 7.06
FHA 16.6 13.07 30.7 7.4 1.47x
base_vs_FHA_8core.dat
Base 27.7 34.3 28.3 9.6
FHA 28.3 11.45 25.3 9.6 1.34x
I want to have each bar in the histogram labeled with the corresponding value and the value of the last column on the top of the second histogram in each pair. How can I achieve this?
Can I merge all the 4 files and achieve the same goal?

You can merge all 4 files in one file. I would recommend a separation with two empty lines, because with this, you can easily address the (sub)datablocks via index, check help index.
For the labels you can make a double loop, one for the (sub)datablocks and one for the columns. You have to sum up the columns (check help sum) to calculate the y-position of the label (i.e. center of the histogram element). The x-position of the labels is special for the first dataset (since only this has a columnheader), this is taken into account with (i*3+$0-(i==0)), i.e. i==0 will return 1 if i equals 0, and 0 otherwise.
Instead of setting a large fontsize many times you might want to set it in the terminal, e.g. something like: set term pngcairo font ",17".
Find below a minimized example as a starting point for further optimization.
Script:
### rowstacked histogram with numbers in corresponding boxes
reset session
$Data <<EOD
# base_vs_FHA_1core.dat
col1 col2 col3 col4 col5
Base 5 50 40.5 4.5
FHA 5 16 38 5 1.54x
# base_vs_FHA_2core.dat
Base 9.3 47 37.3 6.3
FHA 9.3 15 34.3 6.3 1.54x
# base_vs_FHA_4core.dat
Base 18 41 33.9 7.06
FHA 16.6 13.07 30.7 7.4 1.47x
# base_vs_FHA_8core.dat
Base 27.7 34.3 28.3 9.6
FHA 28.3 11.45 25.3 9.6 1.34x
EOD
set xlabel "Number of Cores"
set ylabel "Time (%)"
set yrange [0:130]
set ytics 0, 10, 100
set grid
set style data histogram
set style histogram rowstacked title
set style fill solid 0.5 border lt -1
set boxwidth 0.9
set key top left noautotitle horizontal
N = 5 # number of last data column
plot newhistogram '1-Core' at 0, \
for [i=2:N] $Data index 0 u i:xtic(1) ti columnheader, \
newhistogram '2-Cores' lt 1 at 3, \
for [i=2:N] '' index 1 u i:xtic(1), \
newhistogram '4-Cores' lt 1 at 6, \
for [i=2:N] '' index 2 u i:xtic(1), \
newhistogram '8-Cores' lt 1 at 9, \
for [i=2:N] '' index 3 u i:xtic(1), \
for [i=0:3] for [j=2:N] '' index i u (i*3+$0-(i==0)): \
((sum [k=2:j] column(k))-column(j)*0.5):j w labels
### end of script
Result:

Related

How can I edit this code to include a for-loop to make 30 output files as well as change the title for each plot heading?

I have to make 30 plots (30 output SVG files). Each plot requires one input file called 'step-x' where x = 1,2,3, ... 30.
I was told to use a for-loop but am not sure how to. The code below is what I have so far.
Additionally I need to be able to change the title of the plot where it says set title "Associative Pathway (0,1)" and where it says title "{/:Bold 0.84 V}" for each individual plot.
Thanks in advance
#!/usr/local/Cellar/gnuplot/5.4.4/bin/gnuplot
set termoption font "Sans,22"
set border 15 front lt black linewidth 3.000 dashtype solid
set xrange [0:5.5]
set yrange[-5:0.1]
set title "Associative Pathway (0,1)"
set title font "{/:Bold},23"
set xlabel "Reaction Coordinate"
set xlabel font "{/:Bold,23}"
set ylabel "Free Energy (eV)"
set ylabel font "{/:Bold,23}"
set xtic scale 0
set ytics out nomirror
set xtics nomirror
set xtics ("O_{2}" 0.3, "O#^*_{2}" 1.3, "OOH^*" 2.3 , "O^*" 3.3, "OH^*" 4.3 ,"H_{2}O" 5.3 ) font "{/:Bold},23"
set ytics font "{/:Bold},23"
## Last datafile plotted: "step-x"
p "step-1" u 7:8 w l dt 4 lc rgb 'blue' notitle, "step-1" u 2:3 w l lw 3 lc rgb 'blue' title "{/:Bold 0 V}"
rep "step-1" u 9:10 w l dt 4 lc rgb 'red' notitle, "step-1" u 4:5 w l lw 3 lc rgb 'red' title "{/:Bold 0.84 V}"
# EOF
Below is the data file
#X-title #X-U(0) #X-U(1.8) #y-title #y-U(0) #y-U(1.8)
#1 #2 #3 #4 #5 #6 #7 #8 #9 #10
O_{2} 0 0 0 -3.00 O_{2} 0.5 0 0.5 -3.00
O#^*_{2} 0.5 0 0.5 -3.00 O_{2} 1 -0.1 1 -3.04
O#^*_{2} 1 -0.1 1 -3.04 OOH^* 1.5 -0.1 1.5 -3.04
OOH^* 1.5 -0.1 1.5 -3.04 OOH^* 2 -1.00 2 -3.12
OOH^* 2 -1.00 2 -3.12 O^* 2.5 -1.0 2.5 -3.12
O^* 2.5 -1.00 2.5 -3.12 O^* 3 -2.00 3 -4.00
O^* 3 -2.00 3 -4.00 OH^* 3.5 -2.00 3.5 -4.00
OH^* 3.5 -2.00 3.5 -4.00 OH^* 4 -4.00 4 -4.50
OH^* 4 -4.00 4 -4.50 H_{2}O 4.5 -4.00 4.5 -4.50
H_{2}O 4.5 -4.00 4.5 -4.50 H_{2}O 5 -4.50 5 -4.50
H_{2}O 5 -4.50 5 -4.50
H_{2}O 5.5 -4.50 5.5 -4.50
Glad that you added some data. This is essential for making reasonable suggestions.
However, I wouldn't call your data above "simplified". You basically ignored the suggestions from the answers to your other question.
Your data structure here is horribly complicated and difficult to create and maintain. You can simplify the data to the absolute minimum, but well, then you have to put a little bit more effort into the plotting command.
Yes, you can create your 30 graphs in a loop (check help do), no need for bash.
define functions for your input/output file names (check help sprintf).
you have to set the output before the actual plotting command.
I hope you can adapt the example below to your needs.
Data: SO73873363_step-1.dat
Isn't this data format much smaller, clearer and easier to understand?
"Reaction Coordinate" "0 V" "0.84 V"
O_{2} 0 -3.00
O#^*_{2} -0.1 -3.04
OOH^* -1.00 -3.12
O^* -2.00 -4.00
OH^* -4.00 -4.50
H_{2}O -4.50 -4.50
Script:
### create multiple output files from multiple input files
reset session
myFileIn(i) = sprintf("SO73873363_step-%d.dat",i)
myFileOut(i) = sprintf("SO73873363_step-%d.svg",i)
set term svg font "Sans,20"
set border 15 front lt black linewidth 3.000 dashtype solid
set title "Associative Pathway (0,1)"
set xlabel "Reaction Coordinate"
set xrange [-0.5:5.5]
set xtics nomirror scale 0
set ylabel "Free Energy (eV)"
set yrange[-5:0.1]
set ytics out nomirror
set key noautotitle samplen 2
set errorbars 0
dx = 0.2
do for [i=1:30] {
set output myFileOut(i)
plot myFileIn(i) u 0:2:(dx):xtic(1) w xerr lc "blue" lw 3 ps 0 ti columnheader(2), \
'' u 0:3:(dx) w xerr lc "red" lw 3 ps 0 ti columnheader(3), \
x1=y1=NaN '' u (x0=x1,x1=$0,x0-1+dx):(y0=y1,y1=$2,y0):(1-2*dx):(y1-y0) w vec dt 4 lc "blue" nohead, \
x1=y1=NaN '' u (x0=x1,x1=$0,x0-1+dx):(y0=y1,y1=$3,y0):(1-2*dx):(y1-y0) w vec dt 4 lc "red" nohead
}
set output # close the last file
### end of script
Result:

gnuplot : setting line style in a for loop

I have to plot several curve on a same graph. I necessarly need to use a for loop to do this. I would like to plot the 2 first curves with lines and the others with points. I am able to plot all the curves with lines or all the curves with points but not to change in the same for loop.
Here is the concerned part of my code:
set style line 1 lw 1 lc rgb "green"
set style line 2 lw 1 lc rgb "purple"
set style line 3 pt 1 ps 1.0 lc rgb "red"
set style line 4 pt 2 ps 1.0 lc rgb "red"
set style line 5 pt 3 ps 1.0 lc rgb "red"
plot for [i=1:words(FILES)] myDataFile(i) u (column(1)):((word(UTAUS_ch,i))) ls i title myTitle(i)
I would like to preface "ls i" with "w l" for the 2 first curves and "ls i" for the others. I tried to use a if statement by replacing "ls i" by "if (i < 2) {w l ls i} else {ls i}" but Gnuplot does not expect to find a if statement at this location.
Can someone help me ?
Thank you,
Martin
As mentioned here you probably cannot switch plotting styles within a plot for loop.
So, either you do two separate loops, one with points and the other with lines or you do one loop with linespoints and define all necessary parameters for points and lines as functions (to keep the plot command readable).
As mentioned here, linewidth 0 is not zero but the thinnest possible line which is typically 1 pixel. To make the line disappear completely you have to use linetype -2.
Code:
### lines and points in the same plot for-loop
reset session
LINECOLORS = "red green blue magenta cyan"
LINEWIDTHS = '1.0 4.0 0.0 0.0 0.0'
POINTTYPES = '0 0 5 7 9'
POINTSIZES = '0 0 1.0 2.0 3.0'
TITLES = 'one two three four five'
myLinecolor(i) = word(LINECOLORS,i)
myLinewidth(i) = real(word(LINEWIDTHS,i))
myPointtype(i) = int(word(POINTTYPES,i))
myPointsize(i) = real(word(POINTSIZES,i))
myLinetype(i) = myLinewidth(i) == 0 ? -2 : 1
myTitle(i) = word(TITLES,i)
set samples 31
set key out
plot for [i=1:words(TITLES)] (sin(0.25*x-i)) w lp pt myPointtype(i) ps myPointsize(i) \
lt myLinetype(i) lw myLinewidth(i) lc rgb myLinecolor(i) title myTitle(i)
### end of code
Result:
Addition:
In order to keep the plot command as short and clear as possible you could also define line styles and use it in the plot for command via ls i, with the same result as above.
...
do for [i=1:words(TITLES)] {
set style line i pt myPointtype(i) ps myPointsize(i) \
lt myLinetype(i) lw myLinewidth(i) lc rgb myLinecolor(i)
}
plot for [i=1:words(TITLES)] (sin(0.25*x-i)) w lp ls i title myTitle(i)
Here a way using a macro:
set style line 1 lw 1 lc rgb "green"
set style line 2 lw 1 lc rgb "purple"
set style line 3 pt 1 ps 1.0 lc rgb "red"
set style line 4 pt 2 ps 1.0 lc rgb "red"
set style line 5 pt 3 ps 1.0 lc rgb "red"
set samp 100
set macro
cmd = ''
do for [i=1:10] {s = i<3? 'w l' : 'ls '.i;
cmd = cmd . '"+" us 1:(sin(x-'.i.'/10.)) '.s.' title "key '.i.'",'}
plot [0:2*pi] #cmd

Generating a Heatmap Table in gnuplot

I am trying to generate a Heatmap with gnuplot but with a two distinct information for each entry in the heatmap. While heatmap shows the value as color, I want each block in the heatmap to show textual information as well.
The following script creates half of what I have in mind:
set term postscript eps color solid
set output '1.eps'
set title "Heat Map generated from a file containing Z values only"
unset key
set tic scale 0
set border linewidth 2
set palette rgbformula -7,2,-3
unset cbtics
unset colorbox
unset xtics
set x2tics ("A" 0, "B" 1, "C" 2, "D" 3, "E" 4)
set ytics ("N0" 0, "N1" 1, "N2" 2, "N3" 3, "N4" 4)
set style line 102 lc rgb'#101010' lt 0 lw 4
set grid front ls 102
set datafile separator ","
plot 'matrix.txt' matrix with image, "" matrix using 1:2:(sprintf('%.2f', $3)) with labels font ',12' offset 0,1.2
set datafile separator
The data file, matrix.txt contains the following information:
7 B, 5 B, 4 D, 3 B, 1 D
2 B, 2 A, 2 D, 0 C, 0 A
3 B, 0 A, 0 E, 0 E, 1 C
4 C, 0 A, 0 B, 0 E, 2 C
5 D, 0 A, 1 A, 2 A, 4 A
The following graph can be resulted from the script:
I want to be able to add the textual information in each entry as second part of the matrix entries (under the grid line).
I was wondering if you guys have any suggestions on how.
Thanks
Seems like you cannot use stringcolumn (or strcol) together with matrix to get the complete string contained in the respective matrix elements. As workaround you must iterate over all columns and plot each of them separately with labels:
set title "Heat Map generated from a file containing Z values only"
unset key
set tic scale 0
set border linewidth 2
set palette rgbformula -7,2,-3
unset cbtics
unset colorbox
unset xtics
set x2tics ("A" 0, "B" 1, "C" 2, "D" 3, "E" 4)
set ytics ("N0" 0, "N1" 1, "N2" 2, "N3" 3, "N4" 4)
set style line 102 lc rgb'#101010' lt 0 lw 4
set grid front ls 102
set datafile separator ","
plot 'matrix.txt' matrix with image, \
for [i=1:5] '' using 0:(i-1):i with labels font ',12' offset 0,1.2

Matching a Color Gradient to Data in Gnuplot

I have data showing a change over time, and I have used Gnuplot 4.6 to generate the following plot:
Here, I have manually defined eleven line styles to change the color gradually from red (#ff0000) to dark red (#5f0000) as `time' progresses. Here was my input:
# svg
set terminal svg size 600,600 fname 'CMU Sans Serif' fsize '10'
set output 'plot.svg'
# color definitions
set style line 1 lc rgb '#ff0000' lt 1 lw 2 pt 7 # starting light red
set style line 2 lc rgb '#ef0000' lt 1 lw 2 pt 7
set style line 3 lc rgb '#df0000' lt 1 lw 2 pt 7
set style line 4 lc rgb '#cf0000' lt 1 lw 2 pt 7
set style line 5 lc rgb '#bf0000' lt 1 lw 2 pt 7
set style line 6 lc rgb '#af0000' lt 1 lw 2 pt 7
set style line 7 lc rgb '#9f0000' lt 1 lw 2 pt 7
set style line 8 lc rgb '#8f0000' lt 1 lw 2 pt 7
set style line 9 lc rgb '#7f0000' lt 1 lw 2 pt 7
set style line 10 lc rgb '#6f0000' lt 1 lw 2 pt 7
set style line 11 lc rgb '#5f0000' lt 1 lw 2 pt 7
# visual elements
unset key
set xlabel 'x Axis'
set ylabel 'y Axis'
# plot data
plot for [n=2:11] 'data.dat' using 1:n with lines ls (n-1)
Is there a simpler way to get Gnuplot to gradually change the color as it plots multiple lines? I would ideally like to have a single script that can handle an arbitrary number of color gradations depending on the amount of data from the `data.dat' file.
You can e.g. use a function which calculates the colors depending on the iteration counter
# values r, g, b, x must be in the range [0:1]
rgb(r,g,b) = (255*r*256**2 + 255*g*256 + 255*b)
grad(x) = rgb(1 - x*0.7)
set style data lines
plot for [n=2:11] 'data.dat' using 1:2 lc rgb grad((n-2)/9.0)
Alternatively you can define a gradient and select a fractional position for each line
set palette defined (0 '#5f0000', 1 '#ff0000')
set style data lines
plot for [n=2:11] 'data.dat' using 1:2 lc palette frac (n-2)/9.0

GNUPlot - How to control interline spacing in tick labels?

I'm trying to plot a graph that has two-line labels on its xticks. I cannot reduce the font anymore because it becomes unreadable (the plot is part of a 2x2 multiplot).
The problem is that the separation between the two lines in a label is too big, so that they become too close to the labels of the next columns.
I would like to reduce the interline spacing so that the lines of a label become closer between them, but further to the lines of the other labels.
I've thought about placing the labels manually (using a function to compute the position of each line), but before doing it I would like to know if someone has a simpler solution.
Thanks a lot!
I'm using "gnuplot 4.6 patchlevel 4" on Ubuntu 14. The folowing is a MWE:
# Requires gnuplot >= 4.6
set terminal pdf color solid font "Helvetica, 10" enhanced size 4, 3.72
set output 'mwe.pdf'
set border 3 lc rgb "#000000"
set bmargin 9
set ylabel offset -1
TicksFont = ", 10"
Title2Font = ", 14"
set yrange[0:180 < * ]
set format y "%.0f%%"
set xtics out scale 0, 0 nomirror rotate by 90 right offset 0,0 font TicksFont
set ytics out nomirror font TicksFont
unset key
set datafile separator ";"
set style fill transparent solid 1.0 border -1
set style data boxes
set boxwidth 1.0
#Bottom-left plot
set title "C) Third (sub)plot" font Title2Font
plot '-' using ($0):2:(0xFF8080):xtic(1) notitle lc rgb variable
# Label; Value
01. Aaaaa:\nAaaaaaaaa(AA); 100
02. Bbbbb:\nBbbbbbbbbbbb(BB); 20
03. Ccccc: Ccccccc(Ccc),\nCccccccc(CCC); 30
04. Dddd: DDDD,\nDDDDDDDDDDDD(DD); 40
;NaN
01. Aaaaa:\nAaaaaaaaa(AA); 100
02. Bbbbb:\nBbbbbbbbbbbb(BB); 20
03. A single-liner; 30
04. Dddd: DDDD,\nDDDDDDDDDDDD(DD); 40
;NaN
01. Aaaaa:\nAaaaaaaaa(AA); 100
02. Bbbbb:\nBbbbbbbbbbbb(BB); 20
03. A single-liner; 30
04. Dddd: DDDD,\nDDDDDDDDDDDD(DD); 40
05. Eeee: EEEE,\nEEEEEEEEEEEE(EE); 50
end;
From gnuplot you cannot directly control the line height used for the labels. But there is a quite dirty workaround for your problem:
You can split your label at the new line character, change the font size of each line with the enhanced label syntax, but set a different font size for the new line character. So a label
set label at 0,0 "first line\nsecond line" font ",10"
is changed to
set label at 0,0 "{/=10 first line}\n{/=10 second line} font ",8"
And your script changes to:
# Requires gnuplot >= 4.6
set terminal pdf color solid font "Helvetica, 10" enhanced size 4, 3.72
set output 'mwe.pdf'
set border 3 lc rgb "#000000"
set bmargin 9
set ylabel offset -1
TickSize = 10
TicksFont = ", ".TickSize
Title2Font = ", 14"
set yrange[0:180 < * ]
set format y "%.0f%%"
set xtics out scale 0, 0 nomirror rotate by 90 right offset -0.1,0 font ",8"
set ytics out nomirror font TicksFont
unset key
set datafile separator ";"
set style fill transparent solid 1.0 border -1
set style data boxes
set boxwidth 1.0
#Bottom-left plot
set title "C) Third (sub)plot" font Title2Font
set_label_size(s) = sprintf('{/=%d %s}', TickSize, s)
label(s) = strstrt(s, "\n") ? set_label_size(s[:strstrt(s, "\n")-1])."\n".set_label_size(s[strstrt(s, "\n")+1:]) : set_label_size(s)
plot '-' using ($0):2:(0xFF8080):xtic(label(strcol(1))) notitle lc rgb variable
# Label; Value
01. Aaaaa:\nAaaaaaaaa(AA); 100
02. Bbbbb:\nBbbbbbbbbbbb(BB); 20
03. Ccccc: Ccccccc(Ccc),\nCccccccc(CCC); 30
04. Dddd: DDDD,\nDDDDDDDDDDDD(DD); 40
;NaN
01. Aaaaa:\nAaaaaaaaa(AA); 100
02. Bbbbb:\nBbbbbbbbbbbb(BB); 20
03. A single-liner; 30
04. Dddd: DDDD,\nDDDDDDDDDDDD(DD); 40
;NaN
01. Aaaaa:\nAaaaaaaaa(AA); 100
02. Bbbbb:\nBbbbbbbbbbbb(BB); 20
03. A single-liner; 30
04. Dddd: DDDD,\nDDDDDDDDDDDD(DD); 40
05. Eeee: EEEE,\nEEEEEEEEEEEE(EE); 50
end;
Before (left) and after (right):
You can switch to the epslatex terminal and use latex syntax on your gnuplot script directly. Then you can use the \vspace{} command with a negative argument to decrease the interline spacing, something like this:
\shortstack{01. Aaaaa: \vspace{-0.2em} \\ Aaaaaaaaa(AA)}
Although you'll need to escape backslashes:
\\shortstack{01. Aaaaa: \\vspace{-0.2em} \\\\ Aaaaaaaaa(AA)}
Would it be acceptable to just change the size of the whole plot, for example by changing the plot width from 4 inches to 6 and the height from 3.72 to 5.58?
This way the aspect ratio is preserved if you include it in a different document.
Before:
After:

Resources