working on subplots

This commit is contained in:
Thomas Breloff 2016-05-16 01:07:33 -04:00
parent e9ab6e7301
commit c5bcae1e34
22 changed files with 483 additions and 412 deletions

View File

@ -14,10 +14,11 @@ export
AbstractPlot, AbstractPlot,
Plot, Plot,
Subplot, Subplot,
SubplotLayout, AbstractLayout,
GridLayout, GridLayout,
RowsLayout, EmptyLayout,
FlexLayout, # RowsLayout,
# FlexLayout,
AVec, AVec,
AMat, AMat,
KW, KW,

View File

@ -156,6 +156,7 @@ _seriesDefaults[:weights] = nothing # optional weights for histograms
_seriesDefaults[:contours] = false # add contours to 3d surface and wireframe plots _seriesDefaults[:contours] = false # add contours to 3d surface and wireframe plots
_seriesDefaults[:match_dimensions] = false # do rows match x (true) or y (false) for heatmap/image/spy? see issue 196 _seriesDefaults[:match_dimensions] = false # do rows match x (true) or y (false) for heatmap/image/spy? see issue 196
# this ONLY effects whether or not the z-matrix is transposed for a heatmap display! # this ONLY effects whether or not the z-matrix is transposed for a heatmap display!
_seriesDefaults[:subplot_index] = :auto
const _plotDefaults = KW() const _plotDefaults = KW()

View File

@ -48,8 +48,8 @@ include("backends/web.jl")
plot(pkg::AbstractBackend; kw...) = error("plot($pkg; kw...) is not implemented") plot(pkg::AbstractBackend; kw...) = error("plot($pkg; kw...) is not implemented")
plot!(pkg::AbstractBackend, plt::Plot; kw...) = error("plot!($pkg, plt; kw...) is not implemented") plot!(pkg::AbstractBackend, plt::Plot; kw...) = error("plot!($pkg, plt; kw...) is not implemented")
_update_plot(pkg::AbstractBackend, plt::Plot, d::KW) = error("_update_plot($pkg, plt, d) is not implemented") _update_plot(pkg::AbstractBackend, plt::Plot, d::KW) = error("_update_plot($pkg, plt, d) is not implemented")
subplot(pkg::AbstractBackend; kw...) = error("subplot($pkg; kw...) is not implemented") # subplot(pkg::AbstractBackend; kw...) = error("subplot($pkg; kw...) is not implemented")
subplot!(pkg::AbstractBackend, subplt::Subplot; kw...) = error("subplot!($pkg, subplt; kw...) is not implemented") # subplot!(pkg::AbstractBackend, subplt::Subplot; kw...) = error("subplot!($pkg, subplt; kw...) is not implemented")
# don't do anything as a default # don't do anything as a default
_create_backend_figure(plt::Plot) = nothing _create_backend_figure(plt::Plot) = nothing

View File

@ -209,10 +209,10 @@ end
# ---------------------------------------------------------------- # ----------------------------------------------------------------
function _create_subplot(subplt::Subplot{BokehBackend}, isbefore::Bool) # function _create_subplot(subplt::Subplot{BokehBackend}, isbefore::Bool)
# TODO: build the underlying Subplot object. this is where you might layout the panes within a GUI window, for example # # TODO: build the underlying Subplot object. this is where you might layout the panes within a GUI window, for example
#
end # end
function _expand_limits(lims, plt::Plot{BokehBackend}, isx::Bool) function _expand_limits(lims, plt::Plot{BokehBackend}, isx::Bool)
@ -234,6 +234,6 @@ function Base.display(::PlotsDisplay, plt::Plot{BokehBackend})
Bokeh.showplot(plt.o) Bokeh.showplot(plt.o)
end end
function Base.display(::PlotsDisplay, plt::Subplot{BokehBackend}) # function Base.display(::PlotsDisplay, plt::Subplot{BokehBackend})
# TODO: display/show the subplot # # TODO: display/show the subplot
end # end

View File

@ -626,12 +626,12 @@ end
# ---------------------------------------------------------------- # ----------------------------------------------------------------
# create the underlying object (each backend will do this differently) # # create the underlying object (each backend will do this differently)
function _create_subplot(subplt::Subplot{GadflyBackend}, isbefore::Bool) # function _create_subplot(subplt::Subplot{GadflyBackend}, isbefore::Bool)
isbefore && return false # wait until after plotting to create the subplots # isbefore && return false # wait until after plotting to create the subplots
subplt.o = nothing # subplt.o = nothing
true # true
end # end
function _remove_axis(plt::Plot{GadflyBackend}, isx::Bool) function _remove_axis(plt::Plot{GadflyBackend}, isx::Bool)
@ -651,31 +651,31 @@ end
getGadflyContext(plt::Plot{GadflyBackend}) = plt.o getGadflyContext(plt::Plot{GadflyBackend}) = plt.o
getGadflyContext(subplt::Subplot{GadflyBackend}) = buildGadflySubplotContext(subplt) # getGadflyContext(subplt::Subplot{GadflyBackend}) = buildGadflySubplotContext(subplt)
# create my Compose.Context grid by hstacking and vstacking the Gadfly.Plot objects # # create my Compose.Context grid by hstacking and vstacking the Gadfly.Plot objects
function buildGadflySubplotContext(subplt::Subplot) # function buildGadflySubplotContext(subplt::Subplot)
rows = Any[] # rows = Any[]
row = Any[] # row = Any[]
for (i,(r,c)) in enumerate(subplt.layout) # for (i,(r,c)) in enumerate(subplt.layout)
#
# add the Plot object to the row # # add the Plot object to the row
push!(row, getGadflyContext(subplt.plts[i])) # push!(row, getGadflyContext(subplt.plts[i]))
#
# add the row # # add the row
if c == ncols(subplt.layout, r) # if c == ncols(subplt.layout, r)
push!(rows, Gadfly.hstack(row...)) # push!(rows, Gadfly.hstack(row...))
row = Any[] # row = Any[]
end # end
end # end
#
# stack the rows # # stack the rows
Gadfly.vstack(rows...) # Gadfly.vstack(rows...)
end # end
setGadflyDisplaySize(w,h) = Compose.set_default_graphic_size(w * Compose.px, h * Compose.px) setGadflyDisplaySize(w,h) = Compose.set_default_graphic_size(w * Compose.px, h * Compose.px)
setGadflyDisplaySize(plt::Plot) = setGadflyDisplaySize(plt.plotargs[:size]...) setGadflyDisplaySize(plt::Plot) = setGadflyDisplaySize(plt.plotargs[:size]...)
setGadflyDisplaySize(subplt::Subplot) = setGadflyDisplaySize(getplotargs(subplt, 1)[:size]...) # setGadflyDisplaySize(subplt::Subplot) = setGadflyDisplaySize(getplotargs(subplt, 1)[:size]...)
# ------------------------------------------------------------------------- # -------------------------------------------------------------------------
@ -708,39 +708,39 @@ function Base.display(::PlotsDisplay, plt::Plot{GadflyBackend})
end end
function Base.display(::PlotsDisplay, subplt::Subplot{GadflyBackend}) # function Base.display(::PlotsDisplay, subplt::Subplot{GadflyBackend})
setGadflyDisplaySize(getplotargs(subplt,1)[:size]...) # setGadflyDisplaySize(getplotargs(subplt,1)[:size]...)
ctx = buildGadflySubplotContext(subplt) # ctx = buildGadflySubplotContext(subplt)
#
# taken from Gadfly since I couldn't figure out how to do it directly # # taken from Gadfly since I couldn't figure out how to do it directly
#
filename = string(Gadfly.tempname(), ".html") # filename = string(Gadfly.tempname(), ".html")
output = open(filename, "w") # output = open(filename, "w")
#
plot_output = IOBuffer() # plot_output = IOBuffer()
Gadfly.draw(Gadfly.SVGJS(plot_output, Compose.default_graphic_width, # Gadfly.draw(Gadfly.SVGJS(plot_output, Compose.default_graphic_width,
Compose.default_graphic_height, false), ctx) # Compose.default_graphic_height, false), ctx)
plotsvg = takebuf_string(plot_output) # plotsvg = takebuf_string(plot_output)
#
write(output, # write(output,
""" # """
<!DOCTYPE html> # <!DOCTYPE html>
<html> # <html>
<head> # <head>
<title>Gadfly Plot</title> # <title>Gadfly Plot</title>
<meta charset="utf-8"> # <meta charset="utf-8">
</head> # </head>
<body> # <body>
<script charset="utf-8"> # <script charset="utf-8">
$(readall(Compose.snapsvgjs)) # $(readall(Compose.snapsvgjs))
</script> # </script>
<script charset="utf-8"> # <script charset="utf-8">
$(readall(Gadfly.gadflyjs)) # $(readall(Gadfly.gadflyjs))
</script> # </script>
$(plotsvg) # $(plotsvg)
</body> # </body>
</html> # </html>
""") # """)
close(output) # close(output)
Gadfly.open_file(filename) # Gadfly.open_file(filename)
end # end

View File

@ -143,9 +143,9 @@ end
# ---------------------------------------------------------------- # ----------------------------------------------------------------
function _create_subplot(subplt::Subplot{GLVisualizeBackend}) # function _create_subplot(subplt::Subplot{GLVisualizeBackend})
# TODO: build the underlying Subplot object. this is where you might layout the panes within a GUI window, for example # # TODO: build the underlying Subplot object. this is where you might layout the panes within a GUI window, for example
end # end
function _expand_limits(lims, plt::Plot{GLVisualizeBackend}, isx::Bool) function _expand_limits(lims, plt::Plot{GLVisualizeBackend}, isx::Bool)
# TODO: call expand limits for each plot data # TODO: call expand limits for each plot data
@ -169,6 +169,6 @@ function Base.display(::PlotsDisplay, plt::Plot{GLVisualizeBackend})
# wouldn't actually need to do anything # wouldn't actually need to do anything
end end
function Base.display(::PlotsDisplay, plt::Subplot{GLVisualizeBackend}) # function Base.display(::PlotsDisplay, plt::Subplot{GLVisualizeBackend})
# TODO: display/show the subplot # # TODO: display/show the subplot
end # end

View File

@ -832,21 +832,21 @@ function gr_display(plt::Plot{GRBackend}, clear=true, update=true,
update && GR.updatews() update && GR.updatews()
end end
function gr_display(subplt::Subplot{GRBackend}) # function gr_display(subplt::Subplot{GRBackend})
clear = true # clear = true
update = false # update = false
l = enumerate(subplt.layout) # l = enumerate(subplt.layout)
nr = nrows(subplt.layout) # nr = nrows(subplt.layout)
for (i, (r, c)) in l # for (i, (r, c)) in l
nc = ncols(subplt.layout, r) # nc = ncols(subplt.layout, r)
if i == length(l) # if i == length(l)
update = true # update = true
end # end
subplot = [(c-1)/nc, c/nc, 1-r/nr, 1-(r-1)/nr] # subplot = [(c-1)/nc, c/nc, 1-r/nr, 1-(r-1)/nr]
gr_display(subplt.plts[i], clear, update, subplot) # gr_display(subplt.plts[i], clear, update, subplot)
clear = false # clear = false
end # end
end # end
# function _create_plot(pkg::GRBackend, d::KW) # function _create_plot(pkg::GRBackend, d::KW)
# Plot(nothing, pkg, 0, d, KW[]) # Plot(nothing, pkg, 0, d, KW[])
@ -948,7 +948,7 @@ function Base.display(::PlotsDisplay, plt::Plot{GRBackend})
gr_display(plt) gr_display(plt)
end end
function Base.display(::PlotsDisplay, plt::Subplot{GRBackend}) # function Base.display(::PlotsDisplay, plt::Subplot{GRBackend})
gr_display(plt) # gr_display(plt)
true # true
end # end

View File

@ -88,51 +88,51 @@ end
# ---------------------------------------------------------------- # ----------------------------------------------------------------
function _create_subplot(subplt::Subplot{ImmerseBackend}, isbefore::Bool) # function _create_subplot(subplt::Subplot{ImmerseBackend}, isbefore::Bool)
return false # return false
# isbefore && return false # # isbefore && return false
end # end
#
function showSubplotObject(subplt::Subplot{ImmerseBackend}) # function showSubplotObject(subplt::Subplot{ImmerseBackend})
# create the Gtk window with vertical box vsep # # create the Gtk window with vertical box vsep
d = getplotargs(subplt,1) # d = getplotargs(subplt,1)
w,h = d[:size] # w,h = d[:size]
vsep = Gtk.GtkBoxLeaf(:v) # vsep = Gtk.GtkBoxLeaf(:v)
win = Gtk.GtkWindowLeaf(vsep, d[:windowtitle], w, h) # win = Gtk.GtkWindowLeaf(vsep, d[:windowtitle], w, h)
#
figindices = [] # figindices = []
row = Gtk.GtkBoxLeaf(:h) # row = Gtk.GtkBoxLeaf(:h)
push!(vsep, row) # push!(vsep, row)
for (i,(r,c)) in enumerate(subplt.layout) # for (i,(r,c)) in enumerate(subplt.layout)
plt = subplt.plts[i] # plt = subplt.plts[i]
#
# get the components... box is the main plot GtkBox, and canvas is the GtkCanvas where it's plotted # # get the components... box is the main plot GtkBox, and canvas is the GtkCanvas where it's plotted
box, toolbar, canvas = Immerse.createPlotGuiComponents() # box, toolbar, canvas = Immerse.createPlotGuiComponents()
#
# add the plot's box to the row # # add the plot's box to the row
push!(row, box) # push!(row, box)
#
# create the figure and store the index returned for destruction later # # create the figure and store the index returned for destruction later
figidx = Immerse.figure(canvas) # figidx = Immerse.figure(canvas)
push!(figindices, figidx) # push!(figindices, figidx)
#
fig = Immerse.figure(figidx) # fig = Immerse.figure(figidx)
plt.o = (fig, plt.o[2]) # plt.o = (fig, plt.o[2])
#
# add the row # # add the row
if c == ncols(subplt.layout, r) # if c == ncols(subplt.layout, r)
row = Gtk.GtkBoxLeaf(:h) # row = Gtk.GtkBoxLeaf(:h)
push!(vsep, row) # push!(vsep, row)
end # end
#
end # end
#
# destructor... clean up plots # # destructor... clean up plots
Gtk.on_signal_destroy((x...) -> ([Immerse.dropfig(Immerse._display,i) for i in figindices]; subplt.o = nothing), win) # Gtk.on_signal_destroy((x...) -> ([Immerse.dropfig(Immerse._display,i) for i in figindices]; subplt.o = nothing), win)
#
subplt.o = win # subplt.o = win
true # true
end # end
function _remove_axis(plt::Plot{ImmerseBackend}, isx::Bool) function _remove_axis(plt::Plot{ImmerseBackend}, isx::Bool)
@ -151,7 +151,7 @@ end
# ---------------------------------------------------------------- # ----------------------------------------------------------------
getGadflyContext(plt::Plot{ImmerseBackend}) = plt.o[2] getGadflyContext(plt::Plot{ImmerseBackend}) = plt.o[2]
getGadflyContext(subplt::Subplot{ImmerseBackend}) = buildGadflySubplotContext(subplt) # getGadflyContext(subplt::Subplot{ImmerseBackend}) = buildGadflySubplotContext(subplt)
function Base.display(::PlotsDisplay, plt::Plot{ImmerseBackend}) function Base.display(::PlotsDisplay, plt::Plot{ImmerseBackend})
@ -168,20 +168,20 @@ function Base.display(::PlotsDisplay, plt::Plot{ImmerseBackend})
end end
function Base.display(::PlotsDisplay, subplt::Subplot{ImmerseBackend}) # function Base.display(::PlotsDisplay, subplt::Subplot{ImmerseBackend})
#
# if we haven't created the window yet, do it # # if we haven't created the window yet, do it
if subplt.o == nothing # if subplt.o == nothing
showSubplotObject(subplt) # showSubplotObject(subplt)
end # end
#
# display the plots by creating a fresh Immerse.Figure object from the GtkCanvas and Gadfly.Plot # # display the plots by creating a fresh Immerse.Figure object from the GtkCanvas and Gadfly.Plot
for plt in subplt.plts # for plt in subplt.plts
fig, gplt = plt.o # fig, gplt = plt.o
Immerse.figure(fig.figno; displayfig = false) # Immerse.figure(fig.figno; displayfig = false)
display(gplt) # display(gplt)
end # end
#
# o is the window... show it # # o is the window... show it
showall(subplt.o) # showall(subplt.o)
end # end

View File

@ -135,10 +135,10 @@ end
# ---------------------------------------------------------------- # ----------------------------------------------------------------
function _create_subplot(subplt::Subplot{PlotlyBackend}, isbefore::Bool) # function _create_subplot(subplt::Subplot{PlotlyBackend}, isbefore::Bool)
# TODO: build the underlying Subplot object. this is where you might layout the panes within a GUI window, for example # # TODO: build the underlying Subplot object. this is where you might layout the panes within a GUI window, for example
true # true
end # end
function _expand_limits(lims, plt::Plot{PlotlyBackend}, isx::Bool) function _expand_limits(lims, plt::Plot{PlotlyBackend}, isx::Bool)
# TODO: call expand limits for each plot data # TODO: call expand limits for each plot data
@ -516,15 +516,15 @@ function get_series_json(plt::Plot{PlotlyBackend})
JSON.json(map(d -> plotly_series(d, plt.plotargs), plt.seriesargs)) JSON.json(map(d -> plotly_series(d, plt.plotargs), plt.seriesargs))
end end
function get_series_json(subplt::Subplot{PlotlyBackend}) # function get_series_json(subplt::Subplot{PlotlyBackend})
ds = KW[] # ds = KW[]
for (i,plt) in enumerate(subplt.plts) # for (i,plt) in enumerate(subplt.plts)
for d in plt.seriesargs # for d in plt.seriesargs
push!(ds, plotly_series(d, plt.plotargs, plot_index = i)) # push!(ds, plotly_series(d, plt.plotargs, plot_index = i))
end # end
end # end
JSON.json(ds) # JSON.json(ds)
end # end
# ---------------------------------------------------------------- # ----------------------------------------------------------------
@ -557,29 +557,29 @@ function js_body(plt::Plot{PlotlyBackend}, uuid)
end end
function html_body(subplt::Subplot{PlotlyBackend}) # function html_body(subplt::Subplot{PlotlyBackend})
w, h = subplt.plts[1].plotargs[:size] # w, h = subplt.plts[1].plotargs[:size]
html = ["<div style=\"width:$(w)px;height:$(h)px;\">"] # html = ["<div style=\"width:$(w)px;height:$(h)px;\">"]
nr = nrows(subplt.layout) # nr = nrows(subplt.layout)
ph = h / nr # ph = h / nr
#
for r in 1:nr # for r in 1:nr
push!(html, "<div style=\"clear:both;\">") # push!(html, "<div style=\"clear:both;\">")
#
nc = ncols(subplt.layout, r) # nc = ncols(subplt.layout, r)
pw = w / nc # pw = w / nc
#
for c in 1:nc # for c in 1:nc
plt = subplt[r,c] # plt = subplt[r,c]
push!(html, html_body(plt, "float:left; width:$(pw)px; height:$(ph)px;")) # push!(html, html_body(plt, "float:left; width:$(pw)px; height:$(ph)px;"))
end # end
#
push!(html, "</div>") # push!(html, "</div>")
end # end
push!(html, "</div>") # push!(html, "</div>")
#
join(html) # join(html)
end # end
# ---------------------------------------------------------------- # ----------------------------------------------------------------

View File

@ -178,10 +178,10 @@ end
# ---------------------------------------------------------------- # ----------------------------------------------------------------
function _create_subplot(subplt::Subplot{PlotlyJSBackend}, isbefore::Bool) # function _create_subplot(subplt::Subplot{PlotlyJSBackend}, isbefore::Bool)
# TODO: build the underlying Subplot object. this is where you might layout the panes within a GUI window, for example # # TODO: build the underlying Subplot object. this is where you might layout the panes within a GUI window, for example
true # true
end # end
function _expand_limits(lims, plt::Plot{PlotlyJSBackend}, isx::Bool) function _expand_limits(lims, plt::Plot{PlotlyJSBackend}, isx::Bool)
# TODO: call expand limits for each plot data # TODO: call expand limits for each plot data
@ -206,6 +206,6 @@ function Base.display(::PlotsDisplay, plt::Plot{PlotlyJSBackend})
display(plt.o) display(plt.o)
end end
function Base.display(::PlotsDisplay, plt::Subplot{PlotlyJSBackend}) # function Base.display(::PlotsDisplay, plt::Subplot{PlotlyJSBackend})
error() # error()
end # end

View File

@ -222,40 +222,62 @@ end
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
type PyPlotAxisWrapper function getAxis(plt::Plot{PyPlotBackend}, subplot::Subplot = plt.subplots[1])
ax if subplot.o == nothing
rightax @show subplot
fig fig = plt.o
kwargs # for add_subplot @show plt
end # if fig == nothing
# fig =
getfig(wrap::PyPlotAxisWrapper) = wrap.fig # TODO: actual coords?
# NOTE: might want to use ax[:get_tightbbox](ax[:get_renderer_cache]()) to calc size of guides?
# NOTE: can set subplot location later with ax[:set_position]([left, bottom, width, height])
left, bottom, width, height = 0.3, 0.3, 0.5, 0.5
# get a reference to the correct axis ax = fig[:add_axes]([left, bottom, width, height])
function getLeftAxis(wrap::PyPlotAxisWrapper) subplot.o = ax
if wrap.ax == nothing
axes = wrap.fig.o[:axes]
if isempty(axes)
return wrap.fig.o[:add_subplot](111; wrap.kwargs...)
end
axes[1]
else
wrap.ax
end end
subplot.o
end end
function getRightAxis(wrap::PyPlotAxisWrapper) getLeftAxis(plt::Plot{PyPlotBackend}, subplot::Subplot = plt.subplots[1]) = getAxis(plt, subplot)
if wrap.rightax == nothing getfig(o) = o
wrap.rightax = getLeftAxis(wrap)[:twinx]()
end
wrap.rightax
end
getLeftAxis(plt::Plot{PyPlotBackend}) = getLeftAxis(plt.o) # ---------------------------------------------------------------------------
getRightAxis(plt::Plot{PyPlotBackend}) = getRightAxis(plt.o)
getAxis(plt::Plot{PyPlotBackend}, axis::Symbol) = (axis == :right ? getRightAxis : getLeftAxis)(plt) # type PyPlotAxisWrapper
# ax
# rightax
# fig
# kwargs # for add_subplot
# end
#
# getfig(wrap::PyPlotAxisWrapper) = wrap.fig
#
#
#
# # get a reference to the correct axis
# function getLeftAxis(wrap::PyPlotAxisWrapper)
# if wrap.ax == nothing
# axes = wrap.fig.o[:axes]
# if isempty(axes)
# return wrap.fig.o[:add_subplot](111; wrap.kwargs...)
# end
# axes[1]
# else
# wrap.ax
# end
# end
#
# function getRightAxis(wrap::PyPlotAxisWrapper)
# if wrap.rightax == nothing
# wrap.rightax = getLeftAxis(wrap)[:twinx]()
# end
# wrap.rightax
# end
#
# getLeftAxis(plt::Plot{PyPlotBackend}) = getLeftAxis(plt.o)
# getRightAxis(plt::Plot{PyPlotBackend}) = getRightAxis(plt.o)
# # getAxis(plt::Plot{PyPlotBackend}, axis::Symbol) = (axis == :right ? getRightAxis : getLeftAxis)(plt)
function handleSmooth(plt::Plot{PyPlotBackend}, ax, d::KW, smooth::Bool) function handleSmooth(plt::Plot{PyPlotBackend}, ax, d::KW, smooth::Bool)
@ -272,13 +294,13 @@ handleSmooth(plt::Plot{PyPlotBackend}, ax, d::KW, smooth::Real) = handleSmooth(p
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
makePyPlotCurrent(wrap::PyPlotAxisWrapper) = wrap.ax == nothing ? PyPlot.figure(wrap.fig.o[:number]) : nothing # makePyPlotCurrent(wrap::PyPlotAxisWrapper) = wrap.ax == nothing ? PyPlot.figure(wrap.fig.o[:number]) : nothing
makePyPlotCurrent(plt::Plot{PyPlotBackend}) = plt.o == nothing ? nothing : makePyPlotCurrent(plt.o) # makePyPlotCurrent(plt::Plot{PyPlotBackend}) = plt.o == nothing ? nothing : makePyPlotCurrent(plt.o)
#
#
function _before_add_series(plt::Plot{PyPlotBackend}) # function _before_add_series(plt::Plot{PyPlotBackend})
makePyPlotCurrent(plt) # makePyPlotCurrent(plt)
end # end
# ------------------------------------------------------------------ # ------------------------------------------------------------------
@ -297,7 +319,7 @@ function pyplot_figure(plotargs::KW)
fig[:set_size_inches](w, h, forward = true) fig[:set_size_inches](w, h, forward = true)
fig[:set_facecolor](getPyPlotColor(plotargs[:background_color_outside])) fig[:set_facecolor](getPyPlotColor(plotargs[:background_color_outside]))
fig[:set_dpi](DPI) fig[:set_dpi](DPI)
fig[:set_tight_layout](true) # fig[:set_tight_layout](true)
# clear the figure # clear the figure
PyPlot.clf() PyPlot.clf()
@ -315,21 +337,27 @@ end
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
function _create_backend_figure(plt::Plot) function _create_backend_figure(plt::Plot{PyPlotBackend})
if haskey(plt.plotargs, :subplot) fig = pyplot_figure(plt.plotargs)
wrap = nothing # TODO: handle 3d and polar
else fig
wrap = PyPlotAxisWrapper(nothing, nothing, pyplot_figure(plt.plotargs), [])
pyplot_3d_setup!(wrap, plt.plotargs)
if get(plt.plotargs, :polar, false)
push!(wrap.kwargs, (:polar, true))
end
end
wrap
# plt = Plot(wrap, pkg, 0, plt.plotargs, KW[])
# plt
end end
# function _create_backend_figure(plt::Plot)
# if haskey(plt.plotargs, :subplot)
# wrap = nothing
# else
# wrap = PyPlotAxisWrapper(nothing, nothing, pyplot_figure(plt.plotargs), [])
# pyplot_3d_setup!(wrap, plt.plotargs)
# if get(plt.plotargs, :polar, false)
# push!(wrap.kwargs, (:polar, true))
# end
# end
# wrap
# # plt = Plot(wrap, pkg, 0, plt.plotargs, KW[])
# # plt
# end
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
function fix_xy_lengths!(plt::Plot{PyPlotBackend}, d::KW) function fix_xy_lengths!(plt::Plot{PyPlotBackend}, d::KW)
@ -368,11 +396,12 @@ pyfillcolormap(d::KW) = getPyPlotColorMap(d[:fillcolor], d[:fillalpha])
function _add_series(plt::Plot{PyPlotBackend}, series::Series) function _add_series(plt::Plot{PyPlotBackend}, series::Series)
d = series.d d = series.d
st = d[:seriestype] st = d[:seriestype]
if !(st in supportedTypes(pkg)) if !(st in supportedTypes(plt.backend))
error("seriestype $(st) is unsupported in PyPlot. Choose from: $(supportedTypes(pkg))") error("seriestype $(st) is unsupported in PyPlot. Choose from: $(supportedTypes(plt.backend))")
end end
# 3D plots have a different underlying Axes object in PyPlot # 3D plots have a different underlying Axes object in PyPlot
# TODO: BUG: this adds to kwargs but never changes anything... source of subplot(wireframe(...)) bug?
if st in _3dTypes && isempty(plt.o.kwargs) if st in _3dTypes && isempty(plt.o.kwargs)
push!(plt.o.kwargs, (:projection, "3d")) push!(plt.o.kwargs, (:projection, "3d"))
end end
@ -380,7 +409,8 @@ function _add_series(plt::Plot{PyPlotBackend}, series::Series)
# PyPlot doesn't handle mismatched x/y # PyPlot doesn't handle mismatched x/y
fix_xy_lengths!(plt, d) fix_xy_lengths!(plt, d)
ax = getAxis(plt, d[:axis]) # ax = getAxis(plt, d[:axis])
ax = getAxis(plt, get(d, :subplot, plt.subplots[1]))
x, y, z = d[:x], d[:y], d[:z] x, y, z = d[:x], d[:y], d[:z]
@show typeof((x,y,z)) @show typeof((x,y,z))
xyargs = (st in _3dTypes ? (x,y,z) : (x,y)) xyargs = (st in _3dTypes ? (x,y,z) : (x,y))
@ -769,11 +799,11 @@ end
# given a dimension (:x, :y, or :z), loop over the seriesargs KWs to find the min/max of the underlying data # given a dimension (:x, :y, or :z), loop over the seriesargs KWs to find the min/max of the underlying data
function minmaxseries(ds, dimension, axis) function minmaxseries(series_list, dimension, axis)
lo, hi = Inf, -Inf lo, hi = Inf, -Inf
for d in ds for series in series_list
d[:axis] == axis || continue series.d[:axis] == axis || continue
v = d[dimension] v = series.d[dimension]
if length(v) > 0 if length(v) > 0
vlo, vhi = extrema(v) vlo, vhi = extrema(v)
lo = min(lo, vlo) lo = min(lo, vlo)
@ -795,13 +825,13 @@ function set_lims!(plt::Plot{PyPlotBackend}, axis::Symbol)
ax = getAxis(plt, axis) ax = getAxis(plt, axis)
pargs = plt.plotargs pargs = plt.plotargs
if pargs[:xlims] == :auto if pargs[:xlims] == :auto
ax[pargs[:polar] ? :set_tlim : :set_xlim](minmaxseries(plt.seriesargs, :x, axis)...) ax[pargs[:polar] ? :set_tlim : :set_xlim](minmaxseries(plt.series_list, :x, axis)...)
end end
if pargs[:ylims] == :auto if pargs[:ylims] == :auto
ax[pargs[:polar] ? :set_rlim : :set_ylim](minmaxseries(plt.seriesargs, :y, axis)...) ax[pargs[:polar] ? :set_rlim : :set_ylim](minmaxseries(plt.series_list, :y, axis)...)
end end
if pargs[:zlims] == :auto && haskey(ax, :set_zlim) if pargs[:zlims] == :auto && haskey(ax, :set_zlim)
ax[:set_zlim](minmaxseries(plt.seriesargs, :z, axis)...) ax[:set_zlim](minmaxseries(plt.series_list, :z, axis)...)
end end
end end
@ -811,7 +841,7 @@ end
# the x/y data for each handle (for example, plot and scatter) # the x/y data for each handle (for example, plot and scatter)
function setxy!{X,Y}(plt::Plot{PyPlotBackend}, xy::Tuple{X,Y}, i::Integer) function setxy!{X,Y}(plt::Plot{PyPlotBackend}, xy::Tuple{X,Y}, i::Integer)
d = plt.seriesargs[i] d = plt.series_list[i].d
d[:x], d[:y] = xy d[:x], d[:y] = xy
for handle in d[:serieshandle] for handle in d[:serieshandle]
try try
@ -826,7 +856,7 @@ end
function setxyz!{X,Y,Z}(plt::Plot{PyPlotBackend}, xyz::Tuple{X,Y,Z}, i::Integer) function setxyz!{X,Y,Z}(plt::Plot{PyPlotBackend}, xyz::Tuple{X,Y,Z}, i::Integer)
d = plt.seriesargs[i] d = plt.series_list[i].d
d[:x], d[:y], d[:z] = xyz d[:x], d[:y], d[:z] = xyz
for handle in d[:serieshandle] for handle in d[:serieshandle]
handle[:set_data](d[:x], d[:y]) handle[:set_data](d[:x], d[:y])
@ -901,9 +931,9 @@ function updateAxisColors(ax, d::KW)
ax[:title][:set_color](guidecolor) ax[:title][:set_color](guidecolor)
end end
function usingRightAxis(plt::Plot{PyPlotBackend}) # function usingRightAxis(plt::Plot{PyPlotBackend})
any(args -> args[:axis] in (:right,:auto), plt.seriesargs) # any(args -> args[:axis] in (:right,:auto), plt.seriesargs)
end # end
# -------------------------------------------------------------------------- # --------------------------------------------------------------------------
@ -912,7 +942,8 @@ end
function _update_plot(plt::Plot{PyPlotBackend}, d::KW) function _update_plot(plt::Plot{PyPlotBackend}, d::KW)
# @show d # @show d
figorax = plt.o figorax = plt.o
ax = getLeftAxis(figorax) # ax = getLeftAxis(figorax)
ax = getAxis(plt, plt.subplots[1])
# ticksz = get(d, :tickfont, plt.plotargs[:tickfont]).pointsize # ticksz = get(d, :tickfont, plt.plotargs[:tickfont]).pointsize
guidesz = get(d, :guidefont, plt.plotargs[:guidefont]).pointsize guidesz = get(d, :guidefont, plt.plotargs[:guidefont]).pointsize
@ -920,15 +951,16 @@ function _update_plot(plt::Plot{PyPlotBackend}, d::KW)
haskey(d, :title) && ax[:set_title](d[:title]) haskey(d, :title) && ax[:set_title](d[:title])
ax[:title][:set_fontsize](guidesz) ax[:title][:set_fontsize](guidesz)
# handle right y axis axes = [ax]
axes = [getLeftAxis(figorax)] # # handle right y axis
if usingRightAxis(plt) # axes = [getLeftAxis(figorax)]
push!(axes, getRightAxis(figorax)) # if usingRightAxis(plt)
if get(d, :yrightlabel, "") != "" # push!(axes, getRightAxis(figorax))
rightax = getRightAxis(figorax) # if get(d, :yrightlabel, "") != ""
rightax[:set_ylabel](d[:yrightlabel]) # rightax = getRightAxis(figorax)
end # rightax[:set_ylabel](d[:yrightlabel])
end # end
# end
for letter in ("x", "y", "z") for letter in ("x", "y", "z")
axissym = symbol(letter*"axis") axissym = symbol(letter*"axis")
@ -1044,7 +1076,7 @@ end
# #
# # this will be called internally, when creating a subplot from existing plots # # this will be called internally, when creating a subplot from existing plots
# # NOTE: if I ever need to "Rebuild a "ubplot from individual Plot's"... this is what I should use! # # NOTE: if I ever need to "Rebuild a "ubplot from individual Plot's"... this is what I should use!
# function subplot(plts::AVec{Plot{PyPlotBackend}}, layout::SubplotLayout, d::KW) # function subplot(plts::AVec{Plot{PyPlotBackend}}, layout::AbstractLayout, d::KW)
# validateSubplotSupported() # validateSubplotSupported()
# #
# p = length(layout) # p = length(layout)
@ -1104,15 +1136,27 @@ function addPyPlotLegend(plt::Plot, ax)
leg = plt.plotargs[:legend] leg = plt.plotargs[:legend]
if leg != :none if leg != :none
# gotta do this to ensure both axes are included # gotta do this to ensure both axes are included
args = filter(x -> !(x[:seriestype] in ( labels = []
:hist,:density,:hexbin,:hist2d,:hline,:vline, handles = []
:contour,:contour3d,:surface,:wireframe, for series in plt.series_list
:heatmap,:path3d,:scatter3d, :pie, :image if series.d[:label] != "" && !(series.d[:seriestype] in (
)), plt.seriesargs) :hist,:density,:hexbin,:hist2d,:hline,:vline,
args = filter(x -> x[:label] != "", args) :contour,:contour3d,:surface,:wireframe,
if length(args) > 0 :heatmap,:path3d,:scatter3d, :pie, :image))
leg = ax[:legend]([d[:serieshandle][1] for d in args], push!(handles, series.d[:serieshandle][1])
[d[:label] for d in args], push!(labels, series.d[:label])
end
end
# args = filter(x -> !(x.d[:seriestype] in (
# :hist,:density,:hexbin,:hist2d,:hline,:vline,
# :contour,:contour3d,:surface,:wireframe,
# :heatmap,:path3d,:scatter3d, :pie, :image
# )), plt.series_list)
# args = filter(x -> x[:label] != "", args)
# if length(args) > 0
if !isempty(handles)
leg = ax[:legend](handles, #[d[:serieshandle][1] for d in args],
labels, #[d[:label] for d in args],
loc = get(_pyplot_legend_pos, leg, "best"), loc = get(_pyplot_legend_pos, leg, "best"),
scatterpoints = 1, scatterpoints = 1,
fontsize = plt.plotargs[:legendfont].pointsize fontsize = plt.plotargs[:legendfont].pointsize

View File

@ -269,28 +269,28 @@ end
# ------------------------------- # -------------------------------
# create the underlying object (each backend will do this differently) # # create the underlying object (each backend will do this differently)
function _create_subplot(subplt::Subplot{QwtBackend}, isbefore::Bool) # function _create_subplot(subplt::Subplot{QwtBackend}, isbefore::Bool)
isbefore && return false # isbefore && return false
i = 0 # i = 0
rows = Any[] # rows = Any[]
row = Any[] # row = Any[]
for (i,(r,c)) in enumerate(subplt.layout) # for (i,(r,c)) in enumerate(subplt.layout)
push!(row, subplt.plts[i].o) # push!(row, subplt.plts[i].o)
if c == ncols(subplt.layout, r) # if c == ncols(subplt.layout, r)
push!(rows, Qwt.hsplitter(row...)) # push!(rows, Qwt.hsplitter(row...))
row = Any[] # row = Any[]
end # end
end # end
# for rowcnt in subplt.layout.rowcounts # # for rowcnt in subplt.layout.rowcounts
# push!(rows, Qwt.hsplitter([plt.o for plt in subplt.plts[(1:rowcnt) + i]]...)) # # push!(rows, Qwt.hsplitter([plt.o for plt in subplt.plts[(1:rowcnt) + i]]...))
# i += rowcnt # # i += rowcnt
# end # # end
subplt.o = Qwt.vsplitter(rows...) # subplt.o = Qwt.vsplitter(rows...)
# Qwt.resizewidget(subplt.o, getplotargs(subplt,1)[:size]...) # # Qwt.resizewidget(subplt.o, getplotargs(subplt,1)[:size]...)
# Qwt.moveToLastScreen(subplt.o) # hack so it goes to my center monitor... sorry # # Qwt.moveToLastScreen(subplt.o) # hack so it goes to my center monitor... sorry
true # true
end # end
function _expand_limits(lims, plt::Plot{QwtBackend}, isx::Bool) function _expand_limits(lims, plt::Plot{QwtBackend}, isx::Bool)
for series in plt.o.lines for series in plt.o.lines
@ -311,13 +311,13 @@ function Base.writemime(io::IO, ::MIME"image/png", plt::Plot{QwtBackend})
write(io, readall("/tmp/dfskjdhfkh.png")) write(io, readall("/tmp/dfskjdhfkh.png"))
end end
function Base.writemime(io::IO, ::MIME"image/png", subplt::Subplot{QwtBackend}) # function Base.writemime(io::IO, ::MIME"image/png", subplt::Subplot{QwtBackend})
for plt in subplt.plts # for plt in subplt.plts
Qwt.refresh(plt.o) # Qwt.refresh(plt.o)
end # end
Qwt.savepng(subplt.o, "/tmp/dfskjdhfkh.png") # Qwt.savepng(subplt.o, "/tmp/dfskjdhfkh.png")
write(io, readall("/tmp/dfskjdhfkh.png")) # write(io, readall("/tmp/dfskjdhfkh.png"))
end # end
function Base.display(::PlotsDisplay, plt::Plot{QwtBackend}) function Base.display(::PlotsDisplay, plt::Plot{QwtBackend})
@ -325,9 +325,9 @@ function Base.display(::PlotsDisplay, plt::Plot{QwtBackend})
Qwt.showwidget(plt.o) Qwt.showwidget(plt.o)
end end
function Base.display(::PlotsDisplay, subplt::Subplot{QwtBackend}) # function Base.display(::PlotsDisplay, subplt::Subplot{QwtBackend})
for plt in subplt.plts # for plt in subplt.plts
Qwt.refresh(plt.o) # Qwt.refresh(plt.o)
end # end
Qwt.showwidget(subplt.o) # Qwt.showwidget(subplt.o)
end # end

View File

@ -57,9 +57,9 @@ end
# ---------------------------------------------------------------- # ----------------------------------------------------------------
function _create_subplot(subplt::Subplot{[PkgName]AbstractBackend}, isbefore::Bool) # function _create_subplot(subplt::Subplot{[PkgName]AbstractBackend}, isbefore::Bool)
# TODO: build the underlying Subplot object. this is where you might layout the panes within a GUI window, for example # # TODO: build the underlying Subplot object. this is where you might layout the panes within a GUI window, for example
end # end
function _expand_limits(lims, plt::Plot{[PkgName]AbstractBackend}, isx::Bool) function _expand_limits(lims, plt::Plot{[PkgName]AbstractBackend}, isx::Bool)
# TODO: call expand limits for each plot data # TODO: call expand limits for each plot data
@ -79,6 +79,6 @@ function Base.display(::PlotsDisplay, plt::Plot{[PkgName]AbstractBackend})
# TODO: display/show the plot # TODO: display/show the plot
end end
function Base.display(::PlotsDisplay, plt::Subplot{[PkgName]AbstractBackend}) # function Base.display(::PlotsDisplay, plt::Subplot{[PkgName]AbstractBackend})
# TODO: display/show the subplot # # TODO: display/show the subplot
end # end

View File

@ -247,10 +247,10 @@ end
# we don't do very much for subplots... just stack them vertically # we don't do very much for subplots... just stack them vertically
function _create_subplot(subplt::Subplot{UnicodePlotsBackend}, isbefore::Bool) # function _create_subplot(subplt::Subplot{UnicodePlotsBackend}, isbefore::Bool)
isbefore && return false # isbefore && return false
true # true
end # end
function Base.display(::PlotsDisplay, plt::Plot{UnicodePlotsBackend}) function Base.display(::PlotsDisplay, plt::Plot{UnicodePlotsBackend})
@ -260,8 +260,8 @@ end
function Base.display(::PlotsDisplay, subplt::Subplot{UnicodePlotsBackend}) # function Base.display(::PlotsDisplay, subplt::Subplot{UnicodePlotsBackend})
for plt in subplt.plts # for plt in subplt.plts
gui(plt) # gui(plt)
end # end
end # end

View File

@ -261,9 +261,9 @@ end
# ---------------------------------------------------------------- # ----------------------------------------------------------------
function _create_subplot(subplt::Subplot{WinstonBackend}, isbefore::Bool) # function _create_subplot(subplt::Subplot{WinstonBackend}, isbefore::Bool)
# TODO: build the underlying Subplot object. this is where you might layout the panes within a GUI window, for example # # TODO: build the underlying Subplot object. this is where you might layout the panes within a GUI window, for example
end # end
# ---------------------------------------------------------------- # ----------------------------------------------------------------
@ -302,6 +302,6 @@ function Base.display(::PlotsDisplay, plt::Plot{WinstonBackend})
end end
function Base.display(::PlotsDisplay, subplt::Subplot{WinstonBackend}) # function Base.display(::PlotsDisplay, subplt::Subplot{WinstonBackend})
# TODO: display/show the Subplot object # # TODO: display/show the Subplot object
end # end

View File

@ -257,10 +257,6 @@ function text(str, args...)
end end
# ----------------------------------------------------------------------- # -----------------------------------------------------------------------
# simple wrapper around a KW so we can hold all attributes pertaining to the axis in one place
type Axis #<: Associative{Symbol,Any}
d::KW
end
xaxis(args...) = Axis("x", args...) xaxis(args...) = Axis("x", args...)
yaxis(args...) = Axis("y", args...) yaxis(args...) = Axis("y", args...)
@ -299,7 +295,7 @@ function Axis(letter::AbstractString, args...; kw...)
end end
# update an Axis object with magic args and keywords # update an Axis object with magic args and keywords
function update!(a::Axis, args..., kw...) function update!(a::Axis, args...; kw...)
# first process args # first process args
d = a.d d = a.d
for arg in args for arg in args

View File

@ -4,7 +4,7 @@
# ----------------------------------------------------------- # -----------------------------------------------------------
"Simple grid, indices are row-major." "Simple grid, indices are row-major."
immutable GridLayout <: SubplotLayout immutable GridLayout <: AbstractLayout
nr::Int nr::Int
nc::Int nc::Int
end end
@ -30,7 +30,7 @@ Base.getindex(layout::GridLayout, r::Int, c::Int) = (r-1) * layout.nc + c
# ----------------------------------------------------------- # -----------------------------------------------------------
"Number of plots per row" "Number of plots per row"
immutable RowsLayout <: SubplotLayout immutable RowsLayout <: AbstractLayout
numplts::Int numplts::Int
rowcounts::AbstractVector{Int} rowcounts::AbstractVector{Int}
end end
@ -62,7 +62,7 @@ Base.getindex(layout::RowsLayout, r::Int, c::Int) = sum(layout.rowcounts[1:r-1])
# ----------------------------------------------------------- # -----------------------------------------------------------
"Flexible, nested layout with optional size percentages." "Flexible, nested layout with optional size percentages."
immutable FlexLayout <: SubplotLayout immutable FlexLayout <: AbstractLayout
n::Int n::Int
grid::Matrix # Nested layouts. Each position grid::Matrix # Nested layouts. Each position
# can be a plot index or another FlexLayout # can be a plot index or another FlexLayout

View File

@ -100,7 +100,7 @@ function subplot{P,I<:Integer}(pltsPerRow::AVec{I}, plt1::Plot{P}, plts::Plot{P}
end end
# this will be called internally # this will be called internally
function subplot{P<:AbstractBackend}(plts::AVec{Plot{P}}, layout::SubplotLayout, d::KW) function subplot{P<:AbstractBackend}(plts::AVec{Plot{P}}, layout::AbstractLayout, d::KW)
validateSubplotSupported() validateSubplotSupported()
p = length(layout) p = length(layout)
n = sum([plt.n for plt in plts]) n = sum([plt.n for plt in plts])

View File

@ -47,10 +47,15 @@ function plot(args...; kw...)
d = KW(kw) d = KW(kw)
preprocessArgs!(d) preprocessArgs!(d)
layout = pop!(d, :layout, Subplot())
subplots = Subplot[layout] # TODO: build full list
smap = SubplotMap(1 => layout) # TODO: actually build a map
# TODO: this seems wrong... I only call getPlotArgs when creating a new plot??
plotargs = merge(d, getPlotArgs(pkg, d, 1)) plotargs = merge(d, getPlotArgs(pkg, d, 1))
# plt = _create_plot(pkg, plotargs) # create a new, blank plot # plt = _create_plot(pkg, plotargs) # create a new, blank plot
plt = Plot(nothing, pkg, 0, plt.plotargs, KW[]) plt = Plot(nothing, pkg, 0, plotargs, Series[], subplots, smap, layout)
plt.o = _create_backend_figure(plt) plt.o = _create_backend_figure(plt)
# now update the plot # now update the plot

View File

@ -2,11 +2,7 @@
# we are going to build recipes to do the processing and splitting of the args # we are going to build recipes to do the processing and splitting of the args
# build the argument dictionary for a series
# function getSeriesArgs(pkg::AbstractBackend, plotargs::KW, d, commandIndex::Int, plotIndex::Int, globalIndex::Int) # TODO, pass in plotargs, not plt
function _add_defaults!(d::KW, plt::Plot, commandIndex::Int) function _add_defaults!(d::KW, plt::Plot, commandIndex::Int)
# kwdict = KW(d)
# d = KW()
pkg = plt.backend pkg = plt.backend
n = plt.n n = plt.n
plotargs = getplotargs(plt, n) plotargs = getplotargs(plt, n)
@ -18,16 +14,10 @@ function _add_defaults!(d::KW, plt::Plot, commandIndex::Int)
setDictValue(d, d, k, commandIndex, _seriesDefaults) setDictValue(d, d, k, commandIndex, _seriesDefaults)
end end
# # groupby args? if d[:subplot_index] == :auto
# for k in (:idxfilter, :numUncounted, :dataframe) # TODO: something useful
# if haskey(kwdict, k) d[:subplot_index] = 1
# d[k] = kwdict[k] end
# end
# end
# if haskey(_typeAliases, d[:seriestype])
# d[:seriestype] = _typeAliases[d[:seriestype]]
# end
aliasesAndAutopick(d, :axis, _axesAliases, supportedAxes(pkg), plotIndex) aliasesAndAutopick(d, :axis, _axesAliases, supportedAxes(pkg), plotIndex)
aliasesAndAutopick(d, :linestyle, _styleAliases, supportedStyles(pkg), plotIndex) aliasesAndAutopick(d, :linestyle, _styleAliases, supportedStyles(pkg), plotIndex)
@ -77,8 +67,6 @@ function _add_defaults!(d::KW, plt::Plot, commandIndex::Int)
end end
d[:label] = label d[:label] = label
# warnOnUnsupported(pkg, d)
d d
end end

View File

@ -1,18 +1,24 @@
# ----------------------------------------------------------- Base.size(layout::EmptyLayout) = (0,0)
# GridLayout Base.length(layout::EmptyLayout) = 0
# ----------------------------------------------------------- Base.getindex(layout::EmptyLayout, r::Int, c::Int) = nothing
Base.size(layout::RootLayout) = (1,1)
Base.length(layout::RootLayout) = 1
# Base.getindex(layout::RootLayout, r::Int, c::Int) = layout.child
Base.size(subplot::Subplot) = (1,1)
Base.length(subplot::Subplot) = 1
Base.getindex(subplot::Subplot, r::Int, c::Int) = subplot
"nested, gridded layout with optional size percentages."
immutable GridLayout <: SubplotLayout
grid::Matrix # Nested layouts. Each position is an AbstractSubplot or another GridLayout
widths::Vector{Float64}
heights::Vector{Float64}
end
Base.size(layout::GridLayout) = size(layout.grid) Base.size(layout::GridLayout) = size(layout.grid)
Base.length(layout::GridLayout) = length(layout.grid) Base.length(layout::GridLayout) = length(layout.grid)
Base.getindex(layout::GridLayout, r::Int, c::Int) = layout.grid[r,c]
# Base.start(layout::GridLayout) = 1 # Base.start(layout::GridLayout) = 1
# Base.done(layout::GridLayout, state) = state > length(layout) # Base.done(layout::GridLayout, state) = state > length(layout)
# function Base.next(layout::GridLayout, state) # function Base.next(layout::GridLayout, state)
@ -31,11 +37,10 @@ Base.length(layout::GridLayout) = length(layout.grid)
# (r,c), state + 1 # (r,c), state + 1
# end # end
nrows(layout::GridLayout) = size(layout, 1) # nrows(layout::GridLayout) = size(layout, 1)
ncols(layout::GridLayout) = size(layout, 2) # ncols(layout::GridLayout) = size(layout, 2)
# get the plot index given row and column # get the plot index given row and column
Base.getindex(layout::GridLayout, r::Int, c::Int) = layout.grid[r,c]
# ----------------------------------------------------------- # -----------------------------------------------------------

View File

@ -16,39 +16,74 @@ end
wrap{T}(obj::T) = InputWrapper{T}(obj) wrap{T}(obj::T) = InputWrapper{T}(obj)
Base.isempty(wrapper::InputWrapper) = false Base.isempty(wrapper::InputWrapper) = false
# -----------------------------------------------------------
# Axes
# -----------------------------------------------------------
# simple wrapper around a KW so we can hold all attributes pertaining to the axis in one place
type Axis #<: Associative{Symbol,Any}
d::KW
end
type AxisView type AxisView
label::UTF8String label::UTF8String
axis::Axis axis::Axis
end end
abstract AbstractSubplot
immutable EmptySubplot <: AbstractSubplot end
type Subplot <: AbstractSubplot # -----------------------------------------------------------
axisviews::Vector{AxisView} # Layouts
subplotargs::KW # args specific to this subplot # -----------------------------------------------------------
obj # can store backend-specific data... like a pyplot ax
abstract AbstractLayout
# -----------------------------------------------------------
# contains blank space
immutable EmptyLayout <: AbstractLayout end
# this is the parent of the top-level layout
immutable RootLayout <: AbstractLayout
# child::AbstractLayout
end end
type Series # -----------------------------------------------------------
d::KW
# x # a single subplot
# y type Subplot <: AbstractLayout
# z parent::AbstractLayout
# subplots::Vector{Subplot} attr::KW # args specific to this subplot
# axisviews::Vector{AxisView}
o # can store backend-specific data... like a pyplot ax
# Subplot(parent = RootLayout(); attr = KW())
end end
# function Series(d::KW) Subplot() = Subplot(RootLayout(), KW(), nothing)
# x = pop!(d, :x)
# y = pop!(d, :y) # -----------------------------------------------------------
# z = pop!(d, :z)
# Series(d, x, y, z) # nested, gridded layout with optional size percentages
# end immutable GridLayout <: AbstractLayout
parent::AbstractLayout
grid::Matrix{AbstractLayout} # Nested layouts. Each position is a AbstractLayout, which allows for arbitrary recursion
# widths::Vector{Float64}
# heights::Vector{Float64}
attr::KW
end
# -----------------------------------------------------------
typealias SubplotMap Dict{Any, Subplot}
# ----------------------------------------------------------- # -----------------------------------------------------------
# Plot # Plot
# ----------------------------------------------------------- # -----------------------------------------------------------
type Series
d::KW
end
type Plot{T<:AbstractBackend} <: AbstractPlot{T} type Plot{T<:AbstractBackend} <: AbstractPlot{T}
o # the backend's plot object o # the backend's plot object
backend::T # the backend type backend::T # the backend type
@ -57,19 +92,15 @@ type Plot{T<:AbstractBackend} <: AbstractPlot{T}
# seriesargs::Vector{KW} # arguments for each series # seriesargs::Vector{KW} # arguments for each series
series_list::Vector{Series} # arguments for each series series_list::Vector{Series} # arguments for each series
subplots::Vector{Subplot} subplots::Vector{Subplot}
subplot_map::SubplotMap # provide any label as a map to a subplot
layout::AbstractLayout
end end
# -----------------------------------------------------------
# Layout
# -----------------------------------------------------------
abstract SubplotLayout
# ----------------------------------------------------------- # -----------------------------------------------------------
# Subplot # Subplot
# ----------------------------------------------------------- # -----------------------------------------------------------
# type Subplot{T<:AbstractBackend, L<:SubplotLayout} <: AbstractPlot{T} # type Subplot{T<:AbstractBackend, L<:AbstractLayout} <: AbstractPlot{T}
# o # the underlying object # o # the underlying object
# plts::Vector{Plot{T}} # the individual plots # plts::Vector{Plot{T}} # the individual plots
# backend::T # backend::T