MakieOrg / Makie.jl

Interactive data visualizations and plotting in Julia
https://docs.makie.org/stable
MIT License
2.4k stars 306 forks source link

Forward axis kwargs from plot constructors (user friendliness) #3745

Closed IanButterworth closed 1 month ago

IanButterworth commented 6 months ago

I think it would be good to accommodate this kind of typical plotting pattern for setting things like titles and labels

julia> scatter(x, y, markersize=1, title="myplot", xlabel="foo", ylabel="bar")
Error showing value of type Makie.FigureAxisPlot:
ERROR: MethodError: no method matching gl_convert(::String)

Closest candidates are:
  gl_convert(::GLMakie.GLAbstraction.LazyShader, ::Any)
   @ GLMakie ~/.julia/packages/GLMakie/MDlNU/src/GLAbstraction/GLShader.jl:194
  gl_convert(::GLMakie.GLAbstraction.GLProgram, ::Any)
   @ GLMakie ~/.julia/packages/GLMakie/MDlNU/src/GLAbstraction/GLShader.jl:119
  gl_convert(::GLMakie.GLAbstraction.ShaderCache, ::GLMakie.GLAbstraction.AbstractLazyShader, ::Any)
   @ GLMakie ~/.julia/packages/GLMakie/MDlNU/src/GLAbstraction/GLShader.jl:198
  ...

Stacktrace:
  [1] #map#13
    @ ~/.julia/packages/Observables/YdEbO/src/Observables.jl:570 [inlined]
  [2] map
    @ ~/.julia/packages/Observables/YdEbO/src/Observables.jl:568 [inlined]
  [3] const_lift
    @ ~/.julia/packages/GLMakie/MDlNU/src/GLAbstraction/GLUtils.jl:106 [inlined]
  [4] gl_convert(s::Observable{String})
    @ GLMakie.GLAbstraction ~/.julia/packages/GLMakie/MDlNU/src/GLAbstraction/GLUniforms.jl:238
  [5] GLMakie.GLAbstraction.RenderObject(data::Dict{…}, program::GLMakie.GLVisualizeShader, pre::GLMakie.GLAbstraction.StandardPrerender, post::GLFW.Window, context::GLFW.Window)
    @ GLMakie.GLAbstraction ~/.julia/packages/GLMakie/MDlNU/src/GLAbstraction/GLTypes.jl:386
  [6] GLMakie.GLAbstraction.RenderObject(data::Dict{…}, program::GLMakie.GLVisualizeShader, pre::GLMakie.GLAbstraction.StandardPrerender, post::GLFW.Window)
    @ GLMakie.GLAbstraction ~/.julia/packages/GLMakie/MDlNU/src/GLAbstraction/GLTypes.jl:346
  [7] assemble_shader(data::Dict{Symbol, Any})
    @ GLMakie ~/.julia/packages/GLMakie/MDlNU/src/glshaders/visualize_interface.jl:108
  [8] draw_scatter(screen::Any, ::Any, data::Any)
    @ GLMakie ~/.julia/packages/GLMakie/MDlNU/src/glshaders/particles.jl:250
  [9] (::GLMakie.var"#227#234"{GLMakie.Screen{GLFW.Window}, Scene, Scatter{Tuple{Vector{Point{2, Float32}}}}})(gl_attributes::Dict{Symbol, Any})
    @ GLMakie ~/.julia/packages/GLMakie/MDlNU/src/drawing_primitives.jl:435
 [10] (::GLMakie.var"#209#216"{GLMakie.var"#227#234"{GLMakie.Screen{…}, Scene, Scatter{…}}, GLMakie.Screen{GLFW.Window}, Scene, Scatter{Tuple{…}}})()
    @ GLMakie ~/.julia/packages/GLMakie/MDlNU/src/drawing_primitives.jl:305
 [11] get!(default::GLMakie.var"#209#216"{…}, h::Dict{…}, key::UInt64)
    @ Base ./dict.jl:479
 [12] cached_robj!(robj_func::GLMakie.var"#227#234"{…}, screen::GLMakie.Screen{…}, scene::Scene, plot::Scatter{…})
    @ GLMakie ~/.julia/packages/GLMakie/MDlNU/src/drawing_primitives.jl:234
 [13] draw_atomic(screen::GLMakie.Screen{GLFW.Window}, scene::Scene, plot::Union{Scatter, MeshScatter})
    @ GLMakie ~/.julia/packages/GLMakie/MDlNU/src/drawing_primitives.jl:379
 [14] insert!(screen::GLMakie.Screen{GLFW.Window}, scene::Scene, x::Plot)
    @ GLMakie ~/.julia/packages/GLMakie/MDlNU/src/drawing_primitives.jl:322
 [15] insertplots!(screen::GLMakie.Screen{GLFW.Window}, scene::Scene)
    @ GLMakie ~/.julia/packages/GLMakie/MDlNU/src/screen.jl:477
 [16] insertplots!(screen::GLMakie.Screen{GLFW.Window}, scene::Scene) (repeats 2 times)
    @ GLMakie ~/.julia/packages/GLMakie/MDlNU/src/screen.jl:480
 [17] display_scene!(screen::GLMakie.Screen{GLFW.Window}, scene::Scene)
    @ GLMakie ~/.julia/packages/GLMakie/MDlNU/src/screen.jl:408
 [18] GLMakie.Screen(scene::Scene, config::GLMakie.ScreenConfig; visible::Nothing, start_renderloop::Bool)
    @ GLMakie ~/.julia/packages/GLMakie/MDlNU/src/screen.jl:425
 [19] GLMakie.Screen(scene::Scene, config::GLMakie.ScreenConfig)
    @ GLMakie ~/.julia/packages/GLMakie/MDlNU/src/screen.jl:421
 [20] getscreen(::Module, ::Scene, ::Dict{Symbol, Any})
    @ Makie ~/.julia/packages/Makie/z2T2o/src/display.jl:427
 [21] display(figlike::Makie.FigureAxisPlot; backend::Module, inline::Bool, update::Bool, screen_config::@Kwargs{})
    @ Makie ~/.julia/packages/Makie/z2T2o/src/display.jl:165
 [22] display(figlike::Makie.FigureAxisPlot)
    @ Makie ~/.julia/packages/Makie/z2T2o/src/display.jl:130
 [23] print_response(errio::IO, response::Any, show_value::Bool, have_color::Bool, specialdisplay::Union{Nothing, AbstractDisplay})
    @ REPL ~/.julia/juliaup/julia-1.10.2+0.aarch64.apple.darwin14/share/julia/stdlib/v1.10/REPL/src/REPL.jl:0
 [24] (::REPL.var"#57#58"{REPL.LineEditREPL, Pair{Any, Bool}, Bool, Bool})(io::Any)
    @ REPL ~/.julia/juliaup/julia-1.10.2+0.aarch64.apple.darwin14/share/julia/stdlib/v1.10/REPL/src/REPL.jl:284
 [25] with_repl_linfo(f::Any, repl::REPL.LineEditREPL)
    @ REPL ~/.julia/juliaup/julia-1.10.2+0.aarch64.apple.darwin14/share/julia/stdlib/v1.10/REPL/src/REPL.jl:569
 [26] print_response(repl::REPL.AbstractREPL, response::Any, show_value::Bool, have_color::Bool)
    @ REPL ~/.julia/juliaup/julia-1.10.2+0.aarch64.apple.darwin14/share/julia/stdlib/v1.10/REPL/src/REPL.jl:282
 [27] (::REPL.var"#do_respond#80"{Bool, Bool, REPL.var"#93#103"{…}, REPL.LineEditREPL, REPL.LineEdit.Prompt})(s::REPL.LineEdit.MIState, buf::Any, ok::Bool)
    @ REPL ~/.julia/juliaup/julia-1.10.2+0.aarch64.apple.darwin14/share/julia/stdlib/v1.10/REPL/src/REPL.jl:911
 [28] #invokelatest#2
    @ ./essentials.jl:892 [inlined]
 [29] invokelatest
    @ ./essentials.jl:889 [inlined]
 [30] run_interface(terminal::REPL.Terminals.TextTerminal, m::REPL.LineEdit.ModalInterface, s::REPL.LineEdit.MIState)
    @ REPL.LineEdit ~/.julia/juliaup/julia-1.10.2+0.aarch64.apple.darwin14/share/julia/stdlib/v1.10/REPL/src/LineEdit.jl:2656
 [31] run_frontend(repl::REPL.LineEditREPL, backend::REPL.REPLBackendRef)
    @ REPL ~/.julia/juliaup/julia-1.10.2+0.aarch64.apple.darwin14/share/julia/stdlib/v1.10/REPL/src/REPL.jl:1312
 [32] (::REPL.var"#62#68"{REPL.LineEditREPL, REPL.REPLBackendRef})()
    @ REPL ~/.julia/juliaup/julia-1.10.2+0.aarch64.apple.darwin14/share/julia/stdlib/v1.10/REPL/src/REPL.jl:386
Some type information was truncated. Use `show(err)` to see complete types.

Either/and:

  1. have it just work by forwarding any kwargs that Axis can take to the active axis
  2. do a very early check for any unsupported kwargs, so the user gets a friendly message and not a huge stacktrace
  3. at least give a more friendly error. The current one is really unfriendly and has a massive stacktrace

Also, the function xlabel("foo") not existing adds further pain, because the user has seen that scatter(...) works without specifying the active axis...

And the hint to the method here xlabel!(::Any, ::AbstractString) isn't informative because of Any.

julia> xlabel!("foo")
ERROR: MethodError: no method matching xlabel!(::String)

Closest candidates are:
  xlabel!(::Any, ::AbstractString)
   @ Makie ~/.julia/packages/Makie/z2T2o/src/shorthands.jl:13

Stacktrace:
 [1] top-level scope
   @ REPL[27]:1

Also, to add a little more pain

jkrumbiegel commented 6 months ago

we do this by grouping them under axis and figure keywords so they cannot clash with the plot keywords.

scatter(x, y, markersize=1, axis = (; title="myplot", xlabel="foo", ylabel="bar"))

Also, in 0.21 you will get much better errors for this kind of stuff:

grafik

We could also add a hint there if we find keywords probably meant for Axis or Figure

IanButterworth commented 6 months ago

Oh wow. Yeah that's great 👍

ffreyer commented 1 month ago

Closing as, hmm, already implemented in a different way?