2
votes

I'm looking for a way to plot histograms in 3d to produce something like this figure http://www.gnuplot.info/demo/surface1.17.png but where each series is a histogram.

I'm using the procedure given here https://stackoverflow.com/a/19596160 and http://www.gnuplotting.org/calculating-histograms/ to produce histograms, and it works perfectly in 2d. Basically, the commands I use are

hist = 'u (binwidth*(floor(($2-binstart)/binwidth)+0.5)+binstart):(1) smooth freq w boxes
plot 'data.txt' @hist

Now I would just like to add multiple histograms in the same plot, but because they overlap in 2d, I would like to space them out in a 3d plot.

I have tried to do the following command (using above procedure)

hist = 'u (1):(binwidth*(floor(($2-binstart)/binwidth)+0.5)+binstart):(1) smooth freq w boxes
splot 'data.txt' @hist

But gnuplot complains that the z values are undefined.

I don't understand why this would not put a histogram along the value 1 on the x-axis with the bins along the y-axis, and plot the height on the z-axis.

My data is formatted simply in two columns:

Index   angle
0       92.046      
1       91.331      
2       86.604      
3       88.446      
4       85.384      
5       85.975      
6       88.566      
7       90.575      

I have 10 files like this, and since the values in the files are close to each other, they will completely overlap if I plot them all in one 2d histogram. Therefore, I would like to see 10 histograms behind each other in a sort of 3d perspective.

2
Please provide some sample data from your data file.Matthew
You may also want to look at this article: http://www.phyast.pitt.edu/~zov1/gnuplot/html/bargraphs.htmlMatthew
I have added the format of the data I'm using. And thanks for the link, but I still cannot see how I can use it for my situation (perhaps due to lack of understanding)Kaspar H
You'll likely have to do some formatting outside of gnuplot. The problem is that to do this, you need boxes, which can't be used with splot (see help boxes: The boxes style is only relevant to 2D plotting). Your link works because it is plotting functions, which fills in all of the between points. To plot a box, you would need to compute four points, in order (lower left, upper left, upper right, and lower right). I can force gnuplot to capture the upper left values in a named datablock, but can't see how to create the other points.Matthew

2 Answers

0
votes

This second answer is distinct from my first. Whereas the first addresses what the OP was trying to accomplish, this second provides an alternative approach which address the underlying problem the OP was trying to overcome.

I have posted an answer that addresses the ability to do this in 3d. However, this isn't usually the best way to do this with multiple histograms like this. A 3d graph like that will be difficult to compare.

We can address the overlap in 2D by stagnating the position of the boxes. With default settings, the boxes will spread out to touch. We can turn that off and adjust the position of the boxes to allow more than 1 histogram on a graph. Remember, that the coordinates you supply are the center of the boxes.

Suppose that I have the data you have provided and this additional data set

Index Angle
0  85.0804
1  92.2482
2  90.0384
3  99.2974
4  87.729
5  94.6049
6  86.703
7  97.9413

We can set the boxwidth to 2 units with set boxwidth 2 (your bins are 4 units wide). Additionally, we will turn on box filling with set style fill solid border lc black.

Then I can issue

plot datafile1 u (binwidth*(floor(($2-binstart)/binwidth)+0.5)+binstart):(1) smooth freq w boxes, \
     datafile2 u (binwidth*(floor(($2-binstart)/binwidth)+0.5)+binstart+1):(1) smooth freq w boxes

The second plot command is identical to the first, except for the +1 after binstart. This will shift this box 1 unit to the right. This produces

enter image description here

Here, the two series are clear. Keeping track of which box is associated with each is easy because of the overlap, but it is not enough to mask the other series.

We can even move them next to each other, with no overlap, by subtracting 1 from the first plot command:

plot datafile1 u (binwidth*(floor(($2-binstart)/binwidth)+0.5)+binstart-1):(1) smooth freq w boxes, \
     datafile2 u (binwidth*(floor(($2-binstart)/binwidth)+0.5)+binstart+1):(1) smooth freq w boxes

producing

enter image description here

0
votes

This first answer is distinct from my second. This answer address what the OP was trying to accomplish whereas the second addresses the underlying problem the OP was trying to overcome.

Gnuplot isn't going to be able to do this on it's own, as the relevant styles (boxes and histograms) only work in 2D. You would have to do it using an external program.

For example, using your data and your 2d command (your first command), we get (using your data and the linked values of -100 and 4 for binstart and binwidth)

enter image description here

To draw these boxes on the 3d grid, we will need to use the line style and have four points for each: lower left, upper left, upper right, and lower right. We can use the previous command and capture to a table, but this will only gives the upper center point. We can use an external program to pre-process, however. The following python program, makehist.py, does just that.

from sys import argv
import re
from math import floor

pat = re.compile("\s+")

fname = argv[1]
binstart = float(argv[2])
binwidth = float(argv[3])

data = [tuple(map(float,pat.split(x.strip()))) for x in open(fname,"r").readlines()[1:]]

counts = {}
for x in data:
    bn = binwidth*(floor((x[-1]-binstart)/binwidth)+0.5)+binstart
    if not bn in counts: counts[bn] = 0
    counts[bn]+=1

for x in sorted(counts.keys()):
    count = counts[x]
    print(x-binwidth/2,0)
    print(x-binwidth/2,count)
    print(x+binwidth/2,count)
    print(x+binwidth/2,0)

print(max(counts.keys())+binwidth/2,0)
print(min(counts.keys())-binwidth/2,0)

Essentially, this program does the same thing as the smooth frequency option does, but instead of getting the upper center of each box, we get the four previously mentioned points along with two points to draw a line along the bottom of all the boxes.

Running the following command,

plot "< makehist.py data.txt -100 4" u 1:2 with lines

produces

enter image description here

which looks very similar to the original graph. We can use this in a 3d plot

splot "< makehist.py data.txt -100 4" u (1):1:2 with lines

which produces

enter image description here

This isn't all that pretty, but does lay the histogram out on a 3d plot. The same technique can be used to add multiple data files onto it spread out. For example, with the additional data

Index Angle
0  85.0804
1  92.2482
2  90.0384
3  99.2974
4  87.729
5  94.6049
6  86.703
7  97.9413

We can use

splot "< makehist.py data.txt -100 4" u (1):1:2 with lines, \
      "< makehist.py data2.txt -100 4" u (2):1:2 with lines

to produce

enter image description here