Interactive

spb.interactive.iplot(*args, show=True, **kwargs)[source]

Create an interactive application containing widgets and charts in order to study symbolic expressions.

Note: this function is already integrated with many of the usual plotting functions: since their documentation is more specific, it is highly recommended to use those instead.

However, the following documentation explains in details the main features exposed by the interactive module, which might not be included on the documentation of those other functions.

Parameters
argstuples

Each tuple represents an expression. Depending on the type of expression, the tuple should have the following forms:

  1. line: (expr, range, label [optional])

  2. parametric line: (expr1, expr2, expr3 [optional], range, label [optional])

  3. surface: (expr, range1, range2, label [optional])

  4. parametric surface: (expr1, expr2, expr3, range1, range2, label [optional])

The label is always optional, whereas the ranges must always be specified. The ranges will create the discretized domain.

paramsdict

A dictionary mapping the symbols to a parameter. The parameter can be:

  1. an instance of param.parameterized.Parameter.

  2. a tuple of the form: (default, min, max, N, tick_format, label, spacing) where:

    • default, min, maxfloat

      Default value, minimum value and maximum value of the slider, respectively. Must be finite numbers.

    • Nint, optional

      Number of steps of the slider.

    • tick_formatTickFormatter or None, optional

      Provide a formatter for the tick value of the slider. If None, panel will automatically apply a default formatter. Alternatively, an instance of bokeh.models.formatters.TickFormatter can be used. Default to None.

    • label: str, optional

      Custom text associated to the slider.

    • spacingstr, optional

      Specify the discretization spacing. Default to “linear”, can be changed to “log”.

Note that the parameters cannot be linked together (ie, one parameter cannot depend on another one).

aspect(float, float) or str, optional

Set the aspect ratio of the plot. The value depends on the backend being used. Read that backend’s documentation to find out the possible values.

backendPlot, optional

The backend to be used to generate the plot. It must be a subclass of spb.backends.base_backend.Plot. If not provided, the module will use the default backend.

color_funccallable, optional

A numerical function which defines the 2D line color or the surface color:

  • For 2D plots, a function of two variables is needed: x, y (the points computed by the internal algorithm).

  • For 3D surfaces, a function of three variables is needed: x, y, z (the points computed by the internal algorithm).

  • For 3D parametric surfaces, a function of five variables is needed: x, y, z, u, v (the points computed by the internal algorithm and the parameters).

For surface plots, the coloring is applied only if use_cm=True.

labellist/tuple, optional

The labels to be shown in the legend. If not provided, the string representation of expr will be used. The number of labels must be equal to the number of series generated by the plotting function.

layoutstr, optional

The layout for the controls/plot. Possible values:

  • ‘tb’: controls in the top bar.

  • ‘bb’: controls in the bottom bar.

  • ‘sbl’: controls in the left side bar.

  • ‘sbr’: controls in the right side bar.

Default layout to ‘tb’. Note that side bar layouts may not work well with some backends.

ncolsint, optional

Number of columns to lay out the widgets. Default to 2.

is_complexboolean, optional

Default to False. If True, it directs the internal algorithm to create all the necessary series to create a complex plot (for example, one for the real part, one for the imaginary part).

is_vectorboolean, optional

Default to False. If True, it directs the internal algorithm to create all the necessary series to create a vector plot (for example, plotting the magnitude of the vector field as a contour plot).

namestr, optional

The name to be shown on top of the interactive application, when served on a new browser window. Refer to servable to learn more. Default to an empty string.

pane_kwdict, optional

A dictionary of keyword/values which is passed to the pane containing the chart in order to further customize the output (read the Notes section to understand how the interactive plot is built). The following web pages shows the available options:

  • Refer to 2 for MatplotlibBackend. Two interesting options are:

    • interactive: wheter to activate the ipympl interactive backend.

    • dpi: set the dots per inch of the output png. Default to 96.

  • Refer to 3 for PlotlyBackend.

rendering_kwdict or list of dicts, optional

A dictionary of keywords/values which is passed to the backend’s function to customize the appearance of lines, surfaces, etc. Refer to the plotting library (backend) manual for more informations. If a list of dictionaries is provided, the number of dictionaries must be equal to the number of series generated by the plotting function.

servablebool, optional

Default to False, which will show the interactive application on the output cell of a Jupyter Notebook. If True, the application will be served on a new browser window.

showbool, optional

Default to True. If True, it will return an object that will be rendered on the output cell of a Jupyter Notebook. If False, it returns an instance of InteractivePlot, which can later be be shown by calling the show() method.

use_latexbool, optional

Default to True. If True, the latex representation of the symbols will be used in the labels of the parameter-controls. If False, the string representation will be used instead.

detect_polesboolean

Chose whether to detect and correctly plot poles in line plots. Defaulto to False. To improve detection, increase the number of discretization points n and/or change the value of eps.

epsfloat

An arbitrary small value used by the detect_poles algorithm. Default value to 0.1. Before changing this value, it is recommended to increase the number of discretization points.

n1, n2, n3int, optional

Set the number of discretization points in the three directions, respectively.

nint, optional

Set the number of discretization points on all directions. It overrides n1, n2, n3.

ncint, optional

Number of discretization points for the contour plot when is_vector=True.

throttledboolean, optional

Default to False. If True the recompute will be done at mouse-up event on sliders. If False, every slider tick will force a recompute.

titlestr, optional

Title of the plot.

xlabelstr, optional

Label for the x-axis.

ylabelstr, optional

Label for the y-axis.

zlabelstr, optional

Label for the z-axis.

xlim(float, float), optional

Denotes the x-axis limits, (min, max).

ylim(float, float), optional

Denotes the y-axis limits, (min, max).

zlim(float, float), optional

Denotes the z-axis limits, (min, max).

Notes

  1. This function is specifically designed to work within Jupyter Notebook. It is also possible to use it from a regular Python console, by executing: iplot(..., servable=True), which will create a server process loading the interactive plot on the browser. However, K3DBackend is not supported in this mode of operation.

  2. The interactive application generated by iplot consists of two main containers:

    • a pane containing the widgets.

    • a pane containing the chart. We can further customize this container by setting the pane_kw dictionary. Please, read its documentation to understand the available options.

  3. Some examples use an instance of PrintfTickFormatter to format the value shown by a slider. This class is exposed by Bokeh, but can be used by iplot with any backend. Refer to 1 for more information about tick formatting.

  4. It has been observed that Dark Reader (or other night-mode-enabling browser extensions) might interfere with the correct behaviour of the output of iplot. Please, consider adding localhost to the exclusion list of such browser extensions.

  5. Say we are creating two different interactive plots and capturing their output on two variables, using show=False. For example, p1 = iplot(..., show=False) and p2 = iplot(..., show=False). Then, running p1.show() on the screen will result in an error. This is standard behaviour that can’t be changed, as panel’s parameters are class attributes that gets deleted each time a new instance is created.

  6. MatplotlibBackend can be used, but the resulting figure is just a PNG image without any interactive frame. Thus, data exploration is not great. Therefore, the use of PlotlyBackend or BokehBackend is encouraged.

  7. Once this module has been loaded, there could be problems with all other plotting functions when using BokehBackend, namely the figure won’t show up in the output cell. If that is the case, we might try to turn off automatic updates on panning by setting update_event=False in the function call.

  8. When BokehBackend is used:

    • the user-defined theme won’t be applied.

    • rendering of gradient lines is slow.

    • color bars might not update their ranges.

  9. Once this module has been loaded and iplot has been executed, the safest procedure to restart Jupyter Notebook’s kernel is the following:

    • save the current notebook.

    • close the notebook and Jupyter server.

    • restart Jupyter server and open the notebook.

    • reload the cells.

    Failing to follow this procedure might results in the notebook to become unresponsive once the module has been reloaded, with several errors appearing on the output cell.

References

1

https://docs.bokeh.org/en/latest/docs/user_guide/styling.html#tick-label-formats

2

https://panel.holoviz.org/reference/panes/Matplotlib.html

3

https://panel.holoviz.org/reference/panes/Plotly.html

Examples

Surface plot between -10 <= x, y <= 10 with a damping parameter varying from 0 to 1, with a default value of 0.15, discretized with 50 points on both directions. Note the use of threed=True to specify a 3D plot. If threed=False, a contour plot will be generated.

from sympy import (symbols, sqrt, cos, exp, sin, pi, re, im,
    Matrix, Plane, Polygon, I, log)
from spb.interactive import iplot
from spb import PB
x, y, z = symbols("x, y, z")
r = sqrt(x**2 + y**2)
d = symbols('d')
expr = 10 * cos(r) * exp(-r * d)
iplot(
    (expr, (x, -10, 10), (y, -10, 10)),
    params = { d: (0.15, 0, 1) },
    title = "My Title",
    xlabel = "x axis",
    ylabel = "y axis",
    zlabel = "z axis",
    backend = PB,
    n = 51,
    threed = True,
    use_cm = True,
    use_latex=False,
    wireframe = True, wf_n1=15, wf_n2=15,
    wf_rendering_kw={"line_color": "#003428", "line_width": 0.75}
)

A line plot of the magnitude of a transfer function, illustrating the use of multiple expressions and:

  1. some expression may not use all the parameters.

  2. custom labeling of the expressions.

  3. custom rendering of the expressions.

  4. custom number of steps in the slider.

  5. custom format of the value shown on the slider. This might be useful to correctly visualize very small or very big numbers.

  6. custom labeling of the parameter-sliders.

from sympy import (symbols, sqrt, cos, exp, sin, pi, re, im,
    Matrix, Plane, Polygon, I, log)
from spb.interactive import iplot
from spb import MB
from bokeh.models.formatters import PrintfTickFormatter
formatter = PrintfTickFormatter(format="%.3f")
kp, t, z, o = symbols("k_P, tau, zeta, omega")
G = kp / (I**2 * t**2 * o**2 + 2 * z * t * o * I + 1)
mod = lambda x: 20 * log(sqrt(re(x)**2 + im(x)**2), 10)
iplot(
    (mod(G.subs(z, 0)), (o, 0.1, 100), "G(z=0)", {"linestyle": ":"}),
    (mod(G.subs(z, 1)), (o, 0.1, 100), "G(z=1)", {"linestyle": ":"}),
    (mod(G), (o, 0.1, 100), "G"),
    params = {
        kp: (1, 0, 3),
        t: (1, 0, 3),
        z: (0.2, 0, 1, 200, formatter, "z")
    },
    backend = MB,
    n = 2000,
    xscale = "log",
    xlabel = "Frequency, omega, [rad/s]",
    ylabel = "Magnitude [dB]",
    use_latex = False,
)

A line plot with a parameter representing an angle in radians, but showing the value in degrees on its label:

from sympy import sin, pi, symbols
from spb import MB
from spb.interactive import iplot
from bokeh.models.formatters import FuncTickFormatter
# Javascript code is passed to `code=`
formatter = FuncTickFormatter(code="return (180./3.1415926 * tick).toFixed(2)")
x, t = symbols("x, t")

iplot(
    (1 + x * sin(t), (x, -5, 5)),
    params = {
        t: (1, -2 * pi, 2 * pi, 100, formatter, "theta [deg]")
    },
    backend = MB,
    xlabel = "x", ylabel = "y",
    ylim = (-3, 4),
    use_latex = False,
)

Combine together InteractivePlot and Plot instances. The same parameters dictionary must be used for every iplot command. Note:

  1. the first plot dictates the labels, title and wheter to show the legend or not.

  2. Instances of Plot class must be place on the right side of the + sign.

  3. show=False has been set in order for iplot to return an instance of InteractivePlot, which supports addition.

  4. Once we are done playing with parameters, we can access the backend with p.backend. Then, we can use the p.backend.fig attribute to retrieve the figure, or p.backend.save() to save the figure.

from sympy import sin, cos, symbols
from spb import plot, MB
from spb.interactive import iplot
x, u = symbols("x, u")
params = {
    u: (1, 0, 2)
}
p1 = iplot(
    (cos(u * x), (x, -5, 5)),
    params = params,
    backend = MB,
    xlabel = "x1",
    ylabel = "y1",
    title = "title 1",
    legend = True,
    show = False,
    use_latex = False
)
p2 = iplot(
    (sin(u * x), (x, -5, 5)),
    params = params,
    backend = MB,
    xlabel = "x2",
    ylabel = "y2",
    title = "title 2",
    show = False
)
p3 = plot(sin(x)*cos(x), (x, -5, 5), dict(marker="^"), backend=MB,
    adaptive=False, n=50,
    is_point=True, is_filled=True, show=False)
p = p1 + p2 + p3
p.show()

Serves the interactive plot to a separate browser window. Note that K3DBackend is not supported for this operation mode. Also note the two ways to create a integer sliders.

import param
from spb.backends.bokeh import BB
from bokeh.models.formatters import PrintfTickFormatter
formatter = PrintfTickFormatter(format='%.4f')

p1, p2, t, r, c = symbols("p1, p2, t, r, c")
phi = - (r * t + p1 * sin(c * r * t) + p2 * sin(2 * c * r * t))
phip = phi.diff(t)
r1 = phip / (1 + phip)

iplot(
    (r1, (t, 0, 2*pi)),
    params = {
        p1: (0.035, -0.035, 0.035, 50, formatter),
        p2: (0.005, -0.02, 0.02, 50, formatter),
        # integer parameter created with param
        r: param.Integer(2, softbounds=(2, 5), label="r"),
        # integer parameter created with usual syntax
        c: (3, 1, 5, 4)
    },
    is_polar = True,
    use_latex = False,
    backend = BB,
    aspect = "equal",
    n = 5000,
    layout = "sbl",
    ncols = 1,
    servable = True,
    name = "Non Circular Planetary Drive - Ring Profile"
)
spb.interactive.create_series(*args, **kwargs)[source]

Create interactive data series, ie. series whose numerical data depends on the expression and all its parameters.

Typical usage examples are in the followings:

  • Create a single interactive series:

    create_series([expr, range], **kwargs)

  • Create multiple interactive series:

    create_series([(expr1, range1), (expr2, range2)], **kwargs)

The correct series type is instantiated only if all ranges are specified. So, to create an interactive line series, one range must be specified. To create an interactive surface series, two ranges must be provided, and so on.

Parameters
argslist/tuple

A list or tuple of the form [(expr1, range1), ...], where:

exprExpr

Expression (or expressions) representing the function to evaluate.

range: (symbol, min, max)

A 3-tuple (or multiple 3-tuple) denoting the range of the variable. For the function to work properly, all ranges must be provided.

paramsdict

A dictionary mapping symbols to numerical values. If not specified, iplot should be provided instead.

iplotInteractivePlot, optional

An existing instance of InteractivePlot from which the parameters will be extracted. If both params and iplot are provided, then iplot has the precedence.

is_complexboolean, optional

Default to False. If True, it directs the internal algorithm to create all the necessary series to create a complex plot (for example, one for the real part, one for the imaginary part, …).

is_polarboolean, optional

Default to False. If True:

  • for a 2D line plot requests the backend to use a polar chart.

  • for a 3D surface (or contour) requests a polar discretization. In this case, the first range represents the radius, the second one represents the angle.

is_vectorboolean, optional

Default to False. If True, it directs the internal algorithm to create all the necessary series to create a vector plot (for example, plotting the magnitude of the vector field as a contour plot, …).

n1, n2, n3int, optional

Number of discretization points in the 3 directions.

nint, optional

Set the same number of discretization points on all directions.

Returns
slist

A list of interactive data series.

See also

iplot, create_widgets

Notes

The keyword arguments to be provided depends on the interested data series to be created. For example, if we are trying to plot a line, then the same keyword argument associated to the plot() function can be used. Similarly, if we are trying to create vector-related interactive series, the same keyword arguments associated to plot_vector() can be used. And so on.

However, interactive data series do not support adaptive algorithms. Hence, adaptive-related keyword arguments will not be used.

Examples

>>> from sympy import (symbols, pi, sin, cos, exp, Plane,
...     Matrix, gamma, I, sqrt, Abs)
>>> from spb.interactive import create_series
>>> u, v, x, y, z = symbols('u, v, x:z')

2D line interactive series:

>>> s = create_series((u * sqrt(x), (x, -5, 5)), params={u: 1})
>>> print(len(s), type(s[0]))
(1, spb.series.LineInteractiveSeries)

2D parametric line interactive series:

>>> s = create_series((u * cos(x), u * sin(x), (x, -5, 5)), params={u: 1})
>>> len(s), type(s[0])
(1, spb.series.Parametric2DLineInteractiveSeries)

Multiple 2D lines interactive series:

>>> s = create_series(
...     (u * sqrt(x), (x, -5, 5)),
...     (cos(u * x), (x, -3, 3)),
...     params={u: 1})
>>> len(s), type(s[0]), type(s[1])
(2, spb.series.LineInteractiveSeries, spb.series.LineInteractiveSeries)

Surface interactive series:

>>> s = create_series((cos(x**2 + u * y**2), (x, -5, 5), (y, -5, 5)),
...     params={u: 1}, threed=True)
>>> len(s), type(s[0])
(1, spb.series.SurfaceInteractiveSeries)

Contour interactive series:

>>> s = create_series((cos(x**2 + u * y**2), (x, -5, 5), (y, -5, 5)),
...     params={u: 1}, threed=False)
>>> len(s), type(s[0])
(1, spb.series.ContourInteractiveSeries)

Interactive series of the absolute value of a complex function colored by its argument over a real domain. Note that we are passing is_complex=True:

>>> s = create_series((u * sqrt(x), (x, -5, 5)), params={u: 1},
...     is_complex=True)
>>> len(s), type(s[0])
(1, spb.series.AbsArgLineInteractiveSeries)

Real and imaginary parts of a complex function over a real domain:

>>> s = create_series((u * sqrt(x), (x, -5, 5)), params={u: 1},
...     is_complex=True, absarg=False, real=True, imag=True)
>>> len(s), type(s[0]), type(s[1])
(2, spb.series.LineInteractiveSeries, spb.series.LineInteractiveSeries)

Complex domain coloring interactive series:

>>> s = create_series((u * sqrt(x), (x, -5-5j, 5+5j)), params={u: 1},
...     is_complex=True)
>>> len(s), type(s[0])

Real and imaginary parts of a complex function over a complex domain:

>>> s = create_series((u * sqrt(x), (x, -5-5j, 5+5j)), params={u: 1},
...     is_complex=True, threed=True, absarg=False, real=True, imag=True)
>>> len(s), type(s[0]), type(s[1])
(2, spb.series.ComplexSurfaceInteractiveSeries, spb.series.ComplexSurfaceInteractiveSeries)

2D vector interactive series (only quivers):

>>> from sympy.vector import CoordSys3D
>>> N = CoordSys3D("N")
>>> i, j, k = N.base_vectors()
>>> x, y, z = N.base_scalars()
>>> a, b, c = symbols("a:c")
>>> v1 = -a * sin(y) * i + b * cos(x) * j
>>> s = create_series((v1, (x, -5, 5), (y, -4, 4)),
...     params={a: 2, b: 3}, is_vector=False)
>>> len(s), type(s[0])
(1, spb.series.Vector2DInteractiveSeries)

2D vector interactive series (contour + quivers):

>>> s = create_series((v1, (x, -5, 5), (y, -4, 4)),
...     params={a: 2, b: 3}, is_vector=True)
>>> len(s), type(s[0]), type(s[1])
(2, spb.series.ContourInteractiveSeries, spb.series.Vector2DInteractiveSeries)

Sliced 3D vector (single slice):

>>> from sympy import Plane
>>> v3 = a * z * i + b * y * j + c * x * k
>>> s = create_series((v3, (x, -5, 5), (y, -4, 4), (z, -6, 6)),
...     params={a: 2, b: 3, c: 1}, slice=Plane((1, 2, 3), (1, 0, 0)))
>>> len(s), type(s[0])
(1, spb.series.SliceVector3DInteractiveSeries)

Geometry interactive series:

>>> from sympy import Circle
>>> s = create_series((Circle((0, 0), u), ), params={u: 1})
>>> len(s), type(s[0])
(1, spb.series.GeometryInteractiveSeries)
spb.interactive.create_widgets(params, **kwargs)[source]

Create panel’s widgets starting from parameters.

Parameters
paramsdict

A dictionary mapping the symbols to a parameter. The parameter can be:

  1. an instance of param.parameterized.Parameter. Refer to 4 for a list of available parameters.

  2. a tuple of the form: (default, min, max, N, tick_format, label, spacing) where:

    • default, min, maxfloat

      Default value, minimum value and maximum value of the slider, respectively. Must be finite numbers.

    • Nint, optional

      Number of steps of the slider.

    • tick_formatTickFormatter or None, optional

      Provide a formatter for the tick value of the slider. If None, panel will automatically apply a default formatter. Alternatively, an instance of bokeh.models.formatters.TickFormatter can be used. Default to None.

    • label: str, optional

      Custom text associated to the slider.

    • spacingstr, optional

      Specify the discretization spacing. Default to “linear”, can be changed to “log”.

Note that the parameters cannot be linked together (ie, one parameter cannot depend on another one).

use_latexbool, optional

Default to True. If True, the latex representation of the symbols will be used in the labels of the parameter-controls. If False, the string representation will be used instead.

Returns
widgetsdict

A dictionary mapping the symbols from params to the appropriate widget.

See also

iplot, create_series

References

4

https://panel.holoviz.org/user_guide/Param.html

Examples

from sympy.abc import x, y, z
from spb.interactive import create_widgets
import param
from bokeh.models.formatters import PrintfTickFormatter
formatter = PrintfTickFormatter(format="%.4f")
r = create_widgets({
    x: (0.035, -0.035, 0.035, 100, formatter),
    y: (200, 1, 1000, 10, None, "test", "log"),
    z: param.Integer(3, softbounds=(3, 10), label="n")
})