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
    Jan 20, 2012 at 3:56
  • 2
    $\begingroup$ You could use ArrayPad[] for starters: Transpose[{Riffle[bins, bins], ArrayPad[Riffle[counts, counts], 1]}] $\endgroup$ Jan 20, 2012 at 4:01
  • $\begingroup$ Another way: Transpose[{Riffle[bins, bins], Flatten[Partition[counts, 2, 1, {-1, 1}, 0]]}] $\endgroup$ Jan 20, 2012 at 4:25
  • 2
    $\begingroup$ @J.M. Why are you answering in comments?! $\endgroup$ 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$ 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$ 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$ 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
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$ 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$ 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
    Jan 20, 2012 at 9:43
  • $\begingroup$ Okay, it's not, but I also don't find this elegant. Sorry. :-/ $\endgroup$
    – Mr.Wizard
    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
    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$ 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, privacy policy and cookie policy

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