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

Error on unknown plot attributes #2966

Closed
wants to merge 25 commits into from

Conversation

jkrumbiegel
Copy link
Member

Description

It's quite annoying that plot functions silently accept misspelled keyword arguments. The reason is that unlike Blocks like Axis etc., plot objects like Scatter do not have a completely well-defined list of attributes that they accept. Instead, they have dynamically generated default themes that might merge in themes of other plot types etc.

Also, there are a couple of extra keyword arguments in use that are not meant for the plot objects themselves but serve as metadata for other functionality, for example if xautolimits = false is encountered by an Axis, it will ignore the x-dimension of that plot for the limit calculation. Because this system has grown in a rather ad-hoc way where keywords were added by different people for different reasons, it's a bit messy and unclear what's allowed and what's not.

Still I believe an allowlist that is too broad is better than having none at all, especially because misspelled keyword arguments are the main thing we want to filter out.

So here I've implemented a very simple method, I just crosscheck the input plot attributes against the keys in the dynamically generated default theme, and against a (for now static and general) allowlist. If it's not in there it's likely to be wrong. Helpfully, a list of all allowed keywords is printed out for the user to quickly find the correct spelling, for example.

It looks like this:

image

I made some simple plots in the REPL which worked after making a short allowlist, however I'm sure CI will uncover quite a few more that need to be added.

@MakieBot
Copy link
Collaborator

MakieBot commented May 19, 2023

Compile Times benchmark

Note, that these numbers may fluctuate on the CI servers, so take them with a grain of salt. All benchmark results are based on the mean time and negative percent mean faster than the base branch. Note, that GLMakie + WGLMakie run on an emulated GPU, so the runtime benchmark is much slower. Results are from running:

using_time = @ctime using Backend
# Compile time
create_time = @ctime fig = scatter(1:4; color=1:4, colormap=:turbo, markersize=20, visible=true)
display_time = @ctime Makie.colorbuffer(display(fig))
# Runtime
create_time = @benchmark fig = scatter(1:4; color=1:4, colormap=:turbo, markersize=20, visible=true)
display_time = @benchmark Makie.colorbuffer(display(fig))
using create display create display
GLMakie 11.96s (11.80, 12.34) 0.18+- 1.10s (1.06, 1.17) 0.04+- 802.43ms (779.08, 852.65) 26.11+- 11.19ms (10.92, 11.39) 0.18+- 90.54ms (89.20, 92.19) 0.93+-
master 12.12s (11.95, 12.24) 0.10+- 1.11s (1.08, 1.14) 0.02+- 814.34ms (784.99, 839.91) 17.55+- 11.02ms (10.80, 11.25) 0.15+- 90.02ms (89.38, 91.35) 0.68+-
evaluation -1.35%, -0.16s invariant (-1.12d, 0.07p, 0.14std) -1.57%, -0.02s invariant (-0.62d, 0.28p, 0.03std) -1.48%, -11.9ms invariant (-0.54d, 0.34p, 21.83std) +1.46%, 0.16ms invariant (1.00d, 0.09p, 0.16std) +0.58%, 0.53ms invariant (0.65d, 0.25p, 0.80std)
CairoMakie 11.93s (11.49, 12.24) 0.24+- 1.38s (1.27, 1.42) 0.05+- 263.64ms (241.88, 280.07) 11.52+- 12.52ms (12.27, 12.91) 0.22+- 6.01ms (5.79, 6.23) 0.15+-
master 11.88s (11.54, 12.40) 0.29+- 1.36s (1.31, 1.44) 0.04+- 264.39ms (255.15, 274.36) 7.10+- 12.23ms (11.82, 12.48) 0.20+- 6.95ms (6.73, 7.12) 0.13+-
evaluation +0.42%, 0.05s invariant (0.19d, 0.73p, 0.26std) +1.15%, 0.02s invariant (0.34d, 0.54p, 0.05std) -0.28%, -0.74ms invariant (-0.08d, 0.89p, 9.31std) +2.32%, 0.29ms slower X (1.40d, 0.02p, 0.21std) -15.67%, -0.94ms faster✅ (-6.78d, 0.00p, 0.14std)
WGLMakie 12.04s (11.99, 12.10) 0.04+- 1.33s (1.30, 1.36) 0.02+- 11.64s (11.48, 11.87) 0.12+- 13.83ms (13.19, 14.57) 0.42+- 1.14s (1.10, 1.17) 0.02+-
master 12.06s (12.01, 12.11) 0.04+- 1.33s (1.30, 1.37) 0.02+- 11.65s (11.50, 11.85) 0.14+- 13.91ms (13.29, 14.83) 0.47+- 1.12s (1.07, 1.17) 0.03+-
evaluation -0.14%, -0.02s invariant (-0.42d, 0.44p, 0.04std) +0.04%, 0.0s invariant (0.02d, 0.97p, 0.02std) -0.10%, -0.01s invariant (-0.09d, 0.87p, 0.13std) -0.58%, -0.08ms invariant (-0.18d, 0.74p, 0.44std) +1.43%, 0.02s invariant (0.58d, 0.30p, 0.03std)

plot_attributes = merged_get!(
()-> default_theme(scene, FinalType),
plotsym(FinalType), scene, attributes
plotsym(FinalType), scene, attributes;
allowlist = Set([:text, :xautolimits, :yautolimits, :zautolimits, :interpolate_in_fragment_shader, :label, :fxaa, :rasterize, :model])
Copy link
Member

Choose a reason for hiding this comment

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

inspectable, material, texture, transformation, are also things which should be added, plus all the GLMakie lighting stuff (specular, diffuse, etc)

It would also be nice to have a signature which does not perform this check, for easy programmatic passing of attributes inherited from the parent plot!

Copy link
Member Author

Choose a reason for hiding this comment

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

transformation is already removed elsewhere prior to this check

Wouldn't it be better to group all backend related keywords under one umbrella rather than just letting them potentially collide with the rest?

I think I would like it better if an RPRMakie plot had meshscatter(data; RPRMakie = (; material = ...)

Copy link
Member Author

Choose a reason for hiding this comment

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

same for GLMakie

Copy link
Member Author

Choose a reason for hiding this comment

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

and rasterize in CairoMakie

Copy link
Collaborator

Choose a reason for hiding this comment

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

If we want both name checking and the ability to add arbitrary attributes to a plot we need to separate them somehow. I was thinking we could have one whitelisted attribute Dict of core attributes, which may become fields of specific plot object (struct Scatter ... end etc) if we want that, and one Dict with everything else.

Having RPRMakie = (; ...) etc is similar to that I guess. Though I would say attributes that influence other objects (inspectable, label, ...) and overwrites (model, view, ...) should also move out of the directly defined attributes. I guess the latter could also be part of the backend groups. The former is kind of the "random stuff that you want to attach to a plot" group, which I think is useful to have in a dynamic way.

Copy link
Member Author

@jkrumbiegel jkrumbiegel May 19, 2023

Choose a reason for hiding this comment

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

random stuff that you want to attach to a plot

You could still do that by doing plotobject.attributes[:something] = xyz no? For me it's currently most important to make our user interface more robust against user error

Copy link
Member Author

Choose a reason for hiding this comment

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

we could also add a misc allowed key or something which should only ever be set to an Attributes instance with further keys. Then we could disallow such a key for any other recipe so we know it will never conflict, and people can use it to carry arbitrary stuff forward. I want to avoid a situation where people make recipes and we break them by introducing some new add-on keyword arg.

@jariji
Copy link
Contributor

jariji commented Jun 27, 2023

misspelled keyword arguments are the main thing we want to filter out.

In my case I pass kwargs to the wrong function. Eg I pass something to scatter that I'm supposed to pass to Axis or Figure. Maybe it could hint "this keyword doesn't apply here, it's supposed to go in Axis" or something.

@jkrumbiegel
Copy link
Member Author

jkrumbiegel commented Oct 18, 2023

This has not moved forward in a while, I think the main blocker was that we do like to add certain special attributes to plots here and there, and there was no way to detect them.

Now I had the idea, what if we solve this by convention and say, any keyword starting with _ is ignored? Of course people can then still misspell a bunch of things starting with _, but at least for the normal keywords, this would solve the problem. I think we already kind of follow the convention to name "secret" attributes with _. And we could further formalize this by hiding such attributes from tab-completion.

Edit:

The other thing that's difficult is backend-specific keywords. But we could also solve this by convention and prefix those with GL, WGL, CM or RPR or something. Then at least it would be clear where those are going. Like RPR_some_material_property.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants