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

Plotting functions with more general arrays #78

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
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
41 changes: 32 additions & 9 deletions src/UnitfulRecipes.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,17 @@ export @P_str

const clims_types = (:contour, :contourf, :heatmap, :surface)

const UMQ = Union{Missing, <:Quantity}
const AVec = AbstractVector
const AArr = AbstractArray
const AArrArrQ = AArr{<:AArr{<:UMQ}}
const AMat{T} = AArr{T,2} where T

#==========
Main recipe
==========#

@recipe function f(::Type{T}, x::T) where T <: AbstractArray{<:Union{Missing,<:Quantity}}
@recipe function f(::Type{T}, x::T) where T <: AArr{<:UMQ}
axisletter = plotattributes[:letter] # x, y, or z
if (axisletter == :z) &&
get(plotattributes, :seriestype, :nothing) ∈ clims_types
Expand Down Expand Up @@ -59,8 +65,6 @@ function fixaxis!(attr, x, axisletter)
end

# Recipe for (x::AVec, y::AVec, z::Surface) types
const AVec = AbstractVector
const AMat{T} = AbstractArray{T,2} where T
@recipe function f(x::AVec, y::AVec, z::AMat{T}) where T <: Quantity
u = get(plotattributes, :zunit, unit(eltype(z)))
ustripattribute!(plotattributes, :clims, u)
Expand All @@ -70,7 +74,7 @@ const AMat{T} = AbstractArray{T,2} where T
end

# Recipe for vectors of vectors
@recipe function f(::Type{T}, x::T) where T <: AbstractVector{<:AbstractVector{<:Union{Missing,<:Quantity}}}
@recipe function f(::Type{T}, x::T) where T <: AVec{<:AVec{<:UMQ}}
axisletter = plotattributes[:letter] # x, y, or z
[fixaxis!(plotattributes, x, axisletter) for x in x]
end
Expand All @@ -82,19 +86,19 @@ end
end

# Recipes for functions
@recipe function f(f::Function, x::T) where T <: AVec{<:Union{Missing,<:Quantity}}
@recipe function f(f::Function, x::T) where T <: AArr{<:UMQ}
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Meaningful change

x, f.(x)
end
@recipe function f(x::T, f::Function) where T <: AVec{<:Union{Missing,<:Quantity}}
@recipe function f(x::T, f::Function) where T <: AArr{<:UMQ}
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Meaningful change

x, f.(x)
end
@recipe function f(x::T, y::AVec, f::Function) where T <: AVec{<:Union{Missing,<:Quantity}}
@recipe function f(x::T, y::AVec, f::Function) where T <: AVec{<:UMQ}
x, y, f.(x',y)
end
@recipe function f(x::AVec, y::T, f::Function) where T <: AVec{<:Union{Missing,<:Quantity}}
@recipe function f(x::AVec, y::T, f::Function) where T <: AVec{<:UMQ}
x, y, f.(x',y)
end
@recipe function f(x::T1, y::T2, f::Function) where {T1<:AVec{<:Union{Missing,<:Quantity}}, T2<:AVec{<:Union{Missing,<:Quantity}}}
@recipe function f(x::T1, y::T2, f::Function) where {T1<:AVec{<:UMQ}, T2<:AVec{<:UMQ}}
x, y, f.(x',y)
end
@recipe function f(f::Function, u::Units)
Expand All @@ -103,6 +107,25 @@ end
(_, xmin, xmax) = recipedata[1].args
return f, xmin*u, xmax*u
end
@recipe function f(u::Units, f::Function)
return f, u
end
Comment on lines +110 to +112
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

A mirror of f(f, u)

#=========================================================================
If x is an array of arrays of quantities, consider those different series.
No need to dive deeper than this, a plot of arrays of arrays of arrays is
not implemented in Plots.
=========================================================================#
@recipe function f(f::Function, x::AArrArrQ)
for s in x
@series begin
xunit := unit(first(first(x)))
f, s
end
end
end
@recipe function f(x::AArrArrQ, f::Function)
return f, x
end
Comment on lines +113 to +128
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Array of array


"""
```julia
Expand Down
32 changes: 28 additions & 4 deletions test/runtests.jl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
using Test, Unitful, Plots
using Unitful: m, s, cm, DimensionError
using Unitful: m, s, cm, °, rad, DimensionError
using UnitfulRecipes

testfile = "test.png"
Expand Down Expand Up @@ -111,14 +111,17 @@ end
end

@testset "With functions" begin
x, y = randn(3), randn(3)
x, y, α = randn(3), randn(3), (1:5)
@testset "plot(f, x) / plot(x, f)" begin
f(x) = x^2
@test plot( f, x*m) isa Plots.Plot
@test plot(x*m, f) isa Plots.Plot
g(x) = x*m # If the unit comes from the function only then it throws
@test_throws DimensionError plot(x, g) isa Plots.Plot
@test_throws DimensionError plot(g, x) isa Plots.Plot
# a matrix of small angles should give positive `sin`s (otherwise they are probably
# interpreted as radians)
@test all(>(0), yseries(plot(sin, [α*° 2α*°])))
end
@testset "plot(x, y, f)" begin
f(x,y) = x*y
Expand All @@ -128,14 +131,17 @@ end
g(x,y) = x*y*m # If the unit comes from the function only then it throws
@test_throws DimensionError plot(x, y, g) isa Plots.Plot
end
@testset "plot(f, u)" begin
@testset "plot(f, u) / plot(u, f)" begin
f(x) = x^2
pl = plot(x*m, f.(x*m))
@test plot!(pl, f, m) isa Plots.Plot
@test_throws DimensionError plot!(pl, f, s) isa Plots.Plot
pl = plot(f, m)
@test xguide(pl) == string(m)
@test yguide(pl) == string(m^2)
pl = plot(m, f)
@test xguide(pl) == string(m)
@test yguide(pl) == string(m^2)
g(x) = exp(x/(3m))
@test plot(g, u"m") isa Plots.Plot
end
Expand Down Expand Up @@ -324,9 +330,27 @@ end
), testfile)
end

# https://github.com/jw3126/UnitfulRecipes.jl/issues/60
@testset "Start with empty plot" begin
plt = plot()
plot!(plt, (1:3)m)
@test yguide(plt) == "m"
end

@testset "Array of arrays" begin
α, β = (1:5), (0.1:0.1:0.5)
@test yguide(plot(x->x^2, [α*m])) == string(m^2)
plt = plot(sin, [α*°])
@test xguide(plt) == string(°)
# sin(x) > 0 for all x in (1:5)°, but <0 for some x in (1:5)rad
@test all(>(0), yseries(plt))
plt = plot(sin, [α*°, β*°])
@test xguide(plt) == string(°)
@test all(>(0), yseries(plt))
plt = plot(sin, AbstractArray{Unitful.Quantity}[α*°, β*rad])
@test xguide(plt) == string(°)
@test all(>(0), yseries(plt))
plt = plot(AbstractArray{Unitful.Quantity}[α*°, β*rad], sin)
@test xguide(plt) == string(°)
@test all(>(0), yseries(plt))
@test_throws DimensionError plot(x->x^2, AbstractArray{Unitful.Quantity}[α*m, α*s])
end