Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Apply recipes to keyword arguments #4453

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions RecipesPipeline/src/type_recipe.jl
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ function _apply_type_recipe(plotattributes, v, letter)
rdvec = RecipesBase.apply_recipe(plotattributes, typeof(v), v)
warn_on_recipe_aliases!(plotattributes[:plot_object], plotattributes, :type, v)
postprocess_axis_args!(plt, plotattributes, letter)
isnothing(rdvec) && return nothing
return rdvec[1].args[1]
end

Expand Down
38 changes: 25 additions & 13 deletions src/axes.jl
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ end
function attr!(axis::Axis, args...; kw...)
# first process args
plotattributes = axis.plotattributes
dummy_attributes = Dict{Symbol, Any}(:plot_object=>first(axis.sps).plt)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What are those needed for?

Copy link
Collaborator Author

@gustaphe gustaphe Oct 12, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question. RecipesPipeline._apply_type_recipe has

function _apply_type_recipe(plotattributes, v, letter)
plt = plotattributes[:plot_object]
preprocess_axis_args!(plt, plotattributes, letter)
rdvec = RecipesBase.apply_recipe(plotattributes, typeof(v), v)
warn_on_recipe_aliases!(plotattributes[:plot_object], plotattributes, :type, v)
postprocess_axis_args!(plt, plotattributes, letter)
return rdvec[1].args[1]
end

where it asks the first argument for :plot_object, which it then uses for pre- and postprocessing. Perhaps the function should instead be extended to accept an Axis object instead or something, this just seemed like the minimum intrusion operation to me.

for arg in args
process_axis_arg!(plotattributes, arg)
end
Expand All @@ -96,12 +97,6 @@ function attr!(axis::Axis, args...; kw...)
for vi in v
discrete_value!(axis, vi)
end
#could perhaps use TimeType here, as Date and DateTime are both subtypes of TimeType
# or could perhaps check if dateformatter or datetimeformatter is in use
elseif k === :lims && isa(v, Tuple{Date,Date})
plotattributes[k] = (v[1].instant.periods.value, v[2].instant.periods.value)
elseif k === :lims && isa(v, Tuple{DateTime,DateTime})
plotattributes[k] = (v[1].instant.periods.value, v[2].instant.periods.value)
else
plotattributes[k] = v
end
Expand Down Expand Up @@ -335,8 +330,14 @@ get_ticks(ticks::Bool, args...) =
get_ticks(::T, args...) where {T} = error("Unknown ticks type in get_ticks: $T")

_transform_ticks(ticks, axis) = ticks
_transform_ticks(ticks::AbstractArray{T}, axis) where {T<:Dates.TimeType} =
Dates.value.(ticks)
function _transform_ticks(ticks::AbstractArray, axis)
dummy_attributes = Dict{Symbol, Any}(:plot_object=>first(axis.sps).plt)
return RecipesPipeline._apply_type_recipe(
Dict{Symbol, Any}(:plot_object=>first(axis.sps).plt),
ticks,
axis[:letter]
)
end
_transform_ticks(ticks::NTuple{2,Any}, axis) = (_transform_ticks(ticks[1], axis), ticks[2])

function get_minor_ticks(sp, axis, ticks)
Expand Down Expand Up @@ -542,7 +543,7 @@ end
scale_lims!([plt], [letter], factor)

Scale the limits of the axis specified by `letter` (one of `:x`, `:y`, `:z`) by the
given `factor` around the limits' middle point.
given `factor` around the limits' middle point.
If `letter` is omitted, all axes are affected.
"""
function scale_lims!(sp::Subplot, letter, factor)
Expand Down Expand Up @@ -623,11 +624,22 @@ function round_limits(amin, amax, scale)
amin, amax
end

process_limits(lims::Tuple{<:Union{Symbol,Real},<:Union{Symbol,Real}}, axis) = lims
#process_limits(lims::Tuple{<:Union{Symbol,Real},<:Union{Symbol,Real}}, axis) = lims
process_limits(lims::Symbol, axis) = lims
process_limits(lims::AVec, axis) =
length(lims) == 2 && all(map(x -> x isa Union{Symbol,Real}, lims)) ? Tuple(lims) :
nothing
process_limits(lims::Tuple, axis) = process_limits([lims...], axis)
function process_limits(lims::AVec, axis)
lims = RecipesPipeline._apply_type_recipe(
Dict{Symbol, Any}(:plot_object=>first(axis.sps).plt),
lims,
axis[:letter]
)
if lims isa Formatted
lims = lims.data
end
length(lims) == 2 || return nothing
all(x -> x isa Union{Symbol, Real}, lims) || return nothing
return Tuple(lims)
end
process_limits(lims, axis) = nothing

warn_invalid_limits(lims, letter) = @warn """
Expand Down
12 changes: 1 addition & 11 deletions src/unitful.jl
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ using ..RecipesBase
export @P_str

import ..locate_annotation,
..PlotText, ..Subplot, ..AVec, ..AMat, ..Axis, .._transform_ticks, ..process_limits
..PlotText, ..Subplot, ..AVec, ..AMat, ..Axis

const MissingOrQuantity = Union{Missing,<:Quantity}

Expand Down Expand Up @@ -291,14 +291,4 @@ locate_annotation(
locate_annotation(sp::Subplot, rel::NTuple{N,<:MissingOrQuantity}, label) where {N} =
locate_annotation(sp, ustrip.(rel), label)

#==================#
# ticks and limits #
#==================#
_transform_ticks(ticks::AbstractArray{T}, axis) where {T<:Quantity} =
ustrip.(getaxisunit(axis), ticks)
process_limits(lims::AbstractArray{T}, axis) where {T<:Quantity} =
ustrip.(getaxisunit(axis), lims)
process_limits(lims::Tuple{S,T}, axis) where {S<:Quantity,T<:Quantity} =
ustrip.(getaxisunit(axis), lims)

end
9 changes: 5 additions & 4 deletions test/test_dates.jl
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,20 @@ end
@testset "Date xlims" begin
y = [1.0 * i * i for i in 1:10]
x = [Date(2019, 11, i) for i in 1:10]
span = (Date(2019, 10, 31), Date(2019, 11, 11))
span = [Date(2019, 10, 31), Date(2019, 11, 11)]

ref_xlims = map(date -> date.instant.periods.value, span)
ref_xlims = Tuple(map(date -> date.instant.periods.value, span))

pl = plot(x, y, xlims = span, widen = false)
@test Plots.xlims(pl) == ref_xlims
end

@testset "DateTime xlims" begin
y = [1.0 * i * i for i in 1:10]
x = [DateTime(2019, 11, i, 11) for i in 1:10]
span = (DateTime(2019, 10, 31, 11, 59, 59), DateTime(2019, 11, 11, 12, 01, 15))
span = [DateTime(2019, 10, 31, 11, 59, 59), DateTime(2019, 11, 11, 12, 01, 15)]

ref_xlims = map(date -> date.instant.periods.value, span)
ref_xlims = Tuple(map(date -> date.instant.periods.value, span))

pl = plot(x, y, xlims = span, widen = false)
@test Plots.xlims(pl) == ref_xlims
Expand Down
12 changes: 12 additions & 0 deletions test/test_recipes.jl
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,15 @@ end
@test p[1][2][:linestyle] == :dash
@test p[1][3][:linestyle] == :dot
end

@testset "lims and ticks" begin
struct DoubleNumber
x
end
@recipe f(::Type{T}, v::T) where {T<:AbstractArray{DoubleNumber}} = [2*x.x for x in v]

p = plot(1:3; ylims=DoubleNumber.([0.5, 2.0]), yticks=DoubleNumber.([0.4, 0.8, 1.2]))
@test ylims(p) == (1.0, 4.0)
@test first(first(yticks(p))) == [1.6, 2.4]
end

19 changes: 9 additions & 10 deletions test/test_unitful.jl
Original file line number Diff line number Diff line change
Expand Up @@ -59,15 +59,14 @@ end
@testset "yticks" begin
compare_yticks(pl, expected_ticks) = all(first(first(yticks(pl))) .≈ expected_ticks)
encompassing_ylims = (-1m, 6m)
@test compare_yticks(plot(y; ylims = encompassing_ylims, yticks = (1:5)m), 1:5)
@test compare_yticks(
plot(y; ylims = encompassing_ylims, yticks = [1cm, 3cm]),
[0.01, 0.03],
)
@test compare_yticks(
plot!(; ylims = encompassing_ylims, yticks = [-1cm, 4cm]),
[-0.01, 0.04],
)
pl = plot(y; ylims = encompassing_ylims, yticks = (1:5)m)
@test compare_yticks(pl, 1:5)
pl = plot(y; ylims = encompassing_ylims, yticks = [1cm, 3cm])
savefig(pl, testfile)
@test compare_yticks(pl, [0.01, 0.03])
pl = plot!(; ylims = encompassing_ylims, yticks = [-1cm, 4cm])
savefig(pl, testfile)
@test compare_yticks(pl, [-0.01, 0.04])
@test_throws DimensionError begin
pl = plot(y)
plot!(pl; yticks = (1:5)s)
Expand Down Expand Up @@ -190,7 +189,7 @@ end
@test plot(x * m, ylims = (-1, 1)) isa Plot
@test plot(x * m, ylims = (-1, 1) .* m) isa Plot
@test plot(x * m, yunit = u"km") isa Plot
@test plot(x * m, xticks = (1:3) * m) isa Plot
@test plot(x * m, yticks = (1:3) * m) isa Plot
end

@testset "Two arrays" begin
Expand Down