7
$\begingroup$

I want to draw a histogram as scatter plot, i.e. bin center vs. count. I found only a cumbersome way (steps 1-4) to achieve this standard procedure. Is there a more efficient way to draw a bin-centered scatter histogram for given bin number?

0. Create data for demonstration

data = RandomVariate[NormalDistribution[], 10000];

1. Create bins and counts of histogram with defined number of bins

{bins, counts} = HistogramList[data, 100, "PDF"];

2. The variable bins contains the left bin border and of course the data point shall be at the bin center, so we have to add half of the bin width

bins = bins + Abs[bins[[1]] - bins[[2]]]/2;

3. Add place holder to counts as bins contains 1 more value than counts

counts = Append[counts, 0];

4. Reshape data

datadisplay = Transpose[{bins, counts}];

5. Plot histogram

ListPlot[datadisplay]

All together:

data = RandomVariate[NormalDistribution[], 10000];
{bins, counts} = HistogramList[data, 100, "PDF"];
bins += Abs[bins[[1]] - bins[[2]]]/2;
counts = Append[counts, 0];
datadisplay = Transpose[{bins, counts}];
ListPlot[datadisplay]

MMA 12.3

$\endgroup$
6
  • $\begingroup$ Seems a bad idea to draw a histogram as a scatterplot this way. If anything, I'd scatter representatives of the actual data points, under the histogram (with random y values within the range). $\endgroup$ Dec 10, 2021 at 8:14
  • $\begingroup$ I also think it's hard to understand why would you want to do what you ask, but for a different reason. For me, Histograms applied to continuous variables are a tool that belongs in the past when computation was expensive, and they should be considered obsolete. Introducing an arbitrary parameter like the bin size and artificially discretizing a continuous variable seems like a bad idea when you can directly deal with EmpiricalDistribution and FindDistributionParameters. At the very least probably you may want to use a continuous Kernel Density plot, like SmoothHistogram. $\endgroup$
    – rhermans
    Dec 10, 2021 at 10:45
  • $\begingroup$ Smoothing manipulates the histogram shape at locations of sharp changes in the population and pretends that the real histogram follows the smoothed curve. Points show the counts only for the bin and is more serious. $\endgroup$ Dec 12, 2021 at 17:15
  • $\begingroup$ What do you mean by "is more serious"? There is no "real histogram", if the underlying PDF has a "sharp" feature it will also be distorted by binning unless you shift the bins by hand to coincide with the sharp feature. A histogram is just a special case of Kernel density with values rounded and a top-hat kernel, both very unrealistic choices. Choosing Kernels that reflect the expected uncertainty of the data collected makes way more sense. $\endgroup$
    – rhermans
    Dec 13, 2021 at 10:23
  • $\begingroup$ If you smooth by a function then you have to add the function and a width and the result is not easy to understand. The smoothing function and definition of width can be arbitrarily defined. If you just smooth a bin constantly and you add the bin width then everybody understands. $\endgroup$ Dec 13, 2021 at 13:57

1 Answer 1

9
$\begingroup$

You can use ChartElementFunction -> "Point" to get a histogram as a scatter plot in one step:

SeedRandom[1]
data = RandomVariate[NormalDistribution[], 10000];

Histogram[data, 100, "PDF", ChartElementFunction -> "Point", 
 ChartStyle -> ColorData[97][1], ImageSize -> Large]

enter image description here

Add the options ColorFunction -> "Rainbow" and ChartBaseStyle -> AbsolutePointSize[7] to get

enter image description here

Note: Re "Is there a more efficient way ...": Working with HistogramList and using the resulting coordinates with ListPlot or Graphics is faster than using Histogram. Furthermore, Histogram does not render bars with zero height; so, if you need to display those points, then HistogramList is the only way to go:

histogram = Histogram[data, 100, "PDF", ChartElementFunction -> "Point", 
     ChartStyle -> Red, 
     ChartBaseStyle -> Directive[Opacity[1], AbsolutePointSize[8]], 
     ImageSize -> Large]; // RepeatedTiming // First

0.055

listplot = ListPlot[
     Transpose @ MapAt[MovingAverage[#, 2] &, 
       HistogramList[data, 100, "PDF"], {1}], 
     PlotStyle -> Directive[Opacity[1], Green, AbsolutePointSize[5]]]; // 
  RepeatedTiming // First

0.024

graphics = Graphics[{Directive[Opacity[1], Black, AbsolutePointSize[2]], 
      Point @ Transpose @ MapAt[MovingAverage[#, 2] &, 
         HistogramList[data, 100, "PDF"], {1}]}]; // 
  RepeatedTiming // First

0.004

Legended[Show[histogram, listplot, graphics], 
   PointLegend[{Red, Green, Black},
     {"Histogram", "ListPlot", "Graphics"}]]

enter image description here

$\endgroup$
2
  • $\begingroup$ Do these methods place the point in the bin center? Else it would be wrong. $\endgroup$ Dec 10, 2021 at 12:51
  • $\begingroup$ @granularbastard, yes they do. $\endgroup$
    – kglr
    Dec 10, 2021 at 12:53

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.