working on unicodeplots; added args to Plot; some reorg

This commit is contained in:
Thomas Breloff 2015-09-12 00:24:35 -04:00
parent e13fec08ca
commit f322b9ac1c
9 changed files with 164 additions and 150 deletions

View File

@ -6,10 +6,11 @@ Plotting interface and wrapper for several plotting packages.
Please add wishlist items, bugs, or any other comments/questions to the issues list.
## Examples
## Examples for each implemented backend:
- [Qwt.jl](docs/qwt_examples.md)
- [Gadfly.jl](docs/gadfly_examples.md)
- [UnicodePlots.jl](docs/gadfly_examples.md)
## Installation
@ -187,6 +188,10 @@ When plotting multiple lines, you can give every line the same trait by using th
- [x] Plot vectors/matrices/functions
- [ ] Plot DataFrames
- [ ] Scales
- [ ] Categorical Inputs (strings, etc... for hist, bar? or can split one series into multiple?)
- [ ] Custom markers
- [ ] Special plots (boxplot, ohlc?)
- [x] Subplots
- [x] Histograms
- [ ] 3D plotting

View File

@ -39,15 +39,7 @@ const IMG_DIR = Pkg.dir("Plots") * "/img/"
include("types.jl")
include("utils.jl")
# ---------------------------------------------------------
include("qwt.jl")
include("gadfly.jl")
include("plotter.jl")
# ---------------------------------------------------------
include("args.jl")
include("plot.jl")
include("subplot.jl")

View File

@ -125,7 +125,11 @@ function getPlotKeywordArgs(kw, idx::Int, n::Int)
# set label
label = d[:label]
d[:label] = string(label == "AUTO" ? "y_$n" : label, d[:axis] == :left ? "" : " (R)")
label = (label == "AUTO" ? "y_$n" : label)
if d[:axis] == :right && label[end-3:end] != " (R)"
label = string(label, " (R)")
end
d[:label] = label
end
d

View File

@ -27,7 +27,7 @@ function plot(pkg::GadflyPackage; kw...)
plt.theme = Gadfly.Theme(background_color = (haskey(d, :background_color) ? d[:background_color] : colorant"white"))
Plot(plt, pkg, 0)
Plot(plt, pkg, 0, kw, Dict[])
end
function getGeomFromLineType(linetype::Symbol, nbins::Int)
@ -95,6 +95,9 @@ function plot!(::GadflyPackage, plt::Plot; kw...)
warn("Gadly only supports one y axis")
end
# save the kw args
plt.push!(plt.seriesargs, d)
# add the layer to the Gadfly.Plot
prepend!(plt.o.layers, Gadfly.layer(unique(gfargs)...; x = x, y = d[:y]))
plt
@ -115,9 +118,7 @@ end
# -------------------------------
# # create the underlying object (each backend will do this differently)
# o = buildSubplotObject(plts, pkg, layout)
# create the underlying object (each backend will do this differently)
function buildSubplotObject!(::GadflyPackage, subplt::Subplot)
i = 0
rows = []

View File

@ -24,13 +24,16 @@ end
function plot(pkg::QwtPackage; kw...)
kw = adjustQwtKeywords(true; kw...)
plt = Plot(Qwt.plot(zeros(0,0); kw..., show=false), pkg, 0)
o = Qwt.plot(zeros(0,0); kw..., show=false)
plt = Plot(o, pkg, 0, kw, Dict[])
plt
end
function plot!(::QwtPackage, plt::Plot; kw...)
kw = adjustQwtKeywords(false; kw...)
Qwt.oplot(plt.o; kw...)
plt.push!(plt.seriesargs, kw)
plt
end
function Base.display(::QwtPackage, plt::Plot)
@ -44,9 +47,7 @@ savepng(::QwtPackage, plt::PlottingObject, fn::String, args...) = Qwt.savepng(pl
# -------------------------------
# # create the underlying object (each backend will do this differently)
# o = buildSubplotObject(plts, pkg, layout)
# create the underlying object (each backend will do this differently)
function buildSubplotObject!(::QwtPackage, subplt::Subplot)
i = 0
rows = []

View File

@ -0,0 +1,124 @@
# https://github.com/Evizero/UnicodePlots.jl
immutable UnicodePlotsPackage <: PlottingPackage end
# -------------------------------
function expandLimits!(lims, x)
e1, e2 = extrema(x)
lims[1] = min(lims[1], e1)
lims[2] = max(lims[2], e2)
nothing
end
# do all the magic here... build it all at once, since we need to know about all the series at the very beginning
function rebuildUnicodePlot!(plt::Plot)
# figure out the plotting area xlim = [xmin, xmax] and ylim = [ymin, ymax]
sargs = plt.seriesargs
xlim = [Inf, -Inf]
ylim = [Inf, -Inf]
for d in sargs
@show xlim ylim d[:x] d[:y]
expandLimits!(xlim, d[:x])
expandLimits!(ylim, d[:y])
@show xlim ylim d[:x] d[:y]
end
x = Float64[xlim[1]]
y = Float64[ylim[1]]
# create a plot window with xlim/ylim set, but the X/Y vectors are outside the bounds
iargs = plt.initargs
width, height = iargs[:size]
o = UnicodePlots.createPlotWindow(x, y; width = width,
height = height,
title = iargs[:title],
# labels = iargs[:legend],
xlim = xlim,
ylim = ylim)
# set the axis labels
UnicodePlots.xlabel!(o, iargs[:xlabel])
UnicodePlots.ylabel!(o, iargs[:ylabel])
# now use the ! functions to add to the plot
for d in sargs
addUnicodeSeries!(o, d, iargs[:legend])
end
# save the object
plt.o = o
end
# add a single series
function addUnicodeSeries!(o, d::Dict, addlegend::Bool)
lt = d[:linetype]
x, y = d[:x], d[:y]
label = addlegend ? d[:label] : ""
stepstyle = :post
# if we happen to pass in allowed color symbols, great... otherwise let UnicodePlots decide
color = d[:color] in UnicodePlots.autoColors ? d[:color] : :auto
if lt == :line
func = UnicodePlots.lineplot!
elseif lt == :dots || d[:marker] != :none
func = UnicodePlots.scatterplot!
elseif lt == :step
func = UnicodePlots.stairs!
elseif lt == :stepinverted
func = UnicodePlots.stairs!
stepstyle = :pre
else
error("Linestyle $lt not supported by UnicodePlots")
end
func(o, x, y; color = color, name = label, style = stepstyle)
end
# -------------------------------
function plot(pkg::UnicodePlotsPackage; kw...)
plt = Plot(nothing, pkg, 0, Dict(kw), Dict[])
# do we want to give a new default size?
if !haskey(plt.initargs, :size) || plt.initargs[:size] == PLOT_DEFAULTS[:size]
plt.initargs[:size] = (60,20)
end
# w,h = plt.initargs[:size]
# plt.initargs[:size] = (min(200,w), min(200,h))
plt
end
function plot!(::UnicodePlotsPackage, plt::Plot; kw...)
push!(plt.seriesargs, Dict(kw))
plt
end
function Base.display(::UnicodePlotsPackage, plt::Plot)
rebuildUnicodePlot!(plt)
show(plt.o)
end
# -------------------------------
savepng(::UnicodePlotsPackage, plt::PlottingObject, fn::String, args...) = error("currently unsupported")
# -------------------------------
# create the underlying object (each backend will do this differently)
function buildSubplotObject!(::UnicodePlotsPackage, subplt::Subplot)
error("UnicodePlots doesn't support subplots")
end
function Base.display(::UnicodePlotsPackage, subplt::Subplot)
error("UnicodePlots doesn't support subplots")
end

View File

@ -104,14 +104,6 @@ end
# this adds to a specific plot... most plot commands will flow through here
function plot!(plt::Plot, args...; kw...)
# # increment n if we're going directly to the package's plot method
# if length(args) == 0
# plt.n += 1
# end
# plot!(plt.plotter, plt, args...; kw...)
kwList = createKWargsList(plt, args...; kw...)
for (i,d) in enumerate(kwList)
plt.n += 1
@ -292,123 +284,3 @@ end
# -------------------------
# # most calls should flow through here now... we create a Dict with the keyword args for each series, and plot them
# function plot!(pkg::PlottingPackage, plt::Plot, args...; kw...)
# kwList = createKWargsList(plt, args...; kw...)
# for (i,d) in enumerate(kwList)
# plt.n += 1
# plot!(pkg, plt; d...)
# end
# plt
# end
# -------------------------
# # These methods are various ways to add to an existing plot
# function plot!{T<:Real}(pkg::PlottingPackage, plt::Plot, y::AVec{T}; kw...)
# plt.n += 1
# # plot!(pkg, plt; x = 1:length(y), y = y, getPlotKeywordArgs(kw, 1, plt)...)
# end
# function plot!{T<:Real,S<:Real}(pkg::PlottingPackage, plt::Plot, x::AVec{T}, y::AVec{S}; kw...) # one line (will assert length(x) == length(y))
# @assert length(x) == length(y)
# plt.n += 1
# plot!(pkg, plt; x=x, y=y, getPlotKeywordArgs(kw, 1, plt)...)
# end
# function plot!(pkg::PlottingPackage, plt::Plot, y::AMat; kw...) # multiple lines (one per column of x), all sharing x = 1:size(y,1)
# n,m = size(y)
# for i in 1:m
# plt.n += 1
# plot!(pkg, plt; x = 1:n, y = y[:,i], getPlotKeywordArgs(kw, i, plt)...)
# end
# plt
# end
# function plot!(pkg::PlottingPackage, plt::Plot, x::AVec, y::AMat; kw...) # multiple lines (one per column of x), all sharing x (will assert length(x) == size(y,1))
# n,m = size(y)
# for i in 1:m
# @assert length(x) == n
# plt.n += 1
# plot!(pkg, plt; x = x, y = y[:,i], getPlotKeywordArgs(kw, i, plt)...)
# end
# plt
# end
# function plot!(pkg::PlottingPackage, plt::Plot, x::AMat, y::AMat; kw...) # multiple lines (one per column of x/y... will assert size(x) == size(y))
# @assert size(x) == size(y)
# for i in 1:size(x,2)
# plt.n += 1
# plot!(pkg, plt; x = x[:,i], y = y[:,i], getPlotKeywordArgs(kw, i, plt)...)
# end
# plt
# end
# function plot!(pkg::PlottingPackage, plt::Plot, x::AVec, f::Function; kw...) # one line, y = f(x)
# plt.n += 1
# plot!(pkg, plt; x = x, y = map(f,x), getPlotKeywordArgs(kw, 1, plt)...)
# end
# function plot!(pkg::PlottingPackage, plt::Plot, x::AMat, f::Function; kw...) # multiple lines, yᵢⱼ = f(xᵢⱼ)
# for i in 1:size(x,2)
# xi = x[:,i]
# plt.n += 1
# plot!(pkg, plt; x = xi, y = map(f, xi), getPlotKeywordArgs(kw, i, plt)...)
# end
# plt
# end
# # function plot!(pkg::PlottingPackage, plt::Plot, x::AVec, fs::AVec{Function}; kw...) # multiple lines, yᵢⱼ = fⱼ(xᵢ)
# # for i in 1:length(fs)
# # plt.n += 1
# # plot!(pkg, plt; x = x, y = map(fs[i], x), getPlotKeywordArgs(kw, i, plt)...)
# # end
# # plt
# # end
# function plot!(pkg::PlottingPackage, plt::Plot, y::AVec; kw...) # multiple lines, each with x = 1:length(y[i])
# for i in 1:length(y)
# plt.n += 1
# plot!(pkg, plt; x = 1:length(y[i]), y = y[i], getPlotKeywordArgs(kw, i, plt)...)
# end
# plt
# end
# function plot!{T<:Real}(pkg::PlottingPackage, plt::Plot, x::AVec{T}, y::AVec; kw...) # multiple lines, will assert length(x) == length(y[i])
# for i in 1:length(y)
# if typeof(y[i]) <: AbstractVector
# @assert length(x) == length(y[i])
# plt.n += 1
# plot!(pkg, plt; x = x, y = y[i], getPlotKeywordArgs(kw, i, plt)...)
# elseif typeof(y[i]) == Function
# plt.n += 1
# plot!(pkg, plt; x = x, y = map(y[i], x), getPlotKeywordArgs(kw, 1, plt)...)
# end
# end
# plt
# end
# function plot!(pkg::PlottingPackage, plt::Plot, x::AVec, y::AVec; kw...) # multiple lines, will assert length(x[i]) == length(y[i])
# @assert length(x) == length(y)
# for i in 1:length(x)
# @assert length(x[i]) == length(y[i])
# plt.n += 1
# plot!(pkg, plt; x = x[i], y = y[i], getPlotKeywordArgs(kw, i, plt)...)
# end
# plt
# end
# function plot!(pkg::PlottingPackage, plt::Plot, n::Integer; kw...) # n lines, all empty (for updating plots)
# for i in 1:n
# plt.n += 1
# plot(pkg, plt, x = zeros(0), y = zeros(0), getPlotKeywordArgs(kw, i, plt)...)
# end
# end
# -------------------------
# # this is the core method... add to a plot object using kwargs, with args already converted into kwargs
# function plot!(pkg::PlottingPackage, plt::Plot; kw...)
# plot!(pl, plt; kw...)
# end

View File

@ -1,5 +1,13 @@
include("backends/qwt.jl")
include("backends/gadfly.jl")
include("backends/unicodeplots.jl")
# ---------------------------------------------------------
plot(pkg::PlottingPackage; kw...) = error("plot($pkg; kw...) is not implemented")
plot!(pkg::PlottingPackage, plt::Plot; kw...) = error("plot!($pkg, plt; kw...) is not implemented")
Base.display(pkg::PlottingPackage, plt::Plot) = error("display($pkg, plt) is not implemented")
@ -7,14 +15,13 @@ Base.display(pkg::PlottingPackage, plt::Plot) = error("display($pkg, plt) is not
# ---------------------------------------------------------
const AVAILABLE_PACKAGES = [:qwt, :gadfly]
const AVAILABLE_PACKAGES = [:qwt, :gadfly, :unicodeplots]
const INITIALIZED_PACKAGES = Set{Symbol}()
type CurrentPackage
sym::Symbol
pkg::PlottingPackage
end
# const CURRENT_PACKAGE = CurrentPackage(:qwt, QwtPackage())
const CURRENT_PACKAGE = CurrentPackage(:gadfly, GadflyPackage())
@ -32,6 +39,8 @@ function plotter()
@eval import Qwt
elseif currentPackageSymbol == :gadfly
@eval import Gadfly
elseif currentPackageSymbol == :unicodeplots
@eval import UnicodePlots
else
error("Unknown plotter $currentPackageSymbol. Choose from: $AVAILABLE_PACKAGES")
end
@ -43,7 +52,7 @@ function plotter()
end
doc"""
Set the plot backend. Choose from: :qwt, :gadfly
Set the plot backend. Choose from: :qwt, :gadfly, :unicodeplots
"""
function plotter!(modname)
@ -52,6 +61,8 @@ function plotter!(modname)
CURRENT_PACKAGE.pkg = QwtPackage()
elseif modname == :gadfly
CURRENT_PACKAGE.pkg = GadflyPackage()
elseif modname == :unicodeplots
CURRENT_PACKAGE.pkg = UnicodePlotsPackage()
else
error("Unknown plotter $modname. Choose from: $AVAILABLE_PACKAGES")
end

View File

@ -9,6 +9,10 @@ type Plot <: PlottingObject
o # the underlying object
plotter::PlottingPackage
n::Int # number of series
# store these just in case
initargs::Dict
seriesargs::Vector{Dict} # args for each series
end