You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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:
Detecting which kwargs should be used for widget controls. These are generated by passing them to a Controls object
Writing an update function. This function updates the artists returned from the underlying matplotlib function
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:
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
Check if we were passed an ax and use that, otherwise grab the current axis. gogogo_figure
Check if the user specified the format strings any sliders we may be creating create_slider_format_dict
Extract any matplotlib styling kwargs so that we can pass them through kwarg_popper
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.
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.
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.
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 ofpyplot.py
Then also add the abbreviated version to
ipyplot.py
basic approach
mpl-interactions functions work by doing the following:
Controls
objectupdate
function. This function updates the artists returned from the underlying matplotlib functionStart of function
At the start of every interactive function we need to dor a few things:
notebook_backend
use_ipywidgets
ax
and use that, otherwise grab the current axis.gogogo_figure
create_slider_format_dict
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
inaxvline
). For these mpl-interactions supports all of: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
andvmax
. For these mpl-interactions adds avmin_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. Thegogogo_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
functionWe 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 theparams
as an argument and then use the appropriate matplotlibset___
method.The update function must have signature
(params, indices, cache)
.params
: a dict of the current parameter valuesindicies
: 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 nothttps://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 thaty
takes the result ofx
as an argumentThis is useful for cases like scatter where we may have separate functions for
x
andy
.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
The text was updated successfully, but these errors were encountered: