From b08212e2f94fa52354947b08613372a8ac140ef5 Mon Sep 17 00:00:00 2001 From: Thomas Breloff Date: Thu, 10 Mar 2016 23:38:14 -0500 Subject: [PATCH] more layouts --- src/layouts.jl | 138 +++++++++++++++++++++++++++++++++++-------------- src/subplot.jl | 91 ++++++++++++++++---------------- src/types.jl | 31 +---------- 3 files changed, 143 insertions(+), 117 deletions(-) diff --git a/src/layouts.jl b/src/layouts.jl index f8952b86..76f1bde8 100644 --- a/src/layouts.jl +++ b/src/layouts.jl @@ -1,4 +1,102 @@ +# ----------------------------------------------------------- +# GridLayout +# ----------------------------------------------------------- + +"Simple grid, indices are row-major." +immutable GridLayout <: SubplotLayout + nr::Int + nc::Int +end + +Base.length(layout::GridLayout) = layout.nr * layout.nc +Base.start(layout::GridLayout) = 1 +Base.done(layout::GridLayout, state) = state > length(layout) +function Base.next(layout::GridLayout, state) + r = div(state-1, layout.nc) + 1 + c = mod1(state, layout.nc) + (r,c), state + 1 +end + +nrows(layout::GridLayout) = layout.nr +ncols(layout::GridLayout) = layout.nc +ncols(layout::GridLayout, row::Int) = layout.nc + +# get the plot index given row and column +Base.getindex(layout::GridLayout, r::Int, c::Int) = (r-1) * layout.nc + c + +# ----------------------------------------------------------- +# RowsLayout +# ----------------------------------------------------------- + +"Number of plots per row" +immutable RowsLayout <: SubplotLayout + numplts::Int + rowcounts::AbstractVector{Int} +end + +Base.length(layout::RowsLayout) = layout.numplts +Base.start(layout::RowsLayout) = 1 +Base.done(layout::RowsLayout, state) = state > length(layout) +function Base.next(layout::RowsLayout, state) + r = 1 + c = 0 + for i = 1:state + c += 1 + if c > layout.rowcounts[r] + r += 1 + c = 1 + end + end + (r,c), state + 1 +end + +nrows(layout::RowsLayout) = length(layout.rowcounts) +ncols(layout::RowsLayout, row::Int) = row < 1 ? 0 : (row > nrows(layout) ? 0 : layout.rowcounts[row]) + +# get the plot index given row and column +Base.getindex(layout::RowsLayout, r::Int, c::Int) = sum(layout.rowcounts[1:r-1]) + c + +# ----------------------------------------------------------- +# FlexLayout +# ----------------------------------------------------------- + +"Flexible, nested layout with optional size percentages." +immutable FlexLayout <: SubplotLayout + n::Int + grid::Matrix # Nested layouts. Each position + # can be a plot index or another FlexLayout + widths::Vector{Float64} + heights::Vector{Float64} +end + +typealias IntOrFlex Union{Int,FlexLayout} + +Base.length(layout::FlexLayout) = layout.n +Base.start(layout::FlexLayout) = 1 +Base.done(layout::FlexLayout, state) = state > length(layout) +function Base.next(layout::FlexLayout, state) + # TODO: change this method to return more info + # TODO: might consider multiple iterator types.. some backends might have an easier time row-by-row for example + error() + r = 1 + c = 0 + for i = 1:state + c += 1 + if c > layout.rowcounts[r] + r += 1 + c = 1 + end + end + (r,c), state + 1 +end + +nrows(layout::FlexLayout) = size(layout.grid, 1) +ncols(layout::FlexLayout, row::Int) = size(layout.grid, 2) + +# get the plot index given row and column +Base.getindex(layout::FlexLayout, r::Int, c::Int) = layout.grid[r,c] + # ----------------------------------------------------------- # we're taking in a nested structure of some kind... parse it out and build a FlexLayout @@ -78,43 +176,3 @@ function subplotlayout(numplts::Int, nr::Int, nc::Int) RowsLayout(numplts, rowcounts) end - - - -Base.length(layout::RowsLayout) = layout.numplts -Base.start(layout::RowsLayout) = 1 -Base.done(layout::RowsLayout, state) = state > length(layout) -function Base.next(layout::RowsLayout, state) - r = 1 - c = 0 - for i = 1:state - c += 1 - if c > layout.rowcounts[r] - r += 1 - c = 1 - end - end - (r,c), state + 1 -end - -nrows(layout::RowsLayout) = length(layout.rowcounts) -ncols(layout::RowsLayout, row::Int) = row < 1 ? 0 : (row > nrows(layout) ? 0 : layout.rowcounts[row]) - -# get the plot index given row and column -Base.getindex(layout::RowsLayout, r::Int, c::Int) = sum(layout.rowcounts[1:r-1]) + c - -Base.length(layout::GridLayout) = layout.nr * layout.nc -Base.start(layout::GridLayout) = 1 -Base.done(layout::GridLayout, state) = state > length(layout) -function Base.next(layout::GridLayout, state) - r = div(state-1, layout.nc) + 1 - c = mod1(state, layout.nc) - (r,c), state + 1 -end - -nrows(layout::GridLayout) = layout.nr -ncols(layout::GridLayout) = layout.nc -ncols(layout::GridLayout, row::Int) = layout.nc - -# get the plot index given row and column -Base.getindex(layout::GridLayout, r::Int, c::Int) = (r-1) * layout.nc + c diff --git a/src/subplot.jl b/src/subplot.jl index 5bad03ac..573104eb 100644 --- a/src/subplot.jl +++ b/src/subplot.jl @@ -1,53 +1,18 @@ -Base.getindex(subplt::Subplot, args...) = subplt.plts[subplt.layout[args...]] - -# handle "linking" the subplot axes together -# each backend should implement the _remove_axis and _expand_limits methods -function link_axis(subplt::Subplot, isx::Bool) - - # collect the list of plots and the expanded limits for those plots that should be linked on this axis - includedPlots = Any[] - # lims = [Inf, -Inf] - lims = Dict{Int,Any}() # maps column to xlim - for (i,(r,c)) in enumerate(subplt.layout) - - # shouldlink will be a bool or nothing. if nothing, then use linkx/y (which is true if we get to this code) - shouldlink = subplt.linkfunc(r,c)[isx ? 1 : 2] - if shouldlink == nothing || shouldlink - plt = subplt.plts[i] - - # if we don't have this - k = isx ? c : r - if (firstone = !haskey(lims, k)) - lims[k] = [Inf, -Inf] - end - - isinner = (isx && r < nrows(subplt.layout)) || (!isx && !firstone) - push!(includedPlots, (plt, isinner, k)) - - _expand_limits(lims[k], plt, isx) - end - - end - - # do the axis adjustments - for (plt, isinner, k) in includedPlots - if isinner - _remove_axis(plt, isx) - end - (isx ? xlims! : ylims!)(plt, lims[k]...) - end -end - - - # ------------------------------------------------------------ - Base.string(subplt::Subplot) = "Subplot{$(subplt.backend) p=$(subplt.p) n=$(subplt.n)}" Base.print(io::IO, subplt::Subplot) = print(io, string(subplt)) Base.show(io::IO, subplt::Subplot) = print(io, string(subplt)) +function Base.copy(subplt::Subplot) + subplot(subplt.plts, subplt.layout, subplt.plotargs) +end + +Base.getindex(subplt::Subplot, args...) = subplt.plts[subplt.layout[args...]] + +# -------------------------------------------------------------------- + getplot(subplt::Subplot, idx::Int = subplt.n) = subplt.plts[mod1(idx, subplt.p)] getplotargs(subplt::Subplot, idx::Int) = getplot(subplt, idx).plotargs convertSeriesIndex(subplt::Subplot, n::Int) = ceil(Int, n / subplt.p) @@ -297,10 +262,42 @@ function _add_series_subplot(plt::Plot, args...; kw...) warnOnUnsupportedScales(plt.backend, d) end - - # -------------------------------------------------------------------- -function Base.copy(subplt::Subplot) - subplot(subplt.plts, subplt.layout, subplt.plotargs) +# handle "linking" the subplot axes together +# each backend should implement the _remove_axis and _expand_limits methods +function link_axis(subplt::Subplot, isx::Bool) + + # collect the list of plots and the expanded limits for those plots that should be linked on this axis + includedPlots = Any[] + # lims = [Inf, -Inf] + lims = Dict{Int,Any}() # maps column to xlim + for (i,(r,c)) in enumerate(subplt.layout) + + # shouldlink will be a bool or nothing. if nothing, then use linkx/y (which is true if we get to this code) + shouldlink = subplt.linkfunc(r,c)[isx ? 1 : 2] + if shouldlink == nothing || shouldlink + plt = subplt.plts[i] + + # if we don't have this + k = isx ? c : r + if (firstone = !haskey(lims, k)) + lims[k] = [Inf, -Inf] + end + + isinner = (isx && r < nrows(subplt.layout)) || (!isx && !firstone) + push!(includedPlots, (plt, isinner, k)) + + _expand_limits(lims[k], plt, isx) + end + + end + + # do the axis adjustments + for (plt, isinner, k) in includedPlots + if isinner + _remove_axis(plt, isx) + end + (isx ? xlims! : ylims!)(plt, lims[k]...) + end end diff --git a/src/types.jl b/src/types.jl index 95529ad7..b50c0fe3 100644 --- a/src/types.jl +++ b/src/types.jl @@ -20,40 +20,11 @@ type Plot{T<:AbstractBackend} <: AbstractPlot{T} end # ----------------------------------------------------------- -# Layouts +# Layout # ----------------------------------------------------------- abstract SubplotLayout -# ----------------------------------------------------------- - -"Simple grid, indices are row-major." -immutable GridLayout <: SubplotLayout - nr::Int - nc::Int -end - -# ----------------------------------------------------------- - -"Number of plots per row" -immutable RowsLayout <: SubplotLayout - numplts::Int - rowcounts::AbstractVector{Int} -end - -# ----------------------------------------------------------- - -"Flexible, nested layout with optional size percentages." -immutable FlexLayout <: SubplotLayout - n::Int - grid::Matrix # Nested layouts. Each position - # can be a plot index or another FlexLayout - widths::Vector{Float64} - heights::Vector{Float64} -end - -typealias IntOrFlex Union{Int,FlexLayout} - # ----------------------------------------------------------- # Subplot # -----------------------------------------------------------