Makie.jl
Makie.jl copied to clipboard
Provide suggestions for unknown kwargs passed to blocks
Description
Fixes #4391. There might be a better way to do what I'm doing here, but at least it's something to test with instead of my code snippets on that issue.
Adds a check to block constructors to see if the passed kwargs are all valid. Reuses the InvalidAttributeError code. Some examples:
julia> fig = Figure(); ax = Axis(fig[1, 1], badkwarg = 1, badkwarg2 = 2, xlabel = "x")
ERROR: Invalid attributes badkwarg and badkwarg2 for block type Axis.
The available block attributes for Axis are:
alignmode leftspinevisible subtitlevisible topspinevisible xlabelpadding xminorticksvisible xticklabelfont xzoomkey ylabelrotation yminortickwidth yticklabelpad yzoomlock
aspect limits tellheight valign xlabelrotation xminortickwidth xticklabelpad xzoomlock ylabelsize ypankey yticklabelrotation zoombutton
autolimitaspect panbutton tellwidth width xlabelsize xpankey xticklabelrotation yautolimitmargin ylabelvisible ypanlock yticklabelsize
backgroundcolor rightspinecolor title xautolimitmargin xlabelvisible xpanlock xticklabelsize yaxisposition yminorgridcolor yrectzoom yticklabelspace
bottomspinecolor rightspinevisible titlealign xaxisposition xminorgridcolor xrectzoom xticklabelspace ygridcolor yminorgridstyle yreversed yticklabelsvisible
bottomspinevisible spinewidth titlecolor xgridcolor xminorgridstyle xreversed xticklabelsvisible ygridstyle yminorgridvisible yscale yticks
dim1_conversion subtitle titlefont xgridstyle xminorgridvisible xscale xticks ygridvisible yminorgridwidth ytickalign yticksize
dim2_conversion subtitlecolor titlegap xgridvisible xminorgridwidth xtickalign xticksize ygridwidth yminortickalign ytickcolor yticksmirrored
flip_ylabel subtitlefont titlelineheight xgridwidth xminortickalign xtickcolor xticksmirrored ylabel yminortickcolor ytickformat yticksvisible
halign subtitlegap titlesize xlabel xminortickcolor xtickformat xticksvisible ylabelcolor yminorticks yticklabelalign ytickwidth
height subtitlelineheight titlevisible xlabelcolor xminorticks xticklabelalign xtickwidth ylabelfont yminorticksize yticklabelcolor ytrimspine
leftspinecolor subtitlesize topspinecolor xlabelfont xminorticksize xticklabelcolor xtrimspine ylabelpadding yminorticksvisible yticklabelfont yzoomkey
Stacktrace:
[1] _check_remaining_kwargs(T::Type{Axis}, kwdict::Dict{Symbol, Any})
@ Makie c:\Users\danjv\.julia\dev\Makie.jl\src\makielayout\blocks.jl:298
[2] _block(T::Type{…}, fig_or_scene::Figure, args::Vector{…}, kwdict::Dict{…}, bbox::Nothing; kwdict_complete::Bool)
@ Makie c:\Users\danjv\.julia\dev\Makie.jl\src\makielayout\blocks.jl:316
[3] _block
@ c:\Users\danjv\.julia\dev\Makie.jl\src\makielayout\blocks.jl:303 [inlined]
[4] #_block#1490
@ c:\Users\danjv\.julia\dev\Makie.jl\src\makielayout\blocks.jl:259 [inlined]
[5] _block(::Type{Axis}, ::GridPosition; kwargs::@Kwargs{badkwarg::Int64, badkwarg2::Int64, xlabel::String})
@ Makie c:\Users\danjv\.julia\dev\Makie.jl\src\makielayout\blocks.jl:253
[6] _block
@ c:\Users\danjv\.julia\dev\Makie.jl\src\makielayout\blocks.jl:246 [inlined]
[7] #_#1488
@ c:\Users\danjv\.julia\dev\Makie.jl\src\makielayout\blocks.jl:237 [inlined]
[8] top-level scope
@ REPL[25]:1
Some type information was truncated. Use `show(err)` to see complete types.
julia> lines([2.0], [2.0], axis = (xlabel="x", bad = 1, bad2 = [2]))
ERROR: Invalid attributes bad and bad2 for block type Axis.
The available block attributes for Axis are:
alignmode leftspinevisible subtitlevisible topspinevisible xlabelpadding xminorticksvisible xticklabelfont xzoomkey ylabelrotation yminortickwidth yticklabelpad yzoomlock
aspect limits tellheight valign xlabelrotation xminortickwidth xticklabelpad xzoomlock ylabelsize ypankey yticklabelrotation zoombutton
autolimitaspect panbutton tellwidth width xlabelsize xpankey xticklabelrotation yautolimitmargin ylabelvisible ypanlock yticklabelsize
backgroundcolor rightspinecolor title xautolimitmargin xlabelvisible xpanlock xticklabelsize yaxisposition yminorgridcolor yrectzoom yticklabelspace
bottomspinecolor rightspinevisible titlealign xaxisposition xminorgridcolor xrectzoom xticklabelspace ygridcolor yminorgridstyle yreversed yticklabelsvisible
bottomspinevisible spinewidth titlecolor xgridcolor xminorgridstyle xreversed xticklabelsvisible ygridstyle yminorgridvisible yscale yticks
dim1_conversion subtitle titlefont xgridstyle xminorgridvisible xscale xticks ygridvisible yminorgridwidth ytickalign yticksize
dim2_conversion subtitlecolor titlegap xgridvisible xminorgridwidth xtickalign xticksize ygridwidth yminortickalign ytickcolor yticksmirrored
flip_ylabel subtitlefont titlelineheight xgridwidth xminortickalign xtickcolor xticksmirrored ylabel yminortickcolor ytickformat yticksvisible
halign subtitlegap titlesize xlabel xminortickcolor xtickformat xticksvisible ylabelcolor yminorticks yticklabelalign ytickwidth
height subtitlelineheight titlevisible xlabelcolor xminorticks xticklabelalign xtickwidth ylabelfont yminorticksize yticklabelcolor ytrimspine
leftspinecolor subtitlesize topspinecolor xlabelfont xminorticksize xticklabelcolor xtrimspine ylabelpadding yminorticksvisible yticklabelfont yzoomkey
Stacktrace:
[1] _check_remaining_kwargs(T::Type{Axis}, kwdict::Dict{Symbol, Any})
@ Makie c:\Users\danjv\.julia\dev\Makie.jl\src\makielayout\blocks.jl:298
[2] _block(T::Type{…}, fig_or_scene::Figure, args::Vector{…}, kwdict::Dict{…}, bbox::Nothing; kwdict_complete::Bool)
@ Makie c:\Users\danjv\.julia\dev\Makie.jl\src\makielayout\blocks.jl:316
[3] _block(T::Type{Axis}, fig_or_scene::Figure, args::Vector{Any}, kwdict::Dict{Symbol, Any}, bbox::Nothing)
@ Makie c:\Users\danjv\.julia\dev\Makie.jl\src\makielayout\blocks.jl:303
[4] create_axis_for_plot(figure::Figure, plot::Lines{Tuple{Vector{Point{2, Float64}}}}, attributes::Dict{Symbol, Any})
@ Makie c:\Users\danjv\.julia\dev\Makie.jl\src\figureplotting.jl:107
[5] create_axis_like(plot::Lines{Tuple{Vector{Point{2, Float64}}}}, attributes::Dict{Symbol, Any}, ::Nothing)
@ Makie c:\Users\danjv\.julia\dev\Makie.jl\src\figureplotting.jl:199
[6] _create_plot(::Function, ::Dict{Symbol, Any}, ::Vector{Float64}, ::Vararg{Vector{Float64}})
@ Makie c:\Users\danjv\.julia\dev\Makie.jl\src\figureplotting.jl:317
[7] lines(::Vector{Float64}, ::Vararg{Vector{…}}; kw::@Kwargs{axis::@NamedTuple{…}})
@ MakieCore c:\Users\danjv\.julia\dev\Makie.jl\MakieCore\src\recipes.jl:449
[8] top-level scope
@ REPL[26]:1
Some type information was truncated. Use `show(err)` to see complete types.
julia> Label(fig[1,1], bad = 1)
ERROR: Invalid attribute bad for block type Label.
The available block attributes for Label are:
alignmode color font fontsize halign height justification lineheight padding rotation tellheight tellwidth text valign visible width word_wrap
Stacktrace:
[1] _check_remaining_kwargs(T::Type{Label}, kwdict::Dict{Symbol, Any})
@ Makie c:\Users\danjv\.julia\dev\Makie.jl\src\makielayout\blocks.jl:298
[2] _block(T::Type{…}, fig_or_scene::Figure, args::Vector{…}, kwdict::Dict{…}, bbox::Nothing; kwdict_complete::Bool)
@ Makie c:\Users\danjv\.julia\dev\Makie.jl\src\makielayout\blocks.jl:316
[3] _block
@ c:\Users\danjv\.julia\dev\Makie.jl\src\makielayout\blocks.jl:303 [inlined]
[4] #_block#1490
@ c:\Users\danjv\.julia\dev\Makie.jl\src\makielayout\blocks.jl:259 [inlined]
[5] _block(::Type{Label}, ::GridPosition; kwargs::@Kwargs{bad::Int64})
@ Makie c:\Users\danjv\.julia\dev\Makie.jl\src\makielayout\blocks.jl:253
[6] _block
@ c:\Users\danjv\.julia\dev\Makie.jl\src\makielayout\blocks.jl:246 [inlined]
[7] #_#1488
@ c:\Users\danjv\.julia\dev\Makie.jl\src\makielayout\blocks.jl:237 [inlined]
[8] top-level scope
@ REPL[27]:1
Some type information was truncated. Use `show(err)` to see complete types.
julia> Axis3(fig[1, 1], blah = "1")
ERROR: Invalid attribute blah for block type Axis3.
The available block attributes for Axis3 are:
alignmode limits titlegap xlabel xspinecolor_2 xticklabelsvisible ygridcolor ylabelvisible yticklabelfont zautolimitmargin zlabelsize zticklabelcolor
aspect perspectiveness titlesize xlabelalign xspinecolor_3 xticks ygridvisible yreversed yticklabelpad zgridcolor zlabelvisible zticklabelfont
azimuth protrusions titlevisible xlabelcolor xspinesvisible xticksize ygridwidth yspinecolor_1 yticklabelsize zgridvisible zreversed zticklabelpad
backgroundcolor targetlimits valign xlabelfont xspinewidth xticksvisible ylabel yspinecolor_2 yticklabelsvisible zgridwidth zspinecolor_1 zticklabelsize
dim1_conversion tellheight viewmode xlabeloffset xtickcolor xtickwidth ylabelalign yspinecolor_3 yticks zlabel zspinecolor_2 zticklabelsvisible
dim2_conversion tellwidth width xlabelrotation xtickformat xypanelcolor ylabelcolor yspinesvisible yticksize zlabelalign zspinecolor_3 zticks
dim3_conversion title xautolimitmargin xlabelsize xticklabelcolor xypanelvisible ylabelfont yspinewidth yticksvisible zlabelcolor zspinesvisible zticksize
elevation titlealign xgridcolor xlabelvisible xticklabelfont xzpanelcolor ylabeloffset ytickcolor ytickwidth zlabelfont zspinewidth zticksvisible
halign titlecolor xgridvisible xreversed xticklabelpad xzpanelvisible ylabelrotation ytickformat yzpanelcolor zlabeloffset ztickcolor ztickwidth
height titlefont xgridwidth xspinecolor_1 xticklabelsize yautolimitmargin ylabelsize yticklabelcolor yzpanelvisible zlabelrotation ztickformat
Stacktrace:
[1] _check_remaining_kwargs(T::Type{Axis3}, kwdict::Dict{Symbol, Any})
@ Makie c:\Users\danjv\.julia\dev\Makie.jl\src\makielayout\blocks.jl:298
[2] _block(T::Type{…}, fig_or_scene::Figure, args::Vector{…}, kwdict::Dict{…}, bbox::Nothing; kwdict_complete::Bool)
@ Makie c:\Users\danjv\.julia\dev\Makie.jl\src\makielayout\blocks.jl:316
[3] _block
@ c:\Users\danjv\.julia\dev\Makie.jl\src\makielayout\blocks.jl:303 [inlined]
[4] #_block#1490
@ c:\Users\danjv\.julia\dev\Makie.jl\src\makielayout\blocks.jl:259 [inlined]
[5] _block(::Type{Axis3}, ::GridPosition; kwargs::@Kwargs{blah::String})
@ Makie c:\Users\danjv\.julia\dev\Makie.jl\src\makielayout\blocks.jl:253
[6] _block
@ c:\Users\danjv\.julia\dev\Makie.jl\src\makielayout\blocks.jl:246 [inlined]
[7] #_#1488
@ c:\Users\danjv\.julia\dev\Makie.jl\src\makielayout\blocks.jl:237 [inlined]
[8] top-level scope
@ REPL[28]:1
Some type information was truncated. Use `show(err)` to see complete types.
I wanted to get #4390 here too, but Figure isn't a block... the bad keyword arguments are just passed into Scene, e.g.
julia> Figure(bad=1).scene.theme[:bad]
Observable{Any}(1)
Not sure if that's a simple fix. I've never used themes. So, I won't address it here and keep it simple.
Type of change
- [x] Bug fix (non-breaking change which fixes an issue)
Checklist
- [x] Added an entry in CHANGELOG.md (for new features and breaking changes)
- [x] Added unit tests for new algorithms, conversion methods, etc.
Thanks for the PR!
I don't think this qualifies as breaking if it's just changing the type of the error? Any situation that triggers this would have errored anyway.
Right. I was thinking of the case where kwargs used to get silently ignored in recipes but that's not the case here.
exception =
│ Invalid attribute entrygroups for block type Legend.
│
│ The available block attributes for Legend are:
│
│ alignmode labeljustification markerstrokecolor rowgap
│ backgroundcolor labelsize markerstrokewidth tellheight
│ bgcolor labelvalign nbanks tellwidth
│ colgap linecolor orientation titlecolor
│ framecolor linecolormap padding titlefont
│ framevisible linecolorrange patchcolor titlegap
│ framewidth linepoints patchlabelgap titlehalign
│ gridshalign linestyle patchsize titleposition
│ gridsvalign linewidth patchstrokecolor titlesize
│ groupgap margin patchstrokewidth titlevalign
│ halign marker polycolor titlevisible
│ height markercolor polycolormap valign
│ label markercolormap polycolorrange width
│ labelcolor markercolorrange polypoints
│ labelfont markerpoints polystrokecolor
│ labelhalign markersize polystrokewidth
hehe...from the docs build
Legend seems weird. The entrygroups isn't an actual attribute, it's just a field defined in the struct defined in the @Block definition. But in the methods that are actually using it, it seems to get added directly in as an attribute afterwards.. what if I just do
function MakieCore.__valid_attributes(T::Type{<:Legend})
atrs = _attribute_docs(Legend)
atrs[:entrygroups] = ""
return keys(atrs)
end
unless someone can comment on what's going on with entrygroups here..
There are still some issues with the tests with this approach. I am guessing my method of determining the valid attributes is just not great, e.g. pallete and entrygroups are apparently valid for Axis but are not found with my method.
I think given that there are only one or two exceptions to the rule that Blocks have no further kwargs than their attributes, and it's not sure if that's actually necessary, it would be worth refactoring that mechanism such that initialize never takes kwargs. To me the feedback mechanism for wrong usage is much more important than these edge cases. If they cannot be removed completely.
Should that refactoring be handled in this PR? Currently I'm just trying to give a bandaid fix to my current solution but it could be pretty simple to refine it later.
I haven't checked yet what your solution is, but maybe these kwarg uses can just be converted to attributes.
I'll try and get that implemented.
There are a bunch of annoying parts here that I don't understand when trying to convert the kwargs to just be attributes. I think it would be simpler for this PR to just leave it as is and then come back to this issue at another time?
Sure, so what are you doing with those keywords now?
function MakieCore.__valid_attributes(T::Type{S}) where {S<:Block}
attrs = _attribute_docs(T)
# Some blocks have keyword arguments that are not attributes.
# TODO: Refactor intiailize_block! to just not use kwargs?
(S <: Axis || S <: PolarAxis) && (attrs[:palette] = "")
S <: Legend && (attrs[:entrygroups] = "")
S <: Menu && (attrs[:default] = "")
S <: LScene && (attrs[:scenekw] = "")
return keys(attrs)
end
They are just getting added into the available attributes (this function is only used in that error message)
Just a heads up that I probably won't get around to finishing this one up either to properly address your suggestions @SimonDanisch sorry, or at least not for quite a while (at which point I might have forgotten about this anyway 😅 ) now that I've got too much other stuff going on.
I replaced the __ functions:
__obj_nameis now part of InvalidAttributeError and gets set in separate constructors__valid_attributesis now justattribute_names__has_generic_attributesis now just a type check vs Plot
THanks!
Thanks for the help getting this completed @ffreyer :)