working on linked subplots

This commit is contained in:
Thomas Breloff 2015-10-08 17:44:00 -04:00
parent 1115ff83bb
commit f4b716b255
4 changed files with 350 additions and 16 deletions

239
examples/facets.ipynb Normal file
View File

@ -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
}

View File

@ -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])

View File

@ -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)

View File

@ -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