2D general plotting

NOTE: For technical reasons, all interactive-widgets plots in this documentation are created using Holoviz’s Panel. Often, they will ran just fine with ipywidgets too. However, if a specific example uses the param library, or widgets from the panel module, then users will have to modify the params dictionary in order to make it work with ipywidgets. Refer to Interactive module for more information.

spb.graphics.functions_2d.line(expr, range=None, label=None, rendering_kw=None, **kwargs)[source]

Plot a function of one variable over a 2D space.

Parameters:
exprExpr or callable

It can either be a symbolic expression representing the function of one variable to be plotted, or a numerical function of one variable, supporting vectorization. In the latter case the following keyword arguments are not supported: params, sum_bound.

range(symbol, min, max)

A 3-tuple denoting the range of the x variable. Default values: min=-10 and max=10.

labelstr, optional

The label to be shown in the legend. If not provided, the string representation of expr will be used.

rendering_kwdict, optional

A dictionary of keywords/values which is passed to the backend’s function to customize the appearance of lines. Refer to the plotting library (backend) manual for more informations.

adaptivebool, optional

Setting adaptive=True activates the adaptive algorithm implemented in [python-adaptive] to create smooth plots. Use adaptive_goal and loss_fn to further customize the output.

The default value is False, which uses an uniform sampling strategy, where the number of discretization points is specified by the n keyword argument.

adaptive_goalcallable, int, float or None

Controls the “smoothness” of the evaluation. Possible values:

  • None (default): it will use the following goal: lambda l: l.loss() < 0.01

  • number (int or float). The lower the number, the more evaluation points. This number will be used in the following goal: lambda l: l.loss() < number

  • callable: a function requiring one input element, the learner. It must return a float number. Refer to [python-adaptive] for more information.

color_funccallable or Expr, optional

Define the line color mapping. It can either be:

  • A numerical function of 2 variables, x, y (the points computed by the internal algorithm) supporting vectorization.

  • A symbolic expression having at most as many free symbols as expr.

  • None: the default value (no color mapping).

detect_polesboolean or str, optional

Chose whether to detect and correctly plot poles. There are two algorithms at work:

  1. based on the gradient of the numerical data, it introduces NaN values at locations where the steepness is greater than some threshold. This splits the line into multiple segments. To improve detection, increase the number of discretization points n and/or change the value of eps.

  2. a symbolic approach based on the continuous_domain function from the sympy.calculus.util module, which computes the locations of discontinuities. If any is found, vertical lines will be shown.

Possible options:

  • True: activate poles detection computed with the numerical gradient.

  • False: no poles detection.

  • "symbolic": use both numerical and symbolic algorithms.

Default to False.

epsfloat, optional

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.

excludelist, optional

A list of numerical values in the horizontal coordinate which are going to be excluded from the plot. In practice, it introduces discontinuities in the resulting line.

force_real_evalboolean, optional

Default to False, with which the numerical evaluation is attempted over a complex domain, which is slower but produces correct results. Set this to True if performance is of paramount importance, but be aware that it might produce wrong results. It only works with adaptive=False.

scatterboolean, optional

Default to False, which will render a line connecting all the points. If True, a scatter plot will be generated.

fillboolean, optional

Default to True, which will render empty circular markers. It only works if scatter=True. If False, filled circular markers will be rendered.

loss_fncallable or None

The loss function to be used by the adaptive learner. Possible values:

  • None (default): it will use the default_loss from the adaptive module.

  • callable : Refer to [python-adaptive] for more information. Specifically, look at adaptive.learner.learner1D to find more loss functions.

nint, optional

Used when the adaptive=False: the function is uniformly sampled at n number of points. Default value to 1000. If the adaptive=True, this parameter will be ignored.

only_integersboolean, optional

Default to False. If True, discretize the domain with integer numbers. It only works when adaptive=False. When only_integers=True, the number of discretization points is choosen by the algorithm.

paramsdict

A dictionary mapping symbols to parameters. This keyword argument enables the interactive-widgets plot, which doesn’t support the adaptive algorithm (meaning it will use adaptive=False). Learn more by reading the documentation of the interactive sub-module.

steps{‘pre’, ‘post’, ‘mid’, False}, default: False, optional

If set, it connects consecutive points with steps rather than straight segments.

sum_boundint, optional

When plotting sums, the expression will be pre-processed in order to replace lower/upper bounds set to +/- infinity with this +/- numerical value. Default value to 1000. Note: the higher this number, the slower the evaluation.

tx, tycallable, optional

Apply a numerical function to the discretized x-direction or to the output of the numerical evaluation, the y-direction.

xscale‘linear’ or ‘log’, optional

Sets the scaling of the discretized range. Default to 'linear'.

Returns:
serieslist

A list containing one instance of LineOver1DRangeSeries.

Examples

>>> from sympy import symbols, sin, pi, tan, exp, cos, log, floor
>>> from spb import *
>>> x, y = symbols('x, y')

(Source code)

Single Plot

>>> graphics(line(x**2, (x, -5, 5)))
Plot object containing:
[0]: cartesian line: x**2 for x over (-5.0, 5.0)

(Source code, png)

../../_images/functions_2d-2.png

Multiple functions over the same range with custom rendering options:

>>> graphics(
...     line(x, (x, -3, 3)),
...     line(log(x), (x, -3, 3), rendering_kw={"linestyle": "--"}),
...     line(exp(x), (x, -3, 3), rendering_kw={"linestyle": ":"}),
...     aspect="equal", ylim=(-3, 3)
... )
Plot object containing:
[0]: cartesian line: x for x over (-3.0, 3.0)
[1]: cartesian line: log(x) for x over (-3.0, 3.0)
[2]: cartesian line: exp(x) for x over (-3.0, 3.0)

(Source code, png)

../../_images/functions_2d-3.png

Plotting a summation in which the free symbol of the expression is not used in the lower/upper bounds:

>>> from sympy import Sum, oo, latex
>>> expr = Sum(1 / x ** y, (x, 1, oo))
>>> graphics(
...     line(expr, (y, 2, 10), sum_bound=1e03),
...     title="$%s$" % latex(expr)
... )
Plot object containing:
[0]: cartesian line: Sum(x**(-y), (x, 1, 1000)) for y over (2.0, 10.0)

(Source code, png)

../../_images/functions_2d-4.png

Plotting a summation in which the free symbol of the expression is used in the lower/upper bounds. Here, the discretization variable must assume integer values:

>>> expr = Sum(1 / x, (x, 1, y))
>>> graphics(
...     line(expr, (y, 2, 10), scatter=True),
...     title="$%s$" % latex(expr)
... )
Plot object containing:
[0]: cartesian line: Sum(1/x, (x, 1, y)) for y over (2.0, 10.0)

(Source code, png)

../../_images/functions_2d-5.png

Using an adaptive algorithm, detect and plot vertical lines at singularities. Also, apply a transformation function to the discretized domain in order to convert radians to degrees:

>>> import numpy as np
>>> graphics(
...     line(
...         tan(x), (x, -1.5*pi, 1.5*pi),
...         adaptive=True, adaptive_goal=0.001,
...         detect_poles="symbolic", tx=np.rad2deg
...     ),
...     ylim=(-7, 7), xlabel="x [deg]", grid=False
... )
Plot object containing:
[0]: cartesian line: tan(x) for x over (-4.71238898038469, 4.71238898038469)

(Source code, png)

../../_images/functions_2d-6.png

Introducing discontinuities by excluding specified points:

>>> graphics(
...     line(floor(x) / x, (x, -3.25, 3.25), exclude=list(range(-4, 5))),
...     ylim=(-1, 5)
... )
Plot object containing:
[0]: cartesian line: floor(x)/x for x over (-3.25, 3.25)

(Source code, png)

../../_images/functions_2d-7.png

Creating a step plot:

>>> graphics(
...     line(x-2, (x, 0, 10), only_integers=True, steps="pre", label="pre"),
...     line(x, (x, 0, 10), only_integers=True, steps="mid", label="mid"),
...     line(x+2, (x, 0, 10), only_integers=True, steps="post", label="post"),
... )
Plot object containing:
[0]: cartesian line: x - 2 for x over (0.0, 10.0)
[1]: cartesian line: x for x over (0.0, 10.0)
[2]: cartesian line: x + 2 for x over (0.0, 10.0)

(Source code, png)

../../_images/functions_2d-8.png

Advanced example showing:

  • detect singularities by setting adaptive=False (better performance), increasing the number of discretization points (in order to have ‘vertical’ segments on the lines) and reducing the threshold for the singularity-detection algorithm.

  • application of color function.

  • combining together multiple lines.

>>> import numpy as np
>>> expr = 1 / cos(10 * x) + 5 * sin(x)
>>> def cf(x, y):
...     # map a colormap to the distance from the origin
...     d = np.sqrt(x**2 + y**2)
...     # visibility of the plot is limited: ylim=(-10, 10). However,
...     # some of the y-values computed by the function are much higher
...     # (or lower). Filter them out in order to have the entire
...     # colormap spectrum visible in the plot.
...     offset = 12 # 12 > 10 (safety margin)
...     d[(y > offset) | (y < -offset)] = 0
...     return d
>>> graphics(
...     line(
...         expr, (x, -5, 5), "distance from (0, 0)",
...         rendering_kw={"cmap": "plasma"},
...         adaptive=False, detect_poles=True, n=3e04,
...         eps=1e-04, color_func=cf),
...     line(5 * sin(x), (x, -5, 5), rendering_kw={"linestyle": "--"}),
...     ylim=(-10, 10), title="$%s$" % latex(expr)
... )
Plot object containing:
[0]: cartesian line: 5*sin(x) + 1/cos(10*x) for x over (-5.0, 5.0)
[1]: cartesian line: 5*sin(x) for x over (-5.0, 5.0)

(Source code, png)

../../_images/functions_2d-9.png

Interactive-widget plot of an oscillator. Refer to the interactive sub-module documentation to learn more about the params dictionary. This plot illustrates:

  • plotting multiple expressions, each one with its own label and rendering options.

  • the use of prange (parametric plotting range).

  • the use of the params dictionary to specify sliders in their basic form: (default, min, max).

  • the use of panel.widgets.slider.RangeSlider, which is a 2-values widget. In this case it is used to enforce the condition f1 < f2.

  • the use of a parametric title, specified with a tuple of the form: (title_str, param_symbol1, ...), where:

    • title_str must be a formatted string, for example: "test = {:.2f}".

    • param_symbol1, ... must be a symbol or a symbolic expression whose free symbols are contained in the params dictionary.

from sympy import *
from spb import *
import panel as pn
x, y, f1, f2, d, n = symbols("x, y, f_1, f_2, d, n")
params = {
    (f1, f2): pn.widgets.RangeSlider(
        value=(1, 2), start=0, end=10, step=0.1),     # frequencies
    d: (0.25, 0, 1),   # damping
    n: (2, 0, 4)       # multiple of pi
}
graphics(
    line(cos(f1 * x) * exp(-d * x), prange(x, 0, n * pi),
        label="oscillator 1", params=params),
    line(cos(f2 * x) * exp(-d * x), prange(x, 0, n * pi),
        label="oscillator 2", params=params),
    line(exp(-d * x), prange(x, 0, n * pi), label="upper limit",
        rendering_kw={"linestyle": ":"}, params=params),
    line(-exp(-d * x), prange(x, 0, n * pi), label="lower limit",
        rendering_kw={"linestyle": ":"}, params=params),
    ylim=(-1.25, 1.25),
    title=("$f_1$ = {:.2f} Hz", f1)
)

(Source code, small.png)

../../_images/functions_2d-10.small.png
spb.graphics.functions_2d.line_parametric_2d(expr1, expr2, range=None, label=None, rendering_kw=None, colorbar=True, use_cm=True, **kwargs)[source]

Plots a 2D parametric curve.

Parameters:
expr1, expr2Expr or callable

The expression representing the horizontal and vertical components of the parametric function. It can either be a symbolic expression representing the function of one variable to be plotted, or a numerical function of one variable, supporting vectorization. In the latter case the following keyword arguments are not supported: params, sum_bound.

range(symbol, min, max)

A 3-tuple denoting the parameter symbol, start value and stop value. For example, (u, 0, 5). If the range is not specified, then a default range of (-10, 10) is used.

labelstr, optional

The label to be shown in the legend. If not provided, the string representation of expr1 and expr1 will be used.

rendering_kwdict, optional

A dictionary of keywords/values which is passed to the backend’s function to customize the appearance of lines. Refer to the plotting library (backend) manual for more informations.

adaptivebool, optional

Setting adaptive=True activates the adaptive algorithm implemented in [python-adaptive] to create smooth plots. Use adaptive_goal and loss_fn to further customize the output.

The default value is False, which uses an uniform sampling strategy, where the number of discretization points is specified by the n keyword argument.

adaptive_goalcallable, int, float or None

Controls the “smoothness” of the evaluation. Possible values:

  • None (default): it will use the following goal: lambda l: l.loss() < 0.01

  • number (int or float). The lower the number, the more evaluation points. This number will be used in the following goal: lambda l: l.loss() < number

  • callable: a function requiring one input element, the learner. It must return a float number. Refer to [python-adaptive] for more information.

colorbarboolean, optional

Show/hide the colorbar. Default to True (colorbar is visible). Only works when use_cm=True.

color_funccallable, optional

Define the line color mapping when use_cm=True. It can either be:

  • A numerical function supporting vectorization. The arity can be:

    • 1 argument: f(t), where t is the parameter.

    • 2 arguments: f(x, y) where x, y are the coordinates of the points.

    • 3 arguments: f(x, y, t).

  • A symbolic expression having at most as many free symbols as expr1 or expr2.

  • None: the default value (color mapping applied to the parameter).

excludelist, optional

A list of numerical values along the parameter which are going to be excluded from the plot. In practice, it introduces discontinuities in the resulting line.

force_real_evalboolean, optional

Default to False, with which the numerical evaluation is attempted over a complex domain, which is slower but produces correct results. Set this to True if performance is of paramount importance, but be aware that it might produce wrong results. It only works with adaptive=False.

loss_fncallable or None

The loss function to be used by the adaptive learner. Possible values:

  • None (default): it will use the default_loss from the adaptive module.

  • callable : Refer to [python-adaptive] for more information. Specifically, look at adaptive.learner.learner1D to find more loss functions.

nint, optional

Used when the adaptive=False. The function is uniformly sampled at n number of points. Default value to 1000. If the adaptive=True, this parameter will be ignored.

paramsdict

A dictionary mapping symbols to parameters. This keyword argument enables the interactive-widgets plot, which doesn’t support the adaptive algorithm (meaning it will use adaptive=False). Learn more by reading the documentation of the interactive sub-module.

tx, ty, tpcallable, optional

Apply a numerical function to the x-direction, y-direction and parameter, respectively.

use_cmboolean, optional

If True, apply a color map to the parametric lines. If False, solid colors will be used instead. Default to True.

xscale‘linear’ or ‘log’, optional

Sets the scaling of the parameter.

Returns:
serieslist

A list containing one instance of Parametric2DLineSeries.

Examples

>>> from sympy import symbols, cos, sin, pi, floor, log
>>> from spb import *
>>> t, u, v = symbols('t, u, v')

(Source code)

A parametric plot of a single expression (a Hypotrochoid using an equal aspect ratio):

>>> graphics(
...     line_parametric_2d(
...         2 * cos(u) + 5 * cos(2 * u / 3),
...         2 * sin(u) - 5 * sin(2 * u / 3),
...         (u, 0, 6 * pi)
...     ),
...     aspect="equal"
... )
Plot object containing:
[0]: parametric cartesian line: (5*cos(2*u/3) + 2*cos(u), -5*sin(2*u/3) + 2*sin(u)) for u over (0.0, 18.84955592153876)

(Source code, png)

../../_images/functions_2d-12.png

A parametric plot with multiple expressions with the same range with solid line colors:

>>> graphics(
...     line_parametric_2d(2 * cos(t), sin(t), (t, 0, 2*pi), use_cm=False),
...     line_parametric_2d(cos(t), 2 * sin(t), (t, 0, 2*pi), use_cm=False),
... )
Plot object containing:
[0]: parametric cartesian line: (2*cos(t), sin(t)) for t over (0.0, 6.283185307179586)
[1]: parametric cartesian line: (cos(t), 2*sin(t)) for t over (0.0, 6.283185307179586)

(Source code, png)

../../_images/functions_2d-13.png

A parametric plot with multiple expressions with different ranges, custom labels, custom rendering options and a transformation function applied to the discretized parameter to convert radians to degrees:

>>> import numpy as np
>>> graphics(
...     line_parametric_2d(
...         3 * cos(u), 3 * sin(u), (u, 0, 2 * pi), "u [deg]",
...         rendering_kw={"lw": 3}, tp=np.rad2deg),
...     line_parametric_2d(
...         3 * cos(2 * v), 5 * sin(4 * v), (v, 0, pi), "v [deg]",
...         tp=np.rad2deg
...     ),
...     aspect="equal"
... )
Plot object containing:
[0]: parametric cartesian line: (3*cos(u), 3*sin(u)) for u over (0.0, 6.283185307179586)
[1]: parametric cartesian line: (3*cos(2*v), 5*sin(4*v)) for v over (0.0, 3.141592653589793)

(Source code, png)

../../_images/functions_2d-14.png

Introducing discontinuities by excluding specified points:

>>> e1 = log(floor(t))*cos(t)
>>> e2 = log(floor(t))*sin(t)
>>> graphics(
...     line_parametric_2d(
...         e1, e2, (t, 1, 4*pi), exclude=list(range(1, 13))),
...     grid=False
... )
Plot object containing:
[0]: parametric cartesian line: (log(floor(t))*cos(t), log(floor(t))*sin(t)) for t over (1.0, 12.566370614359172)

(Source code, png)

../../_images/functions_2d-15.png

Plotting a numerical function instead of a symbolic expression:

>>> import numpy as np
>>> fx = lambda t: np.sin(t) * (np.exp(np.cos(t)) - 2 * np.cos(4 * t) - np.sin(t / 12)**5)
>>> fy = lambda t: np.cos(t) * (np.exp(np.cos(t)) - 2 * np.cos(4 * t) - np.sin(t / 12)**5)
>>> graphics(
...     line_parametric_2d(fx, fy, ("t", 0, 12 * pi),
...         use_cm=False, n=2000),
...     title="Butterfly Curve",
... )  

(Source code, png)

../../_images/functions_2d-16.png

Interactive-widget plot. Refer to the interactive sub-module documentation to learn more about the params dictionary. This plot illustrates:

  • the use of prange (parametric plotting range).

  • the use of the params dictionary to specify sliders in their basic form: (default, min, max).

from sympy import *
from spb import *
x, a, s, e = symbols("x a s, e")
graphics(
    line_parametric_2d(
        cos(a * x), sin(x), prange(x, s*pi, e*pi),
            params={
            a: (0.5, 0, 2),
            s: (0, 0, 2),
            e: (2, 0, 2),
        }),
    aspect="equal",
    xlim=(-1.25, 1.25), ylim=(-1.25, 1.25)
)

(Source code, small.png)

../../_images/functions_2d-17.small.png
spb.graphics.functions_2d.line_polar(expr, range=None, label=None, rendering_kw=None, **kwargs)[source]

Creates a 2D polar plot of a function of one variable.

This function executes line_parametric_2d. Refer to its documentation for a full list of keyword arguments.

Examples

>>> from sympy import symbols, sin, cos, exp, pi
>>> from spb import *
>>> theta = symbols('theta')

(Source code)

Plot with cartesian axis:

>>> graphics(
...     line_polar(3 * sin(2 * theta), (theta, 0, 2*pi)),
...     aspect="equal"
... )
Plot object containing:
[0]: parametric cartesian line: (3*sin(2*theta)*cos(theta), 3*sin(theta)*sin(2*theta)) for theta over (0.0, 6.283185307179586)

(Source code, png)

../../_images/functions_2d-19.png

Plot with polar axis:

>>> graphics(
...     line_polar(exp(sin(theta)) - 2 * cos(4 * theta), (theta, 0, 2 * pi)),
...     polar_axis=True, aspect="equal"
... )
Plot object containing:
[0]: parametric cartesian line: ((exp(sin(theta)) - 2*cos(4*theta))*cos(theta), (exp(sin(theta)) - 2*cos(4*theta))*sin(theta)) for theta over (0.0, 6.283185307179586)

(Source code, png)

../../_images/functions_2d-20.png

Interactive-widget plot of Guilloché Pattern. Refer to the interactive sub-module documentation to learn more about the params dictionary. This plot illustrates:

  • the use of prange (parametric plotting range).

  • the use of the params dictionary to specify the widgets to be created by Holoviz’s Panel.

from sympy import *
from spb import *
import panel as pn
a, b, c, d, e, f, theta, tp = symbols("a:f theta tp")
def func(n):
    t1 = (c + sin(a * theta + d))
    t2 = ((b + sin(b * theta + e)) - (c + sin(a * theta + d)))
    t3 = (f + sin(a * theta + n / pi))
    return t1 + t2 * t3 / 2
params = {
    a: pn.widgets.IntInput(value=6, name="a"),
    b: pn.widgets.IntInput(value=12, name="b"),
    c: pn.widgets.IntInput(value=18, name="c"),
    d: (4.7, 0, 2*pi),
    e: (1.8, 0, 2*pi),
    f: (3, 0, 5),
    tp: (2, 0, 2)
}
series = []
for n in range(20):
    series += line_polar(
        func(n), prange(theta, 0, tp*pi), params=params,
        rendering_kw={"line_color": "black", "line_width": 0.5})
graphics(
    *series,
    aspect="equal",
    layout = "sbl",
    ncols = 1,
    title="Guilloché Pattern Explorer",
    backend=BB,
    legend=False,
    servable=True,
    imodule="panel"
)

(Source code, small.png)

../../_images/functions_2d-21.small.png
spb.graphics.functions_2d.contour(expr, range1=None, range2=None, label=None, rendering_kw=None, colorbar=True, clabels=True, fill=True, **kwargs)[source]

Plots contour lines or filled contours of a function of two variables.

Parameters:
clabelsbool, optional

Visualize labels of contour lines. Only works when fill=False. Default to True. Note that some backend might not implement this feature.

colorbarboolean, optional

Show/hide the colorbar. Default to True (colorbar is visible). Only works when use_cm=True.

fillbool, optional

Choose between filled contours or line contours. Default to True (filled contours).

**kwargs

Keyword arguments are the same as surface(). Refer to its documentation for a for a full list of keyword arguments.

Returns:
serieslist

A list containing one instance of ContourSeries.

Examples

>>> from sympy import symbols, cos, exp, sin, pi, Eq, Add
>>> from spb import *
>>> x, y = symbols('x, y')

(Source code)

Filled contours of a function of two variables.

>>> graphics(
...     contour(
...         cos((x**2 + y**2)) * exp(-(x**2 + y**2) / 10),
...         (x, -5, 5), (y, -5, 5)
...     ),
...     grid=False
... )
Plot object containing:
[0]: contour: exp(-x**2/10 - y**2/10)*cos(x**2 + y**2) for x over (-5.0, 5.0) and y over (-5.0, 5.0)

(Source code, png)

../../_images/functions_2d-23.png

Line contours of a function of two variables.

>>> expr = 5 * (cos(x) - 0.2 * sin(y))**2 + 5 * (-0.2 * cos(x) + sin(y))**2
>>> graphics(
...     contour(expr, (x, 0, 2 * pi), (y, 0, 2 * pi), fill=False)
... )
Plot object containing:
[0]: contour: 5*(-0.2*sin(y) + cos(x))**2 + 5*(sin(y) - 0.2*cos(x))**2 for x over (0.0, 6.283185307179586) and y over (0.0, 6.283185307179586)

(Source code, png)

../../_images/functions_2d-24.png

Combining together filled and line contours. Use a custom label on the colorbar of the filled contour.

>>> expr = 5 * (cos(x) - 0.2 * sin(y))**2 + 5 * (-0.2 * cos(x) + sin(y))**2
>>> graphics(
...     contour(expr, (x, 0, 2 * pi), (y, 0, 2 * pi), "z",
...         rendering_kw={"cmap": "coolwarm"}),
...     contour(expr, (x, 0, 2 * pi), (y, 0, 2 * pi),
...         rendering_kw={"colors": "k", "cmap": None, "linewidths": 0.75},
...         fill=False),
...     grid=False
... )
Plot object containing:
[0]: contour: 5*(-0.2*sin(y) + cos(x))**2 + 5*(sin(y) - 0.2*cos(x))**2 for x over (0.0, 6.283185307179586) and y over (0.0, 6.283185307179586)
[1]: contour: 5*(-0.2*sin(y) + cos(x))**2 + 5*(sin(y) - 0.2*cos(x))**2 for x over (0.0, 6.283185307179586) and y over (0.0, 6.283185307179586)

(Source code, png)

../../_images/functions_2d-25.png

Visually inspect the solutions of a system of 2 non-linear equations. The intersections between the contour lines represent the solutions.

>>> eq1 = Eq((cos(x) - sin(y) / 2)**2 + 3 * (-sin(x) + cos(y) / 2)**2, 2)
>>> eq2 = Eq((cos(x) - 2 * sin(y))**2 - (sin(x) + 2 * cos(y))**2, 3)
>>> graphics(
...     contour(
...         eq1.rewrite(Add), (x, 0, 2 * pi), (y, 0, 2 * pi),
...         rendering_kw={"levels": [0]},
...         fill=False, clabels=False),
...     contour(
...         eq2.rewrite(Add), (x, 0, 2 * pi), (y, 0, 2 * pi),
...         rendering_kw={"levels": [0]},
...         fill=False, clabels=False),
... )
Plot object containing:
[0]: contour: 3*(-sin(x) + cos(y)/2)**2 + (-sin(y)/2 + cos(x))**2 - 2 for x over (0.0, 6.283185307179586) and y over (0.0, 6.283185307179586)
[1]: contour: -(sin(x) + 2*cos(y))**2 + (-2*sin(y) + cos(x))**2 - 3 for x over (0.0, 6.283185307179586) and y over (0.0, 6.283185307179586)

(Source code, png)

../../_images/functions_2d-26.png

Contour plot with polar axis:

>>> r, theta = symbols("r, theta")
>>> graphics(
...     contour(
...         sin(2 * r) * cos(theta), (theta, 0, 2*pi), (r, 0, 7),
...         rendering_kw={"levels": 100}
...     ),
...     polar_axis=True, aspect="equal"
... )
Plot object containing:
[0]: contour: sin(2*r)*cos(theta) for theta over (0.0, 6.283185307179586) and r over (0.0, 7.0)

(Source code, png)

../../_images/functions_2d-27.png

Interactive-widget plot. Refer to the interactive sub-module documentation to learn more about the params dictionary. This plot illustrates:

  • the use of prange (parametric plotting range).

  • the use of the params dictionary to specify sliders in their basic form: (default, min, max).

  • the use of panel.widgets.slider.RangeSlider, which is a 2-values widget.

from sympy import *
from spb import *
import panel as pn
x, y, a, b = symbols("x y a b")
x_min, x_max, y_min, y_max = symbols("x_min x_max y_min y_max")
expr = (cos(x) + a * sin(x) * sin(y) - b * sin(x) * cos(y))**2
graphics(
    contour(
        expr, prange(x, x_min*pi, x_max*pi), prange(y, y_min*pi, y_max*pi),
        params={
            a: (1, 0, 2), b: (1, 0, 2),
            (x_min, x_max): pn.widgets.RangeSlider(
                value=(-1, 1), start=-3, end=3, step=0.1),
            (y_min, y_max): pn.widgets.RangeSlider(
                value=(-1, 1), start=-3, end=3, step=0.1),
        }),
    grid=False
)

(Source code, small.png)

../../_images/functions_2d-28.small.png
spb.graphics.functions_2d.implicit_2d(expr, range1=None, range2=None, label=None, rendering_kw=None, color=None, border_color=None, border_kw=None, **kwargs)[source]

Plot implicit equations / inequalities.

implicit_2d, by default, generates a contour using a mesh grid of fixednumber of points. The greater the number of points, the better the results, but also the greater the memory used. By setting adaptive=True, interval arithmetic will be used to plot functions. If the expression cannot be plotted using interval arithmetic, it defaults to generating a contour using a mesh grid. With interval arithmetic, the line width can become very small; in those cases, it is better to use the mesh grid approach.

Parameters:
exprExpr, Relational, BooleanFunction

The equation / inequality that is to be plotted.

range1, range2tuples or Symbol

Tuple denoting the discretization domain, for example: (x, -10, 10).

labelstr, optional

The label to be shown when multiple expressions are plotted. If not provided, the string representation of the expression will be used.

rendering_kwdict, optional

A dictionary of keywords/values which is passed to the backend’s function to customize the appearance of contours. Refer to the plotting library (backend) manual for more informations.

colorstr, optional

Specify the color of lines/regions. Default to None (automatic coloring by the backend).

border_colorstr or bool, optional

If given, a limiting border will be added when plotting inequalities (<, <=, >, >=). Use border_kw if more customization options are required.

border_kwdict, optional

If given, a limiting border will be added when plotting inequalities (<, <=, >, >=). This is a dictionary of keywords/values which is passed to the backend’s function to customize the appearance of the limiting border. Refer to the plotting library (backend) manual for more informations.

adaptivebool, optional

The default value is set to False, meaning that the internal algorithm uses a mesh grid approach. In such case, Boolean combinations of expressions cannot be plotted. If set to True, the internal algorithm uses interval arithmetic. If the expression cannot be plotted with interval arithmetic, it switches to the meshgrid approach.

depthinteger

The depth of recursion for adaptive grid. Default value is 0. Takes value in the range (0, 4). Think of the resulting plot as a picture composed by pixels. By increasing depth we are increasing the number of pixels, thus obtaining a more accurate plot.

n, n1, n2int

Number of discretization points in the horizontal and vertical directions when adaptive=False. Default to 100. n is a shortcut to set the same number of discretization points on both directions.

paramsdict

A dictionary mapping symbols to parameters. This keyword argument enables the interactive-widgets plot. Learn more by reading the documentation of the interactive sub-module.

show_in_legendbool

If True, add a legend entry for the expression being plotted. This option is useful to hide a particular expression when combining together multiple plots. Default to True.

Returns:
serieslist

A list containing at most two instances of Implicit2DSeries.

Examples

Plot expressions:

>>> from sympy import symbols, Ne, Eq, And, sin, cos, pi, log, latex
>>> from spb import *
>>> x, y = symbols('x y')

(Source code)

Plot a line representing an equality:

>>> graphics(implicit_2d(x - 1, (x, -5, 5), (y, -5, 5)))
Plot object containing:
[0]: Implicit expression: Eq(x - 1, 0) for x over (-5.0, 5.0) and y over (-5.0, 5.0)

(Source code, png)

../../_images/functions_2d-30.png

Plot a region:

>>> graphics(
...     implicit_2d(y > x**2, (x, -5, 5), (y, -10, 10), n=150),
...     grid=False)
Plot object containing:
[0]: Implicit expression: y > x**2 for x over (-5.0, 5.0) and y over (-10.0, 10.0)

(Source code, png)

../../_images/functions_2d-31.png

Plot a region using a custom color, highlights the limiting border and customize its appearance.

>>> expr = 4 * (cos(x) - sin(y) / 5)**2 + 4 * (-cos(x) / 5 + sin(y))**2
>>> graphics(
...     implicit_2d(
...         expr <= pi, (x, -pi, pi), (y, -pi, pi),
...         color="gold", border_color="k",
...         border_kw={"linestyles": "-.", "linewidths": 1}
...     ),
...     grid=False
... )
Plot object containing:
[0]: Implicit expression: 4*(-sin(y)/5 + cos(x))**2 + 4*(sin(y) - cos(x)/5)**2 <= pi for x over (-3.141592653589793, 3.141592653589793) and y over (-3.141592653589793, 3.141592653589793)
[1]: Implicit expression: Eq(-4*(-sin(y)/5 + cos(x))**2 - 4*(sin(y) - cos(x)/5)**2 + pi, 0) for x over (-3.141592653589793, 3.141592653589793) and y over (-3.141592653589793, 3.141592653589793)

(Source code, png)

../../_images/functions_2d-32.png

Boolean expressions will be plotted with the adaptive algorithm. Note the thin width of lines:

>>> graphics(
...     implicit_2d(
...         Eq(y, sin(x)) & (y > 0), (x, -2 * pi, 2 * pi), (y, -4, 4)),
...     implicit_2d(
...         Eq(y, sin(x)) & (y < 0), (x, -2 * pi, 2 * pi), (y, -4, 4)),
...     ylim=(-2, 2)
... )
Plot object containing:
[0]: Implicit expression: (y > 0) & Eq(y, sin(x)) for x over (-6.283185307179586, 6.283185307179586) and y over (-4.0, 4.0)
[1]: Implicit expression: (y < 0) & Eq(y, sin(x)) for x over (-6.283185307179586, 6.283185307179586) and y over (-4.0, 4.0)

(Source code, png)

../../_images/functions_2d-33.png

Plotting multiple implicit expressions and setting labels:

>>> V, t, b, L = symbols("V, t, b, L")
>>> L_array = [5, 10, 15, 20, 25]
>>> b_val = 0.0032
>>> expr = b * V * 0.277 * t - b * L - log(1 + b * V * 0.277 * t)
>>> series = []
>>> for L_val in L_array:
...     series += implicit_2d(
...         expr.subs({b: b_val, L: L_val}), (t, 0, 3), (V, 0, 1000),
...         label="L = %s" % L_val)
>>> graphics(*series)
Plot object containing:
[0]: Implicit expression: Eq(0.0008864*V*t - log(0.0008864*V*t + 1) - 0.016, 0) for t over (0.0, 3.0) and V over (0.0, 1000.0)
[1]: Implicit expression: Eq(0.0008864*V*t - log(0.0008864*V*t + 1) - 0.032, 0) for t over (0.0, 3.0) and V over (0.0, 1000.0)
[2]: Implicit expression: Eq(0.0008864*V*t - log(0.0008864*V*t + 1) - 0.048, 0) for t over (0.0, 3.0) and V over (0.0, 1000.0)
[3]: Implicit expression: Eq(0.0008864*V*t - log(0.0008864*V*t + 1) - 0.064, 0) for t over (0.0, 3.0) and V over (0.0, 1000.0)
[4]: Implicit expression: Eq(0.0008864*V*t - log(0.0008864*V*t + 1) - 0.08, 0) for t over (0.0, 3.0) and V over (0.0, 1000.0)

(Source code, png)

../../_images/functions_2d-34.png

Comparison of similar expressions plotted with different algorithms. Note:

  1. Adaptive algorithm (adaptive=True) can be used with any expression, but it usually creates lines with variable thickness. The depth keyword argument can be used to improve the accuracy, but reduces line thickness even further.

  2. Mesh grid algorithm (adaptive=False) creates lines with constant thickness.

>>> expr1 = Eq(x * y - 20, 15 * y)
>>> expr2 = Eq((x - 3) * y - 20, 15 * y)
>>> expr3 = Eq((x - 6) * y - 20, 15 * y)
>>> ranges = (x, 15, 30), (y, 0, 50)
>>> graphics(
...    implicit_2d(
...        expr1, *ranges, adaptive=True, depth=0,
...        label="adaptive=True, depth=0"),
...    implicit_2d(
...        expr2, *ranges, adaptive=True, depth=1,
...        label="adaptive=True, depth=1"),
...    implicit_2d(
...        expr3, *ranges, adaptive=False, label="adaptive=False"),
...    grid=False
... )
Plot object containing:
[0]: Implicit expression: Eq(x*y - 20, 15*y) for x over (15.0, 30.0) and y over (0.0, 50.0)
[1]: Implicit expression: Eq(y*(x - 3) - 20, 15*y) for x over (15.0, 30.0) and y over (0.0, 50.0)
[2]: Implicit expression: Eq(y*(x - 6) - 20, 15*y) for x over (15.0, 30.0) and y over (0.0, 50.0)

(Source code, png)

../../_images/functions_2d-35.png

If the expression is plotted with the adaptive algorithm and it produces “low-quality” results, maybe it’s possible to rewrite it in order to use the mesh grid approach (contours). For example:

>>> from spb import plotgrid
>>> expr = Ne(x*y, 1)
>>> p1 = graphics(
...     implicit_2d(expr, (x, -10, 10), (y, -10, 10)),
...     grid=False, title="$%s$ : First approach" % latex(expr),
...     aspect="equal", show=False)
>>> p2 = graphics(
...     implicit_2d(x < 20, (x, -10, 10), (y, -10, 10)),
...     implicit_2d(Eq(*expr.args), (x, -10, 10), (y, -10, 10),
...         color="w", show_in_legend=False),
...     grid=False, title="$%s$ : Second approach" % latex(expr),
...     aspect="equal", show=False)
>>> plotgrid(p1, p2, nc=2)  

(Source code, png)

../../_images/functions_2d-36.png

Interactive-widget implicit plot. Refer to the interactive sub-module documentation to learn more about the params dictionary. This plot illustrates:

  • the use of prange (parametric plotting range).

  • the use of the params dictionary to specify sliders in their basic form: (default, min, max).

  • the use of panel.widgets.slider.RangeSlider, which is a 2-values widget.

from sympy import *
from spb import *
import panel as pn
x, y, a, b, c, d = symbols("x, y, a, b, c, d")
y_min, y_max = symbols("y_min, y_max")
expr = Eq(a * x**2 - b * x + c, d * y + y**2)
graphics(
    implicit_2d(expr, (x, -2, 2), prange(y, y_min, y_max),
        params={
            a: (10, -15, 15),
            b: (7, -15, 15),
            c: (3, -15, 15),
            d: (2, -15, 15),
            (y_min, y_max): pn.widgets.RangeSlider(
                value=(-10, 10), start=-15, end=15, step=0.1)
        }, n=150),
    ylim=(-10, 10))

(Source code, small.png)

../../_images/functions_2d-37.small.png
spb.graphics.functions_2d.list_2d(coord_x, coord_y, label=None, rendering_kw=None, **kwargs)[source]

Plots lists of coordinates.

Parameters:
coord_x, coord_ylist or tuple

List of coordinates.

labelstr, optional

The label to be shown in the legend.

rendering_kwdict, optional

A dictionary of keywords/values which is passed to the backend’s function to customize the appearance of lines. Refer to the

scatterboolean, optional

Default to False, which will render a line connecting all the points. If True, a scatter plot will be generated.

fillboolean, optional

Default to False, which will render empty circular markers. It only works if scatter=True. If True, filled circular markers will be rendered.

paramsdict

A dictionary mapping symbols to parameters. This keyword argument enables the interactive-widgets plot. Learn more by reading the documentation of the interactive sub-module.

Returns:
serieslist

A list containing one instance of List2DSeries.

Examples

>>> from sympy import symbols, sin, cos
>>> from spb import *
>>> x = symbols('x')

(Source code)

Plot the coordinates of a single function:

>>> xx = [t / 100 * 6 - 3 for t in list(range(101))]
>>> yy = [cos(x).evalf(subs={x: t}) for t in xx]
>>> graphics(list_2d(xx, yy))
Plot object containing:
[0]: 2D list plot

(Source code, png)

../../_images/functions_2d-39.png

Plot individual points with custom labels. Each point will be converted to a list by the algorithm:

>>> graphics(
...     list_2d(0, 0, "A", scatter=True),
...     list_2d(1, 1, "B", scatter=True),
...     list_2d(2, 0, "C", scatter=True),
... )
Plot object containing:
[0]: 2D list plot
[1]: 2D list plot
[2]: 2D list plot

(Source code, png)

../../_images/functions_2d-40.png

Scatter plot of the coordinates of multiple functions, with custom rendering keywords:

>>> xx = [t / 70 * 6 - 3 for t in list(range(71))]
>>> yy1 = [cos(x).evalf(subs={x: t}) for t in xx]
>>> yy2 = [sin(x).evalf(subs={x: t}) for t in xx]
>>> graphics(
...     list_2d(xx, yy1, "cos", scatter=True),
...     list_2d(xx, yy2, "sin", {"marker": "*", "markerfacecolor": None},
...             scatter=True),
... )
Plot object containing:
[0]: 2D list plot
[1]: 2D list plot

(Source code, png)

../../_images/functions_2d-41.png

Interactive-widget plot. Refer to the interactive sub-module documentation to learn more about the params dictionary.

from sympy import *
from spb import *
x, t = symbols("x, t")
params = {t: (0, 0, 2*pi)}
graphics(
    line_parametric_2d(
        cos(x), sin(x), (x, 0, 2*pi), rendering_kw={"linestyle": ":"},
        use_cm=False),
    line_parametric_2d(
        cos(2 * x) / 2, sin(2 * x) / 2, (x, 0, pi),
        rendering_kw={"linestyle": ":"}, use_cm=False),
    list_2d(
        cos(t), sin(t), "A",
        rendering_kw={"marker": "s", "markerfacecolor": None},
        params=params, scatter=True),
    list_2d(
        cos(2 * t) / 2, sin(2 * t) / 2, "B",
        rendering_kw={"marker": "s", "markerfacecolor": None},
        params=params, scatter=True),
    aspect="equal"
)

(Source code, small.png)

../../_images/functions_2d-42.small.png
spb.graphics.functions_2d.geometry(geom, label=None, rendering_kw=None, fill=True, **kwargs)[source]

Plot entities from the sympy.geometry module.

Parameters:
geomGeometryEntity

Represent the geometric entity to be plotted.

labelstr, optional

The name of the geometry entity to be eventually shown on the legend. If not provided, the string representation of geom will be used.

rendering_kwdict, optional

A dictionary of keywords/values which is passed to the backend’s function to customize the appearance of lines or fills. Refer to the plotting library (backend) manual for more informations.

fillboolean

Default to True. Fill the polygon/circle/ellipse.

A dictionary mapping symbols to parameters. This keyword argument

enables the interactive-widgets plot. Learn more by reading the documentation of the interactive sub-module.

Returns:
serieslist

A list containing one instance of GeometrySeries.

Examples

>>> from sympy import (symbols, Circle, Ellipse, Polygon,
...      Curve, Segment, Point2D, Point3D, Line3D, Plane,
...      Rational, pi, Point, cos, sin)
>>> from spb import *
>>> x, y, z = symbols('x, y, z')

(Source code)

Plot a single geometry, customizing its color:

>>> graphics(
...     geometry(
...         Ellipse(Point(-3, 2), hradius=3, eccentricity=Rational(4, 5)),
...         rendering_kw={"color": "tab:orange"}),
...     grid=False, aspect="equal"
... )
Plot object containing:
[0]: geometry entity: Ellipse(Point2D(-3, 2), 3, 9/5)

(Source code, png)

../../_images/functions_2d-44.png

Plot several numeric geometric entitiesy. By default, circles, ellipses and polygons are going to be filled. Plotting Curve objects is the same as plot_parametric.

>>> graphics(
...     geometry(Circle(Point(0, 0), 5)),
...     geometry(Ellipse(Point(-3, 2), hradius=3, eccentricity=Rational(4, 5))),
...     geometry(Polygon((4, 0), 4, n=5)),
...     geometry(Curve((cos(x), sin(x)), (x, 0, 2 * pi))),
...     geometry(Segment((-4, -6), (6, 6))),
...     geometry(Point2D(0, 0)),
...     aspect="equal", grid=False
... )
Plot object containing:
[0]: geometry entity: Circle(Point2D(0, 0), 5)
[1]: geometry entity: Ellipse(Point2D(-3, 2), 3, 9/5)
[2]: geometry entity: RegularPolygon(Point2D(4, 0), 4, 5, 0)
[3]: parametric cartesian line: (cos(x), sin(x)) for x over (0.0, 6.283185307179586)
[4]: geometry entity: Segment2D(Point2D(-4, -6), Point2D(6, 6))
[5]: geometry entity: Point2D(0, 0)

(Source code, png)

../../_images/functions_2d-45.png

Plot several numeric geometric entities defined by numbers only, turn off fill. Every entity is represented as a line.

>>> graphics(
...     geometry(Circle(Point(0, 0), 5), fill=False),
...     geometry(
...         Ellipse(Point(-3, 2), hradius=3, eccentricity=Rational(4, 5)),
...         fill=False),
...     geometry(Polygon((4, 0), 4, n=5), fill=False),
...     geometry(Curve((cos(x), sin(x)), (x, 0, 2 * pi)), fill=False),
...     geometry(Segment((-4, -6), (6, 6)), fill=False),
...     geometry(Point2D(0, 0), fill=False),
...     aspect="equal", grid=False
... )
Plot object containing:
[0]: geometry entity: Circle(Point2D(0, 0), 5)
[1]: geometry entity: Ellipse(Point2D(-3, 2), 3, 9/5)
[2]: geometry entity: RegularPolygon(Point2D(4, 0), 4, 5, 0)
[3]: parametric cartesian line: (cos(x), sin(x)) for x over (0.0, 6.283185307179586)
[4]: geometry entity: Segment2D(Point2D(-4, -6), Point2D(6, 6))
[5]: geometry entity: Point2D(0, 0)

(Source code, png)

../../_images/functions_2d-46.png

Plot 3D geometric entities. Instances of Plane must be plotted with implicit_3d or with plane (with the necessary ranges).

from sympy import *
from spb import *
x, y, z = symbols("x, y, z")
graphics(
     geometry(
         Point3D(0, 0, 0), label="center",
         rendering_kw={"point_size": 1}),
     geometry(Line3D(Point3D(-2, -3, -4), Point3D(2, 3, 4)), "line"),
     plane(
         Plane((0, 0, 0), (1, 1, 1)),
         (x, -5, 5), (y, -4, 4), (z, -10, 10)),
     backend=KB
 )

(Source code, small.png)

../../_images/functions_2d-47.small.png

Interactive-widget plot. Refer to the interactive sub-module documentation to learn more about the params dictionary.

from sympy import *
from spb import *
import panel as pn
a, b, c, d = symbols("a, b, c, d")
params = {
    a: (0, -1, 1),
    b: (1, -1, 1),
    c: (2, 1, 2),
    d: pn.widgets.IntInput(value=6, start=3, end=8, name="n")
}
graphics(
    geometry(Polygon((a, b), c, n=d), "a", params=params),
    geometry(
        Polygon((a + 2, b + 3), c, n=d + 1), "b",
        params=params, fill=False),
    aspect="equal",
    xlim=(-2.5, 5.5), ylim=(-3, 6.5), imodule="panel")

(Source code, small.png)

../../_images/functions_2d-48.small.png