Plots GR axis break

Is it possible to plot a figure containing axis break like this using Plots.jl and GR backend?

Especially in boxplot.

1 Like

Never saw such type of example done with gr(), but you may try to implement it using the same subplot trick as done here by @ianshmean

Using the subplot trick mentioned above, the following plots with breaks can be obtained using gr() back-end, but the code is a bit shaky:

Using gr’s ggplot2 theme with no breaks:
plot_no_breaks

Using gr’s ggplot2 theme with breaks:

xb = [(500,800), (1900,2100)]
yb = [(100,300), (500,650), (850,900)]

Using gr’s dark theme with breaks:

Using gr’s dark theme with breaks, but in log-log scale:

Using gr’s ggplot2 theme with 1 ybreak:

xb = []   # empty set for no breaks
yb = [(100,300)]

Here below the code, with a user function breakplot() defined:

using Measures, Plots; gr()

function breakplot(X,Y,xb,yb; lc=:yellow,lw=3,ls=:solid,xlabel="X-axis",ylabel="Y-axis",ptheme=:dark,
                   xscale=:identity, yscale=:identity, size = (1000,700))
    # by @rafael.guerra

    if occursin("dark",lowercase(string(ptheme)))
        gc =:white
    else
        gc =:black
    end
    nx, ny = length(xb), length(yb)

    xb2 = [X[1]; collect(Iterators.flatten(xb)); X[end]]
    yb2 = [minimum(Y); collect(Iterators.flatten(yb)); maximum(Y)]

    w = [diff(xb2[2(i-1)+1:2*i])[1] for i in 1:nx+1]
    if occursin("log10",lowercase(string(xscale)))
        w = log10.(w)
    end
    w = w / sum(w)

    h = [diff(yb2[2(i-1)+1:2*i])[1] for i in 1:ny+1]
    if occursin("log10",lowercase(string(yscale)))
        h = log10.(h)
    end
    h = reverse(h) / sum(h)
    
    theme(ptheme)
    l = @layout [a{0.001w} [grid(ny+1,nx+1, heights=h, widths=w); b{0.001h}]]  # first & last subplots for axes labels
    p = fill(plot( lw=lw,ls=ls), 1 + (ny+1) * (nx+1) + 1)

    p[1] = plot(ylabel=ylabel, guidefont=font(10,gc),guide_position=:right,showaxis=false,xticks=false,yticks=false,margin=5mm)
    for j in 1:ny+1
        jj = (ny+1) - j + 1
        ylj = yb2[2(j-1)+1:2*j]
        for i in 1:nx+1
            xli = xb2[2(i-1)+1:2*i]
            ix = (jj-1)*(nx+1) + i
            if (i == 1) & (j != 1)
                p[1+ix] = plot(X,Y, xlims=xli, ylims=ylj,framestyle=:default,legend=false,margin=0mm,lc=lc,tickfontsize=6,
                               xshowaxis=false,xticks=false,xscale=xscale,yscale=yscale, size=(size[1]*h[j],size[2]*w[i]))
            elseif (i != 1) & (j == 1) 
                showaxis=:x
                p[1+ix] = plot(X,Y, xlims=xli, ylims=ylj,framestyle=:default,legend=false,margin=0mm,lc=lc,tickfontsize=6,
                               yshowaxis=false,yticks=false,xscale=xscale,yscale=yscale, size=(size[1]*h[j],size[2]*w[i]))
            elseif (i == 1) & (j == 1)
                p[1+ix] = plot(X,Y, xlims=xli, ylims=ylj,framestyle=:default,legend=false,margin=0mm,lc=lc,tickfontsize=6,
                               xscale=xscale,yscale=yscale, size=(size[1]*h[j],size[2]*w[i]))
            else
                p[1+ix] = plot(X,Y, xlims=xli, ylims=ylj,framestyle=nothing,legend=false,margin=0mm,lc=lc,showaxis=false,
                               xticks=false,yticks=false,xscale=xscale,yscale=yscale, size=(size[1]*h[j],size[2]*w[i]))
            end
        end
    end
    p[end] = plot(xlabel=xlabel, guidefont=font(10,gc),guide_position=:top,showaxis=false,xticks=false,yticks=false,margin=5mm)

    plot(p..., layout=l, grid=false, size=size)
end


# Examples:
X = 1:2500.0
Y = 1000*(sin.(X/500)).^2 .+ 1

xb = [(500,800), (1900,2100)]
yb = [(100,300), (500,650), (850,900)]

theme(:default)
plot(X,Y, xlabel="Time [min]",ylabel="Trajectory altitude [m]", legend=false)

breakplot(X,Y,xb,yb; lc=:blue, xlabel="Time [min]",ylabel="Trajectory altitude [m]",ptheme=:ggplot2)

breakplot(X,Y,xb,yb; lc=:yellow, xlabel="Time [min]",ylabel="Trajectory altitude [m]")

breakplot(X,Y,xb,yb; lc=:yellow, xlabel="Time [min]",ylabel="Trajectory altitude [m]", xscale=:log10,yscale=:log10)

xb = []   # empty set for no breaks
yb = [(100,300)]
breakplot(X,Y,xb,yb; lc=:blue, xlabel="Time [min]",ylabel="Trajectory altitude [m]",ptheme=:ggplot2)

It seems nice but I cannot found the example code.
Can you share an example or any link?

@iHany, as requested the user function code and examples were updated above.
As indicated, this subplot business in Plots.jl and gr() is a bit shaky…
If you see things that can be obviously improved, please do share.

NB: there was a bug on the list of vertical proportions which were in reverse order. Fixed now.

1 Like

Ok…
I think that your remedy works fine but it needs additional efforts as you said.
It seems that there are already some issues reported in Plots.jl such as this, so subplot method would be the best for now.

Thanks for sharing your example :slight_smile: