boxplot, violin, quiver, and line series recipes; plus some fixes
This commit is contained in:
parent
26779cbf4a
commit
8ec3d18339
@ -222,8 +222,8 @@ plot3d(args...; kw...) = plot(args...; kw..., linetype = :path3d)
|
|||||||
plot3d!(args...; kw...) = plot!(args...; kw..., linetype = :path3d)
|
plot3d!(args...; kw...) = plot!(args...; kw..., linetype = :path3d)
|
||||||
scatter3d(args...; kw...) = plot(args...; kw..., linetype = :scatter3d)
|
scatter3d(args...; kw...) = plot(args...; kw..., linetype = :scatter3d)
|
||||||
scatter3d!(args...; kw...) = plot!(args...; kw..., linetype = :scatter3d)
|
scatter3d!(args...; kw...) = plot!(args...; kw..., linetype = :scatter3d)
|
||||||
boxplot(args...; kw...) = plot(args...; kw..., linetype = :box)
|
boxplot(args...; kw...) = plot(args...; kw..., linetype = :boxplot)
|
||||||
boxplot!(args...; kw...) = plot!(args...; kw..., linetype = :box)
|
boxplot!(args...; kw...) = plot!(args...; kw..., linetype = :boxplot)
|
||||||
violin(args...; kw...) = plot(args...; kw..., linetype = :violin)
|
violin(args...; kw...) = plot(args...; kw..., linetype = :violin)
|
||||||
violin!(args...; kw...) = plot!(args...; kw..., linetype = :violin)
|
violin!(args...; kw...) = plot!(args...; kw..., linetype = :violin)
|
||||||
quiver(args...; kw...) = plot(args...; kw..., linetype = :quiver)
|
quiver(args...; kw...) = plot(args...; kw..., linetype = :quiver)
|
||||||
|
|||||||
@ -11,7 +11,7 @@ const _3dTypes = [:path3d, :scatter3d, :surface, :wireframe, :contour3d]
|
|||||||
const _allTypes = vcat([
|
const _allTypes = vcat([
|
||||||
:none, :line, :path, :steppre, :steppost, :sticks, :scatter,
|
:none, :line, :path, :steppre, :steppost, :sticks, :scatter,
|
||||||
:heatmap, :hexbin, :hist, :hist2d, :hist3d, :density, :bar, :hline, :vline, :ohlc,
|
:heatmap, :hexbin, :hist, :hist2d, :hist3d, :density, :bar, :hline, :vline, :ohlc,
|
||||||
:contour, :pie, :shape, :box, :violin, :quiver, :image
|
:contour, :pie, :shape, :image #, :boxplot, :violin, :quiver,
|
||||||
], _3dTypes)
|
], _3dTypes)
|
||||||
@compat const _typeAliases = KW(
|
@compat const _typeAliases = KW(
|
||||||
:n => :none,
|
:n => :none,
|
||||||
@ -38,7 +38,7 @@ const _allTypes = vcat([
|
|||||||
:shapes => :shape,
|
:shapes => :shape,
|
||||||
:poly => :shape,
|
:poly => :shape,
|
||||||
:polygon => :shape,
|
:polygon => :shape,
|
||||||
:boxplot => :box,
|
:box => :boxplot,
|
||||||
:velocity => :quiver,
|
:velocity => :quiver,
|
||||||
:gradient => :quiver,
|
:gradient => :quiver,
|
||||||
:img => :image,
|
:img => :image,
|
||||||
|
|||||||
@ -28,7 +28,7 @@ supportedAxes(::GadflyBackend) = [:auto, :left]
|
|||||||
supportedTypes(::GadflyBackend) = [
|
supportedTypes(::GadflyBackend) = [
|
||||||
:none, :line, :path, :steppre, :steppost, :sticks,
|
:none, :line, :path, :steppre, :steppost, :sticks,
|
||||||
:scatter, :hist2d, :hexbin, :hist,
|
:scatter, :hist2d, :hexbin, :hist,
|
||||||
:bar, :box, :violin, :quiver,
|
:bar, #:box, :violin, :quiver,
|
||||||
:hline, :vline, :contour, :shape
|
:hline, :vline, :contour, :shape
|
||||||
]
|
]
|
||||||
supportedStyles(::GadflyBackend) = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
|
supportedStyles(::GadflyBackend) = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
|
||||||
|
|||||||
@ -40,7 +40,7 @@ supportedAxes(::PyPlotBackend) = _allAxes
|
|||||||
supportedTypes(::PyPlotBackend) = [
|
supportedTypes(::PyPlotBackend) = [
|
||||||
:none, :line, :path, :steppre, :steppost, :shape,
|
:none, :line, :path, :steppre, :steppost, :shape,
|
||||||
:scatter, :hist2d, :hexbin, :hist, :density,
|
:scatter, :hist2d, :hexbin, :hist, :density,
|
||||||
:bar, :sticks, :box, :violin, :quiver,
|
:bar, :sticks, #:box, :violin, :quiver,
|
||||||
:hline, :vline, :heatmap, :pie, :image,
|
:hline, :vline, :heatmap, :pie, :image,
|
||||||
:contour, :contour3d, :path3d, :scatter3d, :surface, :wireframe
|
:contour, :contour3d, :path3d, :scatter3d, :surface, :wireframe
|
||||||
]
|
]
|
||||||
|
|||||||
22
src/plot.jl
22
src/plot.jl
@ -86,12 +86,15 @@ end
|
|||||||
# natively by the backend
|
# natively by the backend
|
||||||
function _apply_series_recipe(plt::Plot, d::KW)
|
function _apply_series_recipe(plt::Plot, d::KW)
|
||||||
lt = d[:linetype]
|
lt = d[:linetype]
|
||||||
|
# dumpdict(d, "apply_series_recipe", true)
|
||||||
if lt in supportedTypes()
|
if lt in supportedTypes()
|
||||||
|
# println("adding series!!")
|
||||||
|
warnOnUnsupported(plt.backend, d)
|
||||||
_add_series(plt.backend, plt, d)
|
_add_series(plt.backend, plt, d)
|
||||||
else
|
else
|
||||||
# get a sub list of series for this linetype
|
# get a sub list of series for this linetype
|
||||||
try
|
series_list = try
|
||||||
series_list = RecipesBase.apply_recipe(Val{lt}, d[:x], d[:y], d[:z])
|
RecipesBase.apply_recipe(d, Val{lt}, d[:x], d[:y], d[:z])
|
||||||
catch
|
catch
|
||||||
warn("Exception during apply_recipe(Val{$lt}, ...) with types ($(typeof(d[:x])), $(typeof(d[:y])), $(typeof(d[:z])))")
|
warn("Exception during apply_recipe(Val{$lt}, ...) with types ($(typeof(d[:x])), $(typeof(d[:y])), $(typeof(d[:z])))")
|
||||||
rethrow()
|
rethrow()
|
||||||
@ -142,12 +145,25 @@ function _plot!(plt::Plot, d::KW, args...)
|
|||||||
next_series = pop!(still_to_process)
|
next_series = pop!(still_to_process)
|
||||||
series_list = RecipesBase.apply_recipe(next_series.d, next_series.args...)
|
series_list = RecipesBase.apply_recipe(next_series.d, next_series.args...)
|
||||||
for series in series_list
|
for series in series_list
|
||||||
|
# @show series
|
||||||
if isempty(series.args)
|
if isempty(series.args)
|
||||||
# finish processing and add to the kw_list
|
# finish processing and add to the kw_list
|
||||||
_add_markershape(series.d)
|
_add_markershape(series.d)
|
||||||
_filter_input_data!(series.d)
|
_filter_input_data!(series.d)
|
||||||
warnOnUnsupportedArgs(plt.backend, series.d)
|
warnOnUnsupportedArgs(plt.backend, series.d)
|
||||||
warnOnUnsupportedScales(plt.backend, series.d)
|
warnOnUnsupportedScales(plt.backend, series.d)
|
||||||
|
|
||||||
|
# TODO:
|
||||||
|
# # map functions to vectors
|
||||||
|
# if isa(d[:marker_z], Function)
|
||||||
|
# d[:marker_z] = map(d[:marker_z], d[:x])
|
||||||
|
# end
|
||||||
|
# # handle ribbons
|
||||||
|
# if get(d, :ribbon, nothing) != nothing
|
||||||
|
# rib = d[:ribbon]
|
||||||
|
# d[:fillrange] = (d[:y] - rib, d[:y] + rib)
|
||||||
|
# end
|
||||||
|
|
||||||
push!(kw_list, series.d)
|
push!(kw_list, series.d)
|
||||||
else
|
else
|
||||||
push!(still_to_process, series)
|
push!(still_to_process, series)
|
||||||
@ -229,7 +245,7 @@ function _plot!(plt::Plot, d::KW, args...)
|
|||||||
|
|
||||||
# todo: while the linetype is not supported, try to apply a recipe of f(Val{lt}, x,y,z) recursively
|
# todo: while the linetype is not supported, try to apply a recipe of f(Val{lt}, x,y,z) recursively
|
||||||
# the default should throw an error because we can't handle that linetype
|
# the default should throw an error because we can't handle that linetype
|
||||||
_apply_series_recipe(kw)
|
_apply_series_recipe(plt, kw)
|
||||||
|
|
||||||
|
|
||||||
# _add_series(plt.backend, plt, kw)
|
# _add_series(plt.backend, plt, kw)
|
||||||
|
|||||||
@ -204,28 +204,42 @@ end
|
|||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
"""
|
# """
|
||||||
`apply_series_recipe` should take a processed series KW dict and break it up
|
# `apply_series_recipe` should take a processed series KW dict and break it up
|
||||||
into component parts. For example, a box plot is made up of `shape` for the
|
# into component parts. For example, a box plot is made up of `shape` for the
|
||||||
boxes, `path` for the lines, and `scatter` for the outliers.
|
# boxes, `path` for the lines, and `scatter` for the outliers.
|
||||||
|
#
|
||||||
|
# Returns a Vector{KW}.
|
||||||
|
# """
|
||||||
|
# apply_series_recipe(d::KW, lt) = KW[d]
|
||||||
|
|
||||||
Returns a Vector{KW}.
|
|
||||||
"""
|
# for linetype `line`, need to sort by x values
|
||||||
apply_series_recipe(d::KW, lt) = KW[d]
|
@recipe function f(::Type{Val{:line}}, x, y, z)
|
||||||
|
# order by x
|
||||||
|
indices = sortperm(d[:x])
|
||||||
|
d[:x] = d[:x][indices]
|
||||||
|
d[:y] = d[:y][indices]
|
||||||
|
if typeof(d[:z]) <: AVec
|
||||||
|
d[:z] = d[:z][indices]
|
||||||
|
end
|
||||||
|
d[:linetype] = :path
|
||||||
|
()
|
||||||
|
end
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# Box Plot
|
# Box Plot
|
||||||
|
|
||||||
const _box_halfwidth = 0.4
|
const _box_halfwidth = 0.4
|
||||||
|
|
||||||
function apply_series_recipe(d::KW, ::Type{Val{:box}})
|
# function apply_series_recipe(d::KW, ::Type{Val{:box}})
|
||||||
|
@recipe function f(::Type{Val{:boxplot}}, x, y, z)
|
||||||
# dumpdict(d, "box before", true)
|
# dumpdict(d, "box before", true)
|
||||||
# TODO: add scatter series with outliers
|
# TODO: add scatter series with outliers
|
||||||
|
|
||||||
# create a list of shapes, where each shape is a single boxplot
|
# create a list of shapes, where each shape is a single boxplot
|
||||||
shapes = Shape[]
|
shapes = Shape[]
|
||||||
d[:linetype] = :shape
|
groupby = extractGroupArgs(x)
|
||||||
groupby = extractGroupArgs(d[:x])
|
|
||||||
|
|
||||||
for (i, glabel) in enumerate(groupby.groupLabels)
|
for (i, glabel) in enumerate(groupby.groupLabels)
|
||||||
|
|
||||||
@ -249,10 +263,16 @@ function apply_series_recipe(d::KW, ::Type{Val{:box}})
|
|||||||
push!(shapes, Shape(xcoords, ycoords))
|
push!(shapes, Shape(xcoords, ycoords))
|
||||||
end
|
end
|
||||||
|
|
||||||
d[:x], d[:y] = shape_coords(shapes)
|
# d[:plotarg_overrides] = KW(:xticks => (1:length(shapes), groupby.groupLabels))
|
||||||
d[:plotarg_overrides] = KW(:xticks => (1:length(shapes), groupby.groupLabels))
|
|
||||||
|
|
||||||
KW[d]
|
d[:linetype] = :shape
|
||||||
|
xticklabels --> groupby.groupLabels
|
||||||
|
|
||||||
|
# we want to set the fields directly inside series recipes... args are ignored
|
||||||
|
d[:x], d[:y] = shape_coords(shapes)
|
||||||
|
() # expects a tuple returned
|
||||||
|
|
||||||
|
# KW[d]
|
||||||
end
|
end
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
@ -260,17 +280,13 @@ end
|
|||||||
|
|
||||||
# if the user has KernelDensity installed, use this for violin plots.
|
# if the user has KernelDensity installed, use this for violin plots.
|
||||||
# otherwise, just use a histogram
|
# otherwise, just use a histogram
|
||||||
try
|
if is_installed("KernelDensity")
|
||||||
Pkg.installed("KernelDensity")
|
@eval import KernelDensity
|
||||||
import KernelDensity
|
|
||||||
|
|
||||||
# warn("using KD for violin")
|
|
||||||
@eval function violin_coords(y)
|
@eval function violin_coords(y)
|
||||||
kd = KernelDensity.kde(y, npoints = 30)
|
kd = KernelDensity.kde(y, npoints = 30)
|
||||||
kd.density, kd.x
|
kd.density, kd.x
|
||||||
end
|
end
|
||||||
catch
|
else
|
||||||
# warn("using hist for violin")
|
|
||||||
@eval function violin_coords(y)
|
@eval function violin_coords(y)
|
||||||
edges, widths = hist(y, 20)
|
edges, widths = hist(y, 20)
|
||||||
centers = 0.5 * (edges[1:end-1] + edges[2:end])
|
centers = 0.5 * (edges[1:end-1] + edges[2:end])
|
||||||
@ -280,13 +296,13 @@ catch
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function apply_series_recipe(d::KW, ::Type{Val{:violin}})
|
# function apply_series_recipe(d::KW, ::Type{Val{:violin}})
|
||||||
|
@recipe function f(::Type{Val{:violin}}, x, y, z)
|
||||||
# dumpdict(d, "box before", true)
|
# dumpdict(d, "box before", true)
|
||||||
# TODO: add scatter series with outliers
|
# TODO: add scatter series with outliers
|
||||||
|
|
||||||
# create a list of shapes, where each shape is a single boxplot
|
# create a list of shapes, where each shape is a single boxplot
|
||||||
shapes = Shape[]
|
shapes = Shape[]
|
||||||
d[:linetype] = :shape
|
|
||||||
groupby = extractGroupArgs(d[:x])
|
groupby = extractGroupArgs(d[:x])
|
||||||
|
|
||||||
for (i, glabel) in enumerate(groupby.groupLabels)
|
for (i, glabel) in enumerate(groupby.groupLabels)
|
||||||
@ -304,10 +320,14 @@ function apply_series_recipe(d::KW, ::Type{Val{:violin}})
|
|||||||
push!(shapes, Shape(xcoords, ycoords))
|
push!(shapes, Shape(xcoords, ycoords))
|
||||||
end
|
end
|
||||||
|
|
||||||
d[:x], d[:y] = shape_coords(shapes)
|
# d[:plotarg_overrides] = KW(:xticks => (1:length(shapes), groupby.groupLabels))
|
||||||
d[:plotarg_overrides] = KW(:xticks => (1:length(shapes), groupby.groupLabels))
|
d[:linetype] = :shape
|
||||||
|
xticklabels --> groupby.groupLabels
|
||||||
|
|
||||||
KW[d]
|
d[:x], d[:y] = shape_coords(shapes)
|
||||||
|
()
|
||||||
|
|
||||||
|
# KW[d]
|
||||||
end
|
end
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
@ -353,18 +373,22 @@ end
|
|||||||
|
|
||||||
# we will create a series of path segments, where each point represents one
|
# we will create a series of path segments, where each point represents one
|
||||||
# side of an errorbar
|
# side of an errorbar
|
||||||
function apply_series_recipe(d::KW, ::Type{Val{:yerror}})
|
# function apply_series_recipe(d::KW, ::Type{Val{:yerror}})
|
||||||
|
@recipe function f(::Type{Val{:yerror}}, x, y, z)
|
||||||
error_style!(d)
|
error_style!(d)
|
||||||
d[:markershape] = :hline
|
d[:markershape] = :hline
|
||||||
d[:x], d[:y] = error_coords(d[:x], d[:y], error_zipit(d[:yerror]))
|
d[:x], d[:y] = error_coords(d[:x], d[:y], error_zipit(d[:yerror]))
|
||||||
KW[d]
|
# KW[d]
|
||||||
|
()
|
||||||
end
|
end
|
||||||
|
|
||||||
function apply_series_recipe(d::KW, ::Type{Val{:xerror}})
|
# function apply_series_recipe(d::KW, ::Type{Val{:xerror}})
|
||||||
|
@recipe function f(::Type{Val{:xerror}}, x, y, z)
|
||||||
error_style!(d)
|
error_style!(d)
|
||||||
d[:markershape] = :vline
|
d[:markershape] = :vline
|
||||||
d[:y], d[:x] = error_coords(d[:y], d[:x], error_zipit(d[:xerror]))
|
d[:y], d[:x] = error_coords(d[:y], d[:x], error_zipit(d[:xerror]))
|
||||||
KW[d]
|
# KW[d]
|
||||||
|
()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
@ -407,7 +431,7 @@ function quiver_using_arrows(d::KW)
|
|||||||
end
|
end
|
||||||
|
|
||||||
d[:x], d[:y] = x, y
|
d[:x], d[:y] = x, y
|
||||||
KW[d]
|
# KW[d]
|
||||||
end
|
end
|
||||||
|
|
||||||
# function apply_series_recipe(d::KW, ::Type{Val{:quiver}})
|
# function apply_series_recipe(d::KW, ::Type{Val{:quiver}})
|
||||||
@ -453,15 +477,17 @@ function quiver_using_hack(d::KW)
|
|||||||
end
|
end
|
||||||
|
|
||||||
d[:x], d[:y] = Plots.unzip(pts[2:end])
|
d[:x], d[:y] = Plots.unzip(pts[2:end])
|
||||||
KW[d]
|
# KW[d]
|
||||||
end
|
end
|
||||||
|
|
||||||
function apply_series_recipe(d::KW, ::Type{Val{:quiver}})
|
# function apply_series_recipe(d::KW, ::Type{Val{:quiver}})
|
||||||
|
@recipe function f(::Type{Val{:quiver}}, x, y, z)
|
||||||
if :arrow in supportedArgs()
|
if :arrow in supportedArgs()
|
||||||
quiver_using_arrows(d)
|
quiver_using_arrows(d)
|
||||||
else
|
else
|
||||||
quiver_using_hack(d)
|
quiver_using_hack(d)
|
||||||
end
|
end
|
||||||
|
()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -77,7 +77,7 @@ function _add_defaults!(d::KW, plt::Plot, commandIndex::Int)
|
|||||||
end
|
end
|
||||||
d[:label] = label
|
d[:label] = label
|
||||||
|
|
||||||
warnOnUnsupported(pkg, d)
|
# warnOnUnsupported(pkg, d)
|
||||||
|
|
||||||
d
|
d
|
||||||
end
|
end
|
||||||
@ -329,8 +329,8 @@ end
|
|||||||
# end
|
# end
|
||||||
|
|
||||||
@recipe function f{X,Y}(x::AVec{X}, y::AVec{Y}, zf::Function)
|
@recipe function f{X,Y}(x::AVec{X}, y::AVec{Y}, zf::Function)
|
||||||
x = TX <: Number ? sort(x) : x
|
x = X <: Number ? sort(x) : x
|
||||||
y = TY <: Number ? sort(y) : y
|
y = Y <: Number ? sort(y) : y
|
||||||
SliceIt, x, y, Surface(zf, x, y) # TODO: replace with SurfaceFunction when supported
|
SliceIt, x, y, Surface(zf, x, y) # TODO: replace with SurfaceFunction when supported
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user