# Elegantly pairing up mismatched lists

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]


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

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

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
]


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

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

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.

• For those wondering why this works, I gave a mathematical explanation here. Jan 26, 2012 at 9:36

points = Flatten[Through[{PadLeft, PadRight}[{bins, counts}]], {{3, 1}}]

• +1 This is awesomely awesome, though unfortunately not intuitive. Jan 21, 2012 at 5:18

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

• That's a creative use of Outer[]. I like! Jan 20, 2012 at 5:31
• Unfortunately this is much slower than Transpose[{Riffle[bins, bins], ArrayPad[Riffle[counts, counts], 1]}] Jan 20, 2012 at 9:43
• Okay, it's not, but I also don't find this elegant. Sorry. :-/ Jan 20, 2012 at 14:25

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]}]


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

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

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


For equal-spaced bins,

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


gives the same result.