working on subplots
This commit is contained in:
parent
e9ab6e7301
commit
c5bcae1e34
@ -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,
|
||||||
|
|||||||
@ -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()
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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
|
||||||
|
|
||||||
|
|
||||||
# ----------------------------------------------------------------
|
# ----------------------------------------------------------------
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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])
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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
|
||||||
|
|
||||||
|
|||||||
@ -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]
|
|
||||||
|
|
||||||
# -----------------------------------------------------------
|
# -----------------------------------------------------------
|
||||||
|
|
||||||
|
|||||||
81
src/types.jl
81
src/types.jl
@ -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
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user