big shapes overhaul; gadfly ShapeGeometry; some reorg and cleanup... still working on it

This commit is contained in:
Thomas Breloff 2015-10-14 18:14:44 -04:00
parent 027961bffa
commit 4fa697ec75
17 changed files with 988 additions and 304 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -37,8 +37,6 @@ export
ohlc, ohlc,
ohlc!, ohlc!,
spy,
title!, title!,
xlabel!, xlabel!,
ylabel!, ylabel!,
@ -60,6 +58,8 @@ export
backends, backends,
aliases, aliases,
dataframes, dataframes,
Shape,
OHLC, OHLC,
colorscheme, colorscheme,
@ -84,6 +84,7 @@ export
# recipes # recipes
PlotRecipe, PlotRecipe,
EllipseRecipe, EllipseRecipe,
spy,
corrplot corrplot
# --------------------------------------------------------- # ---------------------------------------------------------
@ -123,11 +124,6 @@ vline!(args...; kw...) = plot!(args...; kw..., linetype = :vline)
ohlc(args...; kw...) = plot(args...; kw..., linetype = :ohlc) ohlc(args...; kw...) = plot(args...; kw..., linetype = :ohlc)
ohlc!(args...; kw...) = plot!(args...; kw..., linetype = :ohlc) ohlc!(args...; kw...) = plot!(args...; kw..., linetype = :ohlc)
"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, kw...)
end
title!(s::@compat(AbstractString)) = plot!(title = s) title!(s::@compat(AbstractString)) = plot!(title = s)
xlabel!(s::@compat(AbstractString)) = plot!(xlabel = s) xlabel!(s::@compat(AbstractString)) = plot!(xlabel = s)

View File

@ -38,7 +38,7 @@ const _allStyles = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
) )
const _allMarkers = [:none, :auto, :ellipse, :rect, :diamond, :utriangle, :dtriangle, const _allMarkers = [:none, :auto, :ellipse, :rect, :diamond, :utriangle, :dtriangle,
:cross, :xcross, :star1, :star2, :hexagon, :octagon] :cross, :xcross, :star1, :star2, :hexagon, :octagon, Shape]
@compat const _markerAliases = Dict( @compat const _markerAliases = Dict(
:n => :none, :n => :none,
:no => :none, :no => :none,
@ -515,10 +515,17 @@ end
function warnOnUnsupported(pkg::PlottingPackage, d::Dict) function warnOnUnsupported(pkg::PlottingPackage, d::Dict)
d[:axis] in supportedAxes(pkg) || warn("axis $(d[:axis]) is unsupported with $pkg. Choose from: $(supportedAxes(pkg))") (d[:axis] in supportedAxes(pkg)
d[:linetype] == :none || d[:linetype] in supportedTypes(pkg) || warn("linetype $(d[:linetype]) is unsupported with $pkg. Choose from: $(supportedTypes(pkg))") || warn("axis $(d[:axis]) is unsupported with $pkg. Choose from: $(supportedAxes(pkg))"))
d[:linestyle] in supportedStyles(pkg) || warn("linestyle $(d[:linestyle]) is unsupported with $pkg. Choose from: $(supportedStyles(pkg))") (d[:linetype] == :none
d[:markershape] == :none || d[:markershape] in supportedMarkers(pkg) || warn("markershape $(d[:markershape]) is unsupported with $pkg. Choose from: $(supportedMarkers(pkg))") || d[:linetype] in supportedTypes(pkg)
|| warn("linetype $(d[:linetype]) is unsupported with $pkg. Choose from: $(supportedTypes(pkg))"))
(d[:linestyle] in supportedStyles(pkg)
|| warn("linestyle $(d[:linestyle]) is unsupported with $pkg. Choose from: $(supportedStyles(pkg))"))
(d[:markershape] == :none
|| d[:markershape] in supportedMarkers(pkg)
|| typeof(d[:markershape]) in supportedMarkers(pkg)
|| warn("markershape $(d[:markershape]) is unsupported with $pkg. Choose from: $(supportedMarkers(pkg))"))
end end
function warnOnUnsupportedScales(pkg::PlottingPackage, d::Dict) function warnOnUnsupportedScales(pkg::PlottingPackage, d::Dict)

View File

@ -1,10 +1,10 @@
# https://github.com/dcjones/Gadfly.jl # https://github.com/dcjones/Gadfly.jl
immutable GadflyPackage <: PlottingPackage end # immutable GadflyPackage <: PlottingPackage end
export gadfly # export gadfly
gadfly() = backend(:gadfly) # gadfly() = backend(:gadfly)
# supportedArgs(::GadflyPackage) = setdiff(_allArgs, [:heatmap_c, :pos, :screen, :yrightlabel]) # supportedArgs(::GadflyPackage) = setdiff(_allArgs, [:heatmap_c, :pos, :screen, :yrightlabel])
@ -60,11 +60,11 @@ supportedArgs(::GadflyPackage) = [
supportedAxes(::GadflyPackage) = [:auto, :left] supportedAxes(::GadflyPackage) = [:auto, :left]
supportedTypes(::GadflyPackage) = [:none, :line, :path, :steppost, :sticks, :scatter, :heatmap, :hexbin, :hist, :bar, :hline, :vline, :ohlc] supportedTypes(::GadflyPackage) = [:none, :line, :path, :steppost, :sticks, :scatter, :heatmap, :hexbin, :hist, :bar, :hline, :vline, :ohlc]
supportedStyles(::GadflyPackage) = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot] supportedStyles(::GadflyPackage) = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
supportedMarkers(::GadflyPackage) = [:none, :auto, :rect, :ellipse, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star1, :star2, :hexagon, :octagon] supportedMarkers(::GadflyPackage) = [:none, :auto, :rect, :ellipse, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star1, :star2, :hexagon, :octagon, Shape]
supportedScales(::GadflyPackage) = [:identity, :log, :log2, :log10, :asinh, :sqrt] supportedScales(::GadflyPackage) = [:identity, :log, :log2, :log10, :asinh, :sqrt]
include("gadfly_shapes.jl") # include("gadfly_shapes.jl")
function createGadflyPlotObject(d::Dict) function createGadflyPlotObject(d::Dict)
@eval import DataFrames @eval import DataFrames
@ -115,7 +115,8 @@ function getLineGeoms(d::Dict)
# NOTE: we won't actually show this (we'll set linewidth to 0 later), but we need a geom so that Gadfly doesn't complain # NOTE: we won't actually show this (we'll set linewidth to 0 later), but we need a geom so that Gadfly doesn't complain
if lt in (:none, :ohlc, :scatter) if lt in (:none, :ohlc, :scatter)
return [Gadfly.Geom.path] # return [Gadfly.Geom.path]
return Any[]
end end
# lt == :sticks && return [Gadfly.Geom.bar] # lt == :sticks && return [Gadfly.Geom.bar]
@ -126,13 +127,32 @@ end
# serious hack (I think?) to draw my own shapes as annotations... will it work? who knows... # serious hack (I think?) to draw my own shapes as annotations... will it work? who knows...
function getMarkerGeomsAndGuides(d::Dict, initargs::Dict) function getMarkerGeomsAndGuides(d::Dict, initargs::Dict)
marker = d[:markershape] return Any[], Any[] # don't do this step anymore
if marker == :none && d[:linetype] != :ohlc # marker = d[:markershape]
return Any[], Any[]
end # if marker == :none && d[:linetype] != :ohlc
return Any[], [createGadflyAnnotation(d, initargs)] # return Any[], Any[]
# elseif marker == :diamond
# geom = DIAMOND
# @show geom
# return Any[geom], Any[]
# else
# return Any[], [createGadflyAnnotation(d, initargs)]
# end
end end
function getMarkerGeoms(d::Dict)
shape = d[:markershape]
isa(shape, Shape) && return [gadflyshape(shape)]
shape == :none && return Any[]
shape == :ellipse && return [Gadfly.Geom.point]
shape == :rect && return [gadflyshape(_square)]
shape == :diamond && return [gadflyshape(_diamond)]
shape == :cross && return [gadflyshape(_cross)]
error("unhandled marker: ", shape)
end
function addGadflyFixedLines!(gplt, d::Dict, theme) function addGadflyFixedLines!(gplt, d::Dict, theme)
@ -206,16 +226,18 @@ function addGadflySeries!(gplt, d::Dict, initargs::Dict)
if d[:linetype] == :scatter if d[:linetype] == :scatter
d[:linetype] = :none d[:linetype] = :none
if d[:markershape] in (:none,:ellipse)
push!(gfargs, Gadfly.Geom.point) # if d[:markershape] in (:none,:ellipse)
d[:markershape] = :none # push!(gfargs, Gadfly.Geom.point)
# if d[:markershape] == :none # d[:markershape] = :none
# d[:markershape] = :ellipse # # if d[:markershape] == :none
end # # d[:markershape] = :ellipse
# end
end end
# add the Geoms # add the Geoms
append!(gfargs, getLineGeoms(d)) append!(gfargs, getLineGeoms(d))
append!(gfargs, getMarkerGeoms(d))
# colorgroup # colorgroup
z = d[:z] z = d[:z]
@ -274,7 +296,9 @@ function addGadflySeries!(gplt, d::Dict, initargs::Dict)
# add a regression line? # add a regression line?
if d[:reg] if d[:reg]
# TODO: make more flexible
push!(gfargs, Gadfly.Geom.smooth(method=:lm)) push!(gfargs, Gadfly.Geom.smooth(method=:lm))
# push!(gfargs, Gadfly.Geom.smooth(method=:loess, smoothing=0.95))
end end
# add to the legend, but only without the continuous scale # add to the legend, but only without the continuous scale

View File

@ -1,283 +1,400 @@
# Geometry which displays arbitrary shapes at given (x, y) positions.
immutable ShapeGeometry <: Gadfly.GeometryElement
vertices::AbstractVector{@compat(Tuple{Float64,Float64})}
tag::Symbol
function ShapeGeometry(shape; tag::Symbol=Gadfly.Geom.empty_tag)
new(shape, tag)
end
end
# TODO: add for PR
# const shape = ShapeGeometry
function Gadfly.element_aesthetics(::ShapeGeometry)
[:x, :y, :size, :color]
end
# Generate a form for a shape geometry.
#
# Args:
# geom: shape geometry.
# theme: the plot's theme.
# aes: aesthetics.
#
# Returns:
# A compose Form.
#
function Gadfly.render(geom::ShapeGeometry, theme::Gadfly.Theme, aes::Gadfly.Aesthetics)
# TODO: add for PR
# Gadfly.assert_aesthetics_defined("Geom.shape", aes, :x, :y)
# Gadfly.assert_aesthetics_equal_length("Geom.shape", aes,
# element_aesthetics(geom)...)
default_aes = Gadfly.Aesthetics()
default_aes.color = Gadfly.DataFrames.PooledDataArray(RGBA{Float32}[theme.default_color])
default_aes.size = Compose.Measure[theme.default_point_size]
aes = Gadfly.inherit(aes, default_aes)
lw_hover_scale = 10
lw_ratio = theme.line_width / aes.size[1]
aes_x, aes_y = Gadfly.concretize(aes.x, aes.y)
ctx = Compose.compose!(
Compose.context(),
# circle(aes.x, aes.y, aes.size, geom.tag),
makeGadflyShapeContext(geom, aes.x, aes.y, aes.size),
Compose.fill(aes.color),
Compose.linewidth(theme.highlight_width))
if aes.color_key_continuous != nothing && aes.color_key_continuous
Compose.compose!(ctx,
Compose.stroke(map(theme.continuous_highlight_color, aes.color)))
else
Compose.compose!(ctx,
Compose.stroke(map(theme.discrete_highlight_color, aes.color)),
Compose.svgclass([Gadfly.svg_color_class_from_label(Gadfly.escape_id(aes.color_label([c])[1]))
for c in aes.color]))
end
return Compose.compose!(Compose.context(order=4), Compose.svgclass("geometry"), ctx)
end
function gadflyshape(sv::Shape)
ShapeGeometry(sv.vertices)
end
# const _square = ShapeGeometry(@compat(Tuple{Float64,Float64})[
# ( 1.0, -1.0),
# ( 1.0, 1.0),
# (-1.0, 1.0),
# (-1.0, -1.0)
# ])
# const _diamond = ShapeGeometry(@compat(Tuple{Float64,Float64})[
# ( 0.0, -1.0),
# ( 1.0, 0.0),
# ( 0.0, 1.0),
# (-1.0, 0.0)
# ])
# const _cross = ShapeGeometry(@compat(Tuple{Float64,Float64})[
# (-1.0, -0.4), (-1.0, 0.4), # L edge
# (-0.4, 0.4), # BL inside
# (-0.4, 1.0), ( 0.4, 1.0), # B edge
# ( 0.4, 0.4), # BR inside
# ( 1.0, 0.4), ( 1.0, -0.4), # R edge
# ( 0.4, -0.4), # TR inside
# ( 0.4, -1.0), (-0.4, -1.0), # T edge
# (-0.4, -0.4) # TL inside
# ])
# create a Compose context given a ShapeGeometry and the xs/ys/sizes
function makeGadflyShapeContext(geom::ShapeGeometry, xs::AbstractArray, ys::AbstractArray, rs::AbstractArray)
n = max(length(xs), length(ys), length(rs))
T = @compat(Tuple{Compose.Measure, Compose.Measure})
polys = Array(Vector{T}, n)
for i in 1:n
x = Compose.x_measure(xs[mod1(i, length(xs))])
y = Compose.y_measure(ys[mod1(i, length(ys))])
r = rs[mod1(i, length(rs))]
# polys[i] = [(x, y - r), (x + r, y), (x, y + r), (x - r, y)]
polys[i] = T[(x + r * sx, y + r * sy) for (sx,sy) in geom.vertices]
end
Gadfly.polygon(polys, geom.tag)
end
# ---------------------------------------------------------------------------------------------
# Compose pseudo-forms for simple symbols, all parameterized by center and size # Compose pseudo-forms for simple symbols, all parameterized by center and size
# using Compose: x_measure, y_measure # using Compose: x_measure, y_measure
function createGadflyAnnotation(d::Dict, initargs::Dict) # function createGadflyAnnotation(d::Dict, initargs::Dict)
sz = [d[:markersize] * Gadfly.px] # sz = [d[:markersize] * Gadfly.px]
x, y = d[:x], d[:y] # x, y = d[:x], d[:y]
marker = d[:markershape] # marker = d[:markershape]
if d[:linetype] == :ohlc # if d[:linetype] == :ohlc
shape = ohlcshape(x, y, d[:markersize]) # shape = ohlcshape(x, y, d[:markersize])
d[:y] = Float64[z.open for z in y] # d[:y] = Float64[z.open for z in y]
d[:linetype] = :none # d[:linetype] = :none
return Gadfly.Guide.annotation(Gadfly.compose(Gadfly.context(), shape, Gadfly.fill(nothing), Gadfly.stroke(getColor(d[:color])))) # return Gadfly.Guide.annotation(Gadfly.compose(Gadfly.context(), shape, Gadfly.fill(nothing), Gadfly.stroke(getColor(d[:color]))))
elseif marker == :rect # elseif marker == :rect
shape = square(x, y, sz) # shape = square(x, y, sz)
elseif marker == :diamond # elseif marker == :diamond
shape = diamond(x, y, sz) # shape = diamond(x, y, sz)
elseif marker == :utriangle # elseif marker == :utriangle
shape = utriangle(x, y, sz) # shape = utriangle(x, y, sz)
elseif marker == :dtriangle # elseif marker == :dtriangle
shape = utriangle(x, y, sz, -1) # shape = utriangle(x, y, sz, -1)
elseif marker == :cross # elseif marker == :cross
shape = cross(x, y, sz) # shape = cross(x, y, sz)
elseif marker == :xcross # elseif marker == :xcross
shape = xcross(x, y, sz) # shape = xcross(x, y, sz)
elseif marker == :star1 # elseif marker == :star1
shape = star1(x, y, sz) # shape = star1(x, y, sz)
elseif marker == :star2 # elseif marker == :star2
shape = star2(x, y, sz) # shape = star2(x, y, sz)
elseif marker == :hexagon # elseif marker == :hexagon
shape = hexagon(x, y, sz) # shape = hexagon(x, y, sz)
elseif marker == :octagon # elseif marker == :octagon
shape = octagon(x, y, sz) # shape = octagon(x, y, sz)
else # else
# make circles # # make circles
sz = 0.8 * d[:markersize] * Gadfly.px # sz = 0.8 * d[:markersize] * Gadfly.px
xs = collect(float(d[:x])) # xs = collect(float(d[:x]))
ys = collect(float(d[:y])) # ys = collect(float(d[:y]))
shape = Gadfly.circle(xs,ys,[sz]) # shape = Gadfly.circle(xs,ys,[sz])
end # end
Gadfly.Guide.annotation(Gadfly.compose(Gadfly.context(), shape, Gadfly.fill(getColorVector(d[:markercolor])), Gadfly.stroke(getColor(initargs[:foreground_color])))) # Gadfly.Guide.annotation(Gadfly.compose(Gadfly.context(), shape, Gadfly.fill(getColorVector(d[:markercolor])), Gadfly.stroke(getColor(initargs[:foreground_color]))))
end # end
function square(xs::AbstractArray, ys::AbstractArray, rs::AbstractArray) # function square(xs::AbstractArray, ys::AbstractArray, rs::AbstractArray)
n = max(length(xs), length(ys), length(rs)) # n = max(length(xs), length(ys), length(rs))
rect_xs = Array(Compose.Measure, n) # rect_xs = Array(Compose.Measure, n)
rect_ys = Array(Compose.Measure, n) # rect_ys = Array(Compose.Measure, n)
rect_ws = Array(Compose.Measure, n) # rect_ws = Array(Compose.Measure, n)
s = 1/sqrt(2) # s = 1/sqrt(2)
for i in 1:n # for i in 1:n
x = Compose.x_measure(xs[mod1(i, length(xs))]) # x = Compose.x_measure(xs[mod1(i, length(xs))])
y = Compose.y_measure(ys[mod1(i, length(ys))]) # y = Compose.y_measure(ys[mod1(i, length(ys))])
r = rs[mod1(i, length(rs))] # r = rs[mod1(i, length(rs))]
rect_xs[i] = x - s*r # rect_xs[i] = x - s*r
rect_ys[i] = y + s*r # rect_ys[i] = y + s*r
rect_ws[i] = 2*s*r # rect_ws[i] = 2*s*r
end # end
return Gadfly.rectangle(rect_xs, rect_ys, rect_ws, rect_ws) # return Gadfly.rectangle(rect_xs, rect_ys, rect_ws, rect_ws)
end # end
function diamond(xs::AbstractArray, ys::AbstractArray, rs::AbstractArray) # function diamond(xs::AbstractArray, ys::AbstractArray, rs::AbstractArray)
n = max(length(xs), length(ys), length(rs)) # n = max(length(xs), length(ys), length(rs))
polys = Array(Vector{@compat(Tuple{Compose.Measure, Compose.Measure})}, n) # polys = Array(Vector{@compat(Tuple{Compose.Measure, Compose.Measure})}, n)
for i in 1:n # for i in 1:n
x = Compose.x_measure(xs[mod1(i, length(xs))]) # x = Compose.x_measure(xs[mod1(i, length(xs))])
y = Compose.y_measure(ys[mod1(i, length(ys))]) # y = Compose.y_measure(ys[mod1(i, length(ys))])
r = rs[mod1(i, length(rs))] # r = rs[mod1(i, length(rs))]
polys[i] = [(x, y - r), (x + r, y), (x, y + r), (x - r, y)] # polys[i] = [(x, y - r), (x + r, y), (x, y + r), (x - r, y)]
end # end
return Gadfly.polygon(polys) # return Gadfly.polygon(polys)
end # end
function cross(xs::AbstractArray, ys::AbstractArray, rs::AbstractArray) # function cross(xs::AbstractArray, ys::AbstractArray, rs::AbstractArray)
n = max(length(xs), length(ys), length(rs)) # n = max(length(xs), length(ys), length(rs))
polys = Array(Vector{@compat(Tuple{Compose.Measure, Compose.Measure})}, n) # polys = Array(Vector{@compat(Tuple{Compose.Measure, Compose.Measure})}, n)
for i in 1:n # for i in 1:n
x = Compose.x_measure(xs[mod1(i, length(xs))]) # x = Compose.x_measure(xs[mod1(i, length(xs))])
y = Compose.y_measure(ys[mod1(i, length(ys))]) # y = Compose.y_measure(ys[mod1(i, length(ys))])
r = rs[mod1(i, length(rs))] # r = rs[mod1(i, length(rs))]
u = 0.4r # u = 0.4r
# make a "plus sign" # # make a "plus sign"
polys[i] = [ # polys[i] = [
(x-r, y-u), (x-r, y+u), # L edge # (x-r, y-u), (x-r, y+u), # L edge
(x-u, y+u), # BL inside # (x-u, y+u), # BL inside
(x-u, y+r), (x+u, y+r), # B edge # (x-u, y+r), (x+u, y+r), # B edge
(x+u, y+u), # BR inside # (x+u, y+u), # BR inside
(x+r, y+u), (x+r, y-u), # R edge # (x+r, y+u), (x+r, y-u), # R edge
(x+u, y-u), # TR inside # (x+u, y-u), # TR inside
(x+u, y-r), (x-u, y-r), # T edge # (x+u, y-r), (x-u, y-r), # T edge
(x-u, y-u) # TL inside # (x-u, y-u) # TL inside
] # ]
end # end
return Gadfly.polygon(polys) # return Gadfly.polygon(polys)
end # end
function xcross(xs::AbstractArray, ys::AbstractArray, rs::AbstractArray) # function xcross(xs::AbstractArray, ys::AbstractArray, rs::AbstractArray)
n = max(length(xs), length(ys), length(rs)) # n = max(length(xs), length(ys), length(rs))
polys = Array(Vector{@compat(Tuple{Compose.Measure, Compose.Measure})}, n) # polys = Array(Vector{@compat(Tuple{Compose.Measure, Compose.Measure})}, n)
s = 1/sqrt(5) # s = 1/sqrt(5)
for i in 1:n # for i in 1:n
x = Compose.x_measure(xs[mod1(i, length(xs))]) # x = Compose.x_measure(xs[mod1(i, length(xs))])
y = Compose.y_measure(ys[mod1(i, length(ys))]) # y = Compose.y_measure(ys[mod1(i, length(ys))])
r = rs[mod1(i, length(rs))] # r = rs[mod1(i, length(rs))]
u = s*r # u = s*r
polys[i] = [ # polys[i] = [
(x, y - u), (x + u, y - 2u), (x + 2u, y - u), # (x, y - u), (x + u, y - 2u), (x + 2u, y - u),
(x + u, y), (x + 2u, y + u), (x + u, y + 2u), # (x + u, y), (x + 2u, y + u), (x + u, y + 2u),
(x, y + u), (x - u, y + 2u), (x - 2u, y + u), # (x, y + u), (x - u, y + 2u), (x - 2u, y + u),
(x - u, y), (x - 2u, y - u), (x - u, y - 2u) # (x - u, y), (x - 2u, y - u), (x - u, y - 2u)
] # ]
end # end
return Gadfly.polygon(polys) # return Gadfly.polygon(polys)
end # end
function utriangle(xs::AbstractArray, ys::AbstractArray, rs::AbstractArray, scalar = 1) # function utriangle(xs::AbstractArray, ys::AbstractArray, rs::AbstractArray, scalar = 1)
n = max(length(xs), length(ys), length(rs)) # n = max(length(xs), length(ys), length(rs))
polys = Array(Vector{@compat(Tuple{Compose.Measure, Compose.Measure})}, n) # polys = Array(Vector{@compat(Tuple{Compose.Measure, Compose.Measure})}, n)
s = 0.8 # s = 0.8
for i in 1:n # for i in 1:n
x = Compose.x_measure(xs[mod1(i, length(xs))]) # x = Compose.x_measure(xs[mod1(i, length(xs))])
y = Compose.y_measure(ys[mod1(i, length(ys))]) # y = Compose.y_measure(ys[mod1(i, length(ys))])
r = rs[mod1(i, length(rs))] # r = rs[mod1(i, length(rs))]
u = 0.8 * scalar * r # u = 0.8 * scalar * r
polys[i] = [ # polys[i] = [
(x - r, y + u), # (x - r, y + u),
(x + r, y + u), # (x + r, y + u),
(x, y - u) # (x, y - u)
] # ]
end # end
return Gadfly.polygon(polys) # return Gadfly.polygon(polys)
end # end
function star1(xs::AbstractArray, ys::AbstractArray, rs::AbstractArray, scalar = 1) # function star1(xs::AbstractArray, ys::AbstractArray, rs::AbstractArray, scalar = 1)
n = max(length(xs), length(ys), length(rs)) # n = max(length(xs), length(ys), length(rs))
polys = Array(Vector{@compat(Tuple{Compose.Measure, Compose.Measure})}, n) # polys = Array(Vector{@compat(Tuple{Compose.Measure, Compose.Measure})}, n)
# some magic scalars # # some magic scalars
sx1, sx2, sx3 = 0.7, 0.4, 0.2 # sx1, sx2, sx3 = 0.7, 0.4, 0.2
sy1, sy2, sy3 = 1.2, 0.45, 0.1 # sy1, sy2, sy3 = 1.2, 0.45, 0.1
for i in 1:n # for i in 1:n
x = Compose.x_measure(xs[mod1(i, length(xs))]) # x = Compose.x_measure(xs[mod1(i, length(xs))])
y = Compose.y_measure(ys[mod1(i, length(ys))]) # y = Compose.y_measure(ys[mod1(i, length(ys))])
r = rs[mod1(i, length(rs))] # r = rs[mod1(i, length(rs))]
polys[i] = [ # polys[i] = [
(x-sx1*r, y+ r), # BL # (x-sx1*r, y+ r), # BL
(x, y+sy2*r), # (x, y+sy2*r),
(x+sx1*r, y+ r), # BR # (x+sx1*r, y+ r), # BR
(x+sx2*r, y+sy3*r), # (x+sx2*r, y+sy3*r),
(x+ r, y-sy2*r), # R # (x+ r, y-sy2*r), # R
(x+sx3*r, y-sy2*r), # (x+sx3*r, y-sy2*r),
(x, y-sy1*r), # T # (x, y-sy1*r), # T
(x-sx3*r, y-sy2*r), # (x-sx3*r, y-sy2*r),
(x- r, y-sy2*r), # L # (x- r, y-sy2*r), # L
(x-sx2*r, y+sy3*r) # (x-sx2*r, y+sy3*r)
] # ]
end # end
return Gadfly.polygon(polys) # return Gadfly.polygon(polys)
end # end
function star2(xs::AbstractArray, ys::AbstractArray, rs::AbstractArray, scalar = 1) # function star2(xs::AbstractArray, ys::AbstractArray, rs::AbstractArray, scalar = 1)
n = max(length(xs), length(ys), length(rs)) # n = max(length(xs), length(ys), length(rs))
polys = Array(Vector{@compat(Tuple{Compose.Measure, Compose.Measure})}, n) # polys = Array(Vector{@compat(Tuple{Compose.Measure, Compose.Measure})}, n)
for i in 1:n # for i in 1:n
x = Compose.x_measure(xs[mod1(i, length(xs))]) # x = Compose.x_measure(xs[mod1(i, length(xs))])
y = Compose.y_measure(ys[mod1(i, length(ys))]) # y = Compose.y_measure(ys[mod1(i, length(ys))])
r = rs[mod1(i, length(rs))] # r = rs[mod1(i, length(rs))]
u = 0.4r # u = 0.4r
polys[i] = [ # polys[i] = [
(x-u, y), (x-r, y-r), # TL # (x-u, y), (x-r, y-r), # TL
(x, y-u), (x+r, y-r), # TR # (x, y-u), (x+r, y-r), # TR
(x+u, y), (x+r, y+r), # BR # (x+u, y), (x+r, y+r), # BR
(x, y+u), (x-r, y+r) # BL # (x, y+u), (x-r, y+r) # BL
] # ]
end # end
return Gadfly.polygon(polys) # return Gadfly.polygon(polys)
end # end
function hexagon(xs::AbstractArray, ys::AbstractArray, rs::AbstractArray) # function hexagon(xs::AbstractArray, ys::AbstractArray, rs::AbstractArray)
n = max(length(xs), length(ys), length(rs)) # n = max(length(xs), length(ys), length(rs))
polys = Array(Vector{@compat(Tuple{Compose.Measure, Compose.Measure})}, n) # polys = Array(Vector{@compat(Tuple{Compose.Measure, Compose.Measure})}, n)
for i in 1:n # for i in 1:n
x = Compose.x_measure(xs[mod1(i, length(xs))]) # x = Compose.x_measure(xs[mod1(i, length(xs))])
y = Compose.y_measure(ys[mod1(i, length(ys))]) # y = Compose.y_measure(ys[mod1(i, length(ys))])
r = rs[mod1(i, length(rs))] # r = rs[mod1(i, length(rs))]
u = 0.6r # u = 0.6r
polys[i] = [ # polys[i] = [
(x-r, y-u), (x-r, y+u), # L edge # (x-r, y-u), (x-r, y+u), # L edge
(x, y+r), # B # (x, y+r), # B
(x+r, y+u), (x+r, y-u), # R edge # (x+r, y+u), (x+r, y-u), # R edge
(x, y-r) # T # (x, y-r) # T
] # ]
end # end
return Gadfly.polygon(polys) # return Gadfly.polygon(polys)
end # end
function octagon(xs::AbstractArray, ys::AbstractArray, rs::AbstractArray) # function octagon(xs::AbstractArray, ys::AbstractArray, rs::AbstractArray)
n = max(length(xs), length(ys), length(rs)) # n = max(length(xs), length(ys), length(rs))
polys = Array(Vector{@compat(Tuple{Compose.Measure, Compose.Measure})}, n) # polys = Array(Vector{@compat(Tuple{Compose.Measure, Compose.Measure})}, n)
for i in 1:n # for i in 1:n
x = Compose.x_measure(xs[mod1(i, length(xs))]) # x = Compose.x_measure(xs[mod1(i, length(xs))])
y = Compose.y_measure(ys[mod1(i, length(ys))]) # y = Compose.y_measure(ys[mod1(i, length(ys))])
r = rs[mod1(i, length(rs))] # r = rs[mod1(i, length(rs))]
u = 0.4r # u = 0.4r
polys[i] = [ # polys[i] = [
(x-r, y-u), (x-r, y+u), # L edge # (x-r, y-u), (x-r, y+u), # L edge
(x-u, y+r), (x+u, y+r), # B edge # (x-u, y+r), (x+u, y+r), # B edge
(x+r, y+u), (x+r, y-u), # R edge # (x+r, y+u), (x+r, y-u), # R edge
(x+u, y-r), (x-u, y-r), # T edge # (x+u, y-r), (x-u, y-r), # T edge
] # ]
end # end
return Gadfly.polygon(polys) # return Gadfly.polygon(polys)
end # end
# --------------------------- # # ---------------------------
function ohlcshape(xs::AVec, ys::AVec{OHLC}, tickwidth::Real) # function ohlcshape(xs::AVec, ys::AVec{OHLC}, tickwidth::Real)
@assert length(xs) == length(ys) # @assert length(xs) == length(ys)
n = length(xs) # n = length(xs)
u = tickwidth * Compose.px # u = tickwidth * Compose.px
polys = Array(Vector{@compat(Tuple{Compose.Measure, Compose.Measure})}, n) # polys = Array(Vector{@compat(Tuple{Compose.Measure, Compose.Measure})}, n)
for i in 1:n # for i in 1:n
x = Compose.x_measure(xs[i]) # x = Compose.x_measure(xs[i])
o = Compose.y_measure(ys[i].open) # o = Compose.y_measure(ys[i].open)
h = Compose.y_measure(ys[i].high) # h = Compose.y_measure(ys[i].high)
l = Compose.y_measure(ys[i].low) # l = Compose.y_measure(ys[i].low)
c = Compose.y_measure(ys[i].close) # c = Compose.y_measure(ys[i].close)
# o,h,l,c = map(Compose.y_measure, ys[i]) # # o,h,l,c = map(Compose.y_measure, ys[i])
polys[i] = [ # polys[i] = [
(x, o), (x - u, o), (x, o), # open tick # (x, o), (x - u, o), (x, o), # open tick
(x, l), (x, h), (x, c), # high/low bar # (x, l), (x, h), (x, c), # high/low bar
(x + u, c), (x, c) # close tick # (x + u, c), (x, c) # close tick
] # ]
end # end
return Gadfly.polygon(polys) # return Gadfly.polygon(polys)
end # end

View File

@ -1,10 +1,10 @@
# https://github.com/JuliaGraphics/Immerse.jl # https://github.com/JuliaGraphics/Immerse.jl
immutable ImmersePackage <: PlottingPackage end # immutable ImmersePackage <: PlottingPackage end
export immerse # export immerse
immerse() = backend(:immerse) # immerse() = backend(:immerse)
supportedArgs(::ImmersePackage) = supportedArgs(GadflyPackage()) supportedArgs(::ImmersePackage) = supportedArgs(GadflyPackage())

View File

@ -1,10 +1,10 @@
# https://github.com/stevengj/PyPlot.jl # https://github.com/stevengj/PyPlot.jl
immutable PyPlotPackage <: PlottingPackage end # immutable PyPlotPackage <: PlottingPackage end
export pyplot # export pyplot
pyplot() = backend(:pyplot) # pyplot() = backend(:pyplot)
# ------------------------------- # -------------------------------

View File

@ -1,10 +1,10 @@
# https://github.com/tbreloff/Qwt.jl # https://github.com/tbreloff/Qwt.jl
immutable QwtPackage <: PlottingPackage end # immutable QwtPackage <: PlottingPackage end
export qwt # export qwt
qwt() = backend(:qwt) # qwt() = backend(:qwt)
# supportedArgs(::QwtPackage) = setdiff(_allArgs, [:xlims, :ylims, :xticks, :yticks]) # supportedArgs(::QwtPackage) = setdiff(_allArgs, [:xlims, :ylims, :xticks, :yticks])
supportedArgs(::QwtPackage) = [ supportedArgs(::QwtPackage) = [

View File

@ -3,11 +3,6 @@
# [WEBSITE] # [WEBSITE]
immutable [PkgName]Package <: PlottingPackage end
export [pkgname]
[pkgname]() = backend(:[pkgname])
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# supportedArgs(::[PkgName]Package) = _allArgs # supportedArgs(::[PkgName]Package) = _allArgs

View File

@ -1,10 +1,10 @@
# https://github.com/Evizero/UnicodePlots.jl # https://github.com/Evizero/UnicodePlots.jl
immutable UnicodePlotsPackage <: PlottingPackage end # immutable UnicodePlotsPackage <: PlottingPackage end
export unicodeplots # export unicodeplots
unicodeplots() = backend(:unicodeplots) # unicodeplots() = backend(:unicodeplots)
# ------------------------------- # -------------------------------

View File

@ -3,10 +3,10 @@
# credit goes to https://github.com/jverzani for contributing to the first draft of this backend implementation # credit goes to https://github.com/jverzani for contributing to the first draft of this backend implementation
immutable WinstonPackage <: PlottingPackage end # immutable WinstonPackage <: PlottingPackage end
export winston # export winston
winston() = backend(:winston) # winston() = backend(:winston)
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------

View File

@ -1,5 +1,28 @@
immutable GadflyPackage <: PlottingPackage end
immutable ImmersePackage <: PlottingPackage end
immutable PyPlotPackage <: PlottingPackage end
immutable QwtPackage <: PlottingPackage end
immutable UnicodePlotsPackage <: PlottingPackage end
immutable WinstonPackage <: PlottingPackage end
export
gadfly,
immerse,
pyplot,
qwt,
unicodeplots,
winston
gadfly() = backend(:gadfly)
immerse() = backend(:immerse)
pyplot() = backend(:pyplot)
qwt() = backend(:qwt)
unicodeplots() = backend(:unicodeplots)
winston() = backend(:winston)
include("backends/qwt.jl") include("backends/qwt.jl")
include("backends/gadfly.jl") include("backends/gadfly.jl")
include("backends/unicodeplots.jl") include("backends/unicodeplots.jl")
@ -109,6 +132,7 @@ function backend()
try try
@eval import Gadfly, Compose @eval import Gadfly, Compose
@eval export Gadfly, Compose @eval export Gadfly, Compose
@eval include(joinpath(Pkg.dir("Plots"), "src", "backends", "gadfly_shapes.jl"))
catch err catch err
error("Couldn't import Gadfly. Install it with: Pkg.add(\"Gadfly\").\n Error: ", err) error("Couldn't import Gadfly. Install it with: Pkg.add(\"Gadfly\").\n Error: ", err)
end end
@ -137,6 +161,7 @@ function backend()
try try
@eval import Immerse, Gadfly, Compose, Gtk @eval import Immerse, Gadfly, Compose, Gtk
@eval export Immerse, Gadfly, Compose, Gtk @eval export Immerse, Gadfly, Compose, Gtk
@eval include(joinpath(Pkg.dir("Plots"), "src", "backends", "gadfly_shapes.jl"))
catch err catch err
error("Couldn't import Immerse. Install it with: Pkg.add(\"Immerse\").\n Error: ", err) error("Couldn't import Immerse. Install it with: Pkg.add(\"Immerse\").\n Error: ", err)
end end

View File

@ -57,7 +57,7 @@ end
# ------------------------------------------------- # -------------------------------------------------
"Do a correlation plot" "Correlation scatter matrix"
function corrplot{T<:Real,S<:Real}(mat::AMat{T}, corrmat::AMat{S} = cor(mat); function corrplot{T<:Real,S<:Real}(mat::AMat{T}, corrmat::AMat{S} = cor(mat);
colors = :redsblues, colors = :redsblues,
labels = nothing, kw...) labels = nothing, kw...)
@ -105,3 +105,10 @@ function corrplot{T<:Real,S<:Real}(mat::AMat{T}, corrmat::AMat{S} = cor(mat);
subplot!(p, link = (r,c) -> (true, r!=c)) subplot!(p, link = (r,c) -> (true, r!=c))
end 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, kw...)
end

View File

@ -45,7 +45,215 @@ type Subplot{T<:PlottingPackage, L<:SubplotLayout} <: PlottingObject{T}
linkfunc::Function # maps (row,column) -> (BoolOrNothing, BoolOrNothing)... if xlink/ylink are nothing, then use subplt.linkx/y linkfunc::Function # maps (row,column) -> (BoolOrNothing, BoolOrNothing)... if xlink/ylink are nothing, then use subplt.linkx/y
end end
# -----------------------------------------------------------------------
immutable Shape
vertices::AVec
end
const _square = Shape(@compat(Tuple{Float64,Float64})[
( 1.0, -1.0),
( 1.0, 1.0),
(-1.0, 1.0),
(-1.0, -1.0)
])
const _diamond = Shape(@compat(Tuple{Float64,Float64})[
( 0.0, -1.0),
( 1.0, 0.0),
( 0.0, 1.0),
(-1.0, 0.0)
])
const _cross = Shape(@compat(Tuple{Float64,Float64})[
(-1.0, -0.4), (-1.0, 0.4), # L edge
(-0.4, 0.4), # BL inside
(-0.4, 1.0), ( 0.4, 1.0), # B edge
( 0.4, 0.4), # BR inside
( 1.0, 0.4), ( 1.0, -0.4), # R edge
( 0.4, -0.4), # TR inside
( 0.4, -1.0), (-0.4, -1.0), # T edge
(-0.4, -0.4) # TL inside
])
const _xcross = Shape(@compat(Tuple{Float64,Float64})[
(x, y - u), (x + u, y - 2u), (x + 2u, y - u),
(x + u, y), (x + 2u, y + u), (x + u, y + 2u),
(x, y + u), (x - u, y + 2u), (x - 2u, y + u),
(x - u, y), (x - 2u, y - u), (x - u, y - 2u)
]
# function xcross(xs::AbstractArray, ys::AbstractArray, rs::AbstractArray)
# n = max(length(xs), length(ys), length(rs))
# polys = Array(Vector{@compat(Tuple{Compose.Measure, Compose.Measure})}, n)
# s = 1/sqrt(5)
# for i in 1:n
# x = Compose.x_measure(xs[mod1(i, length(xs))])
# y = Compose.y_measure(ys[mod1(i, length(ys))])
# r = rs[mod1(i, length(rs))]
# u = s*r
# polys[i] = [
# (x, y - u), (x + u, y - 2u), (x + 2u, y - u),
# (x + u, y), (x + 2u, y + u), (x + u, y + 2u),
# (x, y + u), (x - u, y + 2u), (x - 2u, y + u),
# (x - u, y), (x - 2u, y - u), (x - u, y - 2u)
# ]
# end
# return Gadfly.polygon(polys)
# end
const _utriangle = Shape(@compat(Tuple{Float64,Float64})[
(x - r, y + u),
(x + r, y + u),
(x, y - u)
]
# function utriangle(xs::AbstractArray, ys::AbstractArray, rs::AbstractArray, scalar = 1)
# n = max(length(xs), length(ys), length(rs))
# polys = Array(Vector{@compat(Tuple{Compose.Measure, Compose.Measure})}, n)
# s = 0.8
# for i in 1:n
# x = Compose.x_measure(xs[mod1(i, length(xs))])
# y = Compose.y_measure(ys[mod1(i, length(ys))])
# r = rs[mod1(i, length(rs))]
# u = 0.8 * scalar * r
# polys[i] = [
# (x - r, y + u),
# (x + r, y + u),
# (x, y - u)
# ]
# end
# return Gadfly.polygon(polys)
# end
"get an array of tuples of points on a circle with radius `r`"
function partialcircle(start_θ, end_θ, n = 20, r=1)
@compat(Tuple{Float64,Float64})[(r*cos(u),r*sin(u)) for u in linspace(start_θ, end_θ, n)]
end
"interleave 2 vectors into each other (like a zipper's teeth)"
function weave(x,y; ordering = [x,y])
ret = eltype(x)[]
done = false
while !done
for o in ordering
try
push!(ret, shift!(o))
end
# try
# push!(ret, shift!(y))
# end
end
done = isempty(x) && isempty(y)
end
ret
end
"create a star by weaving together points from an outer and inner circle. `n` is the number of arms"
function makestar(n; offset = -0.5, radius = 1.0)
z1 = offset * π
z2 = z1 + π / (n)
outercircle = partialcircle(z1, z1 + 2π, n+1, radius)
innercircle = partialcircle(z2, z2 + 2π, n+1, 0.4radius)
Shape(weave(outercircle, innercircle)[1:end-2])
end
"create a shape by picking points around the unit circle. `n` is the number of point/sides, `offset` is the starting angle"
function makeshape(n; offset = -0.5, radius = 1.0)
z = offset * π
Shape(Plots.partialcircle(z, z + 2π, n+1, radius)[1:end-1])
end
function makecross(; offset = -0.5, radius = 1.0)
z1 = offset * π + π/8
z2 = z1 + π/8
outercircle = partialcircle(z1, z1 + 2π, 9, radius)
innercircle = partialcircle(z2, z2 + 2π, 5, 0.4radius)
Shape(weave(outercircle, innercircle)[1:end-2])
end
const _shapes = Dict(
:ellipse => makeshape(20),
:rect => makeshape(4, offset=-0.25),
:diamond => makeshape(4),
:utriangle => makeshape(3),
:dtriangle => makeshape(3, offset=0.5),
:pentagon => makeshape(5),
:hexagon => makeshape(6),
:septagon => makeshape(7),
:octagon => makeshape(8),
)
for n in [4,5,6,7,8]
_shapes[symbol("star$n")] = makestar(n)
end
# :ellipse, :rect, :diamond, :utriangle, :dtriangle,
# :cross, :xcross, :star1, :star2, :hexagon, :octagon
const _xcross = Shape(@compat(Tuple{Float64,Float64})[
]
# function hexagon(xs::AbstractArray, ys::AbstractArray, rs::AbstractArray)
# n = max(length(xs), length(ys), length(rs))
# polys = Array(Vector{@compat(Tuple{Compose.Measure, Compose.Measure})}, n)
# for i in 1:n
# x = Compose.x_measure(xs[mod1(i, length(xs))])
# y = Compose.y_measure(ys[mod1(i, length(ys))])
# r = rs[mod1(i, length(rs))]
# u = 0.6r
# polys[i] = [
# (x-r, y-u), (x-r, y+u), # L edge
# (x, y+r), # B
# (x+r, y+u), (x+r, y-u), # R edge
# (x, y-r) # T
# ]
# end
# return Gadfly.polygon(polys)
# end
const _xcross = Shape(@compat(Tuple{Float64,Float64})[
]
# function octagon(xs::AbstractArray, ys::AbstractArray, rs::AbstractArray)
# n = max(length(xs), length(ys), length(rs))
# polys = Array(Vector{@compat(Tuple{Compose.Measure, Compose.Measure})}, n)
# for i in 1:n
# x = Compose.x_measure(xs[mod1(i, length(xs))])
# y = Compose.y_measure(ys[mod1(i, length(ys))])
# r = rs[mod1(i, length(rs))]
# u = 0.4r
# polys[i] = [
# (x-r, y-u), (x-r, y+u), # L edge
# (x-u, y+r), (x+u, y+r), # B edge
# (x+r, y+u), (x+r, y-u), # R edge
# (x+u, y-r), (x-u, y-r), # T edge
# ]
# end
# return Gadfly.polygon(polys)
# end
# -----------------------------------------------------------------------
type OHLC{T<:Real} type OHLC{T<:Real}
open::T open::T

View File

@ -175,6 +175,7 @@ limsType(lims::Symbol) = lims == :auto ? :auto : :invalid
limsType(lims) = :invalid limsType(lims) = :invalid
# --------------------------------------------------------------- # ---------------------------------------------------------------
type DebugMode type DebugMode