Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

HistogramList returns a list of bin boundaries and a list of counts. There is one more boundary than counts, and I'd like to pair them up so I can feed it into ListLinePlot and get an alternative view of a histogram. Here's some code that will do this:

{bins, counts} = N[HistogramList[RandomVariate[NormalDistribution[5, 2], 100]]]

(* => {{0., 2., 4., 6., 8., 10.}, {13., 19., 37., 28., 3.}} *)

points = Transpose[{Riffle[bins, bins], Flatten[{0, Riffle[counts, counts], 0}]}]

(* => {{0., 0}, {0., 13.}, {2., 13.}, {2., 19.}, {4., 19.}, {4., 37.}, {6., 37.}, 
       {6., 28.}, {8., 28.}, {8., 3.}, {10., 3.}, {10., 0}} *)

Note that it also adds in some zeros to bring the resulting curve down to the axis:

ListLinePlot[points]

Mathematica graphics

Is there a simpler and/or more intuitive way of achieving this behavior?

share|improve this question
1  
+1, I'm at a complete loss as to how to improve this. Although, I believe Thread may be faster than Transpose for longer lists. –  rcollyer Jan 20 '12 at 3:56
2  
You could use ArrayPad[] for starters: Transpose[{Riffle[bins, bins], ArrayPad[Riffle[counts, counts], 1]}] –  J. M. Jan 20 '12 at 4:01
    
Another way: Transpose[{Riffle[bins, bins], Flatten[Partition[counts, 2, 1, {-1, 1}, 0]]}] –  J. M. Jan 20 '12 at 4:25
2  
@J.M. Why are you answering in comments?! –  Brett Champion Jan 20 '12 at 4:46
    
@rcollyer I'm not too concerned about speed in this case, but really? I'll have to test that out... –  Brett Champion Jan 20 '12 at 4:51
show 3 more comments

6 Answers

You can use InterpolationOrder for the plot itself to generate the same behavior. I'm assuming here you want the plot you posted in an easier way, not the data handling itself.

{bins, counts} = HistogramList[...];
ListLinePlot[
    {bins, Append[counts, 0]} // Transpose, 
    InterpolationOrder -> 0
]

enter image description here

(You may want to prepend one value to the finished list so that the histogram goes down to zero on the left side as well.)

share|improve this answer
    
Really clever usage of InterpolationOrder -> 0 ;-) –  Vitaliy Kaurov Jan 20 '12 at 4:25
    
Alternatively: Plot[Evaluate[Piecewise[Transpose[{counts, #1 < t <= #2 & @@@ Partition[bins, 2, 1]}], 0]], {t, First[bins], Last[bins]}, Exclusions -> None]. –  J. M. Jan 20 '12 at 4:37
add comment

In the same vein as Andy's answer: Differences[ArrayPad[counts, 1]].UnitStep[x - bins] can be used with Plot[]. Apply PiecewiseExpand[] if need be.

share|improve this answer
    
For those wondering why this works, I gave a mathematical explanation here. –  J. M. Jan 26 '12 at 9:36
add comment

What about this to create the points?

points = Flatten[Through[{PadLeft, PadRight}[{bins, counts}]], {{3, 1}}]
share|improve this answer
    
+1 This is awesomely awesome, though unfortunately not intuitive. –  Brett Champion Jan 21 '12 at 5:18
add comment

Another way of doing it (although, I don't think it fits the "intuitive" part), is:

(Outer[List, {#1}, #2] & @@@ 
   Transpose[{bins, 
     Partition[ArrayPad[counts, 1], 2, 1, {1, -1}]}]) ~Flatten~ 2

One could also do it using MapIndexed and naïve pairing as

With[{counts1 = ArrayPad[counts, 1]}, 
  MapIndexed[{{#1, First@counts1[[#2]]}, {#1, First@counts1[[#2 + 1]]}} &, bins]
  ] ~Flatten~ 1
share|improve this answer
    
That's a creative use of Outer[]. I like! –  J. M. Jan 20 '12 at 5:31
    
Unfortunately this is much slower than Transpose[{Riffle[bins, bins], ArrayPad[Riffle[counts, counts], 1]}] –  Mr.Wizard Jan 20 '12 at 9:43
    
Okay, it's not, but I also don't find this elegant. Sorry. :-/ –  Mr.Wizard Jan 20 '12 at 14:25
add comment

If you are willing to use Plot instead of ListLinePlot then something like this would work and matches up with the style of the PDF in HistogramDistribution:

f[bins_, counts_][x_] := Boole[Thread[Most[bins] <= x < Rest[bins]]].counts
share|improve this answer
    
If taking this approach I think it would be better to construct a Piecewise function. –  Mr.Wizard Jan 20 '12 at 15:50
1  
Equivalently: Piecewise[Transpose[{counts, Thread[Most[bins] <= x < Rest[bins]]}], 0]. Or maybe even Which @@ Join[Riffle[Thread[Most[bins] <= x < Rest[bins]], counts], {True, 0}]. –  J. M. Jan 20 '12 at 15:50
add comment
up vote 1 down vote accepted

J. M. left a solution in a comment that I really like, so I'm creating an answer out of it:

points = Transpose[{Riffle[bins, bins], ArrayPad[Riffle[counts, counts], 1]}]
share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.