# Control plot range of logarithmic histogram

When drawing a histogram with a logarithmic vertical scale, how can I control the vertical plot range? I.e., how can I control where the bars originate? On a linear plot, bars will start at zero, but on a logarithmic plot, there is no natural starting point, and it is useful to customize where bars start.

Example:

data = RandomVariate[ExponentialDistribution[1], 1*^6];

Histogram[data, {0, 15, 0.1}, {"Log", "PDF"}]


Suppose I want the vertical range to be $$10^{-4}$$ to $$1$$. PlotRange doesn't quite have the intended effect:

Histogram[data, {0, 15, 0.1}, {"Log", "PDF"}, PlotRange -> {10^-4, 1}]


I need to bars to start at the bottom of the plot. Adding AxesOrigin -> {0, Log[10^-4]} does not help.

• On v12.2.0-Win7-x64 I see this.
– Syed
Commented Nov 2, 2022 at 12:54
• On version 13.0.1 for Linux x86 (64-bit) (January 29, 2022) I see the same plot of the OP Commented Nov 2, 2022 at 13:23
• The old joke: Patient: "Doc, it hurts when I do this." Doctor: "Don't do that." You've given a few good reasons why one shouldn't log-scale the vertical axis. Another more important reason is that the "apparent area under the curve" is no longer 1 and that makes it impossible/inappropriate to compare different distributions. However, logging the horizontal axis can make much more sense.
– JimB
Commented Nov 2, 2022 at 16:30

Don't do it: a log transform of the horizontal axis is fine but a log transform (or any transform for that matter) of the vertical axis destroys much of any interpretation of an estimate of a probability density function. Determining differences among different distributions becomes next to impossible.

For example consider samples from Exponential distributions with parameters 1 and 2. Here are the "vertical log-scaled" histograms with the same vertical log scaling:

SeedRandom[12345];
data1 = RandomVariate[ExponentialDistribution[1], 10^6];
data2 = RandomVariate[ExponentialDistribution[2], 10^6];

(* Set binwidth and frequency minimum *)
binwidth = 0.1;
fmin = 1/(binwidth*Length[data]); (* Arbitrary lower bound *)
h1 = HistogramList[data1, {0, 15, binwidth}, "PDF"];
h2 = HistogramList[data2, {0, 15, binwidth}, "PDF"];

(* Replace values of 0 density with fmin *)
h1[[2]] = Max[fmin, #] & /@ h1[[2]];
h2[[2]] = Max[fmin, #] & /@ h2[[2]];

(* Generate rectangles to mimic a histogram *)
t1 = Table[{{h1[[1, i]], fmin}, {h1[[1, i]],
h1[[2, i]]}, {h1[[1, i + 1]], h1[[2, i]]}, {h1[[1, i + 1]],
fmin}}, {i, Length[h1[[2]]]}];
t2 = Table[{{h2[[1, i]], fmin}, {h2[[1, i]],
h2[[2, i]]}, {h2[[1, i + 1]], h2[[2, i]]}, {h2[[1, i + 1]],
fmin}}, {i, Length[h2[[2]]]}];

(* Show results *)
GraphicsRow[{ListLinePlot[t1, PlotRange -> {All, {xmin, Max[h[[1]]]}},
PlotStyle -> Orange, AxesOrigin -> {0, xmin},
ScalingFunctions -> {None, "Log"}, Filling -> Axis,
FillingStyle -> Orange],
ListLinePlot[t2, PlotRange -> {All, {xmin, Max[h[[1]]]}},
PlotStyle -> Orange, AxesOrigin -> {0, xmin},
ScalingFunctions -> {None, "Log"}, Filling -> Axis,
FillingStyle -> Orange]}]


Yes, the two figures appear different but can one visually estimate any characteristic of the distributions? The mean? Any percentile? I don't think so.

Consider histograms without log-scaling:

GraphicsRow[{Histogram[data1, "FreedmanDiaconis", "PDF", PlotRange -> {{0, 5}, {0, 2}}],
Histogram[data2, "FreedmanDiaconis", "PDF", PlotRange -> {{0, 5}, {0, 2}}]}]


One can immediately see differences in means and spread. For such distributions maybe constructing a histogram with the log of the data might be more informative and in that case two SmoothHistograms rather than standard histograms would be better:

Show[SmoothHistogram[Log[data1], Automatic, "PDF",
PlotLegends -> LineLegend[{Blue, Orange}, {"Exponential[1]", "Exponential[2]"}]],
SmoothHistogram[Log[data2], Automatic, "PDF", PlotStyle -> Orange]]


So even if you got the desired "base", the ability to compared different sets of data is destroyed.

• Note that HistogramList doesn't complain when the option {"Log", "PDF"} is used but the "Log" part is ignored and the usual density value is returned (and not the log of the density).
– JimB
Commented Nov 3, 2022 at 4:00
• I have to disagree about the usefulness of such figures. This is a straightforward way to judge whether a distribution may have an exponential tail during exploratory data analysis. It is true that it is not a perfect way, and there are aspects that can be misleading. For example, the last few bins will probably contain just one data point, and therefore won't be on the same straight line, even if they were sampled from a perfect exponential. But what better way would you suggest? Commented Feb 14, 2023 at 13:52
• Means and percentiles are not the only relevant characteristics. In this case I am looking to judge whether the tail is exponential. Perhaps one can look at the complementary CDF. But the value of CDFs is affected by the entire dataset, so they are no suitable for judging a distribution within a certain interval only, which is another useful thing one might want to do. Commented Feb 14, 2023 at 13:55
• I'd be happy to continue in chat and hear your opinion. I set a bounty on this because I'd really like to see a direct technical answer to my question, after all Histogram does support a logarithmic y axis, and your arguments apply equally for why it shouldn't have that feature. But since it does, the feature should at least be complete, and include an option for choosing bar origins. Commented Feb 14, 2023 at 14:26
• The answer to stats.stackexchange.com/questions/567032/… is one approach to plot the rate of change of the tail region of a data histogram.
– JimB
Commented Feb 14, 2023 at 21:13

Maybe this?:

y0 = 10^-4;
Histogram[data, {0, 15, 0.1}, {"Log", "PDF"}] //
Show[
#,
ReplacePart[AbsoluteOptions[#, AxesOrigin], {1, 2, 2} -> Log[y0]],
PlotRange -> Log@{y0, 1},
PlotRangeClipping -> True,
PlotRangePadding -> None] &

fmin = 10^-4;
Histogram[data, {0, 15, 0.1}, {"Log", "PDF"}] /.
List[Rectangle[List[x1_, y1_], List[x2_, y2_], Rule["RoundingRadius", 0]]] ->
List[Rectangle[List[x1, Max[Log[fmin], y1]], List[x2, Max[Log[fmin], y2]], Rule["RoundingRadius", 0]]] /. Rule[AxesOrigin, List[x0_, y0_]] ->
Rule[AxesOrigin, List[x0, Log[fmin]]]


Not very elegant ... Just tweaking the parameters:

 Histogram[data, {0, 8.25, 0.1}, {"Log", "PDF"}, AxesOrigin -> {0, Log[10^-4.5]}]