working on subplots and recipes

This commit is contained in:
Thomas Breloff 2015-10-09 13:12:40 -04:00
parent f4b716b255
commit 64b8e15918
10 changed files with 285 additions and 118 deletions

File diff suppressed because one or more lines are too long

View File

@ -72,6 +72,11 @@ export
getColor,
getColorZ,
PlotRecipe,
EllipseRecipe,
debugplots,
supportedArgs,
supportedAxes,
supportedTypes,
@ -94,6 +99,7 @@ include("plotter.jl")
include("args.jl")
include("plot.jl")
include("subplot.jl")
include("recipes.jl")
# ---------------------------------------------------------

View File

@ -150,6 +150,9 @@ _plotDefaults[:n] = -1
_plotDefaults[:nr] = -1
_plotDefaults[:nc] = -1
_plotDefaults[:color_palette] = :auto
_plotDefaults[:link] = false
_plotDefaults[:linkx] = false
_plotDefaults[:linky] = false
@ -260,6 +263,8 @@ end
:gui => :show,
:display => :show,
:palette => :color_palette,
:xlink => :linkx,
:ylink => :linky,
)
# add all pluralized forms to the _keyAliases dict
@ -446,6 +451,14 @@ function preprocessArgs!(d::Dict)
end
delete!(d, :fill)
# handle subplot links
if haskey(d, :link)
l = d[:link]
d[:linkx] = l
d[:linky] = l
delete!(d, :link)
end
return
end

View File

@ -54,6 +54,8 @@ supportedArgs(::GadflyPackage) = [
:xflip,
:yflip,
:z,
:linkx,
:linky,
]
supportedAxes(::GadflyPackage) = [:auto, :left]
supportedTypes(::GadflyPackage) = [:none, :line, :path, :steppost, :sticks, :scatter, :heatmap, :hexbin, :hist, :bar, :hline, :vline, :ohlc]
@ -487,17 +489,32 @@ end
# ----------------------------------------------------------------
getGadflyContext(::GadflyPackage, plt::Plot) = plt.o
getGadflyContext(::GadflyPackage, subplt::Subplot) = buildGadflySubplotContext(subplt)
getGadflyContext(plt::Plot{GadflyPackage}) = plt.o
getGadflyContext(subplt::Subplot{GadflyPackage}) = buildGadflySubplotContext(subplt)
# create my Compose.Context grid by hstacking and vstacking the Gadfly.Plot objects
function buildGadflySubplotContext(subplt::Subplot)
i = 0
# i = 0
# rows = Any[]
# for rowcnt in subplt.layout.rowcounts
# push!(rows, Gadfly.hstack([getGadflyContext(plt) for plt in subplt.plts[(1:rowcnt) + i]]...))
# i += rowcnt
# end
rows = Any[]
for rowcnt in subplt.layout.rowcounts
push!(rows, Gadfly.hstack([getGadflyContext(plt.backend, plt) for plt in subplt.plts[(1:rowcnt) + i]]...))
i += rowcnt
row = Any[]
for (i,(r,c)) in enumerate(subplt.layout)
# add the Plot object to the row
push!(row, getGadflyContext(subplt.plts[i]))
# add the row
if c == ncols(subplt.layout, r)
push!(rows, Gadfly.hstack(row...))
row = Any[]
end
end
# stack the rows
Gadfly.vstack(rows...)
end
@ -506,7 +523,7 @@ function setGadflyDisplaySize(w,h)
end
function Base.writemime(io::IO, ::MIME"image/png", plt::Plot{GadflyPackage})
gplt = getGadflyContext(plt.backend, plt)
gplt = getGadflyContext(plt)
setGadflyDisplaySize(plt.initargs[:size]...)
Gadfly.draw(Gadfly.PNG(io, Compose.default_graphic_width, Compose.default_graphic_height), gplt)
end
@ -520,7 +537,7 @@ end
function Base.writemime(io::IO, ::MIME"image/png", plt::Subplot{GadflyPackage})
gplt = getGadflyContext(plt.backend, plt)
gplt = getGadflyContext(plt)
setGadflyDisplaySize(plt.initargs[1][:size]...)
Gadfly.draw(Gadfly.PNG(io, Compose.default_graphic_width, Compose.default_graphic_height), gplt)
end

View File

@ -125,8 +125,8 @@ end
# ----------------------------------------------------------------
getGadflyContext(::ImmersePackage, plt::Plot) = plt.o[2]
getGadflyContext(::ImmersePackage, subplt::Subplot) = buildGadflySubplotContext(subplt)
getGadflyContext(plt::Plot{ImmersePackage}) = plt.o[2]
getGadflyContext(subplt::Subplot{ImmersePackage}) = buildGadflySubplotContext(subplt)
function Base.writemime(io::IO, ::MIME"image/png", plt::Plot{ImmersePackage})
gplt = getGadflyContext(plt.backend, plt)
@ -149,7 +149,7 @@ end
function Base.writemime(io::IO, ::MIME"image/png", plt::Subplot{ImmersePackage})
gplt = getGadflyContext(plt.backend, plt)
gplt = getGadflyContext(plt)
setGadflyDisplaySize(plt.initargs[1][:size]...)
Gadfly.draw(Gadfly.PNG(io, Compose.default_graphic_width, Compose.default_graphic_height), gplt)
end

View File

@ -334,10 +334,10 @@ mapFuncOrFuncs(f::Function, u::AVec) = map(f, u)
mapFuncOrFuncs(fs::AVec{Function}, u::AVec) = [map(f, u) for f in fs]
# special handling... xmin/xmax with parametric function(s)
function createKWargsList(plt::PlottingObject, fx::FuncOrFuncs, fy::FuncOrFuncs, umin::Real, umax::Real, numPoints::Int = 1000; kw...)
u = collect(linspace(umin, umax, numPoints))
createKWargsList(plt, mapFuncOrFuncs(fx, u), mapFuncOrFuncs(fy, u); kw...)
end
createKWargsList{T<:Real}(plt::PlottingObject, fx::FuncOrFuncs, fy::FuncOrFuncs, u::AVec{T}; kw...) = createKWargsList(plt, mapFuncOrFuncs(fx, u), mapFuncOrFuncs(fy, u); kw...)
createKWargsList{T<:Real}(plt::PlottingObject, u::AVec{T}, fx::FuncOrFuncs, fy::FuncOrFuncs; kw...) = createKWargsList(plt, mapFuncOrFuncs(fx, u), mapFuncOrFuncs(fy, u); kw...)
createKWargsList(plt::PlottingObject, fx::FuncOrFuncs, fy::FuncOrFuncs, umin::Real, umax::Real, numPoints::Int = 1000; kw...) = createKWargsList(plt, fx, fy, linspace(umin, umax, numPoints))
# special handling... no args... 1 series

51
src/recipes.jl Normal file
View File

@ -0,0 +1,51 @@
abstract PlotRecipe
getRecipeXY(recipe::PlotRecipe) = Float64[], Float64[]
getRecipeArgs(recipe::PlotRecipe) = ()
plot(recipe::PlotRecipe, args...; kw...) = plot(getRecipeXY(recipe)..., args...; getRecipeArgs(recipe)..., kw...)
plot!(recipe::PlotRecipe, args...; kw...) = plot!(getRecipeXY(recipe)..., args...; getRecipeArgs(recipe)..., kw...)
plot!(plt::Plot, recipe::PlotRecipe, args...; kw...) = plot!(getRecipeXY(recipe)..., args...; getRecipeArgs(recipe)..., kw...)
# -------------------------------------------------
type EllipseRecipe <: PlotRecipe
w::Float64
h::Float64
x::Float64
y::Float64
θ::Float64
end
EllipseRecipe(w,h,x,y) = EllipseRecipe(w,h,x,y,0)
# return x,y coords of a rotated ellipse, centered at the origin
function rotatedEllipse(w, h, x, y, θ, rotθ)
# coord before rotation
xpre = w * cos(θ)
ypre = h * sin(θ)
# rotate
xrot = xpre * cos(rotθ) + ypre * sin(rotθ)
yrot = ypre * cos(rotθ) - xpre * sin(rotθ)
# translate
xrot + x, yrot + y
end
function getRecipeXY(ep::EllipseRecipe)
x, y = unzip([rotatedEllipse(ep.w, ep.h, ep.x, ep.y, u, ep.θ) for u in linspace(0,2π,100)])
right = rotatedEllipse(ep.w, ep.h, ep.x, ep.y, 0, ep.θ)
top = rotatedEllipse(ep.w, ep.h, ep.x, ep.y, 0.5π, ep.θ)
linex = Float64[top[1], ep.x, right[1]]
liney = Float64[top[2], ep.y, right[2]]
Any[x, linex], Any[y, liney]
end
function getRecipeArgs(ep::EllipseRecipe)
d = Dict()
d[:line] = (3, [:dot :solid], [:red :blue], :path)
d
end

View File

@ -95,13 +95,14 @@ Base.length(layout::GridLayout) = layout.nr * layout.nc
Base.start(layout::GridLayout) = 1
Base.done(layout::GridLayout, state) = state > length(layout)
function Base.next(layout::GridLayout, state)
r = div(state, layout.nc)
r = div(state-1, layout.nc) + 1
c = mod1(state, layout.nc)
(r,c), state + 1
end
nrows(layout::GridLayout) = layout.nr
ncols(layout::GridLayout) = layout.nc
ncols(layout::GridLayout, row::Int) = layout.nc
@ -167,7 +168,7 @@ function subplot(args...; kw...)
# # tmpd[:show] = shouldShow
# create the object and do the plotting
subplt = Subplot(nothing, plts, pkg, length(layout), 0, layout, ds, false)
subplt = Subplot(nothing, plts, pkg, length(layout), 0, layout, ds, false, get(d, :linkx, false), get(d, :linky, false))
subplot!(subplt, args...; kw...)
subplt
@ -235,6 +236,13 @@ function subplot!(subplt::Subplot, args...; kw...)
updatePlotItems(plt, di)
end
if subplt.linkx
linkXAxis(subplt)
end
if subplt.linky
linkYAxis(subplt)
end
# set this to be current
current(subplt)

View File

@ -31,15 +31,17 @@ immutable FlexLayout <: SubplotLayout
end
type Subplot{T<:PlottingPackage} <: PlottingObject{T}
type Subplot{T<:PlottingPackage, L<:SubplotLayout} <: PlottingObject{T}
o # the underlying object
plts::Vector{Plot} # the individual plots
backend::T
p::Int # number of plots
n::Int # number of series
layout::SubplotLayout
layout::L
initargs::Vector{Dict}
initialized::Bool
linkx::Bool
linky::Bool
end

View File

@ -114,6 +114,9 @@ maketuple(x::Real) = (x,x)
maketuple{T,S}(x::@compat(Tuple{T,S})) = x
unzip{T,S}(v::AVec{@compat(Tuple{T,S})}) = [vi[1] for vi in v], [vi[2] for vi in v]
function replaceAliases!(d::Dict, aliases::Dict)
for (k,v) in d
if haskey(aliases, k)
@ -153,6 +156,9 @@ type DebugMode
end
const _debugMode = DebugMode(false)
function debugplots(on = true)
_debugMode.on = on
end
function dumpdict(d::Dict, prefix = "")
_debugMode.on || return