jw3126 / UnitfulRecipes.jl

Plots.jl recipes for Unitful.jl arrays
MIT License
37 stars 10 forks source link

Recipe for parametric with units? #36

Closed schneiderfelipe closed 3 years ago

schneiderfelipe commented 3 years ago

Hi @jw3126, I expected both examples below to yield the same result:

# Example 1
Ξ»s = (100:3000)u"nm"
plot(Ξ»s, I_blackbody.(Ξ»s), label=5000u"K")
ylims!((0, 5e-41))
# Example 2
plot(I_blackbody, 100u"nm", 3000u"nm", label=5000u"K")
ylims!((0, 5e-41))

The first one works as expected (even though it lacks the natural LaTeX string in the y-axis, as I'm using pyplot()):

graph

The second example, on the other hand, throws an error:

MethodError: no method matching adapted_grid(::Base.var"#64#65"{Base.var"#64#65"{RecipesPipeline.var"#11#12"{Symbol},typeof(Main.workspace3803.I_blackbody)},RecipesPipeline.var"#13#14"{Symbol}}, ::Tuple{Unitful.Quantity{Float64,𝐋,Unitful.FreeUnits{(nm,),𝐋,nothing}},Unitful.Quantity{Float64,𝐋,Unitful.FreeUnits{(nm,),𝐋,nothing}}})

Closest candidates are:

adapted_grid(::Any, !Matched::Tuple{Real,Real}; max_recursions) at /home/schneider/.julia/packages/PlotUtils/qd3Sm/src/adapted_grid.jl:15

    _scaled_adapted_grid(::Function, ::Symbol, ::Symbol, ::Unitful.Quantity{Int64,𝐋,Unitful.FreeUnits{(nm,),𝐋,nothing}}, ::Unitful.Quantity{Int64,𝐋,Unitful.FreeUnits{(nm,),𝐋,nothing}})@user_recipe.jl:307
    macro expansion@user_recipe.jl:286[inlined]
    apply_recipe(::AbstractDict{Symbol,Any}, ::Function, ::Number, ::Number)@RecipesBase.jl:282
    _process_userrecipes!(::Plots.Plot{Plots.PyPlotBackend}, ::Dict{Symbol,Any}, ::Tuple{typeof(Main.workspace3803.I_blackbody),Unitful.Quantity{Int64,𝐋,Unitful.FreeUnits{(nm,),𝐋,nothing}},Unitful.Quantity{Int64,𝐋,Unitful.FreeUnits{(nm,),𝐋,nothing}}})@user_recipe.jl:35
    recipe_pipeline!(::Plots.Plot{Plots.PyPlotBackend}, ::Dict{Symbol,Any}, ::Tuple{typeof(Main.workspace3803.I_blackbody),Unitful.Quantity{Int64,𝐋,Unitful.FreeUnits{(nm,),𝐋,nothing}},Unitful.Quantity{Int64,𝐋,Unitful.FreeUnits{(nm,),𝐋,nothing}}})@RecipesPipeline.jl:69
    _plot!(::Plots.Plot{Plots.PyPlotBackend}, ::Dict{Symbol,Any}, ::Tuple{typeof(Main.workspace3803.I_blackbody),Unitful.Quantity{Int64,𝐋,Unitful.FreeUnits{(nm,),𝐋,nothing}},Unitful.Quantity{Int64,𝐋,Unitful.FreeUnits{(nm,),𝐋,nothing}}})@plot.jl:167
    #plot#129(::Base.Iterators.Pairs{Symbol,Unitful.Quantity{Int64,𝚯,Unitful.FreeUnits{(K,),𝚯,nothing}},Tuple{Symbol},NamedTuple{(:label,),Tuple{Unitful.Quantity{Int64,𝚯,Unitful.FreeUnits{(K,),𝚯,nothing}}}}}, ::typeof(RecipesBase.plot), ::Function, ::Vararg{Any,N} where N)@plot.jl:57
    top-level scope@Local: 4

Comparing this with the parametric example in the docs, I suspect this is due to the units of the start- and endpoints of the x-axis range (3000u"nm", etc.). Is this expected?

briochemc commented 3 years ago

Yes, I don't think there is a recipe for

plot(f, xmin, xmax)

What does

plot(I_blackbody, 100, 3000, label=5000u"K")

give you?

briochemc commented 3 years ago

Side note: I don't think the plot(f, xmin, xmax) case qualifies as "parametric". I think the parametric equivalent would be plot(identity, f, xmin, xmax) (but maybe that's what the former dispatches on in the pipeline?).

schneiderfelipe commented 3 years ago

What does

plot(I_blackbody, 100, 3000, label=5000u"K")

give you?

That throws a specific error in the I_blackbody function, as it only accepts Quantity objects (something along ERROR: MethodError: no method matching exp(::Quantity{Int64,𝐋,Unitful.FreeUnits{(nm,),𝐋,nothing}})).

briochemc commented 3 years ago

I think we can fix this with a PR changing Real to T where {T<:Number} in this line of PlotUtils.jl (seemed to work locally for me)

https://github.com/JuliaPlots/PlotUtils.jl/blob/dd8042cf3d2422a981186cef51ce28a0d9349ef9/src/adapted_grid.jl#L15

@jw3126 any thoughts?

jw3126 commented 3 years ago

@briochemc sure sounds fine to me.

briochemc commented 3 years ago

@schneiderfelipe I think it should work now if you update your environment (a new version of PlotUtils β€” with the fix β€” was released) πŸ˜„

schneiderfelipe commented 3 years ago

@briochemc Thanks for the change! But I might be doing something wrong. The following works:

plot(Ξ» -> Ξ», 100, 6000)

Screenshot from 2021-01-07 14-59-25

But the following one still doesn't:

plot(Ξ» -> Ξ», 100u"nm", 6000u"nm")
DimensionError: Inf and 100.0 nm are not dimensionally compatible.

    _isless@quantities.jl:274[inlined]
    isless(::Unitful.Quantity{Float64,NoDims,Unitful.FreeUnits{(),NoDims,nothing}}, ::Unitful.Quantity{Float64,𝐋,Unitful.FreeUnits{(nm,),𝐋,nothing}})@quantities.jl:264
    isless(::Float64, ::Unitful.Quantity{Float64,𝐋,Unitful.FreeUnits{(nm,),𝐋,nothing}})@quantities.jl:266
    min(::Unitful.Quantity{Float64,𝐋,Unitful.FreeUnits{(nm,),𝐋,nothing}}, ::Float64)@operators.jl:422
    expand_extrema!@axes.jl:311[inlined]
    expand_extrema!(::Plots.Axis, ::Array{Unitful.Quantity{Float64,𝐋,Unitful.FreeUnits{(nm,),𝐋,nothing}},1})@axes.jl:334
    expand_extrema!(::Plots.Subplot{Plots.GRBackend}, ::RecipesPipeline.DefaultsDict)@axes.jl:364
    _expand_subplot_extrema(::Plots.Subplot{Plots.GRBackend}, ::RecipesPipeline.DefaultsDict, ::Symbol)@pipeline.jl:361
    add_series!(::Plots.Plot{Plots.GRBackend}, ::RecipesPipeline.DefaultsDict)@pipeline.jl:312
    _process_seriesrecipe(::Plots.Plot{Plots.GRBackend}, ::RecipesPipeline.DefaultsDict)@series_recipe.jl:44
    _process_seriesrecipes!(::Plots.Plot{Plots.GRBackend}, ::Array{Dict{Symbol,Any},1})@series_recipe.jl:25
    recipe_pipeline!(::Plots.Plot{Plots.GRBackend}, ::Dict{Symbol,Any}, ::Tuple{Main.workspace51.var"#1#2",Unitful.Quantity{Int64,𝐋,Unitful.FreeUnits{(nm,),𝐋,nothing}},Unitful.Quantity{Int64,𝐋,Unitful.FreeUnits{(nm,),𝐋,nothing}}})@RecipesPipeline.jl:96
    _plot!(::Plots.Plot{Plots.GRBackend}, ::Dict{Symbol,Any}, ::Tuple{Main.workspace51.var"#1#2",Unitful.Quantity{Int64,𝐋,Unitful.FreeUnits{(nm,),𝐋,nothing}},Unitful.Quantity{Int64,𝐋,Unitful.FreeUnits{(nm,),𝐋,nothing}}})@plot.jl:167
    #plot#129(::Base.Iterators.Pairs{Union{},Union{},Tuple{},NamedTuple{(),Tuple{}}}, ::typeof(RecipesBase.plot), ::Function, ::Vararg{Any,N} where N)@plot.jl:57
    plot(::Function, ::Unitful.Quantity{Int64,𝐋,Unitful.FreeUnits{(nm,),𝐋,nothing}}, ::Vararg{Unitful.Quantity{Int64,𝐋,Unitful.FreeUnits{(nm,),𝐋,nothing}},N} where N)@plot.jl:51
    top-level scope@Local: 1

I'm using PlotUtils v1.0.9 released yesterday:

(@v1.4) pkg> status PlotUtils
Status `~/.julia/environments/v1.4/Project.toml`
  [995b91a9] PlotUtils v1.0.9
briochemc commented 3 years ago

Can you share the notebook file, too?

briochemc commented 3 years ago

This worked for me...

Screen Shot 2021-01-08 at 10 57 16 am
briochemc commented 3 years ago

Are you sure you did not forget using UnitfulRecipes?

schneiderfelipe commented 3 years ago

Are you sure you did not forget using UnitfulRecipes?

You're right, I forgot to do exactly that!

anojo commented 3 years ago

This is not working for me (and I remembered to add using UnitfulRecipes). Is this broken for other people by any chance?

briochemc commented 3 years ago

@anojo what versions are you using?

anojo commented 3 years ago

@briochemc My bad! I was using v1.0.3 but some other package had me stuck at an older version of Unitful, and I imagine that's the reason it wasn't working. Now it does!