# TODO: there should be a distinction between an object that will manage a full plot, vs a component of a plot. # the PlotRecipe as currently implemented is more of a "custom component" # a recipe should fully describe the plotting command(s) and call them, likewise for updating. # actually... maybe those should explicitly derive from PlottingObject??? 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...) num_series(x::AMat) = size(x,2) num_series(x) = 1 _apply_recipe(d::Dict; kw...) = nothing # if it's not a recipe, just do nothing and return the args function _apply_recipe(d::Dict, args...; issubplot=false, kw...) if issubplot && !haskey(d, :n) && !haskey(d, :layout) # put in a sensible default d[:n] = maximum(map(num_series, args)) end args end # # ------------------------------------------------- # function rotate(x::Real, y::Real, θ::Real; center = (0,0)) # cx = x - center[1] # cy = y - center[2] # xrot = cx * cos(θ) - cy * sin(θ) # yrot = cy * cos(θ) + cx * sin(θ) # xrot + center[1], yrot + center[2] # end # # ------------------------------------------------- # 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 and translate # r = rotate(xpre, ypre, rotθ) # x + r[1], y + r[2] # 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)]) # top = rotate(0, ep.h, ep.θ) # right = rotate(ep.w, 0, ep.θ) # linex = Float64[top[1], 0, right[1]] + ep.x # liney = Float64[top[2], 0, right[2]] + ep.y # Any[x, linex], Any[y, liney] # end # function getRecipeArgs(ep::EllipseRecipe) # [(:line, (3, [:dot :solid], [:red :blue], :path))] # end # # ------------------------------------------------- # "Correlation scatter matrix" # function corrplot{T<:Real,S<:Real}(mat::AMat{T}, corrmat::AMat{S} = cor(mat); # colors = :redsblues, # labels = nothing, kw...) # m = size(mat,2) # centers = Float64[mean(extrema(mat[:,i])) for i in 1:m] # # might be a mistake? # @assert m <= 20 # @assert size(corrmat) == (m,m) # # create a subplot grid, and a gradient from -1 to 1 # p = subplot(rand(0,m^2); n=m^2, leg=false, grid=false, 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 # histogram!(plt, mat[:,i], c=:black) # i > 1 && plot!(plt, yticks = :none) # elseif i < j # # annotate correlation value in upper triangle # mi, mj = centers[i], centers[j] # plot!(plt, [mj], [mi], # ann = (mj, mi, text(@sprintf("Corr:\n%0.3f", corrmat[i,j]), 15)), # yticks=:none) # else # # scatter plots in lower triangle; color determined by correlation # c = RGBA(RGB(getColorZ(cgrad, corrmat[i,j])), 0.3) # scatter!(plt, mat[:,j], mat[:,i], w=0, ms=3, c=c, smooth=true) # end # if labels != nothing && length(labels) >= m # i == m && xlabel!(plt, string(labels[j])) # j == 1 && ylabel!(plt, string(labels[i])) # end # end # end # # link the axes # subplot!(p, link = (r,c) -> (true, r!=c)) # end "Sparsity plot... heatmap of non-zero values of a matrix" function spy{T<:Real}(y::AMat{T}; kw...) I,J,V = findnz(y) heatmap(J, I; leg=false, yflip=true, nbins=size(y), kw...) end