recoded boxplot recipe to match violin approach; switched marker to line/fill for shape seriestype: ref #347
This commit is contained in:
parent
2465b3eb5a
commit
1a90ce0950
@ -764,11 +764,11 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
|
|||||||
|
|
||||||
elseif st == :shape
|
elseif st == :shape
|
||||||
# draw the shapes
|
# draw the shapes
|
||||||
gr_set_line(d[:markerstrokewidth], :solid, d[:markerstrokecolor], d[:markerstrokealpha])
|
gr_set_line(d[:linewidth], :solid, d[:linecolor], d[:linealpha])
|
||||||
gr_polyline(d[:x], d[:y])
|
gr_polyline(d[:x], d[:y])
|
||||||
|
|
||||||
# draw the interior
|
# draw the interior
|
||||||
gr_set_fill(d[:markercolor], d[:markeralpha])
|
gr_set_fill(d[:fillcolor], d[:fillalpha])
|
||||||
gr_polyline(d[:x], d[:y], GR.fillarea)
|
gr_polyline(d[:x], d[:y], GR.fillarea)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -374,12 +374,12 @@ function plotly_series(plt::Plot, series::Series)
|
|||||||
# @show map(length, (x,y,d_out[:x],d_out[:y]))
|
# @show map(length, (x,y,d_out[:x],d_out[:y]))
|
||||||
# @show d_out[:x] d_out[:y]
|
# @show d_out[:x] d_out[:y]
|
||||||
d_out[:fill] = "tozeroy"
|
d_out[:fill] = "tozeroy"
|
||||||
d_out[:fillcolor] = webcolor(d[:markercolor], d[:markeralpha])
|
d_out[:fillcolor] = webcolor(d[:fillcolor], d[:fillalpha])
|
||||||
if d[:markerstrokewidth] > 0
|
if d[:markerstrokewidth] > 0
|
||||||
d_out[:line] = KW(
|
d_out[:line] = KW(
|
||||||
:color => webcolor(d[:markerstrokecolor], d[:markerstrokealpha]),
|
:color => webcolor(d[:linecolor], d[:linealpha]),
|
||||||
:width => d[:markerstrokewidth],
|
:width => d[:linewidth],
|
||||||
:dash => string(d[:markerstrokestyle]),
|
:dash => string(d[:linestyle]),
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@ -816,9 +816,9 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
|
|||||||
patches = pypatches.pymember("PathPatch")(path;
|
patches = pypatches.pymember("PathPatch")(path;
|
||||||
label = d[:label],
|
label = d[:label],
|
||||||
zorder = plt.n,
|
zorder = plt.n,
|
||||||
edgecolor = py_markerstrokecolor(d),
|
edgecolor = py_linecolor(d),
|
||||||
facecolor = py_markercolor(d),
|
facecolor = py_fillcolor(d),
|
||||||
linewidth = d[:markerstrokewidth],
|
linewidth = d[:linewidth],
|
||||||
fill = true
|
fill = true
|
||||||
)
|
)
|
||||||
handle = ax[:add_patch](patches)
|
handle = ax[:add_patch](patches)
|
||||||
|
|||||||
@ -303,8 +303,8 @@ PlotExample("Boxplot and Violin series recipes",
|
|||||||
[:(begin
|
[:(begin
|
||||||
import RDatasets
|
import RDatasets
|
||||||
singers = RDatasets.dataset("lattice", "singer")
|
singers = RDatasets.dataset("lattice", "singer")
|
||||||
violin(singers, :VoicePart, :Height, marker = (0.2, :blue, stroke(0)))
|
violin(singers, :VoicePart, :Height, line = 0, fill = (0.2, :blue))
|
||||||
boxplot!(singers, :VoicePart, :Height, marker = (0.3, :orange, stroke(2)))
|
boxplot!(singers, :VoicePart, :Height, line = (2,:black), fill = (0.3, :orange))
|
||||||
end)]
|
end)]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
223
src/recipes.jl
223
src/recipes.jl
@ -454,20 +454,8 @@ end
|
|||||||
if fillto == nothing
|
if fillto == nothing
|
||||||
fillto = 0
|
fillto = 0
|
||||||
end
|
end
|
||||||
# if fillto == nothing
|
|
||||||
# fillto = zeros(1)
|
|
||||||
# elseif isa(fillto, Number)
|
|
||||||
# fillto = Float64[fillto]
|
|
||||||
# end
|
|
||||||
# nf = length(fillto)
|
|
||||||
|
|
||||||
# npts = 3ny + 1
|
# create the bar shapes by adding x/y segments
|
||||||
# heights = y
|
|
||||||
# x = zeros(npts)
|
|
||||||
# y = zeros(npts)
|
|
||||||
# fillrng = zeros(npts)
|
|
||||||
|
|
||||||
# shapes = Shape[]
|
|
||||||
xseg, yseg = Segments(), Segments()
|
xseg, yseg = Segments(), Segments()
|
||||||
for i=1:ny
|
for i=1:ny
|
||||||
fi = cycle(fillto,i)
|
fi = cycle(fillto,i)
|
||||||
@ -475,21 +463,6 @@ end
|
|||||||
push!(yseg, y[i], fi, fi, y[i])
|
push!(yseg, y[i], fi, fi, y[i])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
# # create the path in triplets. after the first bottom-left coord of the first bar:
|
|
||||||
# # add the top-left, top-right, and bottom-right coords for each height
|
|
||||||
# x[1] = edges[1]
|
|
||||||
# y[1] = fillto[1]
|
|
||||||
# fillrng[1] = fillto[1]
|
|
||||||
# for i=1:ny
|
|
||||||
# idx = 3i
|
|
||||||
# rng = idx-1:idx+1
|
|
||||||
# fi = fillto[mod1(i,nf)]
|
|
||||||
# x[rng] = [edges[i], edges[i+1], edges[i+1]]
|
|
||||||
# y[rng] = [heights[i], heights[i], fi]
|
|
||||||
# fillrng[rng] = [fi, fi, fi]
|
|
||||||
# end
|
|
||||||
|
|
||||||
# switch back
|
# switch back
|
||||||
if !isvertical(d)
|
if !isvertical(d)
|
||||||
xseg, yseg = yseg, xseg
|
xseg, yseg = yseg, xseg
|
||||||
@ -497,8 +470,6 @@ end
|
|||||||
|
|
||||||
x := xseg.pts
|
x := xseg.pts
|
||||||
y := yseg.pts
|
y := yseg.pts
|
||||||
# fillrange := fillrng
|
|
||||||
# seriestype := :path
|
|
||||||
seriestype := :shape
|
seriestype := :shape
|
||||||
()
|
()
|
||||||
end
|
end
|
||||||
@ -623,27 +594,25 @@ const _box_halfwidth = 0.4
|
|||||||
|
|
||||||
notch_width(q2, q4, N) = 1.58 * (q4-q2)/sqrt(N)
|
notch_width(q2, q4, N) = 1.58 * (q4-q2)/sqrt(N)
|
||||||
|
|
||||||
# function apply_series_recipe(d::KW, ::Type{Val{:box}})
|
|
||||||
@recipe function f(::Type{Val{:boxplot}}, x, y, z; notch=false, range=1.5)
|
@recipe function f(::Type{Val{:boxplot}}, x, y, z; notch=false, range=1.5)
|
||||||
# Plots.dumpdict(d, "box before", true)
|
delete!(d, :notch)
|
||||||
|
delete!(d, :range)
|
||||||
# create a list of shapes, where each shape is a single boxplot
|
xsegs, ysegs = Segments(), Segments()
|
||||||
shapes = Shape[]
|
glabels = sort(collect(unique(x)))
|
||||||
groupby = extractGroupArgs(x)
|
|
||||||
outliers_y = Float64[]
|
|
||||||
outliers_x = Float64[]
|
|
||||||
|
|
||||||
warning = false
|
warning = false
|
||||||
|
outliers_x, outliers_y = zeros(0), zeros(0)
|
||||||
|
for glabel in glabels
|
||||||
|
# filter y
|
||||||
|
values = y[filter(i -> cycle(x,i) == glabel, 1:length(y))]
|
||||||
|
|
||||||
for (i, glabel) in enumerate(groupby.groupLabels)
|
# compute quantiles
|
||||||
|
|
||||||
# filter y values
|
|
||||||
values = d[:y][groupby.groupIds[i]]
|
|
||||||
# then compute quantiles
|
|
||||||
q1,q2,q3,q4,q5 = quantile(values, linspace(0,1,5))
|
q1,q2,q3,q4,q5 = quantile(values, linspace(0,1,5))
|
||||||
|
|
||||||
# notch
|
# notch
|
||||||
n = notch_width(q2, q4, length(values))
|
n = notch_width(q2, q4, length(values))
|
||||||
|
|
||||||
|
# warn on inverted notches?
|
||||||
if notch && !warning && ( (q2>(q3-n)) || (q4<(q3+n)) )
|
if notch && !warning && ( (q2>(q3-n)) || (q4<(q3+n)) )
|
||||||
warn("Boxplot's notch went outside hinges. Set notch to false.")
|
warn("Boxplot's notch went outside hinges. Set notch to false.")
|
||||||
warning = true # Show the warning only one time
|
warning = true # Show the warning only one time
|
||||||
@ -652,8 +621,10 @@ notch_width(q2, q4, N) = 1.58 * (q4-q2)/sqrt(N)
|
|||||||
# make the shape
|
# make the shape
|
||||||
center = discrete_value!(d[:subplot][:xaxis], glabel)[1]
|
center = discrete_value!(d[:subplot][:xaxis], glabel)[1]
|
||||||
l, m, r = center - _box_halfwidth, center, center + _box_halfwidth
|
l, m, r = center - _box_halfwidth, center, center + _box_halfwidth
|
||||||
|
|
||||||
# internal nodes for notches
|
# internal nodes for notches
|
||||||
L, R = center - 0.5 * _box_halfwidth, center + 0.5 * _box_halfwidth
|
L, R = center - 0.5 * _box_halfwidth, center + 0.5 * _box_halfwidth
|
||||||
|
|
||||||
# outliers
|
# outliers
|
||||||
if Float64(range) != 0.0 # if the range is 0.0, the whiskers will extend to the data
|
if Float64(range) != 0.0 # if the range is 0.0, the whiskers will extend to the data
|
||||||
limit = range*(q4-q2)
|
limit = range*(q4-q2)
|
||||||
@ -670,58 +641,144 @@ notch_width(q2, q4, N) = 1.58 * (q4-q2)/sqrt(N)
|
|||||||
# using maximum and minimum values inside the limits
|
# using maximum and minimum values inside the limits
|
||||||
q1, q5 = extrema(inside)
|
q1, q5 = extrema(inside)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Box
|
# Box
|
||||||
xcoords = notch::Bool ? [
|
if notch
|
||||||
m, l, r, m, m, NaN, # lower T
|
push!(xsegs, m, l, r, m, m) # lower T
|
||||||
l, l, L, R, r, r, l, NaN, # lower box
|
push!(xsegs, l, l, L, R, r, r, l) # lower box
|
||||||
l, l, L, R, r, r, l, NaN, # upper box
|
push!(xsegs, l, l, L, R, r, r, l) # upper box
|
||||||
m, l, r, m, m, NaN, # upper T
|
push!(xsegs, m, l, r, m, m) # upper T
|
||||||
] : [
|
|
||||||
m, l, r, m, m, NaN, # lower T
|
push!(ysegs, q1, q1, q1, q1, q2) # lower T
|
||||||
l, l, r, r, l, NaN, # lower box
|
push!(ysegs, q2, q3-n, q3, q3, q3-n, q2, q2) # lower box
|
||||||
l, l, r, r, l, NaN, # upper box
|
push!(ysegs, q4, q3+n, q3, q3, q3+n, q4, q4) # upper box
|
||||||
m, l, r, m, m, NaN, # upper T
|
push!(ysegs, q5, q5, q5, q5, q4) # upper T
|
||||||
]
|
else
|
||||||
ycoords = notch::Bool ? [
|
push!(xsegs, m, l, r, m, m) # lower T
|
||||||
q1, q1, q1, q1, q2, NaN, # lower T
|
push!(xsegs, l, l, r, r, l) # lower box
|
||||||
q2, q3-n, q3, q3, q3-n, q2, q2, NaN, # lower box
|
push!(xsegs, l, l, r, r, l) # upper box
|
||||||
q4, q3+n, q3, q3, q3+n, q4, q4, NaN, # upper box
|
push!(xsegs, m, l, r, m, m) # upper T
|
||||||
q5, q5, q5, q5, q4, NaN, # upper T
|
|
||||||
] : [
|
push!(ysegs, q1, q1, q1, q1, q2) # lower T
|
||||||
q1, q1, q1, q1, q2, NaN, # lower T
|
push!(ysegs, q2, q3, q3, q2, q2) # lower box
|
||||||
q2, q3, q3, q2, q2, NaN, # lower box
|
push!(ysegs, q4, q3, q3, q4, q4) # upper box
|
||||||
q4, q3, q3, q4, q4, NaN, # upper box
|
push!(ysegs, q5, q5, q5, q5, q4) # upper T
|
||||||
q5, q5, q5, q5, q4, NaN, # upper T
|
end
|
||||||
]
|
|
||||||
push!(shapes, Shape(xcoords, ycoords))
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# d[:plotarg_overrides] = KW(:xticks => (1:length(shapes), groupby.groupLabels))
|
|
||||||
|
|
||||||
seriestype := :shape
|
|
||||||
# n = length(groupby.groupLabels)
|
|
||||||
# xticks --> (linspace(0.5,n-0.5,n), groupby.groupLabels)
|
|
||||||
|
|
||||||
# clean d
|
|
||||||
pop!(d, :notch)
|
|
||||||
pop!(d, :range)
|
|
||||||
|
|
||||||
# we want to set the fields directly inside series recipes... args are ignored
|
|
||||||
d[:x], d[:y] = Plots.shape_coords(shapes)
|
|
||||||
|
|
||||||
# Outliers
|
# Outliers
|
||||||
@series begin
|
@series begin
|
||||||
seriestype := :scatter
|
seriestype := :scatter
|
||||||
markershape := :circle
|
markershape --> :circle
|
||||||
x := outliers_x
|
x := outliers_x
|
||||||
y := outliers_y
|
y := outliers_y
|
||||||
label := ""
|
|
||||||
primary := false
|
primary := false
|
||||||
()
|
()
|
||||||
end
|
end
|
||||||
|
|
||||||
() # expects a tuple returned
|
seriestype := :shape
|
||||||
|
x := xsegs.pts
|
||||||
|
y := ysegs.pts
|
||||||
|
()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# @recipe function f(::Type{Val{:boxplot}}, x, y, z; notch=false, range=1.5)
|
||||||
|
# # Plots.dumpdict(d, "box before", true)
|
||||||
|
|
||||||
|
# # create a list of shapes, where each shape is a single boxplot
|
||||||
|
# shapes = Shape[]
|
||||||
|
# groupby = extractGroupArgs(x)
|
||||||
|
# outliers_y = Float64[]
|
||||||
|
# outliers_x = Float64[]
|
||||||
|
|
||||||
|
# warning = false
|
||||||
|
|
||||||
|
# for (i, glabel) in enumerate(groupby.groupLabels)
|
||||||
|
|
||||||
|
# # filter y values
|
||||||
|
# values = d[:y][groupby.groupIds[i]]
|
||||||
|
# # then compute quantiles
|
||||||
|
# q1,q2,q3,q4,q5 = quantile(values, linspace(0,1,5))
|
||||||
|
# # notch
|
||||||
|
# n = notch_width(q2, q4, length(values))
|
||||||
|
|
||||||
|
# if notch && !warning && ( (q2>(q3-n)) || (q4<(q3+n)) )
|
||||||
|
# warn("Boxplot's notch went outside hinges. Set notch to false.")
|
||||||
|
# warning = true # Show the warning only one time
|
||||||
|
# end
|
||||||
|
|
||||||
|
# # make the shape
|
||||||
|
# center = discrete_value!(d[:subplot][:xaxis], glabel)[1]
|
||||||
|
# l, m, r = center - _box_halfwidth, center, center + _box_halfwidth
|
||||||
|
# # internal nodes for notches
|
||||||
|
# L, R = center - 0.5 * _box_halfwidth, center + 0.5 * _box_halfwidth
|
||||||
|
# # outliers
|
||||||
|
# if Float64(range) != 0.0 # if the range is 0.0, the whiskers will extend to the data
|
||||||
|
# limit = range*(q4-q2)
|
||||||
|
# inside = Float64[]
|
||||||
|
# for value in values
|
||||||
|
# if (value < (q2 - limit)) || (value > (q4 + limit))
|
||||||
|
# push!(outliers_y, value)
|
||||||
|
# push!(outliers_x, center)
|
||||||
|
# else
|
||||||
|
# push!(inside, value)
|
||||||
|
# end
|
||||||
|
# end
|
||||||
|
# # change q1 and q5 to show outliers
|
||||||
|
# # using maximum and minimum values inside the limits
|
||||||
|
# q1, q5 = extrema(inside)
|
||||||
|
# end
|
||||||
|
# # Box
|
||||||
|
# xcoords = notch::Bool ? [
|
||||||
|
# m, l, r, m, m, NaN, # lower T
|
||||||
|
# l, l, L, R, r, r, l, NaN, # lower box
|
||||||
|
# l, l, L, R, r, r, l, NaN, # upper box
|
||||||
|
# m, l, r, m, m, NaN, # upper T
|
||||||
|
# ] : [
|
||||||
|
# m, l, r, m, m, NaN, # lower T
|
||||||
|
# l, l, r, r, l, NaN, # lower box
|
||||||
|
# l, l, r, r, l, NaN, # upper box
|
||||||
|
# m, l, r, m, m, NaN, # upper T
|
||||||
|
# ]
|
||||||
|
# ycoords = notch::Bool ? [
|
||||||
|
# q1, q1, q1, q1, q2, NaN, # lower T
|
||||||
|
# q2, q3-n, q3, q3, q3-n, q2, q2, NaN, # lower box
|
||||||
|
# q4, q3+n, q3, q3, q3+n, q4, q4, NaN, # upper box
|
||||||
|
# q5, q5, q5, q5, q4, NaN, # upper T
|
||||||
|
# ] : [
|
||||||
|
# q1, q1, q1, q1, q2, NaN, # lower T
|
||||||
|
# q2, q3, q3, q2, q2, NaN, # lower box
|
||||||
|
# q4, q3, q3, q4, q4, NaN, # upper box
|
||||||
|
# q5, q5, q5, q5, q4, NaN, # upper T
|
||||||
|
# ]
|
||||||
|
# push!(shapes, Shape(xcoords, ycoords))
|
||||||
|
# end
|
||||||
|
|
||||||
|
# # d[:plotarg_overrides] = KW(:xticks => (1:length(shapes), groupby.groupLabels))
|
||||||
|
|
||||||
|
# seriestype := :shape
|
||||||
|
# # n = length(groupby.groupLabels)
|
||||||
|
# # xticks --> (linspace(0.5,n-0.5,n), groupby.groupLabels)
|
||||||
|
|
||||||
|
# # clean d
|
||||||
|
# pop!(d, :notch)
|
||||||
|
# pop!(d, :range)
|
||||||
|
|
||||||
|
# # we want to set the fields directly inside series recipes... args are ignored
|
||||||
|
# d[:x], d[:y] = Plots.shape_coords(shapes)
|
||||||
|
|
||||||
|
# # Outliers
|
||||||
|
# @series begin
|
||||||
|
# seriestype := :scatter
|
||||||
|
# markershape --> :circle
|
||||||
|
# x := outliers_x
|
||||||
|
# y := outliers_y
|
||||||
|
# primary := false
|
||||||
|
# ()
|
||||||
|
# end
|
||||||
|
|
||||||
|
# () # expects a tuple returned
|
||||||
|
# end
|
||||||
@deps boxplot shape scatter
|
@deps boxplot shape scatter
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|||||||
@ -97,445 +97,3 @@ compute_xyz(x::Void, y::Void, z::FuncOrFuncs) = error("If you want to plot the f
|
|||||||
compute_xyz(x::Void, y::Void, z::Void) = error("x/y/z are all nothing!")
|
compute_xyz(x::Void, y::Void, z::Void) = error("x/y/z are all nothing!")
|
||||||
|
|
||||||
# --------------------------------------------------------------------
|
# --------------------------------------------------------------------
|
||||||
|
|
||||||
# # create n=max(mx,my) series arguments. the shorter list is cycled through
|
|
||||||
# # note: everything should flow through this
|
|
||||||
# function build_series_args(plt::AbstractPlot, kw::KW) #, idxfilter)
|
|
||||||
# x, y, z = map(sym -> pop!(kw, sym, nothing), (:x, :y, :z))
|
|
||||||
# if nothing == x == y == z
|
|
||||||
# return [], nothing, nothing
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# xs, xmeta = convertToAnyVector(x, kw)
|
|
||||||
# ys, ymeta = convertToAnyVector(y, kw)
|
|
||||||
# zs, zmeta = convertToAnyVector(z, kw)
|
|
||||||
#
|
|
||||||
# fr = pop!(kw, :fillrange, nothing)
|
|
||||||
# fillranges, _ = if typeof(fr) <: Number
|
|
||||||
# ([fr],nothing)
|
|
||||||
# else
|
|
||||||
# convertToAnyVector(fr, kw)
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# mx = length(xs)
|
|
||||||
# my = length(ys)
|
|
||||||
# mz = length(zs)
|
|
||||||
# ret = Any[]
|
|
||||||
# for i in 1:max(mx, my, mz)
|
|
||||||
#
|
|
||||||
# # try to set labels using ymeta
|
|
||||||
# d = copy(kw)
|
|
||||||
# if !haskey(d, :label) && ymeta != nothing
|
|
||||||
# if isa(ymeta, Symbol)
|
|
||||||
# d[:label] = string(ymeta)
|
|
||||||
# elseif isa(ymeta, AVec{Symbol})
|
|
||||||
# d[:label] = string(ymeta[mod1(i,length(ymeta))])
|
|
||||||
# end
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# # build the series arg dict
|
|
||||||
# numUncounted = pop!(d, :numUncounted, 0)
|
|
||||||
# commandIndex = i + numUncounted
|
|
||||||
# n = plt.n + i
|
|
||||||
#
|
|
||||||
# dumpdict(d, "before getSeriesArgs")
|
|
||||||
# d = getSeriesArgs(plt.backend, getattr(plt, n), d, commandIndex, convertSeriesIndex(plt, n), n)
|
|
||||||
# dumpdict(d, "after getSeriesArgs")
|
|
||||||
#
|
|
||||||
# d[:x], d[:y], d[:z] = compute_xyz(xs[mod1(i,mx)], ys[mod1(i,my)], zs[mod1(i,mz)])
|
|
||||||
# st = d[:seriestype]
|
|
||||||
#
|
|
||||||
# # for seriestype `line`, need to sort by x values
|
|
||||||
# if st == :line
|
|
||||||
# # order by x
|
|
||||||
# indices = sortperm(d[:x])
|
|
||||||
# d[:x] = d[:x][indices]
|
|
||||||
# d[:y] = d[:y][indices]
|
|
||||||
# d[:seriestype] = :path
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# # special handling for missing x in box plot... all the same category
|
|
||||||
# if st == :box && xs[mod1(i,mx)] == nothing
|
|
||||||
# d[:x] = ones(Int, length(d[:y]))
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# # map functions to vectors
|
|
||||||
# if isa(d[:marker_z], Function)
|
|
||||||
# d[:marker_z] = map(d[:marker_z], d[:x])
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# # @show fillranges
|
|
||||||
# d[:fillrange] = fillranges[mod1(i,length(fillranges))]
|
|
||||||
# if isa(d[:fillrange], Function)
|
|
||||||
# d[:fillrange] = map(d[:fillrange], d[:x])
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# # handle error bars
|
|
||||||
# for esym in (:xerror, :yerror)
|
|
||||||
# if get(d, esym, nothing) != nothing
|
|
||||||
# # we make a copy of the KW and apply an errorbar recipe
|
|
||||||
# append!(ret, apply_series_recipe(copy(d), Val{esym}))
|
|
||||||
# end
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# # handle ribbons
|
|
||||||
# if get(d, :ribbon, nothing) != nothing
|
|
||||||
# rib = d[:ribbon]
|
|
||||||
# d[:fillrange] = (d[:y] - rib, d[:y] + rib)
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# # handle quiver plots
|
|
||||||
# # either a series of velocity vectors are passed in (`:quiver` keyword),
|
|
||||||
# # or we just add arrows to the path
|
|
||||||
#
|
|
||||||
# # if st == :quiver
|
|
||||||
# # d[:seriestype] = st = :path
|
|
||||||
# # d[:linewidth] = 0
|
|
||||||
# # end
|
|
||||||
# if get(d, :quiver, nothing) != nothing
|
|
||||||
# append!(ret, apply_series_recipe(copy(d), Val{:quiver}))
|
|
||||||
# elseif st == :quiver
|
|
||||||
# d[:seriestype] = st = :path
|
|
||||||
# d[:arrow] = arrow()
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# # now that we've processed a given series... optionally split into
|
|
||||||
# # multiple dicts through a recipe (for example, a box plot is split into component
|
|
||||||
# # parts... polygons, lines, and scatters)
|
|
||||||
# # note: we pass in a Val type (i.e. Val{:box}) so that we can dispatch on the seriestype
|
|
||||||
# kwlist = apply_series_recipe(d, Val{st})
|
|
||||||
# append!(ret, kwlist)
|
|
||||||
#
|
|
||||||
# # # add it to our series list
|
|
||||||
# # push!(ret, d)
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# ret, xmeta, ymeta
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# # --------------------------------------------------------------------
|
|
||||||
# # process_inputs
|
|
||||||
# # --------------------------------------------------------------------
|
|
||||||
#
|
|
||||||
# # These methods take a plot and the keyword arguments, and processes the input
|
|
||||||
# # arguments (x/y/z, group, etc), populating the KW dict with appropriate values.
|
|
||||||
#
|
|
||||||
# # --------------------------------------------------------------------
|
|
||||||
# # 0 arguments
|
|
||||||
# # --------------------------------------------------------------------
|
|
||||||
#
|
|
||||||
# # don't do anything
|
|
||||||
# function process_inputs(plt::AbstractPlot, d::KW)
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# # --------------------------------------------------------------------
|
|
||||||
# # 1 argument
|
|
||||||
# # --------------------------------------------------------------------
|
|
||||||
#
|
|
||||||
# function process_inputs(plt::AbstractPlot, d::KW, n::Integer)
|
|
||||||
# # d[:x], d[:y], d[:z] = zeros(0), zeros(0), zeros(0)
|
|
||||||
# d[:x] = d[:y] = d[:z] = n
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# # no special handling... assume x and z are nothing
|
|
||||||
# function process_inputs(plt::AbstractPlot, d::KW, y)
|
|
||||||
# d[:y] = y
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# # matrix... is it z or y?
|
|
||||||
# function process_inputs{T<:Number}(plt::AbstractPlot, d::KW, mat::AMat{T})
|
|
||||||
# if all3D(d)
|
|
||||||
# n,m = size(mat)
|
|
||||||
# d[:x], d[:y], d[:z] = 1:n, 1:m, mat
|
|
||||||
# else
|
|
||||||
# d[:y] = mat
|
|
||||||
# end
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# # images - grays
|
|
||||||
# function process_inputs{T<:Gray}(plt::AbstractPlot, d::KW, mat::AMat{T})
|
|
||||||
# d[:seriestype] = :image
|
|
||||||
# n,m = size(mat)
|
|
||||||
# d[:x], d[:y], d[:z] = 1:n, 1:m, Surface(mat)
|
|
||||||
# # handle images... when not supported natively, do a hack to use heatmap machinery
|
|
||||||
# if !nativeImagesSupported()
|
|
||||||
# d[:seriestype] = :heatmap
|
|
||||||
# d[:yflip] = true
|
|
||||||
# d[:z] = Surface(convert(Matrix{Float64}, mat.surf))
|
|
||||||
# d[:fillcolor] = ColorGradient([:black, :white])
|
|
||||||
# end
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# # images - colors
|
|
||||||
# function process_inputs{T<:Colorant}(plt::AbstractPlot, d::KW, mat::AMat{T})
|
|
||||||
# d[:seriestype] = :image
|
|
||||||
# n,m = size(mat)
|
|
||||||
# d[:x], d[:y], d[:z] = 1:n, 1:m, Surface(mat)
|
|
||||||
# # handle images... when not supported natively, do a hack to use heatmap machinery
|
|
||||||
# if !nativeImagesSupported()
|
|
||||||
# d[:yflip] = true
|
|
||||||
# imageHack(d)
|
|
||||||
# end
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# # plotting arbitrary shapes/polygons
|
|
||||||
# function process_inputs(plt::AbstractPlot, d::KW, shape::Shape)
|
|
||||||
# d[:x], d[:y] = shape_coords(shape)
|
|
||||||
# d[:seriestype] = :shape
|
|
||||||
# end
|
|
||||||
# function process_inputs(plt::AbstractPlot, d::KW, shapes::AVec{Shape})
|
|
||||||
# d[:x], d[:y] = shape_coords(shapes)
|
|
||||||
# d[:seriestype] = :shape
|
|
||||||
# end
|
|
||||||
# function process_inputs(plt::AbstractPlot, d::KW, shapes::AMat{Shape})
|
|
||||||
# x, y = [], []
|
|
||||||
# for j in 1:size(shapes, 2)
|
|
||||||
# tmpx, tmpy = shape_coords(vec(shapes[:,j]))
|
|
||||||
# push!(x, tmpx)
|
|
||||||
# push!(y, tmpy)
|
|
||||||
# end
|
|
||||||
# d[:x], d[:y] = x, y
|
|
||||||
# d[:seriestype] = :shape
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# # function without range... use the current range of the x-axis
|
|
||||||
# function process_inputs(plt::AbstractPlot, d::KW, f::FuncOrFuncs)
|
|
||||||
# process_inputs(plt, d, f, xmin(plt), xmax(plt))
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# # --------------------------------------------------------------------
|
|
||||||
# # 2 arguments
|
|
||||||
# # --------------------------------------------------------------------
|
|
||||||
#
|
|
||||||
# function process_inputs(plt::AbstractPlot, d::KW, x, y)
|
|
||||||
# d[:x], d[:y] = x, y
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# # if functions come first, just swap the order (not to be confused with parametric functions...
|
|
||||||
# # as there would be more than one function passed in)
|
|
||||||
# function process_inputs(plt::AbstractPlot, d::KW, f::FuncOrFuncs, x)
|
|
||||||
# @assert !(typeof(x) <: FuncOrFuncs) # otherwise we'd hit infinite recursion here
|
|
||||||
# process_inputs(plt, d, x, f)
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# # --------------------------------------------------------------------
|
|
||||||
# # 3 arguments
|
|
||||||
# # --------------------------------------------------------------------
|
|
||||||
#
|
|
||||||
# # no special handling... just pass them through
|
|
||||||
# function process_inputs(plt::AbstractPlot, d::KW, x, y, z)
|
|
||||||
# d[:x], d[:y], d[:z] = x, y, z
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# # 3d line or scatter
|
|
||||||
# function process_inputs(plt::AbstractPlot, d::KW, x::AVec, y::AVec, zvec::AVec)
|
|
||||||
# # default to path3d if we haven't set a 3d seriestype
|
|
||||||
# st = get(d, :seriestype, :none)
|
|
||||||
# if st == :scatter
|
|
||||||
# d[:seriestype] = :scatter3d
|
|
||||||
# elseif !(st in _3dTypes)
|
|
||||||
# d[:seriestype] = :path3d
|
|
||||||
# end
|
|
||||||
# d[:x], d[:y], d[:z] = x, y, zvec
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# # surface-like... function
|
|
||||||
# function process_inputs{TX,TY}(plt::AbstractPlot, d::KW, x::AVec{TX}, y::AVec{TY}, zf::Function)
|
|
||||||
# x = TX <: Number ? sort(x) : x
|
|
||||||
# y = TY <: Number ? sort(y) : y
|
|
||||||
# # x, y = sort(x), sort(y)
|
|
||||||
# d[:z] = Surface(zf, x, y) # TODO: replace with SurfaceFunction when supported
|
|
||||||
# d[:x], d[:y] = x, y
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# # surface-like... matrix grid
|
|
||||||
# function process_inputs{TX,TY,TZ}(plt::AbstractPlot, d::KW, x::AVec{TX}, y::AVec{TY}, zmat::AMat{TZ})
|
|
||||||
# # @assert size(zmat) == (length(x), length(y))
|
|
||||||
# # if TX <: Number && !issorted(x)
|
|
||||||
# # idx = sortperm(x)
|
|
||||||
# # x, zmat = x[idx], zmat[idx, :]
|
|
||||||
# # end
|
|
||||||
# # if TY <: Number && !issorted(y)
|
|
||||||
# # idx = sortperm(y)
|
|
||||||
# # y, zmat = y[idx], zmat[:, idx]
|
|
||||||
# # end
|
|
||||||
# d[:x], d[:y], d[:z] = x, y, Surface{Matrix{TZ}}(zmat)
|
|
||||||
# if !like_surface(get(d, :seriestype, :none))
|
|
||||||
# d[:seriestype] = :contour
|
|
||||||
# end
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# # surfaces-like... general x, y grid
|
|
||||||
# function process_inputs{T<:Number}(plt::AbstractPlot, d::KW, x::AMat{T}, y::AMat{T}, zmat::AMat{T})
|
|
||||||
# @assert size(zmat) == size(x) == size(y)
|
|
||||||
# # d[:x], d[:y], d[:z] = Any[x], Any[y], Surface{Matrix{Float64}}(zmat)
|
|
||||||
# d[:x], d[:y], d[:z] = map(Surface{Matrix{Float64}}, (x, y, zmat))
|
|
||||||
# if !like_surface(get(d, :seriestype, :none))
|
|
||||||
# d[:seriestype] = :contour
|
|
||||||
# end
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# # --------------------------------------------------------------------
|
|
||||||
# # Parametric functions
|
|
||||||
# # --------------------------------------------------------------------
|
|
||||||
#
|
|
||||||
# # special handling... xmin/xmax with function(s)
|
|
||||||
# function process_inputs(plt::AbstractPlot, d::KW, f::FuncOrFuncs, xmin::Number, xmax::Number)
|
|
||||||
# width = get(plt.attr, :size, (100,))[1]
|
|
||||||
# x = linspace(xmin, xmax, width)
|
|
||||||
# process_inputs(plt, d, x, f)
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# # special handling... xmin/xmax with parametric function(s)
|
|
||||||
# process_inputs{T<:Number}(plt::AbstractPlot, d::KW, fx::FuncOrFuncs, fy::FuncOrFuncs, u::AVec{T}) = process_inputs(plt, d, mapFuncOrFuncs(fx, u), mapFuncOrFuncs(fy, u))
|
|
||||||
# process_inputs{T<:Number}(plt::AbstractPlot, d::KW, u::AVec{T}, fx::FuncOrFuncs, fy::FuncOrFuncs) = process_inputs(plt, d, mapFuncOrFuncs(fx, u), mapFuncOrFuncs(fy, u))
|
|
||||||
# process_inputs(plt::AbstractPlot, d::KW, fx::FuncOrFuncs, fy::FuncOrFuncs, umin::Number, umax::Number, numPoints::Int = 1000) = process_inputs(plt, d, fx, fy, linspace(umin, umax, numPoints))
|
|
||||||
#
|
|
||||||
# # special handling... 3D parametric function(s)
|
|
||||||
# process_inputs{T<:Number}(plt::AbstractPlot, d::KW, fx::FuncOrFuncs, fy::FuncOrFuncs, fz::FuncOrFuncs, u::AVec{T}) = process_inputs(plt, d, mapFuncOrFuncs(fx, u), mapFuncOrFuncs(fy, u), mapFuncOrFuncs(fz, u))
|
|
||||||
# process_inputs{T<:Number}(plt::AbstractPlot, d::KW, u::AVec{T}, fx::FuncOrFuncs, fy::FuncOrFuncs, fz::FuncOrFuncs) = process_inputs(plt, d, mapFuncOrFuncs(fx, u), mapFuncOrFuncs(fy, u), mapFuncOrFuncs(fz, u))
|
|
||||||
# process_inputs(plt::AbstractPlot, d::KW, fx::FuncOrFuncs, fy::FuncOrFuncs, fz::FuncOrFuncs, umin::Number, umax::Number, numPoints::Int = 1000) = process_inputs(plt, d, fx, fy, fz, linspace(umin, umax, numPoints))
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# # --------------------------------------------------------------------
|
|
||||||
# # Lists of tuples and FixedSizeArrays
|
|
||||||
# # --------------------------------------------------------------------
|
|
||||||
#
|
|
||||||
# # if we get an unhandled tuple, just splat it in
|
|
||||||
# function process_inputs(plt::AbstractPlot, d::KW, tup::Tuple)
|
|
||||||
# process_inputs(plt, d, tup...)
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# # (x,y) tuples
|
|
||||||
# function process_inputs{R1<:Number,R2<:Number}(plt::AbstractPlot, d::KW, xy::AVec{Tuple{R1,R2}})
|
|
||||||
# process_inputs(plt, d, unzip(xy)...)
|
|
||||||
# end
|
|
||||||
# function process_inputs{R1<:Number,R2<:Number}(plt::AbstractPlot, d::KW, xy::Tuple{R1,R2})
|
|
||||||
# process_inputs(plt, d, [xy[1]], [xy[2]])
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# # (x,y,z) tuples
|
|
||||||
# function process_inputs{R1<:Number,R2<:Number,R3<:Number}(plt::AbstractPlot, d::KW, xyz::AVec{Tuple{R1,R2,R3}})
|
|
||||||
# process_inputs(plt, d, unzip(xyz)...)
|
|
||||||
# end
|
|
||||||
# function process_inputs{R1<:Number,R2<:Number,R3<:Number}(plt::AbstractPlot, d::KW, xyz::Tuple{R1,R2,R3})
|
|
||||||
# process_inputs(plt, d, [xyz[1]], [xyz[2]], [xyz[3]])
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# # 2D FixedSizeArrays
|
|
||||||
# function process_inputs{T<:Number}(plt::AbstractPlot, d::KW, xy::AVec{FixedSizeArrays.Vec{2,T}})
|
|
||||||
# process_inputs(plt, d, unzip(xy)...)
|
|
||||||
# end
|
|
||||||
# function process_inputs{T<:Number}(plt::AbstractPlot, d::KW, xy::FixedSizeArrays.Vec{2,T})
|
|
||||||
# process_inputs(plt, d, [xy[1]], [xy[2]])
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# # 3D FixedSizeArrays
|
|
||||||
# function process_inputs{T<:Number}(plt::AbstractPlot, d::KW, xyz::AVec{FixedSizeArrays.Vec{3,T}})
|
|
||||||
# process_inputs(plt, d, unzip(xyz)...)
|
|
||||||
# end
|
|
||||||
# function process_inputs{T<:Number}(plt::AbstractPlot, d::KW, xyz::FixedSizeArrays.Vec{3,T})
|
|
||||||
# process_inputs(plt, d, [xyz[1]], [xyz[2]], [xyz[3]])
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# # --------------------------------------------------------------------
|
|
||||||
# # handle grouping
|
|
||||||
# # --------------------------------------------------------------------
|
|
||||||
#
|
|
||||||
# # function process_inputs(plt::AbstractPlot, d::KW, groupby::GroupBy, args...)
|
|
||||||
# # ret = Any[]
|
|
||||||
# # error("unfinished after series reorg")
|
|
||||||
# # for (i,glab) in enumerate(groupby.groupLabels)
|
|
||||||
# # # TODO: don't automatically overwrite labels
|
|
||||||
# # kwlist, xmeta, ymeta = process_inputs(plt, d, args...,
|
|
||||||
# # idxfilter = groupby.groupIds[i],
|
|
||||||
# # label = string(glab),
|
|
||||||
# # numUncounted = length(ret)) # we count the idx from plt.n + numUncounted + i
|
|
||||||
# # append!(ret, kwlist)
|
|
||||||
# # end
|
|
||||||
# # ret, nothing, nothing # TODO: handle passing meta through
|
|
||||||
# # end
|
|
||||||
|
|
||||||
# --------------------------------------------------------------------
|
|
||||||
# For DataFrame support. Imports DataFrames and defines the necessary methods which support them.
|
|
||||||
# --------------------------------------------------------------------
|
|
||||||
|
|
||||||
# function setup_dataframes()
|
|
||||||
# @require DataFrames begin
|
|
||||||
# # @eval begin
|
|
||||||
# # import DataFrames
|
|
||||||
#
|
|
||||||
# DFS = Union{Symbol, AbstractArray{Symbol}}
|
|
||||||
#
|
|
||||||
# function handle_dfs(df::DataFrames.AbstractDataFrame, d::KW, letter, dfs::DFS)
|
|
||||||
# if isa(dfs, Symbol)
|
|
||||||
# get!(d, Symbol(letter * "label"), string(dfs))
|
|
||||||
# collect(df[dfs])
|
|
||||||
# else
|
|
||||||
# get!(d, :label, reshape(dfs, 1, length(dfs)))
|
|
||||||
# Any[collect(df[s]) for s in dfs]
|
|
||||||
# end
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# function handle_group(df::DataFrames.AbstractDataFrame, d::KW)
|
|
||||||
# if haskey(d, :group)
|
|
||||||
# g = d[:group]
|
|
||||||
# if isa(g, Symbol)
|
|
||||||
# d[:group] = collect(df[g])
|
|
||||||
# end
|
|
||||||
# end
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# @recipe function plot(df::DataFrames.AbstractDataFrame, sy::DFS)
|
|
||||||
# handle_group(df, d)
|
|
||||||
# handle_dfs(df, d, "y", sy)
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# @recipe function plot(df::DataFrames.AbstractDataFrame, sx::DFS, sy::DFS)
|
|
||||||
# handle_group(df, d)
|
|
||||||
# x = handle_dfs(df, d, "x", sx)
|
|
||||||
# y = handle_dfs(df, d, "y", sy)
|
|
||||||
# x, y
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# @recipe function plot(df::DataFrames.AbstractDataFrame, sx::DFS, sy::DFS, sz::DFS)
|
|
||||||
# handle_group(df, d)
|
|
||||||
# x = handle_dfs(df, d, "x", sx)
|
|
||||||
# y = handle_dfs(df, d, "y", sy)
|
|
||||||
# z = handle_dfs(df, d, "z", sz)
|
|
||||||
# x, y, z
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# # get_data(df::DataFrames.AbstractDataFrame, arg::Symbol) = df[arg]
|
|
||||||
# # get_data(df::DataFrames.AbstractDataFrame, arg) = arg
|
|
||||||
# #
|
|
||||||
# # function process_inputs(plt::AbstractPlot, d::KW, df::DataFrames.AbstractDataFrame, args...)
|
|
||||||
# # # d[:dataframe] = df
|
|
||||||
# # process_inputs(plt, d, map(arg -> get_data(df, arg), args)...)
|
|
||||||
# # end
|
|
||||||
# #
|
|
||||||
# # # expecting the column name of a dataframe that was passed in... anything else should error
|
|
||||||
# # function extractGroupArgs(s::Symbol, df::DataFrames.AbstractDataFrame, args...)
|
|
||||||
# # if haskey(df, s)
|
|
||||||
# # return extractGroupArgs(df[s])
|
|
||||||
# # else
|
|
||||||
# # error("Got a symbol, and expected that to be a key in d[:dataframe]. s=$s d=$d")
|
|
||||||
# # end
|
|
||||||
# # end
|
|
||||||
#
|
|
||||||
# # function getDataFrameFromKW(d::KW)
|
|
||||||
# # get(d, :dataframe) do
|
|
||||||
# # error("Missing dataframe argument!")
|
|
||||||
# # end
|
|
||||||
# # end
|
|
||||||
#
|
|
||||||
# # # the conversion functions for when we pass symbols or vectors of symbols to reference dataframes
|
|
||||||
# # convertToAnyVector(s::Symbol, d::KW) = Any[getDataFrameFromKW(d)[s]], s
|
|
||||||
# # convertToAnyVector(v::AVec{Symbol}, d::KW) = (df = getDataFrameFromKW(d); Any[df[s] for s in v]), v
|
|
||||||
#
|
|
||||||
# end
|
|
||||||
# end
|
|
||||||
|
|||||||
@ -180,15 +180,6 @@ end
|
|||||||
newargs
|
newargs
|
||||||
end
|
end
|
||||||
|
|
||||||
# @recipe f(x, y, z) = SliceIt, apply_recipe(typeof(x), x), apply_recipe(typeof(y), y), apply_recipe(typeof(z), z)
|
|
||||||
# @recipe f(x, y) = SliceIt, apply_recipe(typeof(x), x), apply_recipe(typeof(y), y), nothing
|
|
||||||
# @recipe f(y) = SliceIt, nothing, apply_recipe(typeof(y), y), nothing
|
|
||||||
|
|
||||||
# # pass these through to the slicer
|
|
||||||
# @recipe f(x, y, z) = SliceIt, x, y, z
|
|
||||||
# @recipe f(x, y) = SliceIt, x, y, nothing
|
|
||||||
# @recipe f(y) = SliceIt, nothing, y, nothing
|
|
||||||
|
|
||||||
|
|
||||||
# # --------------------------------------------------------------------
|
# # --------------------------------------------------------------------
|
||||||
# # 1 argument
|
# # 1 argument
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user