Stacked and grouped bar histogram with Gnuplot - gnuplot

I would like to reproduce a bar chart like this one, i.e.: multiple groups, every group has many bars (4 bars in my case), each bar is segmented in a few slices (two slices in my case).
In my case, I have four algorithms applied on vectors of different sizes (2^0 to 2^20). Each algorithm has two "sections", local computation and communication. For each vector size I want to show the time required by each algorithm to perform the local computation and the communication, along with the total time corresponding to the sum of these two sections.
As a result, I would like to have a group for every vector size. In each group there are four bars corresponding to the four algorithms and each bar is segmented in a (e.g.) red part corresponding to the local computation and a blue part corresponding to the communication.
Is this feasible with gnuplot? I can provide data in whatever format is useful.
Many thanks in advance.

For your data set it doesn't make sense to stack the local and comm parts, because the comm part is to small to see it in the graph. In any case it would also be quite tricky to combine stacked and clustered, depending on the further requirements (legend entries, tick labels etc).
Here is an example of how to plot a clustered histogram for your data set:
set style histogram clustered gap 1
set style data histogram
set style fill solid 1.0 noborder
set termoption enhanced
set xtics out nomirror
myxtic(x) = sprintf('2^{%d}', int(floor(log(x)/log(2) + 0.5)))
plot 'test.dat' using ($2+$3):xtic(myxtic(stringcolumn(1))) title 'Algorithm 1',\
for [i=2:4] '' using (column(2*i)+column(2*i+1)) title sprintf('Algorithm %d', i)
The result is:
To group by algorithm, you can create new groups with the newhistogram keyword:
set style histogram rowstacked title offset 4,1
set boxwidth 0.9 relative
set style fill solid 1.0 border lt -1
set xtics rotate by 90 right
plot newhistogram "Algorithm 1" lt 1,\
'test.dat' using 2:xtic(1) title columnheader, \
'' using 3 title columnheader,\
newhistogram "Algorithm 2" lt 1,\
'test.dat' using 4:xtic(1) notitle, \
'' using 5 notitle,\
newhistogram "Algorithm 3" lt 1,\
'test.dat' using 6:xtic(1) notitle, \
'' using 7 notitle,\
newhistogram "Algorithm 4" lt 1,\
'test.dat' using 8:xtic(1) notitle, \
'' using 9 notitle
The local and comm dat are stacked, but the comm part is so small, that you cannot see it in the graph (only when you zoom in).
For the output I used 4.6.3 and the following settings:
set terminal pngcairo size 1000,400
set output 'test.png'
set xtics font ',6'
The result is:
A bit more sophisticated display of the xtics requires some tricking, because for histograms the xtics aren't treated as being numerical, but rather strings. Here is an example:
set terminal pngcairo size 1000,400
set output 'test.png'
set style histogram rowstacked title offset 0,-0.5
set bmargin 3
set boxwidth 0.9 relative
set style fill solid 1.0 border lt -1
set termoption enhanced
set xtics out nomirror
myxtic(x) = (int(floor(log(x)/log(2) + 0.5)) % 5 == 0) ? sprintf('2^{%d}', int(floor(log(x)/log(2) + 0.5))) : ""
plot newhistogram "Algorithm 1" lt 1,\
'test.dat' using 2:xtic(myxtic(real(stringcolumn(1)))) title columnheader, \
'' using 3 title columnheader,\
newhistogram "Algorithm 2" lt 1,\
'test.dat' using 4:xtic(myxtic(real(stringcolumn(1)))) notitle, \
'' using 5 notitle,\
newhistogram "Algorithm 3" lt 1,\
'test.dat' using 6:xtic(myxtic(real(stringcolumn(1)))) notitle, \
'' using 7 notitle,\
newhistogram "Algorithm 4" lt 1,\
'test.dat' using 8:xtic(myxtic(real(stringcolumn(1)))) notitle, \
'' using 9 notitle
With the result

Related

Gnuplot: add a filled rectangle to highlight region of plot (date/time on x axis)

I have a file with the following contents that looks like the following line. Data is comma delimited, but the first column has the Date Time as follows:
20201-03-08 18:03:01, SAT1, 1002, 900, 10
.
.
.
Here is my plot of my data:
Here is what I would like to have: two regions highlighted, with labels. First region would span from +/-50Hz on Y axis and all along the x-axis. Second region would be everything else.
Wanted Plot Features:
When I try to simply draw a rectangle, I could do set object rectangle from 0, 50 to *,-50 but that doesn't work... Any advice ? I think I can figure out the rest if somebody could help me how to specify x-range if it is Date/Time....
EDIT: Here is my full gnuplot code:
set term pngcairo size 1600,900
set datafile sep ','
set datafile missing "NaN"
set key font ',17'
set key left top
#set key opaque
set object 1 rectangle from graph 0,50 to graph 1,-50
set object 1 fillstyle solid fillcolor "light-green"
set object 1 behind
set title "Offsets adjust" font 'Ubuntu-Mono-Regular, 24'
set timestamp "Graph Generated (UT): \n%Y-%m-%d %H:%M:%S" top font 'Arial,18'
set timefmt "%Y-%m-%d %H:%M:%S"
set xdata time
set xlabel "Date\nTime" font 'Consolas,12'
set ylabel 'Amount of Change (Hz)' font 'Consolar,16'
set xtics font 'Consolas,16'
set ytics 20 font 'Consolas,16'
set yrange [-150:150]
set grid
set border back
set xzeroaxis linetype 2 linewidth 2.5
set output "/home/temp/temp/abode/beacon_offsets.png"
plot "/home/temp/temp/abode/SAT_1_2200_offset_trend.txt" using 1:7 title 'SAT_1 Offset' with points ps 2 lw 4 lc 8, \
"/home/temp/temp/abode/SAT_1_2200_offset_trend.txt" using 1:7:5 with labels font ',18' offset 1,1 notitle, \
"/home/temp/temp/abode/SAT_2_2200_offset_trend.txt" using 1:7 title 'SAT_2 Offset' with points ps 2 lw 4 lc 7, \
"/home/temp/temp/abode/SAT_2_2200_offset_trend.txt" using 1:7:5 with labels font ',18' offset 1,1 notitle, \
"/home/temp/temp/abode/SAT_3_2200_offset_trend.txt" using 1:7 title 'SAT_3 Offset' with points ps 2 lw 4 lc 6, \
"/home/temp/temp/abode/SAT_3_2200_offset_trend.txt" using 1:7:5 with labels font ',18' offset 1,1 notitle, \
"/home/temp/temp/abode/SAT_4_2200_offset_trend.txt" using 1:7 title 'SAT_4 Offset' with points ps 2 lw 4 lc 5, \
"/home/temp/temp/abode/SAT_4_2200_offset_trend.txt" using 1:7:5 with labels font ',18' offset 1,1 notitle, \
"/home/temp/temp/abode/SAT_5_2200_offset_trend.txt" using 1:7 title 'SAT_5 Offset' with points ps 2 lw 4 lc 4, \
"/home/temp/temp/abode/SAT_5_2200_offset_trend.txt" using 1:7:5 with labels font ',18' offset 1,1 notitle, \
"/home/temp/temp/abode/SAT_6_2200_offset_trend.txt" using 1:7 title 'SAT_6 Offset' with points ps 2 lw 4 lc 3, \
"/home/temp/temp/abode/SAT_6_2200_offset_trend.txt" using 1:7:5 with labels font ',18' offset 1,1 notitle
Here is a screenshot:
In this case you want to fill the entire width of the plot, so you can use graph rather than the time coordinates along the x axis. The y axis (actually the "first y axis") coordinates can be used directly. You also want to make sure the rectangle is drawn behind the plot.
set object 1 rectangle from graph 0, first 50 to graph 1, first -50
set object 1 fillstyle solid fillcolor "light-green"
set object 1 behind

gnuplot histogram chart with overlap

I would like to plot a bar chart or histogram like this in gnuplot.
I tried set style histogram rowstacked which is a start but it adds the columns on top of each other while I need them overlapped. Next is the issue of transparent color shading.
Thanks for your feedback.
UPDATE: user8153 asked for additional data.
The set style histogram clustered gap 0.0 is doing the cluster mode of the histogram bars. If you blur the eye it sort-of shows what I want but with overlap and transparent shading.
The only other histogram modes given in the docs are rowstacked and columnstacked. I never got a plot out of columnstacked so I discarded it. Now rowstacked stacks the histogram bars.
The overlay appearance is there but it is wrong. I don't want the stacked appearance. The histograms have to overlay.
Code :
set boxwidth 1.0 absolute
set style fill solid 0.5 noborder
set style data histogram
set style histogram clustered gap 0.0
#set style histogram rowstacked gap 0.0
set xtics in rotate by 90 offset first +0.5,0 right
set yrange [0:8000]
set xrange [90:180]
plot 'dat1.raw' using 3 lc rgb 'orange', \
'dat2.raw' using 3 lc rgb 'blue', \
'dat3.raw' using 3 lc rgb 'magenta'
Thanks for your feedback.
Given a sample datafile test.dat
-10 4.5399929762484854e-05
-9 0.0003035391380788668
-8 0.001661557273173934
-7 0.007446583070924338
-6 0.02732372244729256
-5 0.0820849986238988
-4 0.20189651799465538
-3 0.4065696597405991
-2 0.6703200460356393
-1 0.9048374180359595
0 1.0
1 0.9048374180359595
2 0.6703200460356393
3 0.4065696597405991
4 0.20189651799465538
5 0.0820849986238988
6 0.02732372244729256
7 0.007446583070924338
8 0.001661557273173934
9 0.0003035391380788668
10 4.5399929762484854e-05
you can use the following commands
set style fill transparent solid 0.7
plot "test.dat" with boxes, \
"test.dat" u ($1+4):2 with boxes
to get the following result (using the pngcairo terminal):
Using transparency as in user8153's solution is certainly the easiest way to visualize an overlap of two histograms.
This works even if the two histogram do not have identical bins or x-data-ranges.
However, the color of the overlap is pretty much bound to the colors of the two histogram and the level of transparency. Furthermore, if you want to show the overlap in the key you have to do it "manually".
Here is a solution where you can choose an independent color for the overlap area.
The overlap is basically the minimum y-value from both histograms for each x-value.
For this you need to compare the y-values for each x-value. This can be done in gnuplot with some "trick" by merging the two files line by line. This requires the data in a datablock (how to get it there from a file). Since this merging procedure is using indexing of datablock lines, it requires gnuplot>=5.2.0.
This assumes that you have the same x-range and bins for each histogram. If this is not the case, you have to implement some further steps.
Script: (works with gnuplot>=5.2.0, Sept. 2017)
### plot overlap of two histograms
reset session
# create some random test data
set samples 21
f(x,a,b) = 1./(a*(x-b)**4+1)
set table $Data1
plot '+' u 1:(f(x,0.01,-2)) w table
set table $Data2
plot '+' u 1:(f(x,0.02,4)) w table
unset table
set boxwidth 1.0
set grid y
set ytics 0.2
set multiplot layout 2,1
set style fill transparent solid 0.3
plot $Data1 u 1:2 w boxes lc 1 ti "Data1", \
$Data2 u 1:2 w boxes lc 2 ti "Data2"
set print $Overlap
do for [i=1:|$Data1|] { print $Data1[i].$Data2[i] }
set print
set style fill solid 0.3
plot $Data1 u 1:2 w boxes lc 1 ti "Data1", \
$Data2 u 1:2 w boxes lc 2 ti "Data2", \
$Overlap u 1:($2>$4?$4:$2) w boxes lc "red" ti "Overlap"
unset multiplot
### end of script
Result:

How can I offset boxes to match steps?

My application deploys to CentOS 6 and CentOS 7. I have just found out that Gnuplot 4.4 (which is the latest I can use on CentOS 6, for logistical reasons) does not support fillsteps, so my lovely graphs are not rendering there.
Said graphs have a series of steps for a bounding line, and a series of fillsteps to create a solid colour. (I'm also faking a stacked plot, but never mind that.)
I reckon I can use steps and boxes instead, but boxes are offset on the axis by half a tic. Can I shuffle them over in an efficient and expressive way? Or perhaps I should be coming at this completely differently?
Original code
set terminal pngcairo enhanced font ",10" size 576, 231
set border back
set grid
set xzeroaxis lt -1
set style line 1 lc rgbcolor "#4E9EF3"
set style line 2 lc rgbcolor "#B23F3F"
set timefmt "%s"
set xdata time
set xlabel "Time (+00:00)"
set format x "%H:%M"
set offset graph 0, graph 0, graph 0.05, graph 0.05
set xrange [571795200:571881600]
set yrange [0:]
plot 'data.csv' using 1:($2+$3) with fillsteps ls 1 fs solid 0.3 noborder notitle,
'' using 1:($2+$3) with steps ls 1 notitle,
'' using 1:2 with fillsteps ls 2 fs solid 0.3 noborder notitle,
'' using 1:2 with steps ls 2 notitle
Attempt at replacing fillsteps with boxes
set terminal pngcairo enhanced font ",10" size 576, 231
set border back
set grid
set xzeroaxis lt -1
set style line 1 lc rgbcolor "#4E9EF3"
set style line 2 lc rgbcolor "#B23F3F"
set boxwidth 1.0 relative
set timefmt "%s"
set xdata time
set xlabel "Time (+00:00)"
set format x "%H:%M"
set offset graph 0, graph 0, graph 0.05, graph 0.05
set xrange [571795200:571881600]
set yrange [0:]
plot 'data.csv' using 1:($2+$3) with boxes ls 1 fs solid 0.3 noborder notitle,
'' using 1:($2+$3) with steps ls 1 notitle,
'' using 1:2 with boxes ls 2 fs solid 0.3 noborder notitle,
'' using 1:2 with steps ls 2 notitle
My input data happens to be evenly spaced, with the X axis increment known to the calling code.
So, instead of:
plot 'data.csv' using 1:2 with fillsteps ls 2 fs solid 0.3 noborder notitle
I can do:
# (for example)
barwidth = 900
set boxwidth 1.0 relative
plot 'data.csv' using ($1+barwidth/2.0):2 with boxes ls 2 fs solid 0.3 noborder notitle
… and this appears to provide consistent results.

GNUplot - How to have an image as a key?

I understand that we can omit the key in GNUplot using unset key. If I want to insert a small image to signify the key onto a XY 2-D plot, how to do it? In MS-Excel, it is just a matter of copying an image and pasting it on to the plot and adjusting its placement and size. Can such a thing be done in GNUPlot too? By what plot option? I am attaching a sample a of what I expect in a multiplot I made (the plot on the top left). And I have the small molecule image as a png file. I have also listed the code below. Please help me. Thanks.
reset
set size 1,1
set multiplot
unset key
#CPD
set size 0.5,0.5
set origin 0,0.5
unset title
plot 'Practice1.dat' using 1:2 w points lw 3 lc rgb 'red'
plot 'Practice1.dat' using 1:6 smooth csplines lw 3 lc rgb 'red'
#Ethene
set size 0.5,0.5
set origin 0.5,0.5
set title 'Ethene'
plot 'Practice1.dat' using 1:3 w l lw 3 lc rgb 'blue'
#Benzene
set size 0.5,0.5
set origin 0,0
set title 'Benzene'
plot 'Practice1.dat' using 1:4 smooth csplines lw 3 lc rgb 'green'
#H2
set size 0.5,0.5
set origin 0.5,0
set title 'H2'
plot 'Practice1.dat' using 1:5 w l lw 3 lc rgb 'black'
The image will be a plot in itself.
plot "image.png" binary filetype=png center=(975,40) dx=200 w rgbimage, \
'Practice1.dat' using 1:2 w points lw 3 lc rgb 'red', \
'Practice1.dat' using 1:6 smooth csplines lw 3 lc rgb 'red'
Note that you should avoid having several plot commands without changing origin/size in multiplot, as the labels and borders are overlaid and this may change their appearance depending on terminal (because e.g of antialiasing), hence the usage of , and the splitting of the command on multiple lines (with \)
Note also that set multiplot could have done the layout of your simple 2x2 plot all by itself for you, set multiplot layout 2,2

Plot boolean values on a time based line graph

I am plotting a time based line graph and would like to add a boolean data series to it.
Is it possible to have the boolean data highlight the full height of the canvas of the graph where the value is true?
Plotfile:
set datafile separator ","
set terminal pngcairo size 800,400
set title "Solar charge monitor"
set yrange [0:]
set ylabel "V"
set y2range [0:]
set y2label "A"
set y2tics
set xlabel "Date"
set xdata time
set timefmt "%Y-%m-%dT%H:%M:%SZ"
set key left top
set grid
set output "samplePlot.png"
plot "sampleData.csv" using 1:2 with lines lw 2 title 'Batt (V)', \
"sampleData.csv" using 1:3 with lines lw 2 title 'Solar (V)', \
"sampleData.csv" using 1:4 with lines lw 2 title 'Charge (A)' axes x1y2, \
"sampleData.csv" using 1:5 with lines lw 2 title 'Load (A)' axes x1y2
Sample Data:
time,V_Batt,V_SolarV,A_Charge,A_Load,bool_charging
2014-09-25T07:06:03.358Z,13.20,14.38,0.52,0.03,1
2014-09-25T07:05:03.639Z,13.16,14.14,0.52,0.05,1
2014-09-25T07:04:02.856Z,13.18,14.19,0.54,0.03,1
2014-09-25T07:03:03.141Z,13.18,14.24,0.52,0.03,1
2014-09-25T07:02:03.410Z,13.18,14.09,0.52,0.03,1
2014-09-25T07:01:03.604Z,13.20,14.38,0.54,0.03,1
2014-09-25T07:00:02.766Z,13.11,14.28,0.50,0.02,1
2014-09-25T06:59:03.025Z,13.09,14.28,0.48,0.02,1
2014-09-25T06:58:03.302Z,13.11,14.28,0.43,0.02,1
2014-09-25T06:57:03.445Z,13.18,14.28,0.56,0.05,1
2014-09-25T06:56:02.611Z,13.16,14.14,0.52,0.03,1
2014-09-25T06:55:02.901Z,13.09,14.58,0.48,0.01,1
2014-09-25T06:54:03.178Z,13.09,14.48,0.52,0.02,1
2014-09-25T06:53:03.432Z,13.13,14.53,0.54,0.06,1
2014-09-25T06:52:03.630Z,13.11,14.28,0.48,0.03,1
2014-09-25T06:51:02.763Z,13.16,14.14,0.54,0.05,1
2014-09-25T06:50:03.068Z,13.16,14.28,0.54,0.03,1
2014-09-25T06:49:03.388Z,13.07,14.38,0.50,0.03,1
2014-09-25T06:48:02.683Z,13.09,14.33,0.50,0.03,1
2014-09-25T06:47:02.967Z,13.07,14.04,0.48,0.02,1
2014-09-25T06:46:03.249Z,13.05,14.19,0.48,0.02,1
2014-09-25T06:45:03.410Z,13.09,14.24,0.56,0.06,1
2014-09-25T06:44:02.677Z,13.07,14.24,0.52,0.03,1
2014-09-25T06:43:02.973Z,13.05,14.09,0.50,0.03,1
2014-09-25T06:42:03.282Z,13.09,14.24,0.52,0.03,1
2014-09-25T06:41:03.389Z,12.96,14.04,0.46,0.02,1
2014-09-25T06:40:02.702Z,12.76,13.59,0.50,0.00,1
I would like to add column 6 which is a boolean (0/1) value. In this sample data, the background would be fully highlighted as the bool is always true
Any tips?
You can use the boxes plotting style to draw background boxes depending on the value of column 6, i.e. something like
plot "sampleData.csv" using 1:($6 * 16) with boxes fc rgb '#ccffcc' fillstyle solid,\
"" using 1:2 lt 1 with lines lw 2 title 'Batt (V)'
That, however, requires you to know the maximum and minimum values of the y-range. If that should be calculated automatically, you'll need first to make a dummy plot with the unknown terminal and then use GPVAL_Y_MIN and GPVAL_Y_MAX:
reset
set datafile separator ","
set terminal pngcairo size 800,400
set title "Solar charge monitor"
set yrange [0:]
set ylabel "V"
set y2range [0:]
set y2label "A"
set y2tics
set xlabel "Date"
set xdata time
set timefmt "%Y-%m-%dT%H:%M:%SZ"
set key left center
set grid
set autoscale xfix
set style data lines
set terminal push
set terminal unknown
plot "sampleData.csv" using 1:2, "" using 1:3
set terminal pop
set output "samplePlot.png"
plot "sampleData.csv" using 1:(GPVAL_Y_MIN + $6 * (GPVAL_Y_MAX - GPVAL_Y_MIN)) with boxes fc rgb '#ccffcc' fillstyle solid notitle,\
"" using 1:2 lt 1 lw 2 title 'Batt (V)', \
"" using 1:3 lt 2 lw 2 title 'Solar (V)', \
"" using 1:4 lt 3 lw 2 title 'Charge (A)' axes x1y2, \
"" using 1:5 lt 4 lw 2 title 'Load (A)' axes x1y2
Using a slightly changed data file (I inserted some zeros to show the effect), I get:
If you don't want vertical lines at the boundaries, you could also use filledcurves with:
...
plot "sampleData.csv" using 1:(GPVAL_Y_MIN + $6 * (GPVAL_Y_MAX - GPVAL_Y_MIN)) with filledcurves x1 fc rgb '#ccffcc' fillstyle solid notitle,
...

Resources