18
$\begingroup$

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?

$\endgroup$
8
  • 1
    $\begingroup$ +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. $\endgroup$
    – rcollyer
    Commented Jan 20, 2012 at 3:56
  • 2
    $\begingroup$ You could use ArrayPad[] for starters: Transpose[{Riffle[bins, bins], ArrayPad[Riffle[counts, counts], 1]}] $\endgroup$ Commented Jan 20, 2012 at 4:01
  • $\begingroup$ Another way: Transpose[{Riffle[bins, bins], Flatten[Partition[counts, 2, 1, {-1, 1}, 0]]}] $\endgroup$ Commented Jan 20, 2012 at 4:25
  • 2
    $\begingroup$ @J.M. Why are you answering in comments?! $\endgroup$ Commented Jan 20, 2012 at 4:46
  • $\begingroup$ @rcollyer I'm not too concerned about speed in this case, but really? I'll have to test that out... $\endgroup$ Commented Jan 20, 2012 at 4:51

7 Answers 7

12
$\begingroup$

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.)

$\endgroup$
2
  • $\begingroup$ Really clever usage of InterpolationOrder -> 0 ;-) $\endgroup$ Commented Jan 20, 2012 at 4:25
  • $\begingroup$ Alternatively: Plot[Evaluate[Piecewise[Transpose[{counts, #1 < t <= #2 & @@@ Partition[bins, 2, 1]}], 0]], {t, First[bins], Last[bins]}, Exclusions -> None]. $\endgroup$ Commented Jan 20, 2012 at 4:37
6
$\begingroup$

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.

$\endgroup$
1
  • $\begingroup$ For those wondering why this works, I gave a mathematical explanation here. $\endgroup$ Commented Jan 26, 2012 at 9:36
6
$\begingroup$

What about this to create the points?

points = Flatten[Through[{PadLeft, PadRight}[{bins, counts}]], {{3, 1}}]
$\endgroup$
1
  • $\begingroup$ +1 This is awesomely awesome, though unfortunately not intuitive. $\endgroup$ Commented Jan 21, 2012 at 5:18
4
$\begingroup$

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
$\endgroup$
3
  • $\begingroup$ That's a creative use of Outer[]. I like! $\endgroup$ Commented Jan 20, 2012 at 5:31
  • $\begingroup$ Unfortunately this is much slower than Transpose[{Riffle[bins, bins], ArrayPad[Riffle[counts, counts], 1]}] $\endgroup$
    – Mr.Wizard
    Commented Jan 20, 2012 at 9:43
  • $\begingroup$ Okay, it's not, but I also don't find this elegant. Sorry. :-/ $\endgroup$
    – Mr.Wizard
    Commented Jan 20, 2012 at 14:25
4
$\begingroup$

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]}]
$\endgroup$
2
$\begingroup$

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
$\endgroup$
2
  • $\begingroup$ If taking this approach I think it would be better to construct a Piecewise function. $\endgroup$
    – Mr.Wizard
    Commented Jan 20, 2012 at 15:50
  • 1
    $\begingroup$ 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}]. $\endgroup$ Commented Jan 20, 2012 at 15:50
1
$\begingroup$
SeedRandom[1]
{bins, counts} = N[HistogramList[RandomVariate[NormalDistribution[5, 2], 100]]];

ListStepPlot[Transpose[{Most @ bins, counts}], Filling -> {1 -> 0}]  /. 
  p_Polygon :> {EdgeForm[Blue], p}

enter image description here

For equal-spaced bins,

ListStepPlot[counts, Filling -> Axis, DataRange -> MinMax[Most @ bins]] /. 
  p_Polygon:>{EdgeForm[Blue],p}

gives the same result.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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