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

How to add an interactive function - create a docs page #180

Open
ianhi opened this issue Apr 15, 2021 · 0 comments
Open

How to add an interactive function - create a docs page #180

ianhi opened this issue Apr 15, 2021 · 0 comments
Labels
documentation Improvements or additions to documentation enhancement New feature or request

Comments

@ianhi
Copy link
Collaborator

ianhi commented Apr 15, 2021

Problem

It's probably not clear to literally anyone in the world except me how to add a new function. This is obviously bad.

Suggested Improvement

Create a docs page with the basic steps. Explaining something like the following:

Adding your function:

Add it to the __all__ at the top of pyplot.py
Then also add the abbreviated version to ipyplot.py

basic approach

mpl-interactions functions work by doing the following:

  1. Detecting which kwargs should be used for widget controls. These are generated by passing them to a Controls object
  2. Writing an update function. This function updates the artists returned from the underlying matplotlib function
  3. Registering this update function with the controls object and which parameters it needs to listen to for changes.

Start of function

At the start of every interactive function we need to dor a few things:

  1. Check the function has been called from inside a notebook. This is in order to know if we should generate ipywidgets sliders or matplotlib sliders notebook_backend
    • This is then used to set the boolean use_ipywidgets
  2. Check if we were passed an ax and use that, otherwise grab the current axis. gogogo_figure
  3. Check if the user specified the format strings any sliders we may be creating create_slider_format_dict
  4. Extract any matplotlib styling kwargs so that we can pass them through kwarg_popper

https://github.com/ianhi/mpl-interactions/blob/99e1552266b8179c03583e585ad262c2670daa63/mpl_interactions/pyplot.py#L671-L675

Dealing with Scalars - optional

Some arguments to matplotlib functions are scalars (e.g. the x in axvline). For these mpl-interactions supports all of:

  • A number
  • a function
  • an indexed controls object: ctrls['x']

To handle all of this use the prep_scalar function like so:

https://github.com/ianhi/mpl-interactions/blob/f866678a9a535695c2c51e8e01ccaf23b06c4f29/mpl_interactions/pyplot.py#L810-L822

A special case of this is for functions with vmin and vmax. For these mpl-interactions adds a vmin_vmax argument that allows for specifying both as a range slider. This is handled like this:
https://github.com/ianhi/mpl-interactions/blob/f866678a9a535695c2c51e8e01ccaf23b06c4f29/mpl_interactions/pyplot.py#L686-L689

Creating a controls object

The Controls objects handle keeping tracking of the sliders and calling the functions that update the plots whenever the slider's values change. The gogogo_controls function handles the complexity of checking if we were passed an existing controls object and adding our kwargs to it, or with creating and displaying a new controls object.
It is defined here:
https://github.com/ianhi/mpl-interactions/blob/f866678a9a535695c2c51e8e01ccaf23b06c4f29/mpl_interactions/controller.py#L333

Here is an example usage in imshow

https://github.com/ianhi/mpl-interactions/blob/99e1552266b8179c03583e585ad262c2670daa63/mpl_interactions/pyplot.py#L691-L693

This gives us params for the first time. This is a dictionary of the values that we should pass to the functions that user provided.
e..g {'alpha': 5, 'beta': 1}

Creating an update function

We now need a function that will be called to update the plot. This function needs to know how to update the returned objects from the underlying matplotlib function.

The basic approach is to check if arguments are Callables and if so call them with the params as an argument and then use the appropriate matplotlib set___ method.

The update function must have signature (params, indices, cache).

params : a dict of the current parameter values
indicies: a dict of the indices of the sliders (mostly ignore this, it makes it easier to implement hyperslicer)
cache : a dictionary provided by the controls object. This is used to cache values from user functions so we don't call them multiple times with the same values. This is cleared after every slider update.

Useful helpers for this include:

callable_else_value which will handle the params cache and checking if an argument is function or not
https://github.com/ianhi/mpl-interactions/blob/f866678a9a535695c2c51e8e01ccaf23b06c4f29/mpl_interactions/pyplot.py#L709

callable_else_value_no_cast - the same as above except it never casts to a numpy array whereas callable_else_value always does.

eval_xy - like callable_else_value except that y takes the result of x as an argument
This is useful for cases like scatter where we may have separate functions for x and y.

https://github.com/ianhi/mpl-interactions/blob/f866678a9a535695c2c51e8e01ccaf23b06c4f29/mpl_interactions/pyplot.py#L161

Here is the update function for imshow
https://github.com/ianhi/mpl-interactions/blob/f866678a9a535695c2c51e8e01ccaf23b06c4f29/mpl_interactions/pyplot.py#L705-L717

Registering withe controls object

Then to attach our update function into the callbacks we register it with the controls:
https://github.com/ianhi/mpl-interactions/blob/f866678a9a535695c2c51e8e01ccaf23b06c4f29/mpl_interactions/pyplot.py#L719

Initial plotting call

Finally we need to call the plotting method from matplotlib. Here we pass through all of the arguments that we share with the underlying matplotlib function and also any kwargs that we ignored for our controls because they are accepted by matplotlib.

Here is the example for imshow:
https://github.com/ianhi/mpl-interactions/blob/99e1552266b8179c03583e585ad262c2670daa63/mpl_interactions/pyplot.py#L724-L740

and the slightly more complex version for scatter:

https://github.com/ianhi/mpl-interactions/blob/99e1552266b8179c03583e585ad262c2670daa63/mpl_interactions/pyplot.py#L561-L583

@ianhi ianhi added documentation Improvements or additions to documentation enhancement New feature or request labels Apr 15, 2021
@ianhi ianhi mentioned this issue Jul 19, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
documentation Improvements or additions to documentation enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

1 participant