2
$\begingroup$

I have the following problem. I have a pre-binned list that I want to plot. Here is a shortened example:

data:={{16.337, 0}, {18.92, 0}, {21.9105, 0.201491}, {25.374, 0.692208}, {29.3855, 1}, {34.0305, 0.849548}, {39.41, 0.512009}, {45.64, 0.240648}, {52.8545, 0.0905944}, {61.21, 0.0265148}, {70.886, 0.00539223}, {82.0915, 0.000554905}, {95.0685, 0}, {110.097, 0}, {127.501, 0}}

The first coordinate refers to the center of the bin and the second one is the count.

Typically I would use:

ListPlot[data, Joined -> True, InterpolationOrder -> 0, Filling -> Axis]

but this creates a histogram where the bins are not centered around the given numbers but rather begin there (as typically done and discussed in other question posts). Due to experimental reasons, the bins' widths increase exponentially, so I cannot just shift all the first coordinates. A possible workaround is to recalculate the beginnings of the bins separately and then feed them into the ListPlot, but I am wondering if there is a more automatic, built-in solution? Something that would work elegantly even if I have bins that have varying bin widths but I know their centers...

*the exponential binning is a result of the experimental equipment that was used (I didn't do the experiments myself, but was told that this cannot be changed). I don't understand why the machine was programmed this way, but there is nothing to do on that side. The data was normalised according to the highest column only to be able to plot relative comparisons between various experimental conditions.

$\endgroup$
5
  • 1
    $\begingroup$ ListStepPlot[data, "Center", Mesh -> Full, PlotRange -> All] $\endgroup$
    – corey979
    Dec 20, 2018 at 14:02
  • 1
    $\begingroup$ A histogram is based on integer counts of things. Are there any counts involved? It appears that the bin centers are transformed from the original equal interval bins. In other words, taking the log of the bin centers results in equally-spaced bins. Also, with the maximum height equaling 1 it appears that the original heights were divided by the maximum height so any "frequency" interpretation of the resulting figure is at best dubious. Giving more information about the data's history might get you better advice. $\endgroup$
    – JimB
    Dec 20, 2018 at 16:44
  • $\begingroup$ You can get the lower and upper boundaries for the bins with delta = Differences[Log[data[[All, 1]]]][[1]]; lower = Exp[Log[data[[All, 1]]] - delta/2]; upper = Exp[Log[data[[All, 1]]] + delta/2];. This addresses your concern " the bins' widths increase exponentially, so I cannot just shift all the first coordinates.". $\endgroup$
    – JimB
    Dec 20, 2018 at 16:50
  • $\begingroup$ Use a pin plot! ListPlot[data, Filling -> Axis]. Otherwise you will have to deal with variable bin widths. $\endgroup$
    – Alan
    Dec 20, 2018 at 17:23
  • 2
    $\begingroup$ You would not need permission of others to edit your own question, if you signed in with your user name (uuu). $\endgroup$
    – bbgodfrey
    Dec 23, 2018 at 13:30

1 Answer 1

2
$\begingroup$

To identify the 16 bin limits {x[1],...,x[16]} from the given 15 bin centers you need one more piece of information. If you know, say, the left limit of the left-most bin, then you can compute the rest using the available bin centers. If not, the following computes bin limits x[2] thru x[16] as a function of x[1] under the constraints that

  1. Moving average of {x[1],..., x[16]} is the same as given bin centers,
  2. 0 < x[1] < x[2] < ... < x[16] and
  3. bin lengths are increasing (x[2]-x[1]< x[3]-x[2]< ... < x[16] - x[15]).

Once we have the bin limits, we can use data[[All, -1]] & as the height specification in the third argument of Histogram:

binlims = Array[x, 1 + Length@data];
bincenters = Rationalize[data[[All, 1]]];
sol = Solve[Join[Thread[MovingAverage[binlims, 2] == bincenters], 
           {Less @@ binlims}, 
           {Less @@ Differences[binlims]},
           {Last[binlims] > bincenters[[-1]], 0 < x[1] < bincenters[[1]]}], 
    Rest@binlims, Reals][[1]];

blf[z_] := Prepend[Rest[binlims] /. sol /. x[1] -> z, z]

blf[w] // Short[#, 2] &

enter image description here

Manipulate[Histogram[data[[All, -1]], {blf[z]}, (data[[All, -1]] &), 
     Frame -> True, Axes -> False, ImageSize -> 400, 
     PlotRange -> {{0, Max[data[[All, 1]]]}, All}], 
  {{z, (30091/2000 + 60997/4000)/2.}, 30091/2000, 60997/4000}]

enter image description here

Update: ListStepPlot[data, "Center"] gives the desired result only for equal-sized bins; for unequal bin sizes it doesn't work:

k = 3;
SeedRandom[1]
limits = Sort[RandomSample[Range[10, 100], 1 + k]];
centers = MovingAverage[limits, 2];
heights = Range[k];
dt = Transpose[{centers, heights}];

Legended[Show[ListStepPlot[dt, "Center", 
        PlotStyle -> Directive[Orange, Thick], 
        FrameTicks -> {{Automatic, Automatic}, {N@centers, Automatic}}, 
        GridLines -> {centers, None}, 
        Method -> {"GridLinesInFront" -> True}, Frame -> True, 
        Epilog -> {Red, PointSize[Medium], Point[dt]}], 
    ListStepPlot[dt,  PlotStyle -> Directive[Purple, Thick]],
    Histogram[{0}, {limits}, (heights &), 
      ChartStyle ->  Directive[EdgeForm[{Thick, Blue}], Opacity[.3, LightBlue]]], 
    PlotRange -> {{0, 100}, All}, ImageSize -> Large], 
  Placed[LineLegend[{Blue, Orange, Purple}, 
      {"Histogram", "ListStepPlot - Center", "ListStepPlot - Left"}, 
      LegendLayout -> { "Row", 1}], Above]]

enter image description here

$\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.