Skip to content

Commit

Permalink
stat_dodge
Browse files Browse the repository at this point in the history
  • Loading branch information
Mattriks committed Jan 8, 2019
1 parent aa8dff9 commit 0fd42b6
Show file tree
Hide file tree
Showing 6 changed files with 150 additions and 2 deletions.
30 changes: 30 additions & 0 deletions docs/src/gallery/geometries.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,36 @@ hstack(p1, p2a, p2b)

See [`Scale.color_discrete_manual`](@ref) for more information.

## [`Geom.barerror`](@ref)

```@example
using Compose, DataFrames, Gadfly, RDatasets, Statistics
set_default_plot_size(21cm, 8cm)
salaries = dataset("car","Salaries")
salaries.Salary /= 1000.0
salaries.Discipline = ["Discipline $(x)" for x in salaries.Discipline]
df = by(salaries, [:Rank,:Discipline], :Salary=>mean, :Salary=>std)
[df[i] = df.Salary_mean.+j*df.Salary_std for (i,j) in zip([:ymin, :ymax], [-1, 1.0])]
df[:label] = string.(round.(Int, df.Salary_mean))
p1 = plot(df, x=:Discipline, y=:Salary_mean, color=:Rank,
Scale.x_discrete(levels=["Discipline A", "Discipline B"]),
ymin=:ymin, ymax=:ymax, Geom.barerror,
Geom.bar(position=:dodge),
Scale.color_discrete(levels=["Prof", "AssocProf", "AsstProf"]),
Guide.colorkey(title="", pos=[0.76w, -0.38h]),
Theme(bar_spacing=0mm, stroke_color=c->"black")
)
p2 = plot(df, y=:Discipline, x=:Salary_mean, color=:Rank,
Coord.cartesian(yflip=true), Scale.y_discrete,
xmin=:ymin, xmax=:ymax, Geom.barerror(axis=:y),
Geom.bar(position=:dodge, orientation=:horizontal),
Scale.color_discrete(levels=["Prof", "AssocProf", "AsstProf"]),
Guide.yticks(orientation=:vertical), Guide.ylabel(nothing),
Theme(bar_spacing=0mm, stroke_color=c->"gray")
)
hstack(p1,p2)
```

## [`Geom.beeswarm`](@ref)

Expand Down
27 changes: 27 additions & 0 deletions docs/src/gallery/statistics.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,33 @@ p2 = plot(vcat(Db...), x=:x, color=:u,
hstack(p1,p2)
```

## [`Stat.dodge`](@ref)

```@example
using DataFrames, Gadfly, RDatasets, Statistics
set_default_plot_size(21cm, 8cm)
salaries = dataset("car","Salaries")
salaries.Salary /= 1000.0
salaries.Discipline = ["Discipline $(x)" for x in salaries.Discipline]
df = by(salaries, [:Rank,:Discipline], :Salary=>mean, :Salary=>std)
[df[i] = df.Salary_mean.+j*df.Salary_std for (i,j) in zip([:ymin, :ymax], [-1, 1.0])]
df[:label] = string.(round.(Int, df.Salary_mean))
p1 = plot(df, x=:Discipline, y=:Salary_mean, color=:Rank,
Scale.x_discrete(levels=["Discipline A", "Discipline B"]),
label=:label, Geom.label(position=:centered), Stat.dodge(position=:stack),
Geom.bar(position=:stack)
)
p2 = plot(df, y=:Discipline, x=:Salary_mean, color=:Rank,
Coord.cartesian(yflip=true), Scale.y_discrete,
label=:label, Geom.label(position=:right), Stat.dodge(axis=:y),
Geom.bar(position=:dodge, orientation=:horizontal),
Scale.color_discrete(levels=["Prof", "AssocProf", "AsstProf"]),
Guide.yticks(orientation=:vertical), Guide.ylabel(nothing)
)
hstack(p1, p2)
```

## [`Stat.qq`](@ref)

```@example
Expand Down
2 changes: 1 addition & 1 deletion src/geom/bar.jl
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ function render_dodged_bar(geom::BarGeometry,
orientation::Symbol)
# preserve factor orders of pooled data arrays
if isa(aes.color, IndirectArray)
idxs = sortperm(aes.color.index, rev=true)
idxs = sortperm(aes.color.index, rev=false)
else
idxs = 1:length(aes.color)
end
Expand Down
17 changes: 16 additions & 1 deletion src/geom/errorbar.jl
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
struct ErrorBarGeometry <: Gadfly.GeometryElement
default_statistic::Gadfly.StatisticElement
tag::Symbol
end
ErrorBarGeometry(; tag=empty_tag) = ErrorBarGeometry(tag)
ErrorBarGeometry(default_statistic=Gadfly.Stat.identity(); tag=empty_tag) =
ErrorBarGeometry(default_statistic, tag)


struct XErrorBarGeometry <: Gadfly.GeometryElement
Expand Down Expand Up @@ -42,9 +44,22 @@ color them with `color`.
"""
const yerrorbar = YErrorBarGeometry


"""
Geom.barerror(;position=:dodge, axis=:x)
Draw barplot errorbars at `xmin` to `xmax` or `ymin` to `ymax`. Optionally color them with `color`.
Particularly for use with dodged bar plots. This geometry is equivalent to [`Geom.errorbar`](@ref) with [`Stat.dodge`](@ref).
See the latter for more information.
"""
barerror(; position::Symbol=:dodge, axis::Symbol=:x) = ErrorBarGeometry(Stat.dodge(position=position, axis=axis))


element_aesthetics(::ErrorBarGeometry) = [:x, :y, :xmin, :xmax, :ymin, :ymax]
element_aesthetics(::XErrorBarGeometry) = [:y, :xmin, :xmax]
element_aesthetics(::YErrorBarGeometry) = [:x, :ymin, :ymax]
default_statistic(geom::ErrorBarGeometry) = geom.default_statistic


# Generate a form for the errorbar geometry.
#
Expand Down
51 changes: 51 additions & 0 deletions src/statistics.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2019,6 +2019,57 @@ function apply_statistic(stat::EllipseStatistic,
aes.y = ellipse_y
linestyle_scale = get(scales, :linestyle, Scale.linestyle_discrete())
Scale.apply_scale(linestyle_scale, [aes], Gadfly.Data(linestyle = aes.linestyle))
end


struct DodgeStatistic <: Gadfly.StatisticElement
position::Symbol
axis::Symbol
end
DodgeStatistic(; position::Symbol=:dodge, axis::Symbol=:x) = DodgeStatistic(position, axis)

input_aesthetics(stat::DodgeStatistic) = [:x, :y]
output_aesthetics(stat::DodgeStatistic) = [:x, :y]
default_scales(stat::DodgeStatistic) = [Gadfly.Scale.x_continuous(), Gadfly.Scale.y_continuous()]

"""
Stat.dodge[(; position=:dodge, axis=:x)]
Transform the points in $(aes2str(input_aesthetics(dodge()))) into set of dodged or stacked points
in $(aes2str(output_aesthetics(dodge()))). `position` is `:dodge` or `:stack`.
`axis` is `:x` or `:y`. Used by [`Geom.barerror`](@ref Gadfly.Geom.barerror).
"""
const dodge = DodgeStatistic


function apply_statistic(stat::DodgeStatistic,
scales::Dict{Symbol, Gadfly.ScaleElement},
coord::Gadfly.CoordinateElement,
aes::Gadfly.Aesthetics)

othervar = (stat.axis == :x) ? :y : :x
vals = getfield(aes, stat.axis)
nbars = length(unique(aes.color))

if stat.position==:dodge
offset = range(-0.5+0.5/nbars, 0.5, step=1/nbars)
dodge = getindex(offset, aes.color.index)
setfield!(aes, stat.axis, vals.+dodge)
elseif stat.position==:stack
ovals = getfield(aes, othervar)
idxs = isa(aes.color, IndirectArray) ? sortperm(aes.color.index, rev=true) : 1:length(aes.color)
idxs2 = sortperm(idxs)
m1 = reshape(idxs, :, nbars)
m2 = cumsum(ovals[m1], dims=2) .- 0.5*ovals[m1]
setfield!(aes, othervar, m2[idxs2])
else
error("position can be :dodge (default) or :stack")
end
end






end # module Stat
25 changes: 25 additions & 0 deletions test/testscripts/stat_dodge.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using Compose, DataFrames, Gadfly, RDatasets, Statistics
set_default_plot_size(21cm, 8cm)

salaries = dataset("car","Salaries")
salaries.Salary /= 1000.0
salaries.Discipline = ["Discipline $(x)" for x in salaries.Discipline]
df = by(salaries, [:Rank,:Discipline], :Salary=>mean, :Salary=>std)
[df[i] = df.Salary_mean.+j*df.Salary_std for (i,j) in zip([:ymin, :ymax], [-1, 1.0])]
df[:label] = string.(round.(Int, df.Salary_mean))

p1 = plot(df, x=:Discipline, y=:Salary_mean, color=:Rank,
Scale.x_discrete(levels=["Discipline A", "Discipline B"]),
ymin=:ymin, ymax=:ymax, Geom.barerror,
Geom.bar(position=:dodge),
Scale.color_discrete(levels=["Prof", "AssocProf", "AsstProf"]),
Guide.colorkey(title="", pos=[0.76w, -0.38h]),
Theme(bar_spacing=0mm, stroke_color=c->"black")
)
p2 = plot(df, x=:Salary_mean, y=:Discipline, color=:Rank,
Scale.y_discrete(levels=["Discipline A", "Discipline B"]),
label=:label, Geom.label(position=:centered), Stat.dodge(position=:stack, axis=:y),
Geom.bar(position=:stack, orientation=:horizontal),
Guide.yticks(orientation=:vertical), Guide.ylabel(nothing)
)
hstack(p1, p2)

0 comments on commit 0fd42b6

Please sign in to comment.