Search code examples
gnuplot

rowstack not stacking in gnuplot


I was trying to learn some histograms tools in gnuplot, I made the following script

set samples 500

set table "set1.dat"
plot [0:10] 5+2*rand(0)
unset table
set table "set2.dat"
plot [0:10] 10*rand(0)
unset table

rmin  = 0.0
rmax  = 10.0
nbins = 20.0
binwidth = (rmax-rmin)/nbins
bin(x,w) = w*(floor((x-rmin)/w)+0.5)+rmin

set table "h1.dat"
plot "set1.dat" u (bin($2,binwidth)):(1.0) smooth freq w boxes noti
unset table
set table "h2.dat"
plot "set2.dat" u (bin($2,binwidth)):(1.0) smooth freq w boxes noti
unset table

I want to plot the histograms h1 and h2 on top of each other (rowstack). It should be noted at that point, that h1.dat and h2.dat have a last line marked u (instead of i), which somehow appears to screw the plot. I then tried the following

set style data histogram
set style histogram rowstack
set boxwidth 0.9*binwidth

plot "< grep i h2.dat" u 1:2 w boxes noti, "< grep i h1.dat" u 1:2 w boxes noti

Which gives me

Overlapping histograms

Individually, the two histograms are fine. But they hardly follow the rowstack-stacking approach. I tried replacing the u 1:2 by u 2 as all examples around seem to be using that. But then the bins are placed on every units instead of every half units. Which I suppose, I could solve by using u 2:xtic(1). But in any case the second (red) histogram is moved down the the left side of the spectrum.

My question is then quite simple: why doesn't the second histogram stack on top of the first one?


Solution

  • You don't need external tools or scripts for this task. You simply need a few extra lines in gnuplot.

    If the x-ranges of your two histograms are not the same, you simply have to make them the same, but how? Since gnuplot 5.0 you can print to datablocks via with table. With this you can simply append datablocks. So, append $Histo1 and $Histo2 into a new table $Histo3. Apply smooth freq on $Histo3 and you will get the sum of $Histo1 and $Histo2 in $Histo4.

    Now, you plot $Histo4 with the color you want for $Histo1 and afterwards $Histo2 on top. Unless you want transparent boxes you can use this to "mimic" a stacked histogram. You can do the same "trick" for impulses: How to stack impulses in Gnuplot

    Script: (works with gnuplot 5.0.0, Jan 2015)

    ### stack histograms with different x-ranges
    reset session
    
    # create some random test data
    set samples 500
    set table $Data1
        plot [0:10] 5+2*rand(0)
    set table $Data2
        plot [0:10] 10*rand(0)
    unset table
    
    rmin  = 0.0
    rmax  = 10.0
    nbins = 20.0
    binwidth = (rmax-rmin)/nbins
    bin(x,w) = w*(floor((x-rmin)/w)+0.5)+rmin
    
    set table $Histo1
        plot $Data1 u (bin($2,binwidth)):(1.0) smooth freq
    set table $Histo2
        plot $Data2 u (bin($2,binwidth)):(1.0) smooth freq
    unset table
    
    set table $Histo3
        plot $Histo1 u 1:2 w table
        plot $Histo2 u 1:2 w table
    set table $Histo4
        plot $Histo3 u 1:2 smooth freq
    unset table
    
    # set offsets 0,0,0,0
    set yrange [0:]
    set key out
    set grid y
    set boxwidth 0.8 relative    # for gnuplot<5.0.7 you should use: set boxwidth 0.4 absolute
    set style fill solid 0.3
    
    set multiplot layout 3,1
    
        set ytics 40
        plot $Histo1 u 1:2 w boxes lc "red" ti "Data1"
    
        set ytics 10
        plot $Histo2 u 1:2 w boxes lc "blue" ti "Data2"
    
        set ytics 40
        plot $Histo4 u 1:2 w boxes lc "red"  ti "Data1", \
             $Histo2 u 1:2 w boxes lc "blue" ti "Data2"
    
    unset multiplot
    ### end of script
    

    Result:

    enter image description here