diff --git a/examples/facets.ipynb b/examples/facets.ipynb new file mode 100644 index 00000000..7a10999b --- /dev/null +++ b/examples/facets.ipynb @@ -0,0 +1,239 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "INFO: Recompiling stale cache file /home/tom/.julia/lib/v0.4/Plots.ji for module Plots.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[Plots.jl] Default backend: immerse\n", + "[Plots.jl] Switched to backend: gadfly" + ] + } + ], + "source": [ + "using Plots\n", + "gadfly()\n", + "default(leg=false);\n", + "#Plots._debugMode.on=true;" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "ename": "LoadError", + "evalue": "LoadError: UndefVarError: GadflyPackage not defined\nwhile loading In[2], in expression starting on line 2", + "output_type": "error", + "traceback": [ + "LoadError: UndefVarError: GadflyPackage not defined\nwhile loading In[2], in expression starting on line 2", + "" + ] + } + ], + "source": [ + "# link the subplots together to share axes... useful for facet plots, cross-scatters, etc\n", + "function linkPlots(subplt::Plots.Subplot{GadflyPackage})\n", + "end" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "[Plots.jl] Initializing backend: gadfly" + ] + } + ], + "source": [ + "y = linspace(0,1,100)\n", + "p = subplot(repmat(y,1,4),n=4);" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "ename": "ErrorException", + "evalue": "type GridLayout has no field rowcounts", + "output_type": "error", + "traceback": [ + "type GridLayout has no field rowcounts", + "", + " in buildGadflySubplotContext at /home/tom/.julia/v0.4/Plots/src/backends/gadfly.jl:497", + " in writemime at /home/tom/.julia/v0.4/Plots/src/backends/gadfly.jl:523", + " in base64encode at base64.jl:160", + " in display_dict at /home/tom/.julia/v0.4/IJulia/src/execute_request.jl:32" + ] + } + ], + "source": [ + "i = 1\n", + "subplot!(ylabel=[\"y1\",\"y1\",\"y2\",\"y2\"], xlabel=[\"x1\",\"x2\",\"x1\",\"x2\"])\n", + "# findGuideAndSet(gplt, t::DataType, s::@compat(AbstractString))\n", + "for (i,(r,c)) in enumerate(p.layout)\n", + "# for (r,nc) in enumerate(p.layout.rowcounts)\n", + "# for c in 1:nc\n", + " gplt = p.plts[i].o\n", + " if r < Plots.nrows(p.layout)\n", + " push!(gplt.guides, Gadfly.Guide.xticks(label=false))\n", + " Plots.findGuideAndSet(gplt, Gadfly.Guide.xlabel, \"\")\n", + " end\n", + " if c > 1\n", + " push!(gplt.guides, Gadfly.Guide.yticks(label=false))\n", + " Plots.findGuideAndSet(gplt, Gadfly.Guide.ylabel, \"\")\n", + " end\n", + "end\n", + "#p1 = p.plts[1].o\n", + "#push!(p1.guides, Gadfly.Guide.xticks(label=false,ticks=nothing))\n", + "p" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "p.layout.rowcounts" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "\n", + "immutable FlexLayout \n", + " numplts::Int\n", + " rowcounts::AbstractVector{Int}\n", + "end\n", + "\n", + "immutable GridLayout \n", + " nr::Int\n", + " nc::Int\n", + "end" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "\n", + "\n", + "Base.length(layout::FlexLayout) = layout.numplts\n", + "Base.start(layout::FlexLayout) = 1\n", + "Base.done(layout::FlexLayout, state) = state > length(layout)\n", + "function Base.next(layout::FlexLayout, state)\n", + " r = 1\n", + " c = 0\n", + " for i = 1:state\n", + " c += 1\n", + " if c > layout.rowcounts[r]\n", + " r += 1\n", + " c = 1\n", + " end\n", + " end\n", + " (r,c), state + 1\n", + "end\n", + "\n", + "\n", + "Base.length(layout::GridLayout) = layout.nr * layout.nc\n", + "Base.start(layout::GridLayout) = 1\n", + "Base.done(layout::GridLayout, state) = state > length(layout)\n", + "function Base.next(layout::GridLayout, state)\n", + " r = div(state, layout.nc)\n", + " c = mod1(state, layout.nc)\n", + " (r,c), state + 1\n", + "end" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "fl = FlexLayout(5, [2,1,2])\n", + "gl = GridLayout(3,2)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "for (r,c) in gl\n", + " @show r,c\n", + "end\n", + "length(gl)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Julia 0.4.0-rc4", + "language": "julia", + "name": "julia-0.4" + }, + "language_info": { + "file_extension": ".jl", + "mimetype": "application/julia", + "name": "julia", + "version": "0.4.0" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/src/backends/gadfly.jl b/src/backends/gadfly.jl index 3ac8d9f5..56fee071 100644 --- a/src/backends/gadfly.jl +++ b/src/backends/gadfly.jl @@ -431,15 +431,17 @@ function plot!(::GadflyPackage, plt::Plot; kw...) end -function findGuideAndSet(gplt, t::DataType, s::@compat(AbstractString)) + +function findGuideAndSet(gplt, t::DataType, args...; kw...) #s::@compat(AbstractString)) for (i,guide) in enumerate(gplt.guides) if isa(guide, t) - gplt.guides[i] = t(s) - # guide.label = s + gplt.guides[i] = t(args...; kw...) end end end + + function updateGadflyGuides(gplt, d::Dict) haskey(d, :title) && findGuideAndSet(gplt, Gadfly.Guide.title, d[:title]) haskey(d, :xlabel) && findGuideAndSet(gplt, Gadfly.Guide.xlabel, d[:xlabel]) diff --git a/src/subplot.jl b/src/subplot.jl index b766ba92..cdc2d50f 100644 --- a/src/subplot.jl +++ b/src/subplot.jl @@ -1,10 +1,16 @@ +function subplotlayout(sz::@compat(Tuple{Int,Int})) + # create a GridLayout + GridLayout(sz...) +end -# create a layout directly -SubplotLayout(rowcounts::AbstractVector{Int}) = SubplotLayout(sum(rowcounts), rowcounts) +function subplotlayout(rowcounts::AVec{Int}) + # create a FlexLayout + FlexLayout(sum(rowcounts), rowcounts) +end + +function subplotlayout(numplts::Int, nr::Int, nc::Int) -# create a layout given counts... nr/nc == -1 implies we figure out a good number automatically -function SubplotLayout(numplts::Int, nr::Int, nc::Int) # figure out how many rows/columns we need if nr == -1 @@ -18,6 +24,11 @@ function SubplotLayout(numplts::Int, nr::Int, nc::Int) nc = ceil(Int, numplts / nr) end + # if it's a perfect rectangle, just create a grid + if numplts == nr * nc + return GridLayout(nr, nc) + end + # create the rowcounts vector i = 0 rowcounts = Int[] @@ -30,8 +41,68 @@ function SubplotLayout(numplts::Int, nr::Int, nc::Int) SubplotLayout(numplts, rowcounts) end +# # create a layout directly +# SubplotLayout(rowcounts::AbstractVector{Int}) = SubplotLayout(sum(rowcounts), rowcounts) + +# # create a layout given counts... nr/nc == -1 implies we figure out a good number automatically +# function SubplotLayout(numplts::Int, nr::Int, nc::Int) + +# # figure out how many rows/columns we need +# if nr == -1 +# if nc == -1 +# nr = round(Int, sqrt(numplts)) +# nc = ceil(Int, numplts / nr) +# else +# nr = ceil(Int, numplts / nc) +# end +# else +# nc = ceil(Int, numplts / nr) +# end + +# # create the rowcounts vector +# i = 0 +# rowcounts = Int[] +# for r in 1:nr +# cnt = min(nc, numplts - i) +# push!(rowcounts, cnt) +# i += cnt +# end + +# SubplotLayout(numplts, rowcounts) +# end + + +Base.length(layout::FlexLayout) = layout.numplts +Base.start(layout::FlexLayout) = 1 +Base.done(layout::FlexLayout, state) = state > length(layout) +function Base.next(layout::FlexLayout, 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::FlexLayout) = length(layout.rowcounts) +ncols(layout::FlexLayout, row::Int) = row < 1 ? 0 : (row > nrows(layout) ? 0 : layout.rowcounts[row]) + +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, layout.nc) + c = mod1(state, layout.nc) + (r,c), state + 1 +end + +nrows(layout::GridLayout) = layout.nr +ncols(layout::GridLayout) = layout.nc -Base.length(layout::SubplotLayout) = layout.numplts # ------------------------------------------------------------ @@ -70,14 +141,14 @@ function subplot(args...; kw...) # figure out the layout layoutarg = get(d, :layout, nothing) - # if haskey(d, :layout) if layoutarg != nothing - layout = SubplotLayout(layoutarg) + layout = subplotlayout(layoutarg) else - if !haskey(d, :n) || d[:n] < 0 + n = get(d, :n, -1) + if n < 0 error("You must specify either layout or n when creating a subplot: ", d) end - layout = SubplotLayout(d[:n], get(d, :nr, -1), get(d, :nc, -1)) + layout = subplotlayout(n, get(d, :nr, -1), get(d, :nc, -1)) end # initialize the individual plots @@ -128,9 +199,10 @@ function subplot!(subplt::Subplot, args...; kw...) d = Dict(kw) preprocessArgs!(d) - for k in keys(_plotDefaults) - delete!(d, k) - end + # for k in keys(_plotDefaults) + # delete!(d, k) + # end + dumpdict(d, "After subplot! preprocessing") kwList, xmeta, ymeta = createKWargsList(subplt, args...; d...) @@ -140,6 +212,7 @@ function subplot!(subplt::Subplot, args...; kw...) subplt.n += 1 plt = getplot(subplt) # get the Plot object where this series will be drawn di[:show] = false + dumpdict(di, "subplot! kwList $i") plot!(plt; di...) end @@ -149,6 +222,19 @@ function subplot!(subplt::Subplot, args...; kw...) subplt.initialized = true end + + # add title, axis labels, ticks, etc + for (i,plt) in enumerate(subplt.plts) + di = copy(d) + for (k,v) in di + if typeof(v) <: AVec + di[k] = v[mod1(i, length(v))] + end + end + dumpdict(di, "Updating sp $i") + updatePlotItems(plt, di) + end + # set this to be current current(subplt) diff --git a/src/types.jl b/src/types.jl index 19d20f98..103aaffd 100644 --- a/src/types.jl +++ b/src/types.jl @@ -18,7 +18,14 @@ type Plot{T<:PlottingPackage} <: PlottingObject{T} end -type SubplotLayout +abstract SubplotLayout + +immutable GridLayout <: SubplotLayout + nr::Int + nc::Int +end + +immutable FlexLayout <: SubplotLayout numplts::Int rowcounts::AbstractVector{Int} end