Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Axes review #206

Closed
mschauer opened this issue Nov 1, 2018 · 5 comments
Closed

Axes review #206

mschauer opened this issue Nov 1, 2018 · 5 comments

Comments

@mschauer
Copy link
Contributor

mschauer commented Nov 1, 2018

For future (maybe far future) reference, I am reviewing some elements, properties of axes with examples. @mkborregaard

Axes can be realised as special margins or be displayed in the plot.

Elements of an axis

  • Axis location (at one of the margins or within the plot)
  • Axis lines
  • (Axis) arrows with arrowhead
  • Axis label, attached to or detached from arrow-head, e.g. measured quantity and unit
  • Major and minor tick marks with tick direction and length
  • Major and minor tick labels
  • Axis limits and transformation (log)

Related objects

  • Grids (or in ggplot style a grid as negative space)
  • Other typical margins are color bars in heatmaps, facet labels and histogram margins.

Axes, multiple plots and facets

Multiple plots can have different axes, these can be at different margins or at the same margin side by side.
Axes between facets can be aligned, and actually shared. Finally, unrelated axis of different facets can share design elements like
location and label font size.

Examples

Axis within the picture, with axis labels at arrow heads and outside ticks.

Axis with major tick marks corresponding to negative space in grid, no axis arrow.

ggplot2

Histogram or density margins

margins

Two axes, left and right, two axes on same side

axes

An example for facets with y axis shared, x axes not aligned.

facets

Mirrored axis sharing

Independent axes of same length, aligned, with same label font size

label

@mkborregaard
Copy link
Contributor

mkborregaard commented Nov 1, 2018

Great review, thanks! It's a nice overview of things I agree completely are important, multiple axes, major/minor ticks, arrowheads, axis name location, linking and scaling.

Three details I view slightly differently: I don't see a colorbar as an axis but as a legend element. And I don't see the histograms as axes but as a different subscene with (in this case) no frames and linked axis to the main plot. And I don't see ggplot2 gridlines as empty space, but white lines on grey background. Does that make sense to you?

In addition I'd add a distinction between frame and axis lines (your first image shows axis lines [with arrows], in the others the ticks lie on the frame; and it's possible to have both at the same time.)
E.g.
billede

@mschauer
Copy link
Contributor Author

mschauer commented Nov 1, 2018

Agreed, good points.

@SimonDanisch
Copy link
Member

Thanks a lot, that's an amazing overview :) Let's turn this into a documentation page and try to implement those one by one!!

@mkborregaard
Copy link
Contributor

I think that a nice Makie-an solution would be to have attributes for all of these under Axis for fine-grained control, but then define Axis Themes to be merged with the overall Theme that can specify attribute combinations with a single symbol?

@cadoubs
Copy link

cadoubs commented Jun 15, 2022

My proposal for multiple axes :

multipleaxes

Function multiaxes :

Could be renamed, improved and integrated into Makie

"""
```
function multiaxes(n::Int=3, fig::Figure=Figure();
        ylabels=["Axis \$i" for i in 1:6],
        positions=[:left, :right, :right, :left, :right, :left],
        colors=Makie.current_default_theme().palette.color.val,
        ytickpositions=[:right, :left, :left, :right, :left, :right])
```

Generates `n` axes for the same figure `f` with defined `ylabels`
Axes `positions` are either `:left` or `:right`
Axes `colors` are supplied as a list of valid colors e.g. `[:blue, :red]`
Positions of y ticks are defined int `ytickpositions` vector

Returns a vector of `n+m` generated axes 
    Axes `1` to `n` for plotting the graphs, these axes are x-linked together
    Axes `n+1` to `n+m` for scale bars reference

Axis 1 is the master axis which will be used for xlabels and zooming options


# Examples :
## Generate a new empty figure with 6 axes
```
axes = multiaxes(6); fig = axes[1].parent 
```
Axis 6 / Axis 4 / Axis 1 [] Axis 2 / Axis 3 / Axis 5

## Generate a 3 axis figure with some plots :
```
fig = Figure()
axes = multiaxes(3, fig)
lines!(axes[1], 0..10, cos, color = axes[1].ylabelcolor)
lines!(axes[2], 0..10, sin, color = axes[2].ylabelcolor)
lines!(axes[3], 0..10, x->2sin(2x), color = axes[3].ylabelcolor)
fig = axes[1].parent 
```
 Axis 1 (-1,1) [ ] Axis 2 (-1,1) / Axis 3 (-2,2)
"""
function multiaxes(n::Int=3, fig::Figure=Figure();
    ylabels=["Axis $i" for i in 1:6],
    positions=[:left, :right, :right, :left, :right, :left],
    colors=Makie.current_default_theme().palette.color.val,
    ytickpositions=[:right, :left, :left, :right, :left, :right],
    xlabel ="x")


    @assert all(x -> x ≥ n,
        length.([ylabels, positions, colors, ytickpositions])) "arguments lengths should at least match n"

    ax, ax2 = [], []

    # Central position of main axis where all plots are displayed
    centraln = sum(p == :left for p in positions[1:n])

    # Current position of left and right axes
    left, right = centraln .+ (1, -1)


    for i in 1:n
        # Update position for axis i
        if positions[i] == :left
            left -= 1
            pos = left
        else
            right += 1
            pos = right
        end

        c = colors[i]

        a = Axis(fig[1, centraln], yaxisposition=positions[i],
            ylabel=ylabels[i], xlabel=xlabel,
            yticklabelcolor=c, ytickcolor=c, ylabelcolor=c)

        if i > 1 # Hide x labels for other axes
            a.xticklabelsvisible = false
            a.xlabelvisible = false
        end

        ca = a
        if pos != centraln
            hidedecorations!(a)
            hidespines!(a)

            a2 = Axis(fig[1, pos], yaxisposition=positions[i],
                ylabel=ylabels[i],
                yticklabelcolor=c, ytickcolor=c, ylabelcolor=c)
            
            hidexdecorations!(a2)

            colsize!(fig.layout, pos, Auto(0))
            ca = a2

            linkyaxes!(a, a2)
            push!(ax2, a2)
        end

        if positions[i] == :left
            ca.leftspinecolor = c
            ca.rightspinevisible = false
            ca.ytickalign = ytickpositions[i] == :left ? 0 : 1
        else
            ca.rightspinecolor = c
            ca.leftspinevisible = false
            ca.ytickalign = ytickpositions[i] == :right ? 0 : 1
        end

        push!(ax, a)
    end

    linkxaxes!(ax...)

    return append!(ax, ax2)
end

And code to make the sample figure :

using CairoMakie
fig = Figure(colorsgroundcolor=:white, resolution=(600, 500))

ax = multiaxes(3, fig,
    ylabels=[L"Deposition Pressure (Torr)$$",
        L"Annealing Temperature $(^{\circ}$C)",
        L"$\Delta T_C$ $(^{\circ}$K)"],
    xlabel=L"Transition Temperature $(^{\circ}$K)",
    colors=[:green, :red, :blue],
    ytickpositions=[:left, :left, :left]
)
x = 90:0.1:91
s1 = scatter!(ax[1], x, x -> rand() * 10.0^rand(-2:2),
             marker=:utriangle, markersize=16, color=ax[1].ylabelcolor)
ax[1].yscale = log10
ax[1].yminorticksvisible = true
ax[1].yminorticks = [x*10^y for x in 1.0:9.0, y in -4.0:1][:]
ylims!(ax[1],1e-4, 100)

x = 84:90

y = @. 780 + 10sin(x-2)
low_eb = high_eb = fill(2, length(x))
errorbars!(ax[2], x, y, low_eb, high_eb, whiskerwidth=10, color=:black, linewidth=1)
s2 = scatter!(ax[2], x, y, marker=:rect, markersize=16, color=ax[2].ylabelcolor)
ylims!(ax[2], 765,795)

y = @. 0.6(x-82) + 0.2sin(x)
lines!(ax[3], x, y, color=ax[3].ylabelcolor)
s3 = scatter!(ax[3], x, y, marker=:circle, markersize=16, color=ax[3].ylabelcolor)
ylims!(ax[3], 0, 6)

for i in 1:3
    xlims!(ax[i], 93, 82)
    ax[i].xgridvisible = false
    ax[i].ygridvisible = false
end

axislegend(ax[1], [s1,s2, s3], [L"$$As Grown",L"$$Annealed",L"\Delta T_C"])

Label(fig[0, :], text=L"Characteristics of Samples Grown Under Different Conditions$$")
fig

Some comments regarding the making of this figure :

  • linkxaxes! does not work with xlims! in "reverse" case
  • Underscore _ symbol does not subscript text this is the reason for using LatexStrings
  • On my system (Windows) LatexStrings do not display degree ° character correctly (switch it to another symbol)
  • $^{circ}$ requires a symbol before to make it superscript, $(^{\circ}$ works

I hope this will be helpful for many

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants