Skip to content

Commit

Permalink
add generic xdodge/ydodge keywords
Browse files Browse the repository at this point in the history
  • Loading branch information
jkrumbiegel committed Sep 13, 2024
1 parent f117480 commit a5e42c0
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 13 deletions.
22 changes: 17 additions & 5 deletions src/aesthetics.jl
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ function aesthetic_mapping(::Type{BarPlot}, N::Int)
1 => :direction => dictionary([
:y => AesY,
:x => AesX,
])
]),
]
else
[
Expand All @@ -105,7 +105,10 @@ function aesthetic_mapping(::Type{BarPlot}, N::Int)
:y => AesDeltaX,
:x => AesDeltaY,
]),
:dodge => AesDodge,
:dodge => :direction => dictionary([
:y => AesDodgeX,
:x => AesDodgeY,
]),
:stack => AesStack,
:fillto => :direction => dictionary([
:y => AesY,
Expand All @@ -127,7 +130,10 @@ function aesthetic_mapping(::Type{Violin}, ::Normal, ::Normal)
]),
:color => AesColor,
:side => AesViolinSide,
:dodge => AesDodge,
:dodge => :orientation => dictionary([
:horizontal => AesDodgeY,
:vertical => AesDodgeX,
]),
])
end

Expand Down Expand Up @@ -290,7 +296,10 @@ function aesthetic_mapping(::Type{BoxPlot}, ::Normal, ::Normal)
:vertical => AesY,
]),
:color => AesColor,
:dodge => AesDodge,
:dodge => :orientation => dictionary([
:horizontal => AesDodgeY,
:vertical => AesDodgeX,
]),
])
end

Expand All @@ -313,7 +322,10 @@ function aesthetic_mapping(::Type{CrossBar}, ::Normal, ::Normal, ::Normal, ::Nor
:vertical => AesY,
]),
:color => AesColor,
:dodge => AesDodge,
:dodge => :orientation => dictionary([
:horizontal => AesDodgeY,
:vertical => AesDodgeX,
]),
])
end

Expand Down
3 changes: 2 additions & 1 deletion src/algebra/layer.jl
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,8 @@ _default_categorical_palette(::Type{AesLineStyle}) = to_value(Makie.current_defa
_default_categorical_palette(::Type{AesLayout}) = wrap
_default_categorical_palette(::Type{<:Union{AesRow,AesCol}}) = Makie.automatic
_default_categorical_palette(::Type{AesGroup}) = Makie.automatic
_default_categorical_palette(::Type{AesDodge}) = Makie.automatic
_default_categorical_palette(::Type{AesDodgeX}) = Makie.automatic
_default_categorical_palette(::Type{AesDodgeY}) = Makie.automatic
_default_categorical_palette(::Type{AesStack}) = Makie.automatic
_default_categorical_palette(::Type{AesViolinSide}) = [:left, :right]

Expand Down
45 changes: 39 additions & 6 deletions src/algebra/layers.jl
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,8 @@ function hardcoded_mapping(key::Symbol)
key === :row ? AesRow :
key === :col ? AesCol :
key === :group ? AesGroup :
key === :xdodge ? AesDodgeX :
key === :ydodge ? AesDodgeY :
nothing
end

Expand Down Expand Up @@ -327,7 +329,7 @@ end
function to_entry(p::ProcessedLayer, categoricalscales::Dictionary, continuousscales::Dictionary)
entry = to_entry(p.plottype, p, categoricalscales, continuousscales)
insert!(entry.named, :cycle, nothing)
for key in (:group, :layout, :row, :col)
for key in (:group, :layout, :row, :col, :xdodge, :ydodge)
if haskey(entry.named, key)
delete!(entry.named, key)
end
Expand All @@ -346,7 +348,7 @@ function to_entry(P, p::ProcessedLayer, categoricalscales::Dictionary, continuou
full_rescale(value, key, aes_mapping, scale_mapping, categoricalscales, continuousscales)
end
primary = map(pairs(p.primary)) do (key, values)
if key in (:group, :layout, :col, :row)
if key in (:group, :layout, :col, :row, :xdodge, :ydodge)
return values
end
# seems that there can be vectors here for concatenated layers, but for unconcatenated these should
Expand All @@ -360,11 +362,25 @@ function to_entry(P, p::ProcessedLayer, categoricalscales::Dictionary, continuou
end
end

for dodge in (:xdodge, :ydodge)
dodge_aes = dodge === :xdodge ? AesDodgeX : AesDodgeY
axis_aes = dodge === :xdodge ? AesX : AesY
if haskey(primary, dodge)
positional = map(eachindex(positional)) do i
aes_mapping[i] == axis_aes || return positional[i]
return compute_dodge(positional[i], dodge, primary[dodge], scale_mapping, categoricalscales, dodge_aes)
end
named = map(pairs(named)) do (key, values)
aes_mapping[key] == axis_aes || return values
return compute_dodge(values, dodge, primary[dodge], scale_mapping, categoricalscales, dodge_aes)
end
end
end

Entry(P, positional, merge(p.attributes, named, primary))
end

function get_scale(key, aes_mapping, scale_mapping, categoricalscales, continuousscales)
aes = aes_mapping[key]
function get_scale(key, aes, scale_mapping, categoricalscales, continuousscales)
scale_id = get(scale_mapping, key, nothing)
scale = if haskey(categoricalscales, aes) && haskey(categoricalscales[aes], scale_id)
categoricalscales[aes][scale_id]
Expand All @@ -378,9 +394,11 @@ function get_scale(key, aes_mapping, scale_mapping, categoricalscales, continuou
end

function full_rescale(data, key, aes_mapping, scale_mapping, categoricalscales, continuousscales)
scale = get_scale(key, aes_mapping, scale_mapping, categoricalscales, continuousscales)
hc_aes = hardcoded_mapping(key)
aes = hc_aes === nothing ? aes_mapping[key] : hc_aes
scale = get_scale(key, aes, scale_mapping, categoricalscales, continuousscales)
scale === nothing && return data # verbatim data
full_rescale(data, aes_mapping[key], scale)
return full_rescale(data, aes, scale)
end

function default_colormap()
Expand Down Expand Up @@ -483,4 +501,19 @@ function Base.show(io::IO, layers::Layers; indent = 0)
for (i, layer) in enumerate(layers)
show(io, layer; indent = indent + 1, index = i)
end
end

function compute_dodge(data, key::Symbol, dodgevalues, scale_mapping, categoricalscales, dodge_aes)
scale_id = get(scale_mapping, key, nothing)
scale = categoricalscales[dodge_aes][scale_id]

indices = rescale(dodgevalues isa AbstractArray ? dodgevalues : [dodgevalues], scale)

props = scale.props.aesprops
n = length(datavalues(scale))
n == 1 && return data
width = props.width !== nothing ? props.width : 0.85
# scale to 0-1, center around 0, shrink to width (like centers of bins that added together result in width)
offsets = ((indices .- 1) ./ (n - 1) .- 0.5) .* width * (n-1) / n
return data .+ offsets
end
14 changes: 13 additions & 1 deletion src/scales.jl
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ struct AesGroup <: Aesthetic end
struct AesColor <: Aesthetic end
struct AesMarker <: Aesthetic end
struct AesMarkerSize <: Aesthetic end
struct AesDodge <: Aesthetic end
struct AesDodgeX <: Aesthetic end
struct AesDodgeY <: Aesthetic end
struct AesStack <: Aesthetic end
struct AesLineStyle <: Aesthetic end
struct AesText <: Aesthetic end
Expand Down Expand Up @@ -182,6 +183,17 @@ function CategoricalScaleProps(aestype::Type{<:Aesthetic}, props::Dictionary)
)
end

Base.@kwdef struct AesDodgeXCategoricalProps <: CategoricalAesProps
width::Union{Nothing,Float64} = nothing
end
Base.@kwdef struct AesDodgeYCategoricalProps <: CategoricalAesProps
width::Union{Nothing,Float64} = nothing
end

categorical_aes_props_type(::Type{AesDodgeX}) = AesDodgeXCategoricalProps
categorical_aes_props_type(::Type{AesDodgeY}) = AesDodgeYCategoricalProps


function CategoricalScale(aestype::Type{<:Aesthetic}, data, label::Union{AbstractString, Nothing}, props)
props_typed = CategoricalScaleProps(aestype, props)
return CategoricalScale(data, nothing, label, props_typed, aestype)
Expand Down

0 comments on commit a5e42c0

Please sign in to comment.