StatsPlot -- axes labels overwrite each other

I’m plotting some results from a Turing session. Using the Turing recipe, I get:

The problem is the tiny variation in the sample value, which makes the density plot look ugly/overlapping (numeric) labels along the abscissa of the density plot. Similarly, when I use StatsPlot directly on the result, e.g.,

fg_tah = density(p_est[:,:Tah0,:],lc=:red,la=1,lw=2,framestyle=:box,xlabel="Sample",

leads to:

which is virtually unreadable…

Question: what is the simplest way to fix the axes labels?

This plot parameter formatter=:plain and proper font size should fix it.

using StatsPlots
x = LinRange(1.5123,1.51234,100)
y = rand(x,100)
p1 = density(x,y, c=:red, label="problem")
p2 = density(x,y, c=:green, label="no problem", formatter=:plain)
plot(p1, p2, tickfontsize=4, legend=:outertop)

Or to manually control the ticks labels
using StatsPlots
x = LinRange(1.5123,1.51234,100)
y = rand(x,100)
p1 = density(x,y, c=:red, label="problem")
x0,x1 = extrema(x)
dx = x1 - x0
xt = LinRange(-dx/4 + x0, dx/4 + x1, 5)
p2 = density(x,y, xticks = (xt, round.(xt, digits=6)), xlims=(-dx/2 + x0, dx/2 + x1), c=:green, label="no problem")
plot(p1, p2, tickfontsize=5, legend=:outertop)

Thanks a lot!

Is it also possible to fix it in more compound plots such as corrplot? Here is a section of what I get now:

In this case, corrplot automates plotting a matrix of figures, so perhaps it is more difficult here… (all element plots will have different axes values…)

…one possible alternative is to set xticks and yticks to false, I guess…

1 Like

Not perfect fix but way better than default:

M = rand(LinRange(1.5123,1.51234,100), 4, 4)
M[:,2] .+= 0.8sqrt.(abs.(M[:,1])) .- 0.5M[:,3] .+ 5
M[:,3] .-= 0.7M[:,1].^2 .+ 2
corrplot(M, label = ["x$i" for i=1:4], tickfontsize=1, guidefontsize=3, formatter=:plain)


Actually, using the code above but saving the corrplot to a format that allows arbitrary zoom (ex: svg, pdf), the result looks OKish. Needs further plumbing.
Better filling an issue, if there isn’t one on this yet.

1 Like

I’m getting quite happy with the results of your suggestions so far. One thing, though…

Is it possible to do the same trick with labels on the ordinate axis as you proposed on the abscissa?

To do so, I need to know the variation in the “density” of the iterations in Turing… I have used the density plot function of StatsPlot, and that function hides how it computes the density. I assume it uses some sort of histogram function, but the peak of the density depends on a lot of things (number of bins, or whatever).

Question: Is there a way to extract the chosen ylims value from a plot?

This gives the plot y-bounds:

p = plot(-10:10,-100:10:100)
y0, y1 = Plots.ylims(p)

Sorry, have you tried formatter=:plain? (it applies to both axes)
(or yformatter=:plain for y-axis only)


How about setting rotation?

1 Like

I’ve got an array plot (layout = (3,2))…

  • Is it possible to extract individual plots from this layout, and operate on the individual plot?
  • Is it possible to scale the data series, e.g., the ordinate values y when I do plot (x,y).

[I’m trying to plot the prior distribution and the posterior distribution in the same plot, and need to scale the ordinate values so that they have similar peak value… – it is the shift in location and width in the abscissa direction that is of interest in this comparison.]

Check this post.

First do p.spmap to see what you’ve got. In case of p = corrplot(...) there are 16 subplots (4x4):

julia> p.spmap
Dict{Any, Plots.Subplot} with 16 entries:
  Symbol("##976") => Subplot{4}
  Symbol("##980") => Subplot{8}
  Symbol("##988") => Subplot{16}
  Symbol("##983") => Subplot{11}
  Symbol("##986") => Subplot{14}
  Symbol("##978") => Subplot{6}
  Symbol("##979") => Subplot{7}
  Symbol("##984") => Subplot{12}
  Symbol("##974") => Subplot{2}
 ⋮               => ⋮

To access the ylims of a given subplot, do:

julia> ylims(p.spmap[Symbol("##976")])
(1.5123100000000003, 1.51233)

Could you ellaborate on this one?

1 Like

Suppose I have two density plots with wildly different maximal ylims values, and I want to show them in the same plot (i.e., comparing apriori and aposteriori distributions). For such a comparison, I don’t really care about the scaling in the ordinate direction – I mainly care about how one distribution is shifted and made wider/narrower compared to the other in the abscissa direction…

Using density plot, the plotting algorithm produces the series to plot (x values, y values) based on “random” outcomes (e.g., from Turing) – but the user doesn’t see the y values.

I don’t know how density works. I assume some histogram function is used (but what bin size?), and then a smooth function is fitted to the histogram … I would guess.

In summary, if I want to put two density plots in the same plot, I would like to scale the y value of each plot so that their peak values are comparable.

Of course – if I want to compare a posterior plot with a priori plot, I can get around this…

  • I can plot the posterior plot using density, then use your trick of reading ylims.
  • Then, since the priori distribution is known, I can use the Distributions package to produce the density – where I do have some control of the scaling.

Since I actually want to compare a priori distribution and a posteriori distribution, I guess I can get around the problem…

That begs for two y-axes solutions using twinx().

using StatsPlots, Measures
x1 = LinRange(1.5, 1.6, 1000); y1 = rand(x1, 1000)
x2 = LinRange(1, 3, 1000); y2 = rand(x2, 1000)
density(y1, c=:red, label="left",legend=:topleft, right_margin=20mm)
density!(twinx(), y2, c=:green, label="right",legend=:topright, right_margin=20mm)


Actually, if the two density plots have wildly different y-scales, then the same probably happens with the x-scales. Meaning that for a nice comparison, double x- and double y-scales might be required. Plots.jl may not cope well with that use case and you may need PyPlot, for example.

NB: if you do not care about the tick labels on the x-axis, then a linear transformation of one of the variables will do.

1 Like

Ah… the embarrassingly simple solution :slight_smile:

I’d want them to have the same x-axis because I want to see how the posterior distribution is changed compared to the prior distribution…

1 Like

Or you can animate the density-plots

using StatsPlots
anim = @animate for i = 1:10
    density(randn(range),leg=false, grid=false, layout=(1,2), size=(760,300))
    density!(rand(mi:ma,range),fill=(0,0.2), sp=2)
    for i = 1:4 density!(rand(mi:ma,range), grid=false, leg=false, sp=2) end
end;gif(anim, "density estimation.gif", fps = 5)
1 Like