symplot#

Create interactive plots for sympy expressions.

The procedure to create interactive plots with for sympy expressions with mpl-interactions has been extracted to this module.

The module is only available here, under the documentation. If this feature turns out to be popular, it can be published as an independent package.

The package also provides other helpful functions, like substitute_indexed_symbols(), that are useful when visualizing sympy expressions.

Slider#

Allowed ipywidgets slider types.

alias of Union[FloatSlider, IntSlider]

RangeDefinition#

Types of range definitions used in set_ranges().

alias of Union[Tuple[float, float], Tuple[float, float, Union[float, int]]]

class SliderKwargs(sliders: Mapping[str, FloatSlider | IntSlider], arg_to_symbol: Mapping[str, str])[source]#

Bases: Mapping

Wrapper around a dict of sliders that can serve as keyword arguments.

Sliders can be defined in interactive_plot() through kwargs. This wrapper class can be used for that.

__getitem__(key: str | Symbol) FloatSlider | IntSlider[source]#

Get slider by symbol, symbol name, or argument name.

property arg_to_symbol: dict[str, str][source]#

Copy of the internal translation dict for argument names.

property symbol_to_arg: dict[str, str][source]#

Inverted dict of arg_to_symbol.

set_values(*args: dict[str, float], **kwargs: float) None[source]#

Set initial values for the sliders.

Either use a dict as input, or use kwargs with slider names as the keywords (see SliderKwargs.__getitem__). This façade method exists in particular for parameter_defaults.

set_ranges(*args: dict[str, Tuple[float, float] | Tuple[float, float, float | int]], **kwargs: Tuple[float, float] | Tuple[float, float, float | int]) None[source]#

Set min, max and (optionally) the nr of steps for each slider.

Tip

n_steps becomes the step size if its value is float.

prepare_sliders(expression: Expr, plot_symbol: Symbol | tuple[Symbol, ...]) tuple[Callable, SliderKwargs][source]#

Lambdify a sympy expression and create sliders for its arguments.

>>> n = sp.Symbol("n", integer=True)
>>> x = sp.Symbol("x")
>>> expression, sliders = prepare_sliders(x**n, plot_symbol=x)
>>> expression
<function _lambdifygenerated at ...>
>>> sliders
SliderKwargs(...)
create_slider(symbol: Symbol) FloatSlider | IntSlider[source]#

Create an int or float slider, depending on Symbol assumptions.

The description for the slider is rendered as LaTeX from the Symbol name.

>>> create_slider(sp.Symbol("a"))
FloatSlider(value=0.0, description='\\(a\\)')
>>> create_slider(sp.Symbol("n0", integer=True))
IntSlider(value=0, description='\\(n_{0}\\)')
partial_doit(expression: Expr, doit_classes: type[Basic] | tuple[type[Basic], ...]) Expr[source]#

Perform doit() up to a certain level.

Parameters:
  • expression (the Expr on which you want to perform a) – doit().

  • doit_classes (types on which the doit() should be) – performed.

rename_symbols(expression: Expr, renames: Callable[[str], str] | dict[str, str]) Expr[source]#

Rename symbols in an expression.

>>> a, b, x = sp.symbols(R"a \beta x")
>>> expr = a + b * x
>>> rename_symbols(expr, renames={"a": "A", R"\beta": "B"})
A + B*x
>>> rename_symbols(expr, renames=lambda s: s.replace("\\", ""))
a + beta*x
>>> rename_symbols(expr, renames={"non-existent": "c"})
Traceback (most recent call last):
    ...
KeyError: "No symbol with name 'non-existent' in expression"
substitute_indexed_symbols(expression: Expr) Expr[source]#

Substitute IndexedBase with symbols.

See Indexed free symbols for more info.

Examples#

The following examples show how to work with prepare_sliders() and the resulting SliderKwargs. For more explanation about what happens behind the scenes, see Inspect model interactively.

Exponential wave#

Construct a mathematical expression with sympy:

import sympy as sp

n = sp.Symbol("n", integer=True)
x, a = sp.symbols("x, a")
expression = sp.sin(n * x) * sp.exp(-a * x)
expression
\[\displaystyle e^{- a x} \sin{\left(n x \right)}\]

Create sliders with prepare_sliders(), set their ranges and (optionally) provide some initial values:

from symplot import prepare_sliders

np_expression, sliders = prepare_sliders(expression, plot_symbol=x)
sliders.set_ranges(
    n=(0, 10),
    a=(-1, 1, 200),
)
sliders.set_values(n=6, a=0.3)

Now use mpl-interactions to plot the lambdified expression. Note how the SliderKwargs are unpacked as keyword arguments:

%matplotlib widget
%config InlineBackend.figure_formats = ['svg']

import matplotlib.pyplot as plt
import mpl_interactions.ipyplot as iplt
import numpy as np

plot_domain = np.linspace(0, 10, 1_000)
fig, ax = plt.subplots(figsize=(7, 4))
controls = iplt.plot(
    plot_domain,
    np_expression,
    **sliders,
    ylim="auto",
)
ax.set_xlabel("$x$")
ax.set_ylabel(f"${sp.latex(expression)}$");
../../_images/a3273441aa60a84fb6196405836216e8fbcfb07959a5e8d6ed878e6174beadb5.png

Range slider#

See Using RangeSliders.

np_expression, sliders = prepare_sliders(expression, plot_symbol=x)
sliders.set_values(n=6, a=0.3)
sliders.set_ranges(
    n=(0, 10),
    a=(-1, 1, 200),
)


def x_domain(x_range, **kwargs):
    min_, max_ = x_range
    return np.linspace(min_, max_, 1_000)


def f(x, **kwargs):
    del kwargs["x_range"]
    return np_expression(x, **kwargs)


fig, ax = plt.subplots()
controls = iplt.plot(
    x_domain,
    f,
    x_range=("r", 0, 10),
    **sliders,
    xlim="auto",
    ylim="auto",
)