jw3126 / unitfulrecipes.jl Goto Github PK
View Code? Open in Web Editor NEWPlots.jl recipes for Unitful.jl arrays
License: MIT License
Plots.jl recipes for Unitful.jl arrays
License: MIT License
Vector{Any} errors out when stripping units
using Unitful, Plots, UnitfulRecipes
x=(1:10)u"m"
y=[]
for n in x
push!(y,n^2)
end
plot(x,y)
ERROR: DimensionError: Inf and 1.0 m^2 are not dimensionally compatible.
I tried initialize the empty vector as Vector{Quantity}()
but that didn't help. I don't know how to initialize it to include the types for the fields.
using Unitful, UnitfulRecipes, Plots
using Unitful: m, s
x = m * (1:5)
y = s * (1:4)
z = x * y'
heatmap(x, y, z, clim=(0,20)) # fine
heatmap(x, y, z, clim=extrema(z)) # error
# ERROR: DimensionError: and m s are not dimensionally compatible.
I'll submit a PR.
Is there any reference to why normal brackets ()
are used to denote the units on the plot axes? I am used to the convension of square backets []
, and the only think I found from quick googling is that one should denote e.g. time as time / s
, which seems worse to me. Could there potentially be a flag or optional argument one can use to change the default?
If I start a figure with plot
with some basic stuff like the title
and then use plot!
to add data, the units do not appear. MWE:
using UnitfulRecipes
using Unitful: m
using Plots
x = (1:5)m
y = x.^2
p1 = plot(x, y, label="")
plot!(title = "this order works")
p2 = plot(title="no axis units here :(")
plot!(x, y, label="")
plot(p1, p2)
I realize that in this MWE I could reverse the order and plot the data first then add the title,
but often I am looping over several datasets and adding each using plot!
so it can be convenient to start with the title or other stuff.
I am unsure if this issue is specific to UR and fixable,
or if it is a more general limitation of Recipes that I must find some other way to work around?
Hi,
I have encountered a problem when trying to use UnitfulRecipes together with my plotting scripts. I have a user-defined struct that contains data read from some files. Without using UnitfulRecipes, I have implemented a user recipe for my own type as follows:
@recipe function f(data::Data, var::AbstractString;
plotrange=[-Inf,Inf,-Inf,Inf], plotinterval=0.1)
ndim = data.head.ndim
if !startswith(data.head.headline, "normalized")
hasunits = true
unitw = getunit(data, var)
end
if ndim == 2
x, y, w = getdata(data, var, plotrange, plotinterval)
unitx = getunit(data, data.head.variables[1])
unity = getunit(data, data.head.variables[2])
#@. x *= unitx
#@. y *= unity
@. w *= unitw
@series begin
seriestype --> :contourf # use := if you want to force it
x, y, w'
end
end
end
In the above function snippet, Data
is the name of my struct, and with this I can plot like plot(data, "Ux")
or contourf(data, "Ux")
. However, with units involved in the function, right at the line @series
, Julia complained about
ERROR: DimensionError: and km s^-1 are not dimensionally compatible.
Stacktrace:
[1] #s56#154 at /home/myuser/.julia/packages/Unitful/1t88N/src/conversion.jl:12 [inlined]
[2] #s56#154(::Any, ::Any, ::Any) at ./none:0
[3] (::Core.GeneratedFunctionStub)(::Any, ::Vararg{Any,N} where N) at ./boot.jl:527
[4] uconvert(::Unitful.FreeUnits{(),NoDims,nothing}, ::Unitful.Quantity{Float32,𝐋 𝐓^-1,Unitful.FreeUnits{(km, s^-1),𝐋 𝐓^-1,nothing}}) at /home/myuser/.julia/packages/Unitful/1t88N/src/conversion.jl:78
[5] convert(::Type{Float32}, ::Unitful.Quantity{Float32,𝐋 𝐓^-1,Unitful.FreeUnits{(km, s^-1),𝐋 𝐓^-1,nothing}}) at /home/hongyang/.julia/packages/Unitful/1t88N/src/conversion.jl:145
[6] setindex! at ./array.jl:849 [inlined]
[7] setindex! at ./multidimensional.jl:559 [inlined]
[8] macro expansion at ./broadcast.jl:932 [inlined]
[9] macro expansion at ./simdloop.jl:77 [inlined]
[10] copyto! at ./broadcast.jl:931 [inlined]
[11] copyto! at ./broadcast.jl:886 [inlined]
[12] materialize! at ./broadcast.jl:848 [inlined]
[13] materialize!(::Array{Float32,2}, ::Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{2},Nothing,typeof(*),Tuple{Array{Float32,2},Base.RefValue{Unitful.FreeUnits{(km, s^-1),𝐋 𝐓^-1,nothing}}}}) at ./broadcast.jl:845
[14] macro expansion at /home/local/myuser/SWMF/VisAnaJulia/src/visual_plots.jl:47 [inlined]
[15] apply_recipe(::AbstractDict{Symbol,Any}, ::Data, ::AbstractString) at /home/hongyang/.julia/packages/RecipesBase/92zOw/src/RecipesBase.jl:282
[16] _process_userrecipes!(::Any, ::Any, ::Any) at /home/myuser/.julia/packages/RecipesPipeline/uPBKQ/src/user_recipe.jl:36
[17] recipe_pipeline!(::Any, ::Any, ::Any) at /home/myuser/.julia/packages/RecipesPipeline/uPBKQ/src/RecipesPipeline.jl:70
[18] _plot!(::Plots.Plot, ::Any, ::Any) at /home/myuser/.julia/packages/Plots/vsE7b/src/plot.jl:172
[19] #plot#129 at /home/myuser/.julia/packages/Plots/vsE7b/src/plot.jl:58 [inlined]
[20] plot(::Any, ::Any) at /home/myuser/.julia/packages/Plots/vsE7b/src/plot.jl:52
[21] top-level scope at REPL[5]:1
Does it mean that I cannot have two user recipes being used togther? What might be the possible solutions?
@JuliaRegistrator register()
using Plots, Unitful, UnitfulRecipes
vline([2u"m"], xunit = u"ft") #works
vline([2u"m"], xunit = u"ft", yunit = u"ft") #LoadError: KeyError: key :unit not found
hline([2u"m"], yunit = u"ft") #works
hline([2u"m"], xunit = u"ft", yunit = u"ft") #LoadError: KeyError: key :unit not found
The calls where vline
has a yunit
and hline
has a xunit
produces
ERROR: LoadError: KeyError: key :unit not found
Stacktrace:
[1] getindex(h::Dict{Symbol, Any}, key::Symbol)
@ Base ./dict.jl:482
[2] default(k::Symbol)
@ Plots ~/.julia/packages/Plots/XuV6v/src/args.jl:740
[3] warn_on_unsupported_args(pkg::Plots.GRBackend, plotattributes::RecipesPipeline.DefaultsDict)
@ Plots ~/.julia/packages/Plots/XuV6v/src/args.jl:1215
[4] _add_the_series(plt::Plots.Plot{Plots.GRBackend}, sp::Plots.Subplot{Plots.GRBackend}, plotattributes::RecipesPipeline.DefaultsDict)
@ Plots ~/.julia/packages/Plots/XuV6v/src/pipeline.jl:359
[5] add_series!(plt::Plots.Plot{Plots.GRBackend}, plotattributes::RecipesPipeline.DefaultsDict)
@ Plots ~/.julia/packages/Plots/XuV6v/src/pipeline.jl:302
[6] _process_seriesrecipe(plt::Any, plotattributes::Any)
@ RecipesPipeline ~/.julia/packages/RecipesPipeline/CirY4/src/series_recipe.jl:46
[7] _process_seriesrecipe(plt::Any, plotattributes::Any)
@ RecipesPipeline ~/.julia/packages/RecipesPipeline/CirY4/src/series_recipe.jl:60
[8] _process_seriesrecipes!(plt::Any, kw_list::Any)
@ RecipesPipeline ~/.julia/packages/RecipesPipeline/CirY4/src/series_recipe.jl:27
[9] recipe_pipeline!(plt::Any, plotattributes::Any, args::Any)
@ RecipesPipeline ~/.julia/packages/RecipesPipeline/CirY4/src/RecipesPipeline.jl:97
[10] _plot!(plt::Plots.Plot, plotattributes::Any, args::Any)
@ Plots ~/.julia/packages/Plots/XuV6v/src/plot.jl:172
[11] #plot#154
@ ~/.julia/packages/Plots/XuV6v/src/plot.jl:58 [inlined]
[12] vline(args::Any; kw::Any)
@ Plots ~/.julia/packages/RecipesBase/92zOw/src/RecipesBase.jl:403
[13] top-level scope
@ ~/Library/Application Support/Code/User/globalStorage/buenon.scratchpads/scratchpads/34cdd249d862f9176704eaed2c12df8d/scratch1.jl:4
in expression starting at /Users/gerlacar/Library/Application Support/Code/User/globalStorage/buenon.scratchpads/scratchpads/34cdd249d862f9176704eaed2c12df8d/scratch1.jl:4
I realize that it doesn't really make sense to spec yunit
for vline
and xunit
for hline
, but this issue creeps up using vline
and hline
series types in a user recipe, e.g.
@userplot MyCoolPlot
@recipe function f(mcp::MyCoolPlot)
x,y = mcp.args
label := nothing
@series begin
seriestype := :vline
seriescolor := :black
linestyle := :dash
x
end
@series begin
seriestype := :hline
seriescolor := :black
linestyle := :dash
y
end
seriestype --> :scatter
x,y
end
mycoolplot(20*rand(3)*u"m", 20*rand(3)*u"m") # works
mycoolplot(20*rand(3)*u"m", 20*rand(3)*u"m", xunit = u"ft") # same issue as above
I'd like to implement a recipe for images stored as an AxisArray with unitful axes. Should I add it here, or are you trying to keep this package as lightweight as possible?
great package! Unfortunately, I couldn't get this to work with a unitful yerr. I'm getting an error message of "incompatible units" if I try to put a unitful yerr on a unitful value. The error message actually reports the y value without units, and the yerr with units.
For example:
momenta = [p*1u"GeV/c" for p in 1.0:0.1:10]
masses = [139.57039u"MeV/c^2"]
piMass = ones(length(momenta))*masses[1]
piErr=[10.882833439073304u"MeV/c^2" for p in momenta]
yerr=piErr
plot(momenta, [piMass], yerr=yerr, label=["pion"])
gives me:
DimensionError: 139.57039 and 10.882833439073304 MeV c^-2 are not dimensionally compatible.
Stacktrace:
[1] -(x::Quantity{Float64, NoDims, Unitful.FreeUnits{(), NoDims, nothing}}, y::Quantity{Float64, 𝐌, Unitful.FreeUnits{(c^-2, MeV), 𝐌, nothing}})
@ Unitful ~/.julia/packages/Unitful/JwSBO/src/quantities.jl:137
[2] -(x::Float64, y::Quantity{Float64, 𝐌, Unitful.FreeUnits{(c^-2, MeV), 𝐌, nothing}})
@ Base ./promotion.jl:323
[3] error_coords(errorbar::Vector{Quantity{Float64, 𝐌, Unitful.FreeUnits{(c^-2, MeV), 𝐌, nothing}}}, errordata::Vector{Float64}, otherdata::Vector{Float64})
@ Plots ~/.julia/packages/Plots/SjqWU/src/recipes.jl:1121
[4] macro expansion
@ ~/.julia/packages/Plots/SjqWU/src/recipes.jl:1159 [inlined]
[5] apply_recipe(plotattributes::AbstractDict{Symbol, Any}, #unused#::Type{Val{:yerror}}, x::Any, y::Any, z::Any)
@ Plots ~/.julia/packages/RecipesBase/92zOw/src/RecipesBase.jl:282
[6] _process_seriesrecipe(plt::Any, plotattributes::Any)
@ RecipesPipeline ~/.julia/packages/RecipesPipeline/VEk89/src/series_recipe.jl:50
[7] _process_seriesrecipes!(plt::Any, kw_list::Any)
@ RecipesPipeline ~/.julia/packages/RecipesPipeline/VEk89/src/series_recipe.jl:27
[8] recipe_pipeline!(plt::Any, plotattributes::Any, args::Any)
@ RecipesPipeline ~/.julia/packages/RecipesPipeline/VEk89/src/RecipesPipeline.jl:97
[9] _plot!(plt::Plots.Plot, plotattributes::Any, args::Any)
@ Plots ~/.julia/packages/Plots/SjqWU/src/plot.jl:172
[10] #plot#129
@ ~/.julia/packages/Plots/SjqWU/src/plot.jl:58 [inlined]
[11] top-level scope
@ In[31]:11
[12] eval
@ ./boot.jl:360 [inlined]
[13] include_string(mapexpr::typeof(REPL.softscope), mod::Module, code::String, filename::String)
@ Base ./loading.jl:1090
Using annotate! with Unitful coordinates fails on GR, InspectDR, PGFPlotsX and UnicodePlots. On PlotlyJS no crash, but annotation ends up on top left corner of plot.
using Plots, PGFPlotsX, Plotly, PlotlyJS, InspectDR, UnicodePlots
using Unitful, UnitfulRecipes
gr() # or other backends
Plots.plot([0,1]u"s", [0,1]u"m")
Plots.annotate!([0.25]u"s", [0.5]u"m", text("annotation"))
Without units no crashes on all backends, but it is assumed that units are the same as in plot() call, i.e. here annotation will be at (0.25s,0.5m)
Plots.plot([0,1]u"s", [0,1]u"m")
Plots.annotate!([0.25], [0.5], text("annotation"))
GR stacktrace
ERROR: MethodError: no method matching wctondc(::Quantity{Float64, 𝐓, Unitful.FreeUnits{(s,), 𝐓, nothing}}, ::Quantity{Float64, 𝐋, Unitful.FreeUnits{(m,), 𝐋, nothing}})
Stacktrace:
[1] gr_display(sp::Plots.Subplot{Plots.GRBackend}, w::Measures.AbsoluteLength, h::Measures.AbsoluteLength, viewport_canvas::Vector{Float64})
@ Plots ~/.local/share/julia/packages/Plots/FCUr0/src/backends/gr.jl:1050
[2] gr_display(plt::Plots.Plot{Plots.GRBackend}, fmt::String)
@ Plots ~/.local/share/julia/packages/Plots/FCUr0/src/backends/gr.jl:699
[3] gr_display
@ ~/.local/share/julia/packages/Plots/FCUr0/src/backends/gr.jl:665 [inlined]
[4] _display(plt::Plots.Plot{Plots.GRBackend})
@ Plots ~/.local/share/julia/packages/Plots/FCUr0/src/backends/gr.jl:2250
[5] display(#unused#::Plots.PlotsDisplay, plt::Plots.Plot{Plots.GRBackend})
@ Plots ~/.local/share/julia/packages/Plots/FCUr0/src/output.jl:164
[6] display(x::Any)
@ Base.Multimedia ./multimedia.jl:328
[7] #invokelatest#2
@ ./essentials.jl:729 [inlined]
[8] invokelatest
@ ./essentials.jl:726 [inlined]
[9] print_response(errio::IO, response::Any, show_value::Bool, have_color::Bool, specialdisplay::Union{Nothing, AbstractDisplay})
@ REPL ~/soft/julia-1.8.1/share/julia/stdlib/v1.8/REPL/src/REPL.jl:296
[10] (::REPL.var"#45#46"{REPL.LineEditREPL, Pair{Any, Bool}, Bool, Bool})(io::Any)
@ REPL ~/soft/julia-1.8.1/share/julia/stdlib/v1.8/REPL/src/REPL.jl:278
[11] with_repl_linfo(f::Any, repl::REPL.LineEditREPL)
@ REPL ~/soft/julia-1.8.1/share/julia/stdlib/v1.8/REPL/src/REPL.jl:521
[12] print_response(repl::REPL.AbstractREPL, response::Any, show_value::Bool, have_color::Bool)
@ REPL ~/soft/julia-1.8.1/share/julia/stdlib/v1.8/REPL/src/REPL.jl:276
[13] (::REPL.var"#do_respond#66"{Bool, Bool, REPL.var"#77#87"{REPL.LineEditREPL, REPL.REPLHistoryProvider}, REPL.LineEditREPL, REPL.LineEdit.Prompt})(s::REPL.LineEdit.MIState, buf::Any, ok::Bool)
@ REPL ~/soft/julia-1.8.1/share/julia/stdlib/v1.8/REPL/src/REPL.jl:857
[14] #invokelatest#2
@ ./essentials.jl:729 [inlined]
[15] invokelatest
@ ./essentials.jl:726 [inlined]
[16] run_interface(terminal::REPL.Terminals.TextTerminal, m::REPL.LineEdit.ModalInterface, s::REPL.LineEdit.MIState)
@ REPL.LineEdit ~/soft/julia-1.8.1/share/julia/stdlib/v1.8/REPL/src/LineEdit.jl:2510
[17] run_frontend(repl::REPL.LineEditREPL, backend::REPL.REPLBackendRef)
@ REPL ~/soft/julia-1.8.1/share/julia/stdlib/v1.8/REPL/src/REPL.jl:1248
[18] (::REPL.var"#49#54"{REPL.LineEditREPL, REPL.REPLBackendRef})()
@ REPL ./task.jl:484
Julia v.1.8.1
Plots v.1.33.0
Unitful v.1.12.0
UnitfulRecipes v.1.6.0
using Plots
using UnitfulRecipes
using Unitful: m, s
vline(randn(10)*s) # works
vline(randn(10)*s, yunit=m) # fails
plot(randn(10)*s, randn(10)*m)
vline!(randn(10)*s) # fails
DimensionError: m and s are not dimensionally compatible.
Stacktrace:
[1] #s56#154 at /home/jan/.julia/packages/Unitful/KE9TK/src/conversion.jl:12 [inlined]
[2] #s56#154(::Any, ::Any, ::Any) at ./none:0
[3] (::Core.GeneratedFunctionStub)(::Any, ::Vararg{Any,N} where N) at ./boot.jl:527
[4] uconvert(::Unitful.FreeUnits{(m,),𝐋,nothing}, ::Unitful.Quantity{Float64,𝐓,Unitful.FreeUnits{(s,),𝐓,nothing}}) at /home/jan/.julia/packages/Unitful/KE9TK/src/conversion.jl:77
[5] ustrip at /home/jan/.julia/packages/Unitful/KE9TK/src/utils.jl:28 [inlined]
[6] _broadcast_getindex_evalf at ./broadcast.jl:648 [inlined]
[7] _broadcast_getindex at ./broadcast.jl:621 [inlined]
[8] getindex at ./broadcast.jl:575 [inlined]
[9] copy at ./broadcast.jl:876 [inlined]
[10] materialize(::Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1},Nothing,typeof(Unitful.ustrip),Tuple{Base.RefValue{Unitful.FreeUnits{(m,),𝐋,nothing}},Array{Unitful.Quantity{Float64,𝐓,Unitful.FreeUnits{(s,),𝐓,nothing}},1}}}) at ./broadcast.jl:837
[11] fixaxis!(::Dict{Symbol,Any}, ::Array{Unitful.Quantity{Float64,𝐓,Unitful.FreeUnits{(s,),𝐓,nothing}},1}, ::Symbol) at /home/jan/.julia/dev/UnitfulRecipes/src/UnitfulRecipes.jl:39
[12] macro expansion at /home/jan/.julia/dev/UnitfulRecipes/src/UnitfulRecipes.jl:13 [inlined]
[13] apply_recipe(::Dict{Symbol,Any}, ::Type{Array{Unitful.Quantity{Float64,𝐓,Unitful.FreeUnits{(s,),𝐓,nothing}},1}}, ::Array{Unitful.Quantity{Float64,𝐓,Unitful.FreeUnits{(s,),𝐓,nothing}},1}) at /home/jan/.julia/packages/RecipesBase/jcXIg/src/RecipesBase.jl:281
[14] _apply_type_recipe(::Dict{Symbol,Any}, ::Array{Unitful.Quantity{Float64,𝐓,Unitful.FreeUnits{(s,),𝐓,nothing}},1}, ::Symbol) at /home/jan/.julia/packages/RecipesPipeline/wolJ9/src/type_recipe.jl:30
[15] macro expansion at /home/jan/.julia/packages/RecipesPipeline/wolJ9/src/user_recipe.jl:144 [inlined]
[16] apply_recipe(::Dict{Symbol,Any}, ::Array{Unitful.Quantity{Float64,𝐓,Unitful.FreeUnits{(s,),𝐓,nothing}},1}) at /home/jan/.julia/packages/RecipesBase/jcXIg/src/RecipesBase.jl:281
[17] _process_userrecipes!(::Plots.Plot{Plots.GRBackend}, ::Dict{Symbol,Any}, ::Tuple{Array{Unitful.Quantity{Float64,𝐓,Unitful.FreeUnits{(s,),𝐓,nothing}},1}}) at /home/jan/.julia/packages/RecipesPipeline/wolJ9/src/user_recipe.jl:35
[18] recipe_pipeline!(::Plots.Plot{Plots.GRBackend}, ::Dict{Symbol,Any}, ::Tuple{Array{Unitful.Quantity{Float64,𝐓,Unitful.FreeUnits{(s,),𝐓,nothing}},1}}) at /home/jan/.julia/packages/RecipesPipeline/wolJ9/src/RecipesPipeline.jl:68
[19] _plot!(::Plots.Plot{Plots.GRBackend}, ::Dict{Symbol,Any}, ::Tuple{Array{Unitful.Quantity{Float64,𝐓,Unitful.FreeUnits{(s,),𝐓,nothing}},1}}) at /home/jan/.julia/packages/Plots/Xnzc7/src/plot.jl:167
[20] plot(::Array{Unitful.Quantity{Float64,𝐓,Unitful.FreeUnits{(s,),𝐓,nothing}},1}; kw::Base.Iterators.Pairs{Symbol,Any,Tuple{Symbol,Symbol},NamedTuple{(:yunit, :seriestype),Tuple{Unitful.FreeUnits{(m,),𝐋,nothing},Symbol}}}) at /home/jan/.julia/packages/Plots/Xnzc7/src/plot.jl:57
[21] #vline#380 at /home/jan/.julia/packages/RecipesBase/jcXIg/src/RecipesBase.jl:402 [inlined]
[22] top-level scope at In[7]:6
@JuliaRegistrator register
using Unitful, UnitfulRecipes, Plots
using Unitful: m, s
x = m * (1:5)
y = s * (1:4)
z = x * y'
heatmap(x, y, z) # units on colorbar as expected
heatmap(z) # runs, but no units on colorbar
I'll try to address this in the same PR as for #57 but if you prefer them separated I can do that.
plot([2u"dB", 3u"dB"])
doesn't work for me. Quick tests like this suggest that logarithmic units aren't working, for either axis. Is it possible/easy to add a recipe for these?
Currently, this MWE
using Unitful, UnitfulRecipes, Plots
x = rand(10)*u"m"
y = rand(10)*u"s"
plot(x,y)
gives
IMHO, it's better to show units in the axis label rather than at every tick. My current solution is either
plot(ustrip(x), ustrip(y), xlabel=string(unit(eltype(x))), ylabel=string(unit(eltype(y))))
which gives
or if I have a name for axis labels already, something like
plot(ustrip(x), ustrip(y), xlabel="x ($(unit(eltype(x))))", ylabel="y ($(string(unit(eltype(y)))))")
which gives
Is that at all doable with recipes? If yes I would love this to be implemented instead of the current behavior!
This is kind of a continuation of #55. Currently xticks
works fine as part of a plot
call with other stuff (thanks to #56), but not in isolation with plot!
. Here is a MWE:
using Unitful: mm
using UnitfulRecipes
using Plots: plot, plot!, gui
xticks = [0mm, 1mm]
plot([0mm, 2mm], [0mm, 3mm], xticks = xticks) # works
plot!(xticks = xticks) # fails
Error showing value of type Plots.Plot{Plots.GRBackend}:
ERROR: DimensionError: -0.06 and 0.0 mm are not dimensionally compatible.
Stacktrace:
[1] _lt
@ ~/.julia/packages/Unitful/ApCuY/src/quantities.jl:272 [inlined]
[2] <(x::Unitful.Quantity{Float64, NoDims, Unitful.FreeUnits{(), NoDims, nothing}}, y::Unitful.Quantity{Float64, 𝐋, Unitful.FreeUnits{(mm,), 𝐋, nothing}})
@ Unitful ~/.julia/packages/Unitful/ApCuY/src/quantities.jl:262
[3] <(x::Float64, y::Unitful.Quantity{Int64, 𝐋, Unitful.FreeUnits{(mm,), 𝐋, nothing}})
@ Unitful ~/.julia/packages/Unitful/ApCuY/src/quantities.jl:264
[4] <=(x::Float64, y::Unitful.Quantity{Int64, 𝐋, Unitful.FreeUnits{(mm,), 𝐋, nothing}})
@ Base ./operators.jl:405
[5] (::Plots.var"#93#95"{Float64, Float64})(t::Unitful.Quantity{Int64, 𝐋, Unitful.FreeUnits{(mm,), 𝐋, nothing}})
@ Plots ~/.julia/packages/Plots/530RA/src/axes.jl:191
Perhaps the bug could be in Plots
somewhere. But I am reporting it here initially because it works fine without units. Current workaround is to always specify xticks
as part of plotting other stuff, instead of afterwards.
The Shape() function gives the ERROR: DimensionError: and m are not dimensionally compatible.
using Unitful, Plots, UnitfulRecipes
Shape([(1u"m",1u"m"),(2u"m",2u"m"),(1u"m",2u"m")])
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()
):
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?
It would be useful to add a recipe for plotting ribbons.
They provide very nice way of displaying propagation errors during simulations using MCM.jl, for instance.
using Unitful, UnitfulRecipes, Plots
x = 1:10
plot(x, -x.^2 .* 1u"m", ribbon=5) # OK
plot(x, -x.^2 .* 1u"m", ribbon=1u"m") # ERROR
Hello!
It would be nice to be able to use UnitfulRecipes.jl with the functions (e.g. groupedbar()
and kde()
) from StatsPlots.jl.
Given that StatsPlots.jl is very closely related to Plots.jl (according to its own documentation), I wonder if this is something that is not too tricky to do?
If this has been posted to the wrong place (perhaps it belongs to StatsPlots instead?) then please let me know!
Many thanks!
J
using StatsPlots
gr()
# Basic example without using Unitful.jl or UnitfulRecipes.jl
x = randn(1024); y = randn(1024);
marginalkde(x, x+y)
using Unitful
x_u = x .* u"m"; y1_u= y .* u"m"
using UnitfulRecipes
marginalkde(x_u, x_u+y_u) # This errors
using UnitfulRecipes
has already been executed in the REPLjulia> marginalkde(x_u, x_u+y_u)
ERROR: MethodError: no method matching kde(::Tuple{Vector{Quantity{Float64, 𝐋, Unitful.FreeUnits{(m,), 𝐋, nothing}}}, Vector{Quantity{Float64, 𝐋, Unitful.FreeUnits{(m,), 𝐋, nothing}}}})
Closest candidates are:
kde(::AbstractVector{T} where T<:Real; bandwidth, kernel, npoints, boundary, weights) at ~/.julia/packages/KernelDensity/bNBAQ/src/univariate.jl:169
kde(::AbstractVector{T} where T<:Real, ::Distributions.UnivariateDistribution; boundary, npoints, weights) at ~/.julia/packages/KernelDensity/bNBAQ/src/univariate.jl:155
kde(::AbstractVector{T} where T<:Real, ::R; bandwidth, kernel, weights) where R<:AbstractRange at ~/.julia/packages/KernelDensity/bNBAQ/src/univariate.jl:162
...
Stacktrace:
[1] macro expansion
@ ~/.julia/packages/StatsPlots/LlHWB/src/marginalkde.jl:24 [inlined]
[2] apply_recipe(plotattributes::AbstractDict{Symbol, Any}, kc::StatsPlots.MarginalKDE)
@ StatsPlots ~/.julia/packages/RecipesBase/qpxEX/src/RecipesBase.jl:289
[3] _process_userrecipes!(plt::Any, plotattributes::Any, args::Any)
@ RecipesPipeline ~/.julia/packages/RecipesPipeline/OXGmH/src/user_recipe.jl:36
[4] recipe_pipeline!(plt::Any, plotattributes::Any, args::Any)
@ RecipesPipeline ~/.julia/packages/RecipesPipeline/OXGmH/src/RecipesPipeline.jl:70
[5] _plot!(plt::Plots.Plot, plotattributes::Any, args::Any)
@ Plots ~/.julia/packages/Plots/lW9ll/src/plot.jl:209
[6] plot(args::Any; kw::Base.Pairs{Symbol, V, Tuple{Vararg{Symbol, N}}, NamedTuple{names, T}} where {V, N, names, T<:Tuple{Vararg{Any, N}}})
@ Plots ~/.julia/packages/Plots/lW9ll/src/plot.jl:91
[7] plot
@ ~/.julia/packages/Plots/lW9ll/src/plot.jl:82 [inlined]
[8] marginalkde(::Vector{Quantity{Float64, 𝐋, Unitful.FreeUnits{(m,), 𝐋, nothing}}}, ::Vararg{Vector{Quantity{Float64, 𝐋, Unitful.FreeUnits{(m,), 𝐋, nothing}}}}; kw::Base.Pairs{Symbol, Union{}, Tuple{}, NamedTuple{(), Tuple{}}})
@ StatsPlots ~/.julia/packages/RecipesBase/qpxEX/src/RecipesBase.jl:364
[9] marginalkde(::Vector{Quantity{Float64, 𝐋, Unitful.FreeUnits{(m,), 𝐋, nothing}}}, ::Vararg{Vector{Quantity{Float64, 𝐋, Unitful.FreeUnits{(m,), 𝐋, nothing}}}})
@ StatsPlots ~/.julia/packages/RecipesBase/qpxEX/src/RecipesBase.jl:364
[10] top-level scope
@ REPL[13]:1
julia> versioninfo()
Julia Version 1.8.0
Commit 5544a0fab76 (2022-08-17 13:38 UTC)
Platform Info:
OS: macOS (x86_64-apple-darwin21.4.0)
CPU: 4 × Intel(R) Core(TM) i5-5250U CPU @ 1.60GHz
WORD_SIZE: 64
LIBM: libopenlibm
LLVM: libLLVM-13.0.1 (ORCJIT, broadwell)
Threads: 1 on 2 virtual cores
Environment:
JULIA_EDITOR = code
JULIA_NUM_THREADS =
(@v1.8) pkg> st # manually edited to only show relevant packages
Status `~/.julia/environments/v1.8/Project.toml`
[f3b207a7] StatsPlots v0.15.1
[1986cc42] Unitful v1.11.0
[42071c24] UnitfulRecipes v1.5.3
Plots appears broken when units are used.
using Unitful, UnitfulRecipes, Plots
const a = 1u"m/s^2"
v(t) = a * t
x(t) = a/2 * t^2
t = (0:0.01:100)*u"s"
plot(x.(t), v.(t), xlabel="position", ylabel="speed")
KeyError: key :letter not found
Stacktrace:
[1] getindex at .\dict.jl:477 [inlined]
[2] macro expansion at C:\Users\james\.julia\packages\UnitfulRecipes\5RFXj\src\UnitfulRecipes.jl:12 [inlined]
[3] apply_recipe(::Dict{Symbol,Any}, ::Type{Array{Quantity{Float64,�,Unitful.FreeUnits{(m,),�,nothing}},1}}, ::Array{Quantity{Float64,�,Unitful.FreeUnits{(m,),�,nothing}},1}) at C:\Users\james\.julia\packages\RecipesBase\G4s6f\src\RecipesBase.jl:279
[4] _apply_type_recipe(::Dict{Symbol,Any}, ::Array{Quantity{Float64,�,Unitful.FreeUnits{(m,),�,nothing}},1}, ::Symbol) at C:\Users\james\.julia\packages\Plots\cc8wh\src\series.jl:186
[5] macro expansion at C:\Users\james\.julia\packages\Plots\cc8wh\src\series.jl:268 [inlined]
[6] apply_recipe(::Dict{Symbol,Any}, ::Array{Quantity{Float64,�,Unitful.FreeUnits{(m,),�,nothing}},1}, ::Array{Quantity{Float64,�*�^-1,Unitful.FreeUnits{(m, s^-1),�*�^-1,nothing}},1}) at C:\Users\james\.julia\packages\RecipesBase\G4s6f\src\RecipesBase.jl:279
[7] _process_userrecipes(::Plots.Plot{Plots.GRBackend}, ::Dict{Symbol,Any}, ::Tuple{Array{Quantity{Float64,�,Unitful.FreeUnits{(m,),�,nothing}},1},Array{Quantity{Float64,�*�^-1,Unitful.FreeUnits{(m, s^-1),�*�^-1,nothing}},1}}) at C:\Users\james\.julia\packages\Plots\cc8wh\src\pipeline.jl:85
[8] _plot!(::Plots.Plot{Plots.GRBackend}, ::Dict{Symbol,Any}, ::Tuple{Array{Quantity{Float64,�,Unitful.FreeUnits{(m,),�,nothing}},1},Array{Quantity{Float64,�*�^-1,Unitful.FreeUnits{(m, s^-1),�*�^-1,nothing}},1}}) at C:\Users\james\.julia\packages\Plots\cc8wh\src\plot.jl:178
[9] plot(::Array{Quantity{Float64,�,Unitful.FreeUnits{(m,),�,nothing}},1}, ::Vararg{Any,N} where N; kw::Base.Iterators.Pairs{Symbol,String,Tuple{Symbol,Symbol},NamedTuple{(:xlabel, :ylabel),Tuple{String,String}}}) at C:\Users\james\.julia\packages\Plots\cc8wh\src\plot.jl:57
@briochemc I think this package is pretty stable and we can do an 1.0 release. What do you think?
It would be nice if plot(x -> f(x), xs)
worked with unitful xs.
The definition at
UnitfulRecipes.jl/src/UnitfulRecipes.jl
Line 16 in 5a720a9
function stripunit(x, u)
uconvert.(NoUnits, x/u)
end
seems to be the same as what Unitful.ustrip
accomplishes. I had the same kind of helper in my code because I couldn't find ustrip
, so I'm bringing it up just in case!
This is just a suggestion.
I suggest this because Plots currently fails to build in Travis Windows CI (which fails the whole CI) and this would also allow us to have OS-specific badges of tests like I just did for DualMatrixTools.jl.
We could more or less copy-paste the workflows from that repo, but you would have to add a few things in the repo's settings:
CODECOV_TOKEN
in the repo's secret tokens (find it in your codecov)DOCUMENTER_KEY
to the secrets and the public documenter
key to the "deploy keys" (keys to be generated using DocumenterTools as per Documenter's documentation)When constructing lists from iterators, tuple and vectors yield different levels of wrapped data, which then gets differently ustripped when plotting. I personally find this tricky in Plots because I'm always putting tuples where vectors belong and vice versa.
using Plots
using Unitful, Unitful.DefaultSymbols, UnitfulRecipes
plot(cos,(0:180)°,label="Tuple")
plot!(cos,[0:180]°,label="Vector")
The vector comprehension ends up [(0:180)°] which then gets stripped to 0:180, whereas the Tuple version forms (0:180)° which uses degree math. So, the Tuple goes through half a rotation, and the Vector goes through 180 rotations.
I think we could have a bit of cleaner way to dispatch on unitful arrays by using traits instead of just dispatch. I had been thinking about this for a while and an answer on slack motivated me to think about this a bit more. This issue is just to start a discussion and keep track of this slack message from Mason Protter (because slack deletes everything):
struct Foo end
struct Contains{T} end
struct Not{T} end
f(args...) = f(check_for_foo(args), args...)
check_for_foo(::T) where {T <: Tuple} = Foo ∈ T.parameters ? Contains{Foo}() : Not{Contains{Foo}}()
f(::Contains{Foo}, args...) = "Foo in $(args)"
f(::Not{Contains{Foo}}, args...) = "Foo not in $(args)"
and then
julia> f(1, 2, 3)
"Foo not in (1, 2, 3)"
julia> f(1, Foo(), 4)
"Foo in (1, Foo(), 4)"
This requires some boiler-plate to set up, but it's at least O(1) methods instead of O(2^N)
I am asking because the pgfplots backend does some processing on labels etc. depending on whether its a LaTeXString
or not.
But since UnitfulString{LaTeXString, ...}
is not a LaTeXString
, it goes the wrong path.
I could add extra handling for this, but in general I'd prefer if recipes didn't change the type of inputs.
I have a surface that is drawn in 3D space (length x, y, and z) with a 4th axis, the colorbar, which could be unitless, time, pressure, or some other dimension. The issue is that the colorbar title keeps the units from the 3rd axis (m). If I try to color based on anything other than a unitless number or a length, I get an error. If I could rename the colorbar_title = "Real Title ($real_units)" I would just strip out those units myself, but the other unit stays in so the title would be: "Real Title (kPa) (m)".
begin
X = [1u"m", 1u"m"; 1u"m", 1u"m"]
Y = [1u"m", 1u"m"; 1u"m", 1u"m"]
Z = [1u"m", 1u"m"; 1u"m", 1u"m"]
C = rand(2, 2)
surface!(X, Y, Z, surfacecolor=C, color=:turbo, colorbar=true, colorbar_title="this should change (kPa)")
end
I considered rolling my own for this, but I have other elements like the ball being brought into the plot using UnitfulRecipes so I would either have to enforce that everything comes in using the correct units or handle it elegantly or not use UnitfulRecipes for any of it and roll my own for the whole thing.
I've only just started making recipes of my own so when I open the code base it's a little beyond me. I think two potential solutions would be:
Please let me know if I've missed an easy solution or I'd be happy to contribute a solution with a little direction. Thanks!
Thanks for this great package. Currently it supports Unitful xlim
very nicely, but Unitful xticks
leads to an error. This caught me because I often use xticks=[x[1],x[end]]
to streamline plots and it fails if x has units. My workaround is xticks=[x[1],x[end]] / oneunit(x[1])
which is fine for now but I wanted to report the issue because it seems like it would be nicely consistent to support having the ticks be specified in the same units as the corresponding axis.
using Unitful, UnitfulRecipes, Plots
x = 1u"mm" * (1:30)
scatter(x, 2x) # works as expected
scatter(x, 2x; xlim=(10u"mm", 20u"mm")) # works as expected!
scatter(x, 2x; xlim=(1u"cm", 2u"cm")) # works as expected - yay!
scatter(x, 2x; xticks=[1u"cm", 2u"cm"]) # error message
ERROR: DimensionError: 0.13 and 1.0 cm are not dimensionally compatible.
The following MWE makes a 2inch by 2inch square, using a mix of inches units and mm units for the two axes.
using Unitful: mm, inch
using UnitfulRecipes
using Plots
x = LinRange(-4,4,201) * 10mm
y = LinRange(-20,20,203) * inch
z = @. (abs(x) < 1inch) * (abs(y) < 1inch)'
ar = [1, :auto, :equal, :none]
pl = Array{Any}(undef, 4)
for (i, aspect_ratio) in enumerate(ar)
pl[i] = heatmap(x, y, z'; aspect_ratio, title="$aspect_ratio",
colorbar=:none, alpha=0.5,
xlabel="x", ylabel="y", ytick=(-1:1)*20inch)
end
plot(pl...)
However, all four options for aspect_ratio
, i.e., [1, :auto, :equal, :none]
produce a rectangle rather than a square, because 1
and equal
make the spacing of the digits equal, rather than the physical units. (Note the grid lines make squares for 1
and equal
.)
Here is the resulting plot using UR v1.5.3 and Plots v1.13.1:
In the long run, it might be preferable to have some option (perhaps equal
) for aspect_ratio
that makes the actual distances match (when the units are compatible). I have no idea whether it can be done here in UR or would require downstream changes in Plots.
In the short run, this issue at least will document the behavior. It would be easy to at least make the current heatmap
example more informative by having axes with units:
This issue is used to trigger TagBot; feel free to unsubscribe.
If you haven't already, you should update your TagBot.yml
to include issue comment triggers.
Please see this post on Discourse for instructions and more details.
If you'd like for me to do this for you, comment TagBot fix
on this issue.
I'll open a PR within a few hours, please be patient!
@JuliaRegistrator register()
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.