added violin plot

This commit is contained in:
Thomas Breloff 2016-04-07 17:05:31 -04:00
parent f3f29fb54f
commit fdf3b3f581
4 changed files with 62 additions and 4 deletions

View File

@ -68,6 +68,8 @@ export
abline!,
boxplot,
boxplot!,
violin,
violin!,
title!,
xlabel!,
@ -192,6 +194,8 @@ 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 = :box)
violin(args...; kw...) = plot(args...; kw..., linetype = :violin)
violin!(args...; kw...) = plot!(args...; kw..., linetype = :violin)
title!(s::AbstractString; kw...) = plot!(; title = s, kw...)

View File

@ -11,7 +11,7 @@ const _3dTypes = [:path3d, :scatter3d, :surface, :wireframe]
const _allTypes = vcat([
:none, :line, :path, :steppre, :steppost, :sticks, :scatter,
:heatmap, :hexbin, :hist, :hist2d, :hist3d, :density, :bar, :hline, :vline, :ohlc,
:contour, :pie, :shape, :box
:contour, :pie, :shape, :box, :violin
], _3dTypes)
@compat const _typeAliases = KW(
:n => :none,

View File

@ -80,7 +80,7 @@ supportedArgs(::GadflyBackend) = [
]
supportedAxes(::GadflyBackend) = [:auto, :left]
supportedTypes(::GadflyBackend) = [:none, :line, :path, :steppre, :steppost, :sticks,
:scatter, :hist2d, :hexbin, :hist, :bar, :box,
:scatter, :hist2d, :hexbin, :hist, :bar, :box, :violin,
:hline, :vline, :contour, :shape]
supportedStyles(::GadflyBackend) = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
supportedMarkers(::GadflyBackend) = vcat(_allMarkers, Shape)
@ -167,7 +167,7 @@ supportedArgs(::PyPlotBackend) = [
]
supportedAxes(::PyPlotBackend) = _allAxes
supportedTypes(::PyPlotBackend) = [:none, :line, :path, :steppre, :steppost, #:sticks,
:scatter, :hist2d, :hexbin, :hist, :density, :bar, :box,
:scatter, :hist2d, :hexbin, :hist, :density, :bar, :box, :violin,
:hline, :vline, :contour, :path3d, :scatter3d, :surface, :wireframe, :heatmap]
supportedStyles(::PyPlotBackend) = [:auto, :solid, :dash, :dot, :dashdot]
# supportedMarkers(::PyPlotBackend) = [:none, :auto, :rect, :ellipse, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5, :hexagon]

View File

@ -43,6 +43,8 @@ apply_series_recipe(d::KW, lt) = KW[d]
# -------------------------------------------------
# Box Plot
const _box_halfwidth = 0.4
function apply_series_recipe(d::KW, ::Type{Val{:box}})
# dumpdict(d, "box before", true)
# TODO: add scatter series with outliers
@ -58,7 +60,7 @@ function apply_series_recipe(d::KW, ::Type{Val{:box}})
q1,q2,q3,q4,q5 = quantile(d[:y][groupby.groupIds[i]], linspace(0,1,5))
# make the shape
l, m, r = i - 0.3, i, i + 0.3
l, m, r = i - _box_halfwidth, i, i + _box_halfwidth
xcoords = [
m, l, r, m, m, NaN, # lower T
l, l, r, r, l, NaN, # lower box
@ -80,6 +82,58 @@ function apply_series_recipe(d::KW, ::Type{Val{:box}})
KW[d]
end
# -------------------------------------------------
# Violin Plot
try
Pkg.installed("KernelDensity")
import KernelDensity
warn("using KD for violin")
function violin_coords(y)
kd = KernelDensity.kde(y, npoints = 30)
kd.density, kd.x
end
catch
warn("using hist for violin")
function violin_coords(y)
edges, widths = hist(y, 20)
centers = 0.5 * (edges[1:end-1] + edges[2:end])
ymin, ymax = extrema(y)
vcat(0.0, widths, 0.0), vcat(ymin, centers, ymax)
end
end
function apply_series_recipe(d::KW, ::Type{Val{:violin}})
# dumpdict(d, "box before", true)
# TODO: add scatter series with outliers
# create a list of shapes, where each shape is a single boxplot
shapes = Shape[]
d[:linetype] = :shape
groupby = extractGroupArgs(d[:x])
for (i, glabel) in enumerate(groupby.groupLabels)
# get the edges and widths
y = d[:y][groupby.groupIds[i]]
widths, centers = violin_coords(y)
# normalize
widths = _box_halfwidth * widths / maximum(widths)
# make the violin
xcoords = vcat(widths, -reverse(widths)) + i
ycoords = vcat(centers, reverse(centers))
push!(shapes, Shape(xcoords, ycoords))
end
d[:x], d[:y] = shape_coords(shapes)
d[:plotarg_overrides] = KW(:xticks => (1:length(shapes), groupby.groupLabels))
KW[d]
end
# -------------------------------------------------