Log scale in histogram

I don’t mind specifying my histogram bins manually in order to get a log scale, but it appears to break the viewport in Plots.jl:

using Plots
x = rand(1000)
b = 10.0 .^ (-5:0)
histogram(x, bins=b)

image

And setting the x-axis to a log scale is even worse:

histogram(x, bins=b, xscale=:log10, yscale=:identity)

image

What can I do about this?

First solution: Use norm = true (pdf-like histogram)

using Plots
x = rand(10^6)
b = 10.0 .^ (-5:0)
histogram(x; alpha=0.3, label="", bin=b, norm=true)

Second solution: Manually use StatsBase.fit(Histogram{Float64}, x, b).

using Plots, StatsBase
x = rand(10^6)
b = 10.0 .^ (-5:0)
h = fit(Histogram{Float64}, x, b)
h.weights ./= diff(h.edges[1])
plot(h; alpha=0.3, label="")

Another example:

using Plots, StatsBase, Random
X = 3randexp(10^6)
bin = [0; [2^(k/2) - 2^(-1/2) for k in 0:8]]
@show round.(bin; digits=2)
h = fit(Histogram{Float64}, X, bin)
h.weights ./= diff(h.edges[1])
plot(h; alpha=0.3, label="")
round.(bin; digits = 2) = [0.0, 0.29, 0.71, 1.29, 2.12, 3.29, 4.95, 7.29, 10.61, 15.29]

2 Likes

Thank you for these suggestions. What about getting a log scale on the x axis?

It seems to work using Plots.jl pyplot() backend and the xaxis keyword:

using Plots; pyplot()
x = rand(1000)
b = 10.0 .^ (-5:0)
# histogram(x, bins=b)  # works OK
histogram(x, bins=b, xaxis=(:log10, (0.001, 10)), yscale=:identity)

Plots_pyplot_xaxis_log_scale

1 Like

It seems to work well if you set xlim=extrema(b) as well as xscale=:log10.

using Plots
n = 10^6
f(x) = n * x * log(10)
x = rand(n)
b = 10.0 .^ (-5:0)
histogram(x; alpha=0.3, label="", bin=b, xscale=:log10, xlim=extrema(b))
x = 10.0 .^ (-5:0.01:0)
plot!(x, f; label="n × pdf on log-scaled xaxis", legend=:topleft)

using Plots
n = 10^6
f(x) = n * x * log(10)
x = rand(n)
b = 10.0 .^ (-5:0.2:0)
histogram(x; alpha=0.3, label="", bin=b, xscale=:log10, xlim=extrema(b))
x = 10.0 .^ (-5:0.01:0)
plot!(x, f; label="n × pdf on log-scaled xaxis", legend=:topleft)

using Plots, StatsBase
n = 10^6
f(x) = n * x * log(10)
x = rand(n)
b = 10.0 .^ (-5:0.2:0)
h = fit(Histogram{Float64}, x, b)
h.weights ./= diff(log10.(h.edges[1]))
plot(h; alpha=0.3, label="", xscale=:log10, xlim=extrema(b))
x = 10.0 .^ (-5:0.01:0)
plot!(x, f; label="n × pdf on log-scaled xaxis", legend=:topleft)

Another example

using Plots, StatsBase, Random
n = 10^6
f(x) = n * exp(-x/3)/3 * x * log(10)
X = 3randexp(10^6)
bin = [1e-3; [2^(k/2) - 2^(-1/2) for k in 0:8]]
@show round.(bin; digits=2)
h = fit(Histogram{Float64}, X, bin)
h.weights ./= diff(log10.(h.edges[1]))
plot(h; alpha=0.3, label="", xscale=:log10, xlim=extrema(bin))
x = exp.(range(log.(extrema(bin))...; length=500))
plot!(x, f; label="n × pdf on log-scaled xaxis", legend=:topleft)
round.(bin; digits = 2) = [0.0, 0.29, 0.71, 1.29, 2.12, 3.29, 4.95, 7.29, 10.61, 15.29]

Edit: Update examples.

1 Like

There’s an extrema function? God, if I owed you a nickle for every time I have typed xlim=(min(x), max(x))

Thank you for the tip.

1 Like