diff --git a/src/Plots.jl b/src/Plots.jl index 09054711..2ba417e0 100644 --- a/src/Plots.jl +++ b/src/Plots.jl @@ -1,5 +1,7 @@ module Plots +using Requires + export Plot, plotter, @@ -10,6 +12,12 @@ export currentPlot!, plotDefault, plotDefault!, + + scatter, + bar, + hist, + heatmap, + savepng # --------------------------------------------------------- @@ -58,6 +66,18 @@ include("gadfly.jl") include("args.jl") include("plot.jl") + +# const LINE_TYPES = (:line, :step, :stepinverted, :sticks, :dots, :none, :heatmap, :hist, :bar) +scatter(args...; kw...) = plot(args...; kw..., linetype = :dots) +scatter!(args...; kw...) = plot!(args...; kw..., linetype = :dots) +bar(args...; kw...) = plot(args...; kw..., linetype = :bar) +bar!(args...; kw...) = plot!(args...; kw..., linetype = :bar) +hist(args...; kw...) = plot(args...; kw..., linetype = :hist) +hist!(args...; kw...) = plot!(args...; kw..., linetype = :hist) +heatmap(args...; kw...) = plot(args...; kw..., linetype = :heatmap) +heatmap!(args...; kw...) = plot!(args...; kw..., linetype = :heatmap) + + # --------------------------------------------------------- # # TODO: how do we handle NA values in dataframes? diff --git a/src/args.jl b/src/args.jl index fa0df7e7..52e2db0e 100644 --- a/src/args.jl +++ b/src/args.jl @@ -6,12 +6,14 @@ const NUMCOLORS = length(COLORS) # these are valid choices... first one is default value if unset const LINE_AXES = (:left, :right) -const LINE_TYPES = (:line, :step, :stepinverted, :sticks, :dots, :none, :heatmap) +const LINE_TYPES = (:line, :step, :stepinverted, :sticks, :dots, :none, :heatmap, :hist, :bar) const LINE_STYLES = (:solid, :dash, :dot, :dashdot, :dashdotdot) const LINE_MARKERS = (:none, :ellipse, :rect, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star1, :star2, :hexagon) const PLOT_DEFAULTS = Dict{Symbol, Any}() + +# series-specific PLOT_DEFAULTS[:axis] = :left PLOT_DEFAULTS[:color] = :auto PLOT_DEFAULTS[:label] = "AUTO" @@ -23,10 +25,16 @@ PLOT_DEFAULTS[:markercolor] = :auto PLOT_DEFAULTS[:markersize] = 10 PLOT_DEFAULTS[:heatmap_n] = 100 PLOT_DEFAULTS[:heatmap_c] = (0.15, 0.5) + +# plot globals PLOT_DEFAULTS[:title] = "" PLOT_DEFAULTS[:xlabel] = "" PLOT_DEFAULTS[:ylabel] = "" PLOT_DEFAULTS[:yrightlabel] = "" +PLOT_DEFAULTS[:legend] = true +PLOT_DEFAULTS[:background_color] = :white +PLOT_DEFAULTS[:xticks] = true +PLOT_DEFAULTS[:yticks] = true plotDefault(sym::Symbol) = PLOT_DEFAULTS[sym] function plotDefault!(sym::Symbol, val) @@ -39,19 +47,19 @@ autocolor(idx::Integer) = COLORS[mod1(idx,NUMCOLORS)] function getPlotKeywordArgs(kw, i::Int) d = Dict(kw) - kw = Dict() + outd = Dict() for k in keys(PLOT_DEFAULTS) plural = makeplural(k) if haskey(d, plural) - kw[k] = d[plural][i] + outd[k] = d[plural][i] elseif haskey(d, k) - kw[k] = d[k] + outd[k] = d[k] else - kw[k] = PLOT_DEFAULTS[k] + outd[k] = PLOT_DEFAULTS[k] end end - kw + outd end diff --git a/src/gadfly.jl b/src/gadfly.jl index feda8ea4..25e3ec83 100644 --- a/src/gadfly.jl +++ b/src/gadfly.jl @@ -6,7 +6,44 @@ immutable GadflyPackage <: PlottingPackage end plot(pkg::GadflyPackage) = Plot(Qwt.plot(zeros(0,0)), pkg, AVec[], AVec[]) plot!(::GadflyPackage, plt::Plot; kw...) = Qwt.oplot(plt.o; kw...) -# plot(::GadflyPackage, y; kw...) = Gadfly.plot(; x = 1:length(y), y = y, kw...) -# plot(::GadflyPackage, x, y; kw...) = Gadfly.plot(; x = x, y = y, kw...) -# plot(::GadflyPackage; kw...) = Gadfly.plot(; kw...) -# savepng(::GadflyPackage, plt, fn::String, args...) = Gadfly.draw(Gadfly.PNG(fn, args...), plt) + +# create a blank Gadfly.Plot object +function plot(pkg::GadflyPackage) + plt = Gadfly.Plot() + plt.mapping = Dict() + plt.data_source = DataFrame() + plt.layers = plt.layers[1:0] + Plot(plt, pkg, AVec[], AVec[]) +end + +# plot one data series +function plot!(::GadflyPackage, plt::Plot; kw...) + d = Dict(kw) + gd = Dict() # the kwargs for the call to Gadfly.layer + + + append!(plt.o.layers, layer(; gd...)) + plt +end + +function Base.display(::GadflyPackage, plt::Plot) + display(plt.o) +end + +# julia> append!(plt.layers, layer(x=collect(1:10), y=collect(1:10), Geom.line(), Geom.point())) +# 2-element Array{Gadfly.Layer,1}: +# Gadfly.Layer(nothing,Dict{Symbol,Union{AbstractArray{T,N},AbstractString,Distributions.Distribution{F<:Distributions.VariateForm,S<:Distributions.ValueSupport},Expr,Function,Integer,Symbol,Void}}(:y=>[1,2,3,4,5,6,7,8,9,10],:x=>[1,2,3,4,5,6,7,8,9,10]),Gadfly.Stat.Nil(),Gadfly.Geom.LineGeometry(Gadfly.Stat.Identity(),false,2),nothing,0) +# Gadfly.Layer(nothing,Dict{Symbol,Union{AbstractArray{T,N},AbstractString,Distributions.Distribution{F<:Distributions.VariateForm,S<:Distributions.ValueSupport},Expr,Function,Integer,Symbol,Void}}(:y=>[1,2,3,4,5,6,7,8,9,10],:x=>[1,2,3,4,5,6,7,8,9,10]),Gadfly.Stat.Nil(),Gadfly.Geom.PointGeometry(),nothing,0) + +# julia> append!(plt.layers, layer(x=collect(1:10), y=rand(10), Geom.point())) +# 3-element Array{Gadfly.Layer,1}: +# Gadfly.Layer(nothing,Dict{Symbol,Union{AbstractArray{T,N},AbstractString,Distributions.Distribution{F<:Distributions.VariateForm,S<:Distributions.ValueSupport},Expr,Function,Integer,Symbol,Void}}(:y=>[1,2,3,4,5,6,7,8,9,10],:x=>[1,2,3,4,5,6,7,8,9,10]),Gadfly.Stat.Nil(),Gadfly.Geom.LineGeometry(Gadfly.Stat.Identity(),false,2),nothing,0) +# Gadfly.Layer(nothing,Dict{Symbol,Union{AbstractArray{T,N},AbstractString,Distributions.Distribution{F<:Distributions.VariateForm,S<:Distributions.ValueSupport},Expr,Function,Integer,Symbol,Void}}(:y=>[1,2,3,4,5,6,7,8,9,10],:x=>[1,2,3,4,5,6,7,8,9,10]),Gadfly.Stat.Nil(),Gadfly.Geom.PointGeometry(),nothing,0) +# Gadfly.Layer(nothing,Dict{Symbol,Union{AbstractArray{T,N},AbstractString,Distributions.Distribution{F<:Distributions.VariateForm,S<:Distributions.ValueSupport},Expr,Function,Integer,Symbol,Void}}(:y=>[0.6084907709968024,0.05206084912131548,0.14212960794916185,0.10981085500127885,0.9921993333039756,0.9552243188578231,0.3255950301920405,0.1328008877835145,0.8717471404048149,0.18183756751204538],:x=>[1,2,3,4,5,6,7,8,9,10]),Gadfly.Stat.Nil(),Gadfly.Geom.PointGeometry(),nothing,0) + +# julia> display(plt) + +# # plot(::GadflyPackage, y; kw...) = Gadfly.plot(; x = 1:length(y), y = y, kw...) +# # plot(::GadflyPackage, x, y; kw...) = Gadfly.plot(; x = x, y = y, kw...) +# # plot(::GadflyPackage; kw...) = Gadfly.plot(; kw...) +# # savepng(::GadflyPackage, plt, fn::String, args...) = Gadfly.draw(Gadfly.PNG(fn, args...), plt) diff --git a/src/plot.jl b/src/plot.jl index 686da690..ca98c500 100644 --- a/src/plot.jl +++ b/src/plot.jl @@ -114,40 +114,48 @@ When plotting multiple lines, you can give every line the same trait by using th # ------------------------- # this creates a new plot with args/kw and sets it to be the current plot -function plot(args...; kw...) +function plot(args...; kw...) plt = plot(plotter(); getPlotKeywordArgs(kw, 1)...) # create a new, blank plot - plot!(plotter(), plt, args...; kw...) # add the series to that plot - currentPlot!(plt) # set this as the current plot - plt + plot!(plt, args...; kw...) # add to it end # this adds to the current plot function plot!(args...; kw...) - plt = currentPlot() - plot!(plotter(), plt, args...; kw...) + plot!(currentPlot(), args...; kw...) +end + +# this adds to a specific plot... most plot commands will flow through here +function plot!(plt::Plot, args...; show=true, kw...) + plot!(plt.plotter, plt, args...; kw...) + currentPlot!(plt) + if show + display(plt) + end plt end +# show/update the plot +function display(plt::Plot) + display(plt.plotter, plt) +end + # ------------------------- # These methods are various ways to add to an existing plot function plot!(pkg::PlottingPackage, plt::Plot, y::AVec; kw...) - kw = getPlotKeywordArgs(kw, 1) - plot!(pkg, plt; x = 1:length(y), y = y, kw...) + plot!(pkg, plt; x = 1:length(y), y = y, getPlotKeywordArgs(kw, 1)...) end function plot!(pkg::PlottingPackage, plt::Plot, x::AVec, y::AVec; kw...) # one line (will assert length(x) == length(y)) @assert length(x) == length(y) - kw = getPlotKeywordArgs(kw, 1) - plot!(pkg, plt; x=x, y=y, kw...) + plot!(pkg, plt; x=x, y=y, getPlotKeywordArgs(kw, 1)...) 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 - kw = getPlotKeywordArgs(kw, i) - plot!(pkg, plt; x = 1:n, y = y[:,i], kw...) + plot!(pkg, plt; x = 1:n, y = y[:,i], getPlotKeywordArgs(kw, i)...) end plt end @@ -156,8 +164,7 @@ function plot!(pkg::PlottingPackage, plt::Plot, x::AVec, y::AMat; kw...) n,m = size(y) for i in 1:m @assert length(x) == n - kw = getPlotKeywordArgs(kw, i) - plot!(pkg, plt; x = x, y = y[:,i], kw...) + plot!(pkg, plt; x = x, y = y[:,i], getPlotKeywordArgs(kw, i)...) end plt end @@ -165,38 +172,33 @@ 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) - kw = getPlotKeywordArgs(kw, i) - plot!(pkg, plt; x = x[:,i], y = y[:,i], kw...) + plot!(pkg, plt; x = x[:,i], y = y[:,i], getPlotKeywordArgs(kw, i)...) end plt end function plot!(pkg::PlottingPackage, plt::Plot, x::AVec, f::Function; kw...) # one line, y = f(x) - kw = getPlotKeywordArgs(kw, 1) - plot!(pkg, plt; x = x, y = map(f,x), kw...) + plot!(pkg, plt; x = x, y = map(f,x), getPlotKeywordArgs(kw, 1)...) 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] - kw = getPlotKeywordArgs(kw, i) - plot!(pkg, plt; x = xi, y = map(f, xi), kw...) + plot!(pkg, plt; x = xi, y = map(f, xi), getPlotKeywordArgs(kw, i)...) 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) - kw = getPlotKeywordArgs(kw, i) - plot!(pkg, plt; x = x, y = map(fs[i], x), kw...) + plot!(pkg, plt; x = x, y = map(fs[i], x), getPlotKeywordArgs(kw, i)...) end plt end function plot!(pkg::PlottingPackage, plt::Plot, y::AVec{AVec}; kw...) # multiple lines, each with x = 1:length(y[i]) for i in 1:length(y) - kw = getPlotKeywordArgs(kw, i) - plot!(pkg, plt; x = 1:length(y[i]), y = y[i], kw...) + plot!(pkg, plt; x = 1:length(y[i]), y = y[i], getPlotKeywordArgs(kw, i)...) end plt end @@ -204,8 +206,7 @@ end function plot!(pkg::PlottingPackage, plt::Plot, x::AVec, y::AVec{AVec}; kw...) # multiple lines, will assert length(x) == length(y[i]) for i in 1:length(y) @assert length(x) == length(y[i]) - kw = getPlotKeywordArgs(kw, i) - plot!(pkg, plt; x = x, y = y[i], kw...) + plot!(pkg, plt; x = x, y = y[i], getPlotKeywordArgs(kw, i)...) end plt end @@ -214,16 +215,14 @@ function plot!(pkg::PlottingPackage, plt::Plot, x::AVec{AVec}, y::AVec{AVec}; kw @assert length(x) == length(y) for i in 1:length(x) @assert length(x[i]) == length(y[i]) - kw = getPlotKeywordArgs(kw, i) - plot!(pkg, plt; x = x[i], y = y[i], kw...) + plot!(pkg, plt; x = x[i], y = y[i], getPlotKeywordArgs(kw, i)...) end plt end function plot!(pkg::PlottingPackage, plt::Plot, n::Integer; kw...) # n lines, all empty (for updating plots) for i in 1:n - kw = getPlotKeywordArgs(kw, i) - plot(pkg, plt, x = zeros(0), y = zeros(0), kw...) + plot(pkg, plt, x = zeros(0), y = zeros(0), getPlotKeywordArgs(kw, i)...) end end diff --git a/src/plotter.jl b/src/plotter.jl index 8c22b883..ff7194bd 100644 --- a/src/plotter.jl +++ b/src/plotter.jl @@ -1,5 +1,4 @@ -using Requires # these are the plotting packages you can load. we use lazymod so that we # don't "import" the module until we want it @@ -8,6 +7,7 @@ using Requires 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") +display(pkg::PlottingPackage, plt::Plot) = error("display($pkg, plt) is not implemented") # --------------------------------------------------------- diff --git a/src/qwt.jl b/src/qwt.jl index 4d3ec0b8..571cf9ad 100644 --- a/src/qwt.jl +++ b/src/qwt.jl @@ -5,5 +5,10 @@ immutable QwtPackage <: PlottingPackage end plot(pkg::QwtPackage; kw...) = Plot(Qwt.plot(zeros(0,0); kw...), pkg, AVec[], AVec[]) plot!(::QwtPackage, plt::Plot; kw...) = Qwt.oplot(plt.o; kw...) +function display(::QwtPackage, plt::Plot) + Qwt.refresh(plt.o) + Qwt.showwidget(plt.o) +end + # subplot(::QwtPackage, args...; kw...) = Qwt.subplot(args...; kw...) # savepng(::QwtPackage, plt, fn::String, args...) = Qwt.savepng(plt, fn)