pyplot subplots

This commit is contained in:
Thomas Breloff 2015-10-13 15:02:27 -04:00
parent 8df4c27285
commit 09fceab75b
11 changed files with 275 additions and 255 deletions

File diff suppressed because one or more lines are too long

View File

@ -241,15 +241,33 @@ Base.display(::Base.REPL.REPLDisplay, ::MIME"text/plain", plt::PlottingObject) =
# ---------------------------------------------------------
try
import DataFrames
dataframes()
end
# const CURRENT_BACKEND = pickDefaultBackend()
# for be in backends()
# try
# backend(be)
# backend()
# catch err
# @show err
# end
# end
function __init__()
global const CURRENT_BACKEND = pickDefaultBackend()
# global CURRENT_BACKEND
println("[Plots.jl] Default backend: ", CURRENT_BACKEND.sym)
# auto init dataframes if the import statement doesn't error out
try
@eval import DataFrames
dataframes()
end
# # auto init dataframes if the import statement doesn't error out
# try
# @eval import DataFrames
# dataframes()
# end
end
# ---------------------------------------------------------

View File

@ -471,8 +471,10 @@ end
# create the underlying object (each backend will do this differently)
function buildSubplotObject!(subplt::Subplot{GadflyPackage})
function buildSubplotObject!(subplt::Subplot{GadflyPackage}, isbefore::Bool)
isbefore && return false
subplt.o = nothing
true
end

View File

@ -16,7 +16,6 @@ supportedScales(::ImmersePackage) = supportedScales(GadflyPackage())
function createImmerseFigure(d::Dict)
# println("Creating immerse figure: ", d)
w,h = d[:size]
figidx = Immerse.figure(; name = d[:windowtitle], width = w, height = h)
Immerse.Figure(figidx)
@ -79,7 +78,8 @@ end
# ----------------------------------------------------------------
function buildSubplotObject!(subplt::Subplot{ImmersePackage})
function buildSubplotObject!(subplt::Subplot{ImmersePackage}, isbefore::Bool)
isbefore && return false
# create the Gtk window with vertical box vsep
d = subplt.initargs[1]
@ -114,39 +114,11 @@ function buildSubplotObject!(subplt::Subplot{ImmersePackage})
end
# # add the plot boxes
# i = 0
# figindices = []
# for rowcnt in subplt.layout.rowcounts
# # create a new row and add it to the main Box vsep
# row = Gtk.GtkBoxLeaf(:h)
# push!(vsep, row)
# # now add the plot components to the row
# for plt in subplt.plts[(1:rowcnt) + i]
# # get the components... box is the main plot GtkBox, and canvas is the GtkCanvas where it's plotted
# box, toolbar, canvas = Immerse.createPlotGuiComponents()
# # add the plot's box to the row
# push!(row, box)
# # create the figure and store the index returned for destruction later
# figidx = Immerse.figure(canvas)
# push!(figindices, figidx)
# fig = Immerse.figure(figidx)
# plt.o = (fig, plt.o[2])
# end
# i += rowcnt
# end
# destructor... clean up plots
Gtk.on_signal_destroy((x...) -> [Immerse.dropfig(Immerse._display,i) for i in figindices], win)
subplt.o = win
true
end

View File

@ -117,19 +117,31 @@ function getPyPlotDrawStyle(linetype::Symbol)
end
type PyPlotFigWrapper
immutable PyPlotFigWrapper
fig
end
type PyPlotAxisWrapper
immutable PyPlotAxisWrapper
ax
end
# addPyPlotAxis(fig, layout) = error("Only GridLayouts are supported with PyPlot")
# function addPyPlotAxis(fig, layout::GridLayout, idx::Int)
# end
# get a reference to the correct axis
getLeftAxis(fig::PyPlotFigWrapper) = fig.o[:axes][1]
getLeftAxis(ax::PyPlotAxisWrapper) = ax
function getLeftAxis(wrap::PyPlotFigWrapper)
# @show wrap.fig.o[:axes]
axes = wrap.fig.o[:axes]
if isempty(axes)
return wrap.fig.o[:add_subplot](111)
end
axes[1]
end
getLeftAxis(wrap::PyPlotAxisWrapper) = wrap.ax
getLeftAxis(plt::Plot{PyPlotPackage}) = getLeftAxis(plt.o)
getRightAxis(x) = getLeftAxis(x)[:twinx]()
getAxis(plt::Plot{PyPlotPackage}, axis::Symbol) = (axis == :right ? getRightAxis : getLeftAxis)(plt)
@ -183,24 +195,18 @@ end
nop() = nothing
makePyPlotCurrent(wrap::PyPlotFigWrapper) = PyPlot.figure(wrap.fig.o[:number])
makePyPlotCurrent(wrap::PyPlotAxisWrapper) = PyPlot.sca(wrap.ax.o)
makePyPlotCurrent(plt::Plot{PyPlotPackage}) = makePyPlotCurrent(plt.o)
# makePyPlotCurrent(plt::Plot) = PyPlot.figure(plt.o.o[:number])
function preparePlotUpdate(plt::Plot{PyPlotPackage})
# makePyPlotCurrent(plt)
makePyPlotCurrent(plt)
end
# ------------------------------------------------------------------
# type PyPlotSubplotFigure
# fig
# axes
# end
# type PyPlotFigure
# fig
# ------------------------------------------------------------------
# TODO:
@ -221,13 +227,15 @@ function plot(pkg::PyPlotPackage; kw...)
# standalone plots will create a figure, but not if part of a subplot (do it later)
if haskey(d, :subplot)
fig = nothing
println("no wrap")
wrap = nothing
else
fig = PyPlotFigWrapper(PyPlot.figure(; figsize = (w,h), facecolor = bgcolor, dpi = 96))
println("yes wrap")
wrap = PyPlotFigWrapper(PyPlot.figure(; figsize = (w,h), facecolor = bgcolor, dpi = 96))
end
# num = fig.o[:number]
plt = Plot(fig, pkg, 0, d, Dict[])
# num = wrap.o[:number]
plt = Plot(wrap, pkg, 0, d, Dict[])
plt
end
@ -307,7 +315,7 @@ function plot!(pkg::PyPlotPackage, plt::Plot; kw...)
end
# set these for all types
extraargs[:figure] = plt.o
# extraargs[:figure] = plt.o
extraargs[:color] = getPyPlotColor(d[:color])
extraargs[:linewidth] = d[:linewidth]
extraargs[:label] = d[:label]
@ -342,23 +350,31 @@ end
# -----------------------------------------------------------------
function addPyPlotLims(lims, isx::Bool)
function addPyPlotLims(ax, lims, isx::Bool)
lims == :auto && return
ltype = limsType(lims)
if ltype == :limits
(isx ? PyPlot.xlim : PyPlot.ylim)(lims...)
# (isx ? PyPlot.xlim : PyPlot.ylim)(lims...)
# @show isx, lims, ax
ax[isx ? :set_xlim : :set_ylim](lims...)
else
error("Invalid input for $(isx ? "xlims" : "ylims"): ", lims)
end
end
function addPyPlotTicks(ticks, isx::Bool)
function addPyPlotTicks(ax, ticks, isx::Bool)
ticks == :auto && return
if ticks == :none
ticks = zeros(0)
end
ttype = ticksType(ticks)
if ttype == :ticks
(isx ? PyPlot.xticks : PyPlot.yticks)(ticks)
# (isx ? PyPlot.xticks : PyPlot.yticks)(ticks)
ax[isx ? :set_xticks : :set_yticks](ticks)
elseif ttype == :ticks_and_labels
(isx ? PyPlot.xticks : PyPlot.yticks)(ticks...)
# (isx ? PyPlot.xticks : PyPlot.yticks)(ticks...)
ax[isx ? :set_xticks : :set_yticks](ticks...)
else
error("Invalid input for $(isx ? "xticks" : "yticks"): ", ticks)
end
@ -366,29 +382,31 @@ end
function updatePlotItems(plt::Plot{PyPlotPackage}, d::Dict)
figorax = plt.o
ax = getLeftAxis(figorax)
# PyPlot.sca(ax)
# title and axis labels
haskey(d, :title) && PyPlot.title(d[:title])
haskey(d, :xlabel) && PyPlot.xlabel(d[:xlabel])
# haskey(d, :xlabel) && PyPlot.xlabel(d[:xlabel])
haskey(d, :xlabel) && ax[:set_xlabel](d[:xlabel])
if haskey(d, :ylabel)
ax = getLeftAxis(figorax)
# ax = getLeftAxis(figorax)
ax[:set_ylabel](d[:ylabel])
end
if haskey(d, :yrightlabel)
ax = getRightAxis(figorax)
ax[:set_ylabel](d[:yrightlabel])
rightax = getRightAxis(figorax)
rightax[:set_ylabel](d[:yrightlabel])
end
# scales
ax = getLeftAxis(figorax)
haskey(d, :xscale) && applyPyPlotScale(ax, d[:xscale], true)
haskey(d, :yscale) && applyPyPlotScale(ax, d[:yscale], false)
# limits and ticks
haskey(d, :xlims) && addPyPlotLims(d[:xlims], true)
haskey(d, :ylims) && addPyPlotLims(d[:ylims], false)
haskey(d, :xticks) && addPyPlotTicks(d[:xticks], true)
haskey(d, :yticks) && addPyPlotTicks(d[:yticks], false)
haskey(d, :xlims) && addPyPlotLims(ax, d[:xlims], true)
haskey(d, :ylims) && addPyPlotLims(ax, d[:ylims], false)
haskey(d, :xticks) && addPyPlotTicks(ax, d[:xticks], true)
haskey(d, :yticks) && addPyPlotTicks(ax, d[:yticks], false)
if get(d, :xflip, false)
ax[:invert_xaxis]()
@ -411,7 +429,7 @@ end
# -----------------------------------------------------------------
function createPyPlotAnnotationObject(plt::Plot{PyPlotPackage}, x, y, val::@compat(AbstractString))
ax = getLeftAxis(plt.o)
ax = getLeftAxis(plt)
ax[:annotate](val, xy = (x,y))
end
@ -424,60 +442,130 @@ end
# -----------------------------------------------------------------
# create the underlying object (each backend will do this differently)
function buildSubplotObject!(subplt::Subplot{PyPlotPackage})
function buildSubplotObject!(subplt::Subplot{PyPlotPackage}, isbefore::Bool)
l = subplt.layout
isa(l, GridLayout) || error("Unsupported layout ", l)
iargs = subplt.initargs[1]
w,h = map(px2inch, iargs[:size])
bgcolor = getPyPlotColor(iargs[:background_color])
fig, axes = PyPlot.subplots(nrows(l), ncols(l),
n, m = nrows(l), ncols(l)
fig, axes = PyPlot.subplots(n, m,
sharex = get(iargs,:linkx,false),
sharey = get(iargs,:linky,false),
figsize = (w,h),
facecolor = bgcolor,
dpi = 96)
@show fig axes
subplt.o = fig
# @show axes
@assert length(axes) == length(subplt.plts)
axes = vec(reshape(axes, n, m)')
for (i,plt) in enumerate(subplt.plts)
plt.o = PyPlotAxisWrapper(axes[i])
end
# @show fig axes
subplt.o = PyPlotFigWrapper(fig)
true
# # TODO: set plt.o = PyPlotAxisWrapper(ax) for each plot
# for (i,(r,c)) in enumerate(subplt.layout)
# plt = subplt.plts[i]
# plt.o = PyPlotAxisWrapper(subplt.o.fig.o[:add_subplot]())
# # return wrap.fig.o[:add_subplot](111)
end
function handleLinkInner(plt::Plot{PyPlotPackage}, isx::Bool)
if isx
plot!(plt, xticks=zeros(0), xlabel="")
else
plot!(plt, yticks=zeros(0), ylabel="")
end
end
function expandLimits!(lims, plt::Plot{PyPlotPackage}, isx::Bool)
pltlims = plt.o.ax[isx ? :get_xbound : :get_ybound]()
expandLimits!(lims, pltlims)
end
# -----------------------------------------------------------------
function addPyPlotLegend(plt::Plot)
# function addPyPlotLegend(plt::Plot)
function addPyPlotLegend(plt::Plot, ax)
if plt.initargs[:legend]
# gotta do this to ensure both axes are included
args = filter(x -> !(x[:linetype] in (:hist,:hexbin,:heatmap,:hline,:vline)), plt.seriesargs)
if length(args) > 0
PyPlot.legend([d[:serieshandle] for d in args], [d[:label] for d in args], loc="best")
# PyPlot.legend([d[:serieshandle] for d in args], [d[:label] for d in args], loc="best")
ax[:legend]([d[:serieshandle] for d in args], [d[:label] for d in args], loc="best")
end
end
end
function Base.writemime(io::IO, m::MIME"image/png", plt::PlottingObject{PyPlotPackage})
fig = plt.o
addPyPlotLegend(plt)
ax = fig.o[:axes][1]
function finalizePlot(plt::Plot{PyPlotPackage})
wrap = plt.o
ax = getLeftAxis(plt)
addPyPlotLegend(plt, ax)
updateAxisColors(ax, getPyPlotColor(plt.initargs[:foreground_color]))
writemime(io, m, fig)
PyPlot.draw()
end
function Base.writemime(io::IO, m::MIME"image/png", plt::Plot{PyPlotPackage})
# wrap = plt.o
# # addPyPlotLegend(plt)
# # ax = fig.o[:axes][1]
# ax = getLeftAxis(plt)
# addPyPlotLegend(plt, ax)
# updateAxisColors(ax, getPyPlotColor(plt.initargs[:foreground_color]))
finalizePlot(plt)
writemime(io, m, plt.o.fig)
end
function Base.display(::PlotsDisplay, plt::Plot{PyPlotPackage})
fig = plt.o
addPyPlotLegend(plt)
ax = fig.o[:axes][1]
updateAxisColors(ax, getPyPlotColor(plt.initargs[:foreground_color]))
display(fig)
# wrap = plt.o
# # addPyPlotLegend(plt)
# # ax = fig.o[:axes][1]
# ax = getLeftAxis(plt)
# addPyPlotLegend(plt, ax)
# updateAxisColors(ax, getPyPlotColor(plt.initargs[:foreground_color]))
# # wrap.fig.o[:show]()
# PyPlot.draw()
# display(wrap.fig)
finalizePlot(plt)
end
function finalizePlot(subplt::Subplot{PyPlotPackage})
fig = subplt.o.fig
for (i,plt) in enumerate(subplt.plts)
# fig.o[:axes][i] = getLeftAxis(plt)
finalizePlot(plt)
end
end
function Base.display(::PlotsDisplay, subplt::Subplot{PyPlotPackage})
display(subplt.o)
# for plt in subplt.plts
# finalizePlot(plt)
# end
finalizePlot(subplt)
display(subplt.o.fig)
end
function Base.writemime(io::IO, m::MIME"image/png", subplt::Subplot{PyPlotPackage})
# wrap = plt.o
# # addPyPlotLegend(plt)
# # ax = fig.o[:axes][1]
# ax = getLeftAxis(plt)
# addPyPlotLegend(plt, ax)
# updateAxisColors(ax, getPyPlotColor(plt.initargs[:foreground_color]))
# for plt in subplt.plts
# finalizePlot(plt)
# end
finalizePlot(subplt)
writemime(io, m, subplt.o.fig)
end

View File

@ -246,7 +246,8 @@ end
# -------------------------------
# create the underlying object (each backend will do this differently)
function buildSubplotObject!(subplt::Subplot{QwtPackage})
function buildSubplotObject!(subplt::Subplot{QwtPackage}, isbefore::Bool)
isbefore && return false
i = 0
rows = []
row = []
@ -264,6 +265,7 @@ function buildSubplotObject!(subplt::Subplot{QwtPackage})
subplt.o = Qwt.vsplitter(rows...)
Qwt.resizewidget(subplt.o, subplt.initargs[1][:size]...)
Qwt.moveToLastScreen(subplt.o) # hack so it goes to my center monitor... sorry
true
end
function handleLinkInner(plt::Plot{QwtPackage}, isx::Bool)

View File

@ -238,8 +238,9 @@ end
# we don't do very much for subplots... just stack them vertically
function buildSubplotObject!(subplt::Subplot{UnicodePlotsPackage})
nothing
function buildSubplotObject!(subplt::Subplot{UnicodePlotsPackage}, isbefore::Bool)
isbefore && return false
true
end

View File

@ -256,7 +256,7 @@ end
# ----------------------------------------------------------------
function buildSubplotObject!(subplt::Subplot{WinstonPackage})
function buildSubplotObject!(subplt::Subplot{WinstonPackage}, isbefore::Bool)
# TODO: build the underlying Subplot object. this is where you might layout the panes within a GUI window, for example
end

View File

@ -68,21 +68,22 @@ function corrplot{T<:Real,S<:Real}(mat::AMat{T}, corrmat::AMat{S};
@assert size(corrmat) == (m,m)
# create a subplot grid, and a gradient from -1 to 1
p = subplot(zeros(1,m^2); n=m^2, link=true, kw...)
p = subplot(rand(0,m^2); n=m^2, kw...)
cgrad = ColorGradient(colors, [-1,1])
# make all the plots
for i in 1:m
for j in 1:m
idx = p.layout[i,j]
plt = p.plts[idx]
if i==j
# histogram on diagonal
plt = histogram(mat[:,i], c=:black, leg=false)
histogram!(plt, mat[:,i], c=:black, leg=false)
i > 1 && plot!(yticks = :none)
else
# scatter plots off-diagonal, color determined by correlation
c = RGBA(RGB(getColorZ(cgrad, corrmat[i,j])), 0.3)
plt = scatter(mat[:,j], mat[:,i], w=0, ms=3, c=c, leg=false)
scatter!(plt, mat[:,j], mat[:,i], w=0, ms=3, c=c, leg=false)
end
if labels != nothing && length(labels) >= m
@ -90,8 +91,8 @@ function corrplot{T<:Real,S<:Real}(mat::AMat{T}, corrmat::AMat{S};
j == 1 && ylabel!(string(labels[i]))
end
# replace the plt
p.plts[idx] = plt
# # replace the plt
# p.plts[idx] = plt
end
end

View File

@ -202,6 +202,7 @@ function subplot(args...; kw...)
ds = Dict[]
for i in 1:length(layout)
push!(ds, getPlotArgs(pkg, d, i))
ds[i][:subplot] = true
push!(plts, plot(pkg; ds[i]...))
end
@ -258,6 +259,14 @@ function subplot!(subplt::Subplot, args...; kw...)
# subplt.linkfunc = d[:linkfunc]
# end
# create the underlying object (each backend will do this differently)
# note: we call it once before doing the individual plots, and once after
# this is because some backends need to set up the subplots and then plot,
# and others need to do it the other way around
if !subplt.initialized
subplt.initialized = buildSubplotObject!(subplt, true)
end
kwList, xmeta, ymeta = createKWargsList(subplt, args...; d...)
# TODO: something useful with meta info?
@ -266,15 +275,14 @@ function subplot!(subplt::Subplot, args...; kw...)
subplt.n += 1
plt = getplot(subplt) # get the Plot object where this series will be drawn
di[:show] = false
di[:subplot] = true
dumpdict(di, "subplot! kwList $i")
plot!(plt; di...)
end
# create the underlying object (each backend will do this differently)
if !subplt.initialized
buildSubplotObject!(subplt)
subplt.initialized = true
subplt.initialized = buildSubplotObject!(subplt, false)
# subplt.initialized = true
end

View File

@ -118,9 +118,11 @@ unzip{T,S}(v::AVec{@compat(Tuple{T,S})}) = [vi[1] for vi in v], [vi[2] for vi in
# given 2-element lims and a vector of data x, widen lims to account for the extrema of x
function expandLimits!(lims, x)
e1, e2 = extrema(x)
lims[1] = min(lims[1], e1)
lims[2] = max(lims[2], e2)
try
e1, e2 = extrema(x)
lims[1] = min(lims[1], e1)
lims[2] = max(lims[2], e2)
end
nothing
end