Skip to content

Commit

Permalink
fixes interactions between geom_bar and scale_fill
Browse files Browse the repository at this point in the history
  • Loading branch information
rdboyes committed Jan 7, 2025
1 parent e60bb6d commit fddf2b4
Show file tree
Hide file tree
Showing 8 changed files with 118 additions and 31 deletions.
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ KernelDensity = "0.6"
Loess = "0.6"
Makie = "0.21"
Reexport = "1.2"
TidierData = "0.15, 0.16, 0.17"
TidierData = "0.15, 0.16, 0.17, 0.18"
julia = "1.10"

[extras]
Expand Down
1 change: 1 addition & 0 deletions src/attributes.jl
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ const _makie_expected_type = Dict{String,Type}(
"color" => Colorant,
"strokecolor" => Colorant,
"dodge" => Integer,
"stack" => Integer,
);

# options that are not meant to go to Makie
Expand Down
36 changes: 24 additions & 12 deletions src/convert.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ try_convert(::Type{Any}, v, ::Any, ::Any) = v

function try_convert(T::Type, v::S, arg, fname) where {S}
try
retvalue = typeof(v) <: T ?
retvalue = typeof(v) <: T || T == Symbol ?
T(v) :
parse(T, v)
return retvalue
Expand All @@ -18,9 +18,11 @@ end
function convert_aes_df_types(aes_df::DataFrame, palette::Dict)
typed_df = DataFrame[]
for col in Symbol.(names(aes_df))
f = haskey(palette, col) ? palette[col] :
f = haskey(palette, col) ?
x -> convert_aes_type(palette[col](x),
get(_makie_expected_type, string(col), Any), col) :
x -> convert_aes_type(x,
get(_makie_expected_type, string(col), Any))
get(_makie_expected_type, string(col), Any), col)

push!(typed_df, DataFrame(col => f(aes_df[!, col])))
end
Expand All @@ -30,9 +32,11 @@ end
function get_unique_labels(aes_df::DataFrame, palette::Dict)
labels_df = DataFrame[]
for col in Symbol.(names(aes_df))
f = haskey(palette, col) ? palette[col] :
f = haskey(palette, col) ?
x -> convert_aes_type(palette[col](x),
get(_makie_expected_type, string(col), Any), col) :
x -> convert_aes_type(x,
get(_makie_expected_type, string(col), Any))
get(_makie_expected_type, string(col), Any), col)

push!(labels_df, DataFrame(
col_name=string(col),
Expand All @@ -48,36 +52,44 @@ end

# fallback methods - if there isn't a method defined, just do nothing

function convert_aes_type(aes_col::Any, ::Type{T}) where {T}
function convert_aes_type(aes_col::Any, ::Type{T}, col::Symbol) where {T}
verbose[] && println("No conversion for $col: $(typeof(aes_col))")
return aes_col
end

# aes_col is a Number

function convert_aes_type(aes_col::Vector{Number}, ::Type{Colorant})
function convert_aes_type(aes_col::Vector{Number}, ::Type{Colorant}, col::Symbol)
verbose[] && println("Converting $col to Colorant")
return _default_continuous_palette(aes_col)
end

function convert_aes_type(aes_col::Vector{Number}, ::Type{Integer})
function convert_aes_type(aes_col::Vector{Number}, ::Type{Integer}, col::Symbol) verbose[] && println("Converting $col to Integer")
return round.(aes_col)
end

# aes_col is a String

function convert_aes_type(aes_col::Vector{AbstractString}, ::Type{Colorant})
function convert_aes_type(aes_col::AbstractVector{T}, ::Type{Colorant}, col::Symbol) where
{T <: AbstractString}
verbose[] && println("Converting $col to Colorant")
return _default_discrete_palette(aes_col)
end

function convert_aes_type(aes_col::Vector{AbstractString}, ::Type{Integer})
function convert_aes_type(aes_col::AbstractVector{T}, ::Type{Integer}, col::Symbol) where
{T <: AbstractString}
verbose[] && println("Converting $col to Integer")
return levelcode.(CategoricalArray(aes_col))
end

# aes_col is a CategoricalArray

function convert_aes_type(aes_col::CategoricalArray, ::Type{Colorant})
function convert_aes_type(aes_col::CategoricalArray, ::Type{Colorant}, col::Symbol)
verbose[] && println("Converting $col to Colorant")
return _default_discrete_palette(aes_col)
end

function convert_aes_type(aes_col::CategoricalArray, ::Type{Integer})
function convert_aes_type(aes_col::CategoricalArray, ::Type{Integer}, col::Symbol)
verbose[] && println("Converting $col to Integer")
return levelcode.(aes_col)
end
47 changes: 30 additions & 17 deletions src/draw.jl
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ function as_GridLayout(plot::GGPlot)
element=Any[],
title=String[])

legend_title = " "

ymin = Inf
xmin = Inf
xmax = -Inf
Expand Down Expand Up @@ -59,15 +61,17 @@ function as_GridLayout(plot::GGPlot)
end

verbose[] && println("Translated aes dict:")
verbose[] && println(aes_dict)
verbose[] && println(aes_dict_makie)

# build a new dataframe with column names equal to the required aesthetics
# this dataframe will take data from plot_data according to the rules outlined in the aes object
aes_df_list = DataFrame[]

for (aes, rule) in aes_dict_makie
println(aes)
# aes is a symbol, the target column name
# rule is a pair, the source columns and function to apply
println(plot_data)
push!(aes_df_list, select(plot_data, rule[1] => rule[2] => aes))
end

Expand Down Expand Up @@ -154,6 +158,9 @@ function as_GridLayout(plot::GGPlot)

# convert all aes columns to the format expected by makie

println(plot_palette)
println(aes_df)

typed_aes_df = convert_aes_df_types(aes_df, plot_palette)
labels_aes_df = get_unique_labels(aes_df, plot_palette)

Expand Down Expand Up @@ -231,22 +238,15 @@ function as_GridLayout(plot::GGPlot)
labels_for_this_aes = subset(labels_aes_df,
:col_name => ByRow(x -> x == a))

if plot.legend_options[:color][:type] in
["manual", "discrete"]

append!(legend,
sort(DataFrame(
labels=labels_for_this_aes.original_value,
colors=labels_for_this_aes.new_value,
options=_legend_geom_symbols[geom.args["geom_name"]],
element=_legend_geom_elements[geom.args["geom_name"]],
title=get(plot.legend_options[:color], :name, titlecase(string(:color)))
),
:labels)
)
if haskey(plot.legend_options, :color)
draw_colorbar = get(plot.legend_options[:color], :type, "na")
legend_title = get(plot.legend_options[:color], :name, " ")
else
draw_colorbar = "na"
legend_title = " "
end
if plot.legend_options[:color][:type] in
["continuous", "binned"]

if draw_colorbar in ["continuous", "binned"]

colorbar_kwargs[:colormap] =
plot.legend_options[:color][:type] == "continuous" ? Symbol(plot.legend_options[:color][:palette]) :
Expand All @@ -259,6 +259,17 @@ function as_GridLayout(plot::GGPlot)
maximum(labels_for_this_aes.original_value), colorbar_highlim)

colorbar = true
else
append!(legend,
sort(DataFrame(
labels=labels_for_this_aes.original_value,
colors=labels_for_this_aes.new_value,
options=_legend_geom_symbols[geom.args["geom_name"]],
element=_legend_geom_elements[geom.args["geom_name"]],
title=legend_title
),
:labels)
)
end

end
Expand Down Expand Up @@ -319,7 +330,9 @@ function as_GridLayout(plot::GGPlot)
labels = String[]
elems = Any[]

title = get(plot.legend_options[:color], :name, " ")
title = legend_title

legend = subset(legend, :colors => ByRow(x -> typeof(x) <: Colorant))

for (k, v) in pairs(groupby(legend, :labels))
push!(elems, [l.element(color=l.colors; l.options...) for l in eachrow(v)])
Expand Down
11 changes: 10 additions & 1 deletion src/geoms/geom_bar.jl
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ function handle_position(aes_dict::Dict{Symbol,Pair},
elseif haskey(aes_dict, :color)
aes_dict[:dodge] = aes_dict[:color]
split_var = aes_dict[:dodge][1]
elseif haskey(aes_dict, :fill)
aes_dict[:dodge] = aes_dict[:fill]
split_var = aes_dict[:dodge][1]
end
elseif args_dict["position"] != "none"
if haskey(aes_dict, :group)
Expand All @@ -26,6 +29,9 @@ function handle_position(aes_dict::Dict{Symbol,Pair},
elseif haskey(aes_dict, :color)
aes_dict[:stack] = aes_dict[:color]
split_var = aes_dict[:stack][1]
elseif haskey(aes_dict, :fill)
aes_dict[:stack] = aes_dict[:fill]
split_var = aes_dict[:stack][1]
end
end
else
Expand All @@ -38,6 +44,9 @@ function handle_position(aes_dict::Dict{Symbol,Pair},
elseif haskey(aes_dict, :color)
aes_dict[:stack] = aes_dict[:color]
split_var = aes_dict[:stack][1]
elseif haskey(aes_dict, :fill)
aes_dict[:stack] = aes_dict[:fill]
split_var = aes_dict[:stack][1]
end
end

Expand All @@ -58,7 +67,7 @@ function handle_position(aes_dict::Dict{Symbol,Pair},

if !isnothing(split_var)
plot_data = @chain plot_data begin
groupby([grouping_var, split_var])
groupby([grouping_var; split_var])
@summarize(count = n())
@ungroup
end
Expand Down
1 change: 1 addition & 0 deletions test/Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ Images = "916415d5-f1e6-5110-898d-aaa5f9f070e0"
KernelDensity = "5ab0869b-81aa-558d-bb23-cbf5423bbe9b"
Loess = "4345ca2d-374a-55d4-8d30-97f9976e7612"
Makie = "ee78f7c6-11fb-53f2-987a-cfe4a2b5a57a"
PalmerPenguins = "8b842266-38fa-440a-9b57-31493939ab85"
Parquet2 = "98572fba-bba0-415d-956f-fa77e587d26d"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
TidierData = "fe2206b3-d496-4ee9-a338-6a095c4ece80"
Expand Down
1 change: 1 addition & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,5 @@ set_theme!(theme_ggplot2())
include("test_lims.jl")
include("test_patchwork.jl")
include("test_scale_colour.jl")
include("test_docs_will_render.jl")
end
50 changes: 50 additions & 0 deletions test/test_docs_will_render.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
@testset "docs-render" begin
@testset "geom_bar" begin
include("../docs/examples/geoms/geom_bar.jl")
@test true
end
@testset "geom_boxplot" begin
include("../docs/examples/geoms/geom_boxplot.jl")
@test true
end
@testset "geom_density" begin
include("../docs/examples/geoms/geom_density.jl")
@test true
end
@testset "geom_errorbar" begin
include("../docs/examples/geoms/geom_errorbars.jl")
@test true
end
@testset "geom_hist" begin
include("../docs/examples/geoms/geom_hist.jl")
@test true
end
@testset "geom_hvlines" begin
include("../docs/examples/geoms/geom_hvlines.jl")
@test true
end
@testset "geom_lines" begin
include("../docs/examples/geoms/geom_lines.jl")
@test true
end
@testset "geom_point" begin
include("../docs/examples/geoms/geom_point.jl")
@test true
end
@testset "geom_smooth" begin
include("../docs/examples/geoms/geom_smooth.jl")
@test true
end
@testset "geom_text" begin
include("../docs/examples/geoms/geom_text.jl")
@test true
end
@testset "geom_tile" begin
include("../docs/examples/geoms/geom_violin.jl")
@test true
end
@testset "geom_violin" begin
include("../docs/examples/geoms/geom_violin.jl")
@test true
end
end

0 comments on commit fddf2b4

Please sign in to comment.