Skip to content

Name collision(s) in pyplot.interactive_plot #295

@origen-jak

Description

@origen-jak

Bug report

My first time using this library and just by chance I managed to run into a weird edge case in the first few minutes:

Bug summary

If you use a variable name in your target function, that is also declared in the pyplot.interactive_plot function, it'll throw a confusing TypeError due to the name collision. For me it was declaring a variable named xlim.

Code for reproduction

Using the Basic example from the doc's, but changing the declared variable name in the user defined function f to trigger a name collision:

%matplotlib ipympl
import matplotlib.pyplot as plt
import numpy as np

import mpl_interactions.ipyplot as iplt

# Name collision defined here: xlim
def f(x, xlim, beta):
    return np.sin(x * xlim) * x**beta

x = np.linspace(0, 2 * np.pi, 1000)
xlim = np.linspace(5, 10)
beta = np.linspace(0.25, 1)

fig, ax = plt.subplots()
controls = iplt.plot(x, f, xlim=xlim, beta=beta)  # Pow!

Actual outcome

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[1], line 15
     12 beta = np.linspace(0.25, 1)
     14 fig, ax = plt.subplots()
---> 15 controls = iplt.plot(x, f, xlim=xlim, beta=beta)

File ...\mpl_interactions\pyplot.py:227, in interactive_plot(parametric, ax, slider_formats, xlim, ylim, force_ipywidgets, play_buttons, controls, display_controls, *args, **kwargs)
    224 controls._register_function(update, fig, params.keys())
    226 if x_and_y:
--> 227     x_, y_ = eval_xy(x, y, params)
    228     if fmt:
    229         lines = ax.plot(x_, y_, fmt, **plot_kwargs)

File ...\mpl_interactions\helpers.py:173, in eval_xy(x_, y_, params, cache)
    171             cache[y_] = y
    172     else:
--> 173         y = y_(x, **params)
    174 else:
    175     y = y_

TypeError: f() missing 1 required positional argument: 'xlim'

The exception thrown is confusing as it classifies xlim as a missing positional argument, when the user supplied it as a keyword argument.

Expected outcome

The code should work without throwing an exception, exactly as in the documentation.

Some ideas for a fix:

  • prefix all the variables declared in interactive_plot with a _.: e.g. _xlim
  • Add a validation step to check for name collisions and throw a helpful exception if found. e.g. '_xlim is a reserved name, please change your argument name in function f' or similar.

Thanks for your work, it's a helpful package.

Version Info

  • Operating system: Windows 11
  • Matplotlib version: 3.8.0
  • Matplotlib backend (print(matplotlib.get_backend())): ipympl.backend_nbagg
  • Python version: 3.11.5

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions