コード例 #1
0
def test_plot_sympify():
    x, y = symbols("x, y")

    # argument is already sympified
    args = x + y
    r = _plot_sympify(args)
    assert r == args

    # one argument needs to be sympified
    args = (x + y, 1)
    r = _plot_sympify(args)
    assert isinstance(r, (list, tuple, Tuple)) and len(r) == 2
    assert isinstance(r[0], Expr)
    assert isinstance(r[1], Integer)

    # string should not be sympified
    args = (x + y, (x, 0, 1), "str", 1)
    r = _plot_sympify(args)
    assert isinstance(r, (list, tuple, Tuple)) and len(r) == 4
    assert isinstance(r[0], Expr)
    assert isinstance(r[1], Tuple)
    assert isinstance(r[2], str)
    assert isinstance(r[3], Integer)

    # nested arguments containing strings
    args = ((x + y, (y, 0, 1), "a"), (x + 1, (x, 0, 1), "$f_{1}$"))
    r = _plot_sympify(args)
    assert isinstance(r, (list, tuple, Tuple)) and len(r) == 2
    assert isinstance(r[0], Tuple)
    assert isinstance(r[0][1], Tuple)
    assert isinstance(r[0][1][1], Integer)
    assert isinstance(r[0][2], str)
    assert isinstance(r[1], Tuple)
    assert isinstance(r[1][1], Tuple)
    assert isinstance(r[1][1][1], Integer)
    assert isinstance(r[1][2], str)
コード例 #2
0
def smart_plot(*args, show=True, **kwargs):
    """Smart plot interface. Using the same interface of the other plot
    functions, namely (expr, range, label), it unifies the plotting experience.
    If a symbolic expression can be plotted with any of the plotting functions
    exposed by spb.functions or spb.vectors, then this function will be able
    to plot it as well.

    Keyword Arguments
    =================
        The usual keyword arguments available on every other plotting functions
        are available (`xlabel`, ..., `adaptive`, `n`, ...). On top of that
        we can set:

        pt : str
            Specify which kind of plot we are intereseted. Default value
            is None, indicating the function will use automatic detection.
            Possible values are:
                "p": to specify a line plot.
                "pp": to specify a 2d parametric line plot.
                "p3dl": to specify a 3d parametric line plot.
                "p3d": to specify a 3d plot.
                "p3ds": to specify a 3d parametric surface plot.
                "pi": to specify an implificit plot.
                "pinter": to specify an interactive plot. In such a case, you
                        will also have to provide a `param` dictionary mapping
                        theparameters to their values.
                        To specify a complex-interactive plot, set
                        `is_complex=True`.
                "v2d": to specify a 2D vector plot.
                "v3d": to specify a 3D vector plot.
                "c": to specify a complex plot.
                "g": to specify a geometric entity plot.

    Examples
    ========

    Plotting different types of expressions with automatic detection:

    .. code-block:: python
        from sympy import symbols, sin, cos, Matrix
        from spb.backends.plotly import PB
        x, y = symbols("x, y")
        smart_plot(
            (Matrix([-sin(y), cos(x)]), (x, -5, 5), (y, -3, 3), "vector"),
            (sin(x), (x, -5, 5)),
            aspect="equal", n=20, legend=True,
            quiver_kw=dict(scale=0.25), line_kw=dict(line_color="cyan"),
            backend=PB
        )

    Specify the kind of plot we are interested in:

    .. code-block:: python
        from sympy import symbols, cos
        x, y = symbols("x, y")
        plot(cos(x**2 + y**2), (x, -3, 3), (y, -3, 3),
            xlabel="x", ylabel="y", pt="pc")

    See also
    ========

    plot, plot_parametric, plot3d, plot3d_parametric_line,
    plot3d_parametric_surface, plot_contour, plot_implicit,
    vector_plot, complex_plot
    """

    args = _plot_sympify(args)
    if not all([isinstance(a, (list, tuple, Tuple)) for a in args]):
        args = [args]
    series = []

    for arg in args:
        series.append(_build_series(*arg, **kwargs))

    if "backend" not in kwargs.keys():
        from spb.defaults import TWO_D_B, THREE_D_B

        is_3D = any([s.is_3D for s in series])
        kwargs["backend"] = THREE_D_B if is_3D else TWO_D_B
    plots = Plot(*series, **kwargs)
    if show:
        plots.show()
    return plots
コード例 #3
0
def _build_series(*args, **kwargs):
    """Read the docstring of get_plot_data to unsertand what args and kwargs
    are.
    """

    mapping = {
        "p": [LineOver1DRangeSeries, 1, 1],  # [cls, nexpr, npar]
        "pp": [Parametric2DLineSeries, 2, 1],
        "p3dl": [Parametric3DLineSeries, 3, 1],
        "p3ds": [ParametricSurfaceSeries, 3, 2],
        "p3d": [SurfaceOver2DRangeSeries, 1, 2],
        "pi": [ImplicitSeries, 1, 2],
        "pinter": [InteractiveSeries, 0, 0],
        "v2d": [Vector2DSeries, 2, 2],
        "v3d": [Vector3DSeries, 3, 3],
        "v3ds": [SliceVector3DSeries, 3, 3],
        "pc": [ContourSeries, 1, 2],
        "c": [ComplexSeries, 1, 1],
        "g": [GeometrySeries, 9, 9],
    }

    # In the following dictionary the key is composed of two characters:
    # 1. The first represents the number of sub-expressions. For example,
    #    a line plot or a surface plot have 1 expression. A 2D parametric line
    #    does have 2 parameters, ...
    # 2. The second represent the number of parameters.
    # There will be ambiguities due to the fact that some series use the same
    # number of expressions and parameters. This dictionary set a default series
    reverse_mapping = {
        "11": "p",
        "21": "pp",
        "31": "p3dl",
        "32": "p3ds",
        "12": "p3d",
        "22": "v2d",
        "33": "v3d",
    }

    args = _plot_sympify(args)
    exprs, ranges, label = _unpack_args(*args)
    args = [*exprs, *ranges, label]

    pt = kwargs.pop("pt", None)
    if pt is None:
        # Automatic detection based on the number of free symbols and the number
        # of expressions

        pt = ""
        skip_check = False

        if (len(ranges) > 0) and (ranges[0][1].has(I) or ranges[0][2].has(I)):
            pt = "c"
        elif isinstance(exprs[0], GeometryEntity):
            if len(ranges) == 0:
                ranges = [None]
            args = [*exprs, *ranges, label]
            pt = "g"
            skip_check = True
        elif isinstance(exprs[0], (Boolean, Relational)):
            # implicit series
            pt = "pi"
        elif isinstance(exprs[0], (DenseMatrix, Vector)):
            split_expr, ranges = _split_vector(exprs[0], ranges)
            if split_expr[-1] is S.Zero:
                args = [split_expr[:2], *ranges, label]
                pt = "v2d"
            else:
                args = [split_expr, *ranges, label]
                pt = "v3d"
        elif isinstance(exprs[0], (list, tuple, Tuple)):
            if any(t.has(I) for t in exprs[0]):
                # list of complex points
                pt = "c"
                skip_check = True
                if len(args) == 2:
                    # no range has been provided
                    args = [args[0], None, args[1]]
            else:
                # Two possible cases:
                # 1. The actual parametric expression has been provided in the form
                #    (expr1, expr2, expr3 [optional]), range1, range2 [optional]
                # 2. A vector has been written as a tuple/list
                fs = set().union(*[e.free_symbols for e in exprs[0]])
                npar = len(fs)
                nexpr = len(exprs[0])
                tmp = str(nexpr) + str(npar)
                if tmp in reverse_mapping.keys():
                    pt = reverse_mapping[tmp]
        elif exprs[0].has(I):
            # complex series -> return complex numbers
            pt = "c"
        else:
            # the actual expression (parametric or not) is not contained in a
            # tuple. For example:
            # expr1, expr2, expr3 [optional]), range1, range2 [optional]
            fs = set().union(*[e.free_symbols for e in exprs])
            npar = len(fs)
            nexpr = len(exprs)
            tmp = str(nexpr) + str(npar)
            if tmp in reverse_mapping.keys():
                pt = reverse_mapping[tmp]

        params = kwargs.get("params", dict())
        if len(params) > 0:
            # we are most likely dealing with an interactive series
            skip_check = True
            pt = "pinter"
            args = [exprs, ranges, label]

        if pt not in mapping.keys():
            raise ValueError(
                "Don't know how to plot the expression:\n"
                + "Received: {}\n".format(args)
                + "Number of subexpressions: {}\n".format(nexpr)
                + "Number of parameters: {}".format(npar)
            )

        _cls, nexpr, npar = mapping[pt]
        if not skip_check:
            # In case of LineOver1DRangeSeries, Parametric2DLineSeries,
            # Parametric3DLineSeries, ParametricSurfaceSeries,
            # SurfaceOver2DRangeSeries, validate the provided expressions/ranges
            args = _check_arguments(args, nexpr, npar)[0]

        _slice = kwargs.pop("slice", None)
        if pt == "v3d" and (_slice is not None):
            args = [_slice] + list(args)
            _cls, nexpr, npar = mapping["v3ds"]

    else:
        if pt in mapping.keys():
            _cls, nexpr, npar = mapping[pt]
            k = str(nexpr) + str(npar)
            if k == "00":
                args = [exprs, ranges, label]
                if kwargs.get("is_complex", False):
                    _cls = ComplexInteractiveSeries
                    args = [exprs[0], ranges[0], label]
            elif k == "22":
                if isinstance(args[0], (Vector, DenseMatrix)):
                    split_expr, ranges = _split_vector(exprs[0], ranges)
                    args = [split_expr[:2], *ranges, label]
                args = _check_arguments(args, 2, 2)[0]
            elif k == "33":
                if isinstance(args[0], (Vector, DenseMatrix)):
                    split_expr, ranges = _split_vector(exprs[0], ranges)
                    args = [split_expr, *ranges, label]
                args = _check_arguments(args, 3, 3)[0]

                _slice = kwargs.pop("slice", None)
                if _slice is not None:
                    args = [_slice] + list(args)
                    _cls = SliceVector3DSeries
            elif k == "99":
                _cls = GeometrySeries
                if len(ranges) == 0:
                    ranges = [None]
                args = [*exprs, *ranges, label]
                if (
                    isinstance(exprs[0], Plane)
                    and len(kwargs.get("params", dict())) > 0
                ):
                    _cls = PlaneInteractiveSeries
                    args = [exprs, ranges, label]
            else:
                args = _check_arguments(args, nexpr, npar)[0]
        else:
            raise ValueError(
                "Wrong `pt` value. Please, check the docstring "
                + "of `get_plot_data` to list the possible values."
            )
    kwargs = _set_discretization_points(kwargs, _cls)
    return _cls(*args, **kwargs)
コード例 #4
0
def plot_implicit(*args, show=True, **kwargs):
    """Plot implicit equations / inequalities.

    plot_implicit, by default, generates a contour using a mesh grid of fixed
    number of points. The greater the number of points, 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.

    Arguments
    =========
        expr : Expr, Relational, BooleanFunction
            The equation / inequality that is to be plotted.

        ranges : tuples
            Two tuple denoting the discretization domain, for example:
            `(x, -10, 10), (y, -10, 10)`
            If no range is given, then the free symbols in the expression will
            be assigned in the order they are sorted.

        label : str
            The name of the expression to be eventually shown on the legend.
            If none is provided, the string representation will be used.

    Keyword Arguments
    =================

        adaptive : Boolean
            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.
            It switches to a fall back algorithm (meshgrid approach) if the
            expression cannot be plotted using interval arithmetic.

        depth : integer
            The depth of recursion for adaptive mesh 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.

        n1, n2 : int
            Number of discretization points in the horizontal and vertical
            directions when `adaptive=False`. Default to 1000.

        n : integer
            Set the number of discretization points when `adaptive=False` in
            both direction simultaneously. Default value is 1000.
            The greater the value the more accurate the plot, but the more
            memory will be used.

        show : Boolean
            Default value is True. If set to False, the plot will not be shown.
            See ``Plot`` for further information.

        title : string
            The title for the plot.

        xlabel : string
            The label for the x-axis

        ylabel : string
            The label for the y-axis

    Examples
    ========

    Plot expressions:

    .. plot::
        :context: reset
        :format: doctest
        :include-source: True

        >>> from sympy import plot_implicit, symbols, Eq, And
        >>> x, y = symbols('x y')

    Without any ranges for the symbols in the expression:

    .. plot::
        :context: close-figs
        :format: doctest
        :include-source: True

        >>> p1 = plot_implicit(Eq(x**2 + y**2, 5))

    With the range for the symbols:

    .. plot::
        :context: close-figs
        :format: doctest
        :include-source: True

        >>> p2 = plot_implicit(
        ...     Eq(x**2 + y**2, 3), (x, -3, 3), (y, -3, 3))

    Using mesh grid without adaptive meshing with number of points
    specified:

    .. plot::
        :context: close-figs
        :format: doctest
        :include-source: True

        >>> p3 = plot_implicit(
        ...     (x**2 + y**2 - 1)**3 - x**2 * y**3,
        ...     (x, -1.5, 1.5), (y, -1.5, 1.5),
        ...     n = 1000)

    Using adaptive meshing and Boolean expressions:

    .. plot::
        :context: close-figs
        :format: doctest
        :include-source: True

        >>> p4 = plot_implicit(
        ...     Eq(y, sin(x)) & (y > 0),
        ...     Eq(y, sin(x)) & (y < 0),
        ...     (x, -2 * pi, 2 * pi), (y, -4, 4),
        ...     adaptive=True)

    Using adaptive meshing with depth of recursion as argument:

    .. plot::
        :context: close-figs
        :format: doctest
        :include-source: True

        >>> p5 = plot_implicit(
        ...     Eq(x**2 + y**2, 5), (x, -4, 4), (y, -4, 4),
        ...     adaptive=True, depth = 2)

    Plotting regions:

    .. plot::
        :context: close-figs
        :format: doctest
        :include-source: True

        >>> p6 = plot_implicit(y > x**2)

    """
    from spb.defaults import TWO_D_B

    args = _plot_sympify(args)
    args = _check_arguments(args, 1, 2)

    kwargs = _set_discretization_points(kwargs, ImplicitSeries)

    series_kw = dict()
    series_kw["n1"] = kwargs.pop("n1", 1000)
    series_kw["n2"] = kwargs.pop("n2", 1000)
    series_kw["depth"] = kwargs.pop("depth", 0)
    series_kw["adaptive"] = kwargs.pop("adaptive", False)

    series = []
    xmin, xmax, ymin, ymax = oo, -oo, oo, -oo
    for a in args:
        s = ImplicitSeries(*a, **series_kw)
        if s.start_x < xmin:
            xmin = s.start_x
        if s.end_x > xmax:
            xmax = s.end_x
        if s.start_y < ymin:
            ymin = s.start_y
        if s.end_y > ymax:
            ymax = s.end_y
        series.append(s)

    kwargs.setdefault("backend", TWO_D_B)
    kwargs.setdefault("xlim", (xmin, xmax))
    kwargs.setdefault("ylim", (ymin, ymax))
    kwargs.setdefault("xlabel", series[-1].var_x.name)
    kwargs.setdefault("ylabel", series[-1].var_y.name)
    p = Plot(*series, **kwargs)
    if show:
        p.show()
    return p
コード例 #5
0
def plot_contour(*args, show=True, **kwargs):
    """
    Draws contour plot of a function

    Usage
    =====

    Single plot

    ``plot_contour(expr, range_x, range_y, **kwargs)``

    If the ranges are not specified, then a default range of (-10, 10) is used.

    Multiple plot with the same range.

    ``plot_contour(expr1, expr2, range_x, range_y, **kwargs)``

    If the ranges are not specified, then a default range of (-10, 10) is used.

    Multiple plots with different ranges.

    ``plot_contour((expr1, range_x, range_y), (expr2, range_x, range_y), ..., **kwargs)``

    Ranges have to be specified for every expression.

    Default range may change in the future if a more advanced default range
    detection algorithm is implemented.

    Arguments
    =========

    ``expr`` : Expression representing the function along x.

    ``range_x``: (x, 0, 5), A 3-tuple denoting the range of the x
    variable.

    ``range_y``: (y, 0, 5), A 3-tuple denoting the range of the y
     variable.

    Keyword Arguments
    =================

    Arguments for ``ContourSeries`` class:

    ``n1``: int. The x range is sampled uniformly at ``n1`` of points.

    ``n2``: int. The y range is sampled uniformly at ``n2`` of points.

    ``n``: int. The x and y ranges are sampled uniformly at ``n`` of points.
    It overrides ``n1`` and ``n2``.

    Arguments for ``Plot`` class:

    ``title`` : str. Title of the plot.
    ``size`` : (float, float), optional
        A tuple in the form (width, height) in inches to specify the size of
        the overall figure. The default value is set to ``None``, meaning
        the size will be set by the default backend.

    See Also
    ========

    Plot, ContourSeries

    """
    from spb.defaults import TWO_D_B

    args = _plot_sympify(args)
    kwargs.setdefault("backend", TWO_D_B)
    kwargs = _set_discretization_points(kwargs, ContourSeries)
    plot_expr = _check_arguments(args, 1, 2)
    series = [ContourSeries(*arg, **kwargs) for arg in plot_expr]
    xlabel = series[0].var_x.name
    ylabel = series[0].var_y.name
    kwargs.setdefault("xlabel", xlabel)
    kwargs.setdefault("ylabel", ylabel)
    plot_contours = Plot(*series, **kwargs)
    if show:
        plot_contours.show()
    return plot_contours
コード例 #6
0
def plot3d_parametric_surface(*args, show=True, **kwargs):
    """
    Plots a 3D parametric surface plot.

    Explanation
    ===========

    Single plot.

    ``plot3d_parametric_surface(expr_x, expr_y, expr_z, range_u, range_v, **kwargs)``

    If the ranges is not specified, then a default range of (-10, 10) is used.

    Multiple plots.

    ``plot3d_parametric_surface((expr_x, expr_y, expr_z, range_u, range_v), ..., **kwargs)``

    Ranges have to be specified for every expression.

    Default range may change in the future if a more advanced default range
    detection algorithm is implemented.

    Arguments
    =========

    ``expr_x``: Expression representing the function along ``x``.

    ``expr_y``: Expression representing the function along ``y``.

    ``expr_z``: Expression representing the function along ``z``.

    ``range_u``: ``(u, 0, 5)``,  A 3-tuple denoting the range of the ``u``
    variable.

    ``range_v``: ``(v, 0, 5)``,  A 3-tuple denoting the range of the v
    variable.

    Keyword Arguments
    =================

    Arguments for ``ParametricSurfaceSeries`` class:

    ``n1``: int. The ``u`` range is sampled uniformly at ``n1`` of points

    ``n2``: int. The ``v`` range is sampled uniformly at ``n2`` of points

    ``n``: int. The u and v ranges are sampled uniformly at ``n`` of points.
    It overrides ``n1`` and ``n2``.

    Arguments for ``Plot`` class:

    ``title`` : str. Title of the plot.
    ``size`` : (float, float), optional
    A tuple in the form (width, height) in inches to specify the size of the
    overall figure. The default value is set to ``None``, meaning the size will
    be set by the default backend.

    Examples
    ========

    .. plot::
       :context: reset
       :format: doctest
       :include-source: True

       >>> from sympy import symbols, cos, sin
       >>> from sympy.plotting import plot3d_parametric_surface
       >>> u, v = symbols('u v')

    Single plot.

    .. plot::
       :context: close-figs
       :format: doctest
       :include-source: True

       >>> plot3d_parametric_surface(cos(u + v), sin(u - v), u - v,
       ...     (u, -5, 5), (v, -5, 5))
       Plot object containing:
       [0]: parametric cartesian surface: (cos(u + v), sin(u - v), u - v) for u over (-5.0, 5.0) and v over (-5.0, 5.0)


    See Also
    ========

    Plot, ParametricSurfaceSeries

    """
    from spb.defaults import THREE_D_B

    args = _plot_sympify(args)
    kwargs.setdefault("backend", THREE_D_B)
    kwargs = _set_discretization_points(kwargs, ParametricSurfaceSeries)
    plot_expr = _check_arguments(args, 3, 2)
    kwargs.setdefault("xlabel", "x")
    kwargs.setdefault("ylabel", "y")
    kwargs.setdefault("zlabel", "z")
    series = [ParametricSurfaceSeries(*arg, **kwargs) for arg in plot_expr]
    plots = Plot(*series, **kwargs)
    if show:
        plots.show()
    return plots
コード例 #7
0
def plot3d(*args, show=True, **kwargs):
    """
    Plots a 3D surface plot.

    Usage
    =====

    Single plot

    ``plot3d(expr, range_x, range_y, **kwargs)``

    If the ranges are not specified, then a default range of (-10, 10) is used.

    Multiple plot with the same range.

    ``plot3d(expr1, expr2, range_x, range_y, **kwargs)``

    If the ranges are not specified, then a default range of (-10, 10) is used.

    Multiple plots with different ranges.

    ``plot3d((expr1, range_x, range_y), (expr2, range_x, range_y), ..., **kwargs)``

    Ranges have to be specified for every expression.

    Default range may change in the future if a more advanced default range
    detection algorithm is implemented.

    Arguments
    =========

    ``expr`` : Expression representing the function along x.

    ``range_x``: (x, 0, 5), A 3-tuple denoting the range of the x
    variable.

    ``range_y``: (y, 0, 5), A 3-tuple denoting the range of the y
     variable.

    Keyword Arguments
    =================

    Arguments for ``SurfaceOver2DRangeSeries`` class:

    ``n1``: int. The x range is sampled uniformly at ``n1`` of points.

    ``n2``: int. The y range is sampled uniformly at ``n2`` of points.

    ``n``: int. The x and y ranges are sampled uniformly at ``n`` of points.
    It overrides ``n1`` and ``n2``.

    Arguments for ``Plot`` class:

    ``title`` : str. Title of the plot.
    ``size`` : (float, float), optional
    A tuple in the form (width, height) in inches to specify the size of the
    overall figure. The default value is set to ``None``, meaning the size will
    be set by the default backend.

    Examples
    ========

    .. plot::
       :context: reset
       :format: doctest
       :include-source: True

       >>> from sympy import symbols
       >>> from sympy.plotting import plot3d
       >>> x, y = symbols('x y')

    Single plot

    .. plot::
       :context: close-figs
       :format: doctest
       :include-source: True

       >>> plot3d(x*y, (x, -5, 5), (y, -5, 5))
       Plot object containing:
       [0]: cartesian surface: x*y for x over (-5.0, 5.0) and y over (-5.0, 5.0)


    Multiple plots with same range

    .. plot::
       :context: close-figs
       :format: doctest
       :include-source: True

       >>> plot3d(x*y, -x*y, (x, -5, 5), (y, -5, 5))
       Plot object containing:
       [0]: cartesian surface: x*y for x over (-5.0, 5.0) and y over (-5.0, 5.0)
       [1]: cartesian surface: -x*y for x over (-5.0, 5.0) and y over (-5.0, 5.0)


    Multiple plots with different ranges.

    .. plot::
       :context: close-figs
       :format: doctest
       :include-source: True

       >>> plot3d((x**2 + y**2, (x, -5, 5), (y, -5, 5)),
       ...     (x*y, (x, -3, 3), (y, -3, 3)))
       Plot object containing:
       [0]: cartesian surface: x**2 + y**2 for x over (-5.0, 5.0) and y over (-5.0, 5.0)
       [1]: cartesian surface: x*y for x over (-3.0, 3.0) and y over (-3.0, 3.0)


    See Also
    ========

    Plot, SurfaceOver2DRangeSeries

    """
    from spb.defaults import THREE_D_B

    args = _plot_sympify(args)
    kwargs.setdefault("backend", THREE_D_B)
    kwargs = _set_discretization_points(kwargs, SurfaceOver2DRangeSeries)
    series = []
    plot_expr = _check_arguments(args, 1, 2)
    series = [SurfaceOver2DRangeSeries(*arg, **kwargs) for arg in plot_expr]
    xlabel = series[0].var_x.name
    ylabel = series[0].var_y.name
    kwargs.setdefault("xlabel", xlabel)
    kwargs.setdefault("ylabel", ylabel)
    kwargs.setdefault("zlabel", "f(%s, %s)" % (xlabel, ylabel))
    plots = Plot(*series, **kwargs)
    if show:
        plots.show()
    return plots
コード例 #8
0
def plot3d_parametric_line(*args, show=True, **kwargs):
    """
    Plots a 3D parametric line plot.

    Usage
    =====

    Single plot:

    ``plot3d_parametric_line(expr_x, expr_y, expr_z, range, label, **kwargs)``

    If the range is not specified, then a default range of (-10, 10) is used.

    Multiple plots.

    ``plot3d_parametric_line((expr_x, expr_y, expr_z, range, label), ..., **kwargs)``

    Ranges have to be specified for every expression.

    Default range may change in the future if a more advanced default range
    detection algorithm is implemented.

    Arguments
    =========

    ``expr_x`` : Expression representing the function along x.

    ``expr_y`` : Expression representing the function along y.

    ``expr_z`` : Expression representing the function along z.

    ``range``: ``(u, 0, 5)``, A 3-tuple denoting the range of the parameter
    variable.

    ``label`` : An optional string denoting the label of the expression
        to be visualized on the legend. If not provided, the label will be the
        string representation of the expression.

    Keyword Arguments
    =================

    Arguments for ``Parametric3DLineSeries`` class.

    ``n``: The range is uniformly sampled at ``n`` number of points.

    Arguments for ``Plot`` class.

    ``title`` : str. Title of the plot.

    ``size`` : (float, float), optional
        A tuple in the form (width, height) in inches to specify the size of
        the overall figure. The default value is set to ``None``, meaning
        the size will be set by the default backend.

    Examples
    ========

    .. plot::
       :context: reset
       :format: doctest
       :include-source: True

       >>> from sympy import symbols, cos, sin
       >>> from sympy.plotting import plot3d_parametric_line
       >>> u = symbols('u')

    Single plot.

    .. plot::
       :context: close-figs
       :format: doctest
       :include-source: True

       >>> plot3d_parametric_line(cos(u), sin(u), u, (u, -5, 5))
       Plot object containing:
       [0]: 3D parametric cartesian line: (cos(u), sin(u), u) for u over (-5.0, 5.0)


    Multiple plots with different ranges and custom labels.

    .. plot::
       :context: close-figs
       :format: doctest
       :include-source: True

       >>> plot3d_parametric_line((cos(u), sin(u), u, (u, -5, 5), "a"),
       ...     (sin(u), u**2, u, (u, -3, 3), "b"), legend=True)
       Plot object containing:
       [0]: 3D parametric cartesian line: (cos(u), sin(u), u) for u over (-5.0, 5.0)
       [1]: 3D parametric cartesian line: (sin(u), u**2, u) for u over (-3.0, 3.0)


    See Also
    ========

    Plot, Parametric3DLineSeries

    """
    from spb.defaults import THREE_D_B

    args = _plot_sympify(args)
    kwargs.setdefault("backend", THREE_D_B)
    kwargs = _set_discretization_points(kwargs, Parametric3DLineSeries)
    series = []
    plot_expr = _check_arguments(args, 3, 1)
    series = [Parametric3DLineSeries(*arg, **kwargs) for arg in plot_expr]
    kwargs.setdefault("xlabel", "x")
    kwargs.setdefault("ylabel", "y")
    kwargs.setdefault("zlabel", "z")
    plots = Plot(*series, **kwargs)
    if show:
        plots.show()
    return plots
コード例 #9
0
def plot_parametric(*args, show=True, **kwargs):
    """
    Plots a 2D parametric curve.

    Parameters
    ==========

    args
        Common specifications are:

        - Plotting a single parametric curve with a range
            ``plot_parametric(expr_x, expr_y, range)``
        - Plotting multiple parametric curves with the same range
            ``plot_parametric((expr_x, expr_y), ..., range)``
        - Plotting multiple parametric curves with different ranges
            ``plot_parametric((expr_x, expr_y, range), ...)``
        - Plotting multiple parametric curves with different ranges and
            custom labels
            ``plot_parametric((expr_x, expr_y, range, label), ...)``

        ``expr_x`` is the expression representing $x$ component of the
        parametric function.

        ``expr_y`` is the expression representing $y$ component of the
        parametric function.

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

        However, if the arguments are specified as
        ``(expr_x, expr_y, range), ...``, you must specify the ranges
        for each expressions manually.

        Default range may change in the future if a more advanced
        algorithm is implemented.

        ``label`` : An optional string denoting the label of the expression
        to be visualized on the legend. If not provided, the label will be the
        string representation of the expression.

    adaptive : bool, optional
        Specifies whether to use the adaptive sampling or not.

        The default value is set to ``True``. Set adaptive to ``False``
        and specify ``n`` if uniform sampling is required.

    depth :  int, optional
        The recursion depth of the adaptive algorithm. A depth of
        value $n$ samples a maximum of $2^n$ points.

    n : int, optional
        Used when the ``adaptive`` flag is set to ``False``.

        Specifies the number of the points used for the uniform
        sampling.

    xlabel : str, optional
        Label for the x-axis.

    ylabel : str, optional
        Label for the y-axis.

    xscale : 'linear' or 'log', optional
        Sets the scaling of the x-axis.

    yscale : 'linear' or 'log', optional
        Sets the scaling of the y-axis.

    axis_center : (float, float), optional
        Tuple of two floats denoting the coordinates of the center or
        {'center', 'auto'}

    xlim : (float, float), optional
        Denotes the x-axis limits, ``(min, max)```.

    ylim : (float, float), optional
        Denotes the y-axis limits, ``(min, max)```.

    size : (float, float), optional
        A tuple in the form (width, height) in inches to specify the size of
        the overall figure. The default value is set to ``None``, meaning
        the size will be set by the default backend.

    Examples
    ========

    .. plot::
       :context: reset
       :format: doctest
       :include-source: True

       >>> from sympy import symbols, cos, sin
       >>> from sympy.plotting import plot_parametric
       >>> u = symbols('u')

    A parametric plot with a single expression:

    .. plot::
       :context: close-figs
       :format: doctest
       :include-source: True

       >>> plot_parametric((cos(u), sin(u)), (u, -5, 5))
       Plot object containing:
       [0]: parametric cartesian line: (cos(u), sin(u)) for u over (-5.0, 5.0)

    A parametric plot with multiple expressions with the same range:

    .. plot::
       :context: close-figs
       :format: doctest
       :include-source: True

       >>> plot_parametric((cos(u), sin(u)), (u, cos(u)), (u, -10, 10))
       Plot object containing:
       [0]: parametric cartesian line: (cos(u), sin(u)) for u over (-10.0, 10.0)
       [1]: parametric cartesian line: (u, cos(u)) for u over (-10.0, 10.0)

    A parametric plot with multiple expressions with different ranges and
    custom labels for each curve:

    .. plot::
       :context: close-figs
       :format: doctest
       :include-source: True

       >>> plot_parametric((cos(u), sin(u), (u, -5, 5), "a"),
       ...     (cos(u), u, "b"))
       Plot object containing:
       [0]: parametric cartesian line: (cos(u), sin(u)) for u over (-5.0, 5.0)
       [1]: parametric cartesian line: (cos(u), u) for u over (-10.0, 10.0)

    Notes
    =====

    The plotting uses an adaptive algorithm which samples recursively to
    accurately plot the curve. The adaptive algorithm uses a random point
    near the midpoint of two points that has to be further sampled.
    Hence, repeating the same plot command can give slightly different
    results because of the random sampling.

    See Also
    ========

    Plot, Parametric2DLineSeries
    """
    from spb.defaults import TWO_D_B

    args = _plot_sympify(args)
    series = []
    kwargs.setdefault("backend", TWO_D_B)
    kwargs = _set_discretization_points(kwargs, Parametric2DLineSeries)
    plot_expr = _check_arguments(args, 2, 1)
    series = [Parametric2DLineSeries(*arg, **kwargs) for arg in plot_expr]
    plots = Plot(*series, **kwargs)
    if show:
        plots.show()
    return plots
コード例 #10
0
def plot(*args, show=True, **kwargs):
    """Plots a function of a single variable as a curve.

    Parameters
    ==========

    args :
        The first argument is the expression representing the function
        of single variable to be plotted.

        The next argument is a 3-tuple denoting the range of the free
        variable. e.g. ``(x, 0, 5)``

        The last optional argument is a string denoting the label of the
        expression to be visualized on the legend. If not provided, the label
        will be the string representation of the expression.

        Typical usage examples are in the followings:

        - Plotting a single expression with a single range.
            ``plot(expr, range, **kwargs)``
        - Plotting a single expression with the default range (-10, 10).
            ``plot(expr, **kwargs)``
        - Plotting multiple expressions with a single range.
            ``plot(expr1, expr2, ..., range, **kwargs)``
        - Plotting multiple expressions with multiple ranges.
            ``plot((expr1, range1), (expr2, range2), ..., **kwargs)``
        - Plotting multiple expressions with multiple ranges and custom labels.
            ``plot((expr1, range1, label1), (expr2, range2, label2), ..., legend=True, **kwargs)``

        It is best practice to specify range explicitly because default
        range may change in the future if a more advanced default range
        detection algorithm is implemented.

    adaptive : bool, optional
        The default value is set to ``True``. Set adaptive to ``False``
        and specify ``n`` if uniform sampling is required.

        The plotting uses an adaptive algorithm which samples
        recursively to accurately plot. The adaptive algorithm uses a
        random point near the midpoint of two points that has to be
        further sampled. Hence the same plots can appear slightly
        different.

    axis_center : (float, float), optional
        Tuple of two floats denoting the coordinates of the center or
        {'center', 'auto'}. Only available with MatplotlibBackend.

    depth : int, optional
        Recursion depth of the adaptive algorithm. A depth of value
        ``n`` samples a maximum of `2^{n}` points.

        If the ``adaptive`` flag is set to ``False``, this will be
        ignored.

    detect_poles : boolean
            Chose whether to detect and correctly plot poles. 
            Defaulto to False. This improve detection, increase the number of 
            discretization points and/or change the value of `eps`.

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

    n : int, optional
        Used when the ``adaptive`` is set to ``False``. The function
        is uniformly sampled at ``n`` number of points.

        If the ``adaptive`` flag is set to ``True``, this will be
        ignored.

    only_integers : boolean, optional
        Default to False. If True, discretize the domain with integer numbers.
        This can be useful to plot sums.

    polar : boolean
        Default to False. If True, generate a polar plot of a curve with radius
        `expr` as a function of the range

    show : bool, optional
        The default value is set to ``True``. Set show to ``False`` and
        the function will not display the plot. The returned instance of
        the ``Plot`` class can then be used to save or display the plot
        by calling the ``save()`` and ``show()`` methods respectively.

    size : (float, float), optional
        A tuple in the form (width, height) in inches to specify the size of
        the overall figure. The default value is set to ``None``, meaning
        the size will be set by the default backend.

    steps : boolean, optional
        Default to False. If True, connects consecutive points with steps 
        rather than straight segments.

    title : str, optional
        Title of the plot. It is set to the latex representation of
        the expression, if the plot has only one expression.

    xlabel : str, optional
        Label for the x-axis.

    ylabel : str, optional
        Label for the y-axis.

    xscale : 'linear' or 'log', optional
        Sets the scaling of the x-axis.

    yscale : 'linear' or 'log', optional
        Sets the scaling of the y-axis.

    xlim : (float, float), optional
        Denotes the x-axis limits, ``(min, max)```.

    ylim : (float, float), optional
        Denotes the y-axis limits, ``(min, max)```.


    Examples
    ========

    .. plot::
       :context: close-figs
       :format: doctest
       :include-source: True

       >>> from sympy import symbols
       >>> from sympy.plotting import plot
       >>> x = symbols('x')

    Single Plot

    .. plot::
       :context: close-figs
       :format: doctest
       :include-source: True

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

    Multiple plots with single range.

    .. plot::
       :context: close-figs
       :format: doctest
       :include-source: True

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

    Multiple plots with different ranges and custom labels.

    .. plot::
       :context: close-figs
       :format: doctest
       :include-source: True

       >>> plot((x**2, (x, -6, 6), "$f_{1}$"), (x, (x, -5, 5), "f2"), legend=True)
       Plot object containing:
       [0]: cartesian line: x**2 for x over (-6.0, 6.0)
       [1]: cartesian line: x for x over (-5.0, 5.0)

    No adaptive sampling.

    .. plot::
       :context: close-figs
       :format: doctest
       :include-source: True

       >>> plot(x**2, adaptive=False, n=400)
       Plot object containing:
       [0]: cartesian line: x**2 for x over (-10.0, 10.0)

    Polar plot:

    .. code-block:: python
        plot(1 + sin(10 * x) / 10, (x, 0, 2 * pi), polar=True, aspect="equal")

    See Also
    ========

    Plot, LineOver1DRangeSeries

    """
    from spb.defaults import TWO_D_B

    args = _plot_sympify(args)
    free = set()
    for a in args:
        if isinstance(a, Expr):
            free |= a.free_symbols
            if len(free) > 1:
                raise ValueError("The same variable should be used in all "
                                 "univariate expressions being plotted.")
    x = free.pop() if free else Symbol("x")
    kwargs.setdefault("backend", TWO_D_B)
    kwargs.setdefault("xlabel", x.name)
    kwargs.setdefault("ylabel", "f(%s)" % x.name)
    kwargs = _set_discretization_points(kwargs, LineOver1DRangeSeries)
    series = []
    plot_expr = _check_arguments(args, 1, 1)
    series = _build_line_series(*plot_expr, **kwargs)

    plots = Plot(*series, **kwargs)
    if show:
        plots.show()
    return plots
コード例 #11
0
def geometry_plot(*args, show=True, **kwargs):
    """Plot entities from the sympy.geometry module.

    Arguments
    =========
        geom : GeometryEntity
            Represent the geometric entity to be plotted.

        label : str
            The name of the complex function to be eventually shown on the
            legend. If none is provided, the string representation of the
            function will be used.

        To specify multiple complex functions, wrap them into a tuple.
        Refer to the examples to learn more.

    Keyword Arguments
    =================

        fill : boolean
            Default to True. Fill the polygon/circle/ellipse.

        params : dict
            Substitution dictionary to properly evaluate symbolic geometric
            entities. The keys contains symbols, the values the numeric number
            associated to the symbol.

    Examples
    ========

    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`.

    .. code-block:: python
        geometry_plot(
            Circle(Point(0, 0), 5),
            Ellipse(Point(-3, 2), hradius=3, eccentricity=Rational(4, 5)),
            Polygon((4, 0), 4, n=5),
            Curve((cos(x), sin(x)), (x, 0, 2 * pi)),
            Segment((-4, -6), (6, 6)),
            Point2D(0, 0))

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

    .. code-block:: python
        geometry_plot(
            Circle(Point(0, 0), 5),
            Ellipse(Point(-3, 2), hradius=3, eccentricity=Rational(4, 5)),
            Polygon((4, 0), 4, n=5),
            Curve((cos(x), sin(x)), (x, 0, 2 * pi)),
            Segment((-4, -6), (6, 6)),
            Point2D(0, 0), fill=False)

    Plot several symbolic geometric entities. We need to pass in the `params`
    dictionary, which will be used to substitute symbols before numerical
    evaluation. Note: here we also set custom labels:

    .. code-block:: python
        a, b, c, d = symbols("a, b, c, d")
        geometry_plot(
            (Polygon((a, b), c, n=d), "triangle"),
            (Polygon((a + 2, b + 3), c, n=d + 1), "square"),
            params = {a: 0, b: 1, c: 2, d: 3}
        )

    Plot 3D geometric entities. Note: when plotting a Plane, we must always
    provide the x/y/z ranges:

    .. code-block:: python
        geometry_plot(
            (Point3D(5, 5, 5), "center"),
            (Line3D(Point3D(-2, -3, -4), Point3D(2, 3, 4)), "line"),
            (Plane((0, 0, 0), (1, 1, 1)), (x, -5, 5), (y, -4, 4), (z, -10, 10))
        )

    """
    from spb.defaults import TWO_D_B, THREE_D_B

    args = _plot_sympify(args)

    series = []
    if not all([isinstance(a, (list, tuple, Tuple)) for a in args]):
        args = [args]

    for a in args:
        exprs, ranges, label = _unpack_args(*a)
        r = ranges if len(ranges) > 0 else [None]
        if len(exprs) == 1:
            series.append(GeometrySeries(exprs[0], *r, label, **kwargs))
        else:
            # this is the case where the user provided: v1, v2, ..., range
            # we use the same ranges for each expression
            for e in exprs:
                series.append(GeometrySeries(e, *r, str(e), **kwargs))

    any_3D = any(s.is_3D for s in series)
    if ("aspect" not in kwargs) and (not any_3D):
        kwargs["aspect"] = "equal"

    if any_3D:
        kwargs.setdefault("backend", THREE_D_B)
    else:
        kwargs.setdefault("backend", TWO_D_B)

    p = Plot(*series, **kwargs)
    if show:
        p.show()
    return p
コード例 #12
0
def pw(*args):
    """_preprocess wrapper. Only need it to sympify the arguments before
    calling _preprocess."""
    args = _plot_sympify(args)
    return _preprocess(*args)
コード例 #13
0
def complex_plot(*args, show=True, **kwargs):
    """Plot complex numbers or complex functions. By default, the aspect ratio
    of the plot is set to ``aspect="equal"``.

    Depending on the provided expression, this function will produce different
    types of plots:
    * list of complex numbers: creates a scatter plot.
    * function of 1 variable over a real range:
        1. line plot separating the real and imaginary parts.
        2. line plot of the modulus of the complex function colored by its
            argument, if `absarg=True`.
        3. line plot of the modulus and the argument, if `abs=True, arg=True`.
    * function of 2 variables over 2 real ranges:
        1. By default, a surface plot of the real part is created.
        2. By toggling `real=True, imag=True, abs=True` we can create surface
            plots of the real, imaginary part or the absolute value.
    * complex function over a complex range:
        1. domain coloring plot.
        2. 3D plot of the modulus colored by the argument, if `threed=True`.
        3. 3D plot of the real and imaginary part.

    Explore the example below to better understand how to use it.

    Arguments
    =========
        expr : Expr
            Represent the complex number or complex function to be plotted.

        range : 3-element tuple
            Denotes the range of the variables. For example:
            * (z, -5, 5): plot a line from complex point (-5 + 0*I) to (5 + 0*I)
            * (z, -5 + 2*I, 5 + 2*I): plot a line from complex point (-5 + 2*I)
                to (5 + 2 * I). Note the same imaginary part for the start/end
                point.
            * (z, -5 - 3*I, 5 + 3*I): domain coloring plot of the complex
                function over the specified domain.

        label : str
            The name of the complex function to be eventually shown on the
            legend. If none is provided, the string representation of the
            function will be used.

        To specify multiple complex functions, wrap them into a tuple.
        Refer to the examples to learn more.

    Keyword Arguments
    =================

        absarg : boolean
            If True, plot the modulus of the complex function colored by its
            argument. If False, separately plot the real and imaginary parts.
            Default to False.

        abs : boolean
            If True, and if the provided range is a real segment, plot the
            modulus of the complex function. Default to False.

        adaptive : boolean
            Attempt to create line plots by using an adaptive algorithm.
            Default to True. If `absarg=True`, the function will automatically
            switch to `adaptive=False`, using a uniformly-spaced grid.

        arg : boolean
            If True, and if the provided range is a real segment, plot the
            argument of the complex function. Default to False.

        depth : int
            Controls the smootheness of the overall evaluation. The higher
            the number, the smoother the function, the more memory will be
            used by the recursive procedure. Default value is 9.

        detect_poles : boolean
            Chose whether to detect and correctly plot poles. Defaulto to False.
            This improve detection, increase the number of discretization points
            and/or change the value of `eps`.

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

        n1, n2 : int
            Number of discretization points in the real/imaginary-directions,
            respectively. For domain coloring plots (2D and 3D), default to 300.
            For line plots default to 1000.

        n : int
            Set the same number of discretization points in all directions.
            For domain coloring plots (2D and 3D), default to 300. For line
            plots default to 1000.

        real : boolean
            If True, and if the provided range is a real segment, plot the
            real part of the complex function.
            If a complex range is given and `threed=True`, plot a 3D
            representation of the real part. Default to False.

        imag : boolean
            If True, and if the provided range is a real segment, plot the
            imaginary part of the complex function.
            If a complex range is given and `threed=True`, plot a 3D
            representation of the imaginary part. Default to False.

        show : boolean
            Default to True, in which case the plot will be shown on the screen.

        threed : boolean
            Default to False. When True, it will plot a 3D representation of the
            absolute value of the complex function colored by its argument.

        use_cm : boolean
            If `absarg=True` and `use_cm=True` then plot the modulus of the
            complex function colored by its argument. If `use_cm=False`, plot
            the modulus of the complex function with a solid color.
            Default to True.

    Domain Coloring Arguments
    =========================

        coloring : str
            Default to "a". Chose between different coloring options:
            "a": standard domain coloring using HSV.
            "b": enhanced domain coloring using HSV, showing iso-modulus and
                is-phase lines.
            "c": enhanced domain coloring using HSV, showing iso-modulus lines.
            "d": enhanced domain coloring using HSV, showing iso-phase lines.
            "e": HSV color grading. Read the following article to understand it:
                https://www.codeproject.com/Articles/80641/Visualizing-Complex-Functions
            "f": domain coloring implemented by cplot:
                https://github.com/nschloe/cplot
                Use the following keywords to further customize the appearance:
                    `abs_scaling`: str
                        Default to "h-1". It can be used to adjust the use of
                        colors. h with a value less than 1.0 adds more color
                        which can help isolating the roots and poles (which are
                        still black and white, respectively). "h-0.0" ignores
                        the magnitude of f(z) completely. "arctan" is another
                        possible scaling.
                    `colorspace` : str
                        Default to "cam16". Can be set to "hsl" to get the
                        common fully saturated, vibrant colors.
                    `abs` and/or `args` : boolean
                        Set them to True to show contour lines for absolute
                        value and argument.
                    `levels` : (n_abs, n_arg)
                        Number of contour levels for the absolute value and the
                        argument.
                WARNING: if `abs=True` and/or `arg=True`, only MatplotlibBackend
                will be able to render the plot! Moreover, `iplot` won't be
                able to update these contour lines.
            "g": alternating black and white stripes corresponding to modulus.
            "h": alternating black and white stripes corresponding to phase.
            "i": alternating black and white stripes corresponding to real part.
            "j": alternating black and white stripes corresponding to imaginary
                part.
            "k": cartesian chessboard on the complex points space. The result
                will hide zeros.
            "l": polar Chessboard on the complex points space. The result will
                show conformality.

        alpha : float
            This parameter works when `coloring="f"`.
            Default to 1. Can be `0 <= alpha <= 1`. It adjust the use of colors.
            A value less than 1 adds more color which can help isolating the
            roots and poles (which are still black and white, respectively).
            alpha=0 ignores the magnitude of f(z) completely.

        colorspace : str
            This parameter works when `coloring="f"`.
            Default to `"cam16"`. Other options are `"cielab", "oklab", "hsl"`.
            It can be set to `"hsl"` to get the common fully saturated, vibrant
            colors. This is usually a bad idea since it creates artifacts which
            are not related with the underlying data.

        phaseres : int
            This parameter works when `coloring` is different from `"f"`.
            Default value to 20. It controls the number of iso-phase or
            iso-modulus lines.

    Examples
    ========

    Plot individual complex points:

    .. code-block:: python
        complex_plot(3 + 2 * I, 4 * I, 2, aspect="equal", legend=True)

    Plot two lists of complex points:

    .. code-block:: python
        z = symbols("z")
        expr1 = z * exp(2 * pi * I * z)
        expr2 = 2 * expr1
        l1 = [expr1.subs(z, t / 20) for t in range(20)]
        l2 = [expr2.subs(z, t / 20) for t in range(20)]
        complex_plot((l1, "f1"), (l2, "f2"), aspect="equal", legend=True)

    Plot the real and imaginary part of a function:

    .. code-block:: python
        z = symbols("z")
        complex_plot(sqrt(z), (z, -3, 3), legend=True)

    .. code-block:: python
        z = symbols("z")
        complex_plot((cos(z) + sin(I * z), "f"), (z, -2, 2), legend=True)

    Plot the modulus of a complex function colored by its magnitude:

    .. code-block:: python
        z = symbols("z")
        complex_plot((cos(z) + sin(I * z), "f"), (z, -2, 2), legend=True,
            absarg=True)

    Plot the modulus and the argument of a complex function:

    .. code-block:: python
        z = symbols("z")
        complex_plot((cos(z) + sin(I * z), "f"), (z, -2, 2), legend=True,
            abs=True, arg=True, real=False, imag=False)

    Plot the real and imaginary part of a function of two variables over two
    real ranges:

    .. code-block:: python
        x, y = symbols("x, y")
        complex_plot(sqrt(x*y), (x, -5, 5), (y, -5, 5), real=True, imag=True)

    Domain coloring plot. Note that it might be necessary to increase the number
    of discretization points in order to get a smoother plot:

    .. code-block:: python
        z = symbols("z")
        complex_plot(gamma(z), (z, -3 - 3*I, 3 + 3*I), coloring="b", n=500)

    3D plot of the absolute value of a complex function colored by its argument:

    .. code-block:: python
        z = symbols("z")
        complex_plot(gamma(z), (z, -3 - 3*I, 3 + 3*I), threed=True,
            legend=True, zlim=(-1, 6))

    3D plot of the real part a complex function:

    .. code-block:: python
        z = symbols("z")
        complex_plot(gamma(z), (z, -3 - 3*I, 3 + 3*I), threed=True,
            real=True)

    """
    args = _plot_sympify(args)
    kwargs = _set_discretization_points(kwargs, ComplexSeries)

    series = _build_series(*args, **kwargs)

    if "backend" not in kwargs:
        kwargs["backend"] = TWO_D_B
        if any(s.is_3Dsurface for s in series):
            kwargs["backend"] = THREE_D_B

    if all(
            isinstance(s, (SurfaceOver2DRangeSeries, InteractiveSeries))
            for s in series):
        # function of 2 variables
        if kwargs.get("xlabel", None) is None:
            kwargs["xlabel"] = str(series[0].var_x)
        if kwargs.get("ylabel", None) is None:
            kwargs["ylabel"] = str(series[0].var_y)
        # do not set anything for zlabel since it could be f(x,y) or
        # abs(f(x, y)) or something else
    elif all(not s.is_parametric for s in series):
        # when plotting real/imaginary or domain coloring/3D plots, the
        # horizontal axis is the real, the vertical axis is the imaginary
        if kwargs.get("xlabel", None) is None:
            kwargs["xlabel"] = "Re"
        if kwargs.get("ylabel", None) is None:
            kwargs["ylabel"] = "Im"
        if kwargs.get("zlabel", None) is None:
            kwargs["zlabel"] = "Abs"
    else:
        if kwargs.get("xlabel", None) is None:
            kwargs["xlabel"] = "Real"
        if kwargs.get("ylabel", None) is None:
            kwargs["ylabel"] = "Abs"

    if (kwargs.get("aspect", None) is None) and any(
            s.is_complex and s.is_domain_coloring for s in series):
        kwargs["aspect"] = "equal"

    p = Plot(*series, **kwargs)
    if show:
        p.show()
    return p
コード例 #14
0
def test_check_arguments():
    x, y = symbols("x, y")

    ### Test arguments for plot()

    # single expressions
    args = _plot_sympify((x + 1, ))
    r = _check_arguments(args, 1, 1)
    assert isinstance(r, (list, tuple, Tuple)) and len(r) == 1
    assert r[0] == (x + 1, (x, -10, 10), "x + 1")

    # single expressions with range
    args = _plot_sympify((x + 1, (x, -2, 2)))
    r = _check_arguments(args, 1, 1)
    assert isinstance(r, (list, tuple, Tuple)) and len(r) == 1
    assert r[0] == (x + 1, (x, -2, 2), "x + 1")

    # single expressions with range and label
    args = _plot_sympify((x + 1, (x, -2, 2), "test"))
    r = _check_arguments(args, 1, 1)
    assert isinstance(r, (list, tuple, Tuple)) and len(r) == 1
    assert r[0] == (x + 1, (x, -2, 2), "test")

    # multiple expressions
    args = _plot_sympify((x + 1, x**2))
    r = _check_arguments(args, 1, 1)
    assert isinstance(r, (list, tuple, Tuple)) and len(r) == 2
    assert r[0] == (x + 1, (x, -10, 10), "x + 1")
    assert r[1] == (x**2, (x, -10, 10), "x**2")

    # multiple expressions over the same range
    args = _plot_sympify((x + 1, x**2, (x, 0, 5)))
    r = _check_arguments(args, 1, 1)
    assert isinstance(r, (list, tuple, Tuple)) and len(r) == 2
    assert r[0] == (x + 1, (x, 0, 5), "x + 1")
    assert r[1] == (x**2, (x, 0, 5), "x**2")

    # multiple expressions with different ranges and labels
    args = _plot_sympify([(x + 1, (x, 0, 5)), (x**2, (x, -2, 2), "test")])
    r = _check_arguments(args, 1, 1)
    assert isinstance(r, (list, tuple, Tuple)) and len(r) == 2
    assert r[0] == (x + 1, (x, 0, 5), "x + 1")
    assert r[1] == (x**2, (x, -2, 2), "test")

    ### Test arguments for plot_parametric()

    # single parametric expression
    args = _plot_sympify((x + 1, x))
    r = _check_arguments(args, 2, 1)
    assert isinstance(r, (list, tuple, Tuple)) and len(r) == 1
    assert r[0] == (x + 1, x, (x, -10, 10), "(x + 1, x)")

    # single parametric expression with custom range and label
    args = _plot_sympify((x + 1, x, (x, -2, 2), "test"))
    r = _check_arguments(args, 2, 1)
    assert isinstance(r, (list, tuple, Tuple)) and len(r) == 1
    assert r[0] == (x + 1, x, (x, -2, 2), "test")

    args = _plot_sympify(((x + 1, x), (x, -2, 2), "test"))
    r = _check_arguments(args, 2, 1)
    assert isinstance(r, (list, tuple, Tuple)) and len(r) == 1
    assert r[0] == (x + 1, x, (x, -2, 2), "test")

    # multiple parametric expressions
    args = _plot_sympify([(x + 1, x), (x**2, x + 1)])
    r = _check_arguments(args, 2, 1)
    assert isinstance(r, (list, tuple, Tuple)) and len(r) == 2
    assert r[0] == (x + 1, x, (x, -10, 10), "(x + 1, x)")
    assert r[1] == (x**2, x + 1, (x, -10, 10), "(x**2, x + 1)")

    # multiple parametric expressions same range
    args = _plot_sympify([(x + 1, x), (x**2, x + 1), (x, -2, 2)])
    r = _check_arguments(args, 2, 1)
    assert isinstance(r, (list, tuple, Tuple)) and len(r) == 2
    assert r[0] == (x + 1, x, (x, -2, 2), "(x + 1, x)")
    assert r[1] == (x**2, x + 1, (x, -2, 2), "(x**2, x + 1)")

    # multiple parametric expressions, custom ranges and labels
    args = _plot_sympify([(x + 1, x, (x, -2, 2)),
                          (x**2, x + 1, (x, -3, 3), "test")])
    r = _check_arguments(args, 2, 1)
    assert isinstance(r, (list, tuple, Tuple)) and len(r) == 2
    assert r[0] == (x + 1, x, (x, -2, 2), "(x + 1, x)")
    assert r[1] == (x**2, x + 1, (x, -3, 3), "test")

    ### Test arguments for plot3d_parametric_line()

    # single parametric expression
    args = _plot_sympify((x + 1, x, sin(x)))
    r = _check_arguments(args, 3, 1)
    assert isinstance(r, (list, tuple, Tuple)) and len(r) == 1
    assert r[0] == (x + 1, x, sin(x), (x, -10, 10), "(x + 1, x, sin(x))")

    # single parametric expression with custom range and label
    args = _plot_sympify((x + 1, x, sin(x), (x, -2, 2), "test"))
    r = _check_arguments(args, 3, 1)
    assert isinstance(r, (list, tuple, Tuple)) and len(r) == 1
    assert r[0] == (x + 1, x, sin(x), (x, -2, 2), "test")

    args = _plot_sympify(((x + 1, x, sin(x)), (x, -2, 2), "test"))
    r = _check_arguments(args, 3, 1)
    assert isinstance(r, (list, tuple, Tuple)) and len(r) == 1
    assert r[0] == (x + 1, x, sin(x), (x, -2, 2), "test")

    # multiple parametric expression
    args = _plot_sympify([(x + 1, x, sin(x)), (x**2, 1, cos(x))])
    r = _check_arguments(args, 3, 1)
    assert isinstance(r, (list, tuple, Tuple)) and len(r) == 2
    assert r[0] == (x + 1, x, sin(x), (x, -10, 10), "(x + 1, x, sin(x))")
    assert r[1] == (x**2, Integer(1), cos(x), (x, -10, 10),
                    "(x**2, 1, cos(x))")

    # multiple parametric expression, custom ranges and labels
    args = _plot_sympify([(x + 1, x, sin(x)),
                          (x**2, 1, cos(x), (x, -2, 2), "test")])
    r = _check_arguments(args, 3, 1)
    assert isinstance(r, (list, tuple, Tuple)) and len(r) == 2
    assert r[0] == (x + 1, x, sin(x), (x, -10, 10), "(x + 1, x, sin(x))")
    assert r[1] == (x**2, Integer(1), cos(x), (x, -2, 2), "test")

    ### Test arguments for plot3d() and plot_contour()

    # single expression
    args = _plot_sympify((x + y, ))
    r = _check_arguments(args, 1, 2)
    assert isinstance(r, (list, tuple, Tuple)) and len(r) == 1
    assert len(r[0]) == 4
    assert r[0][0] == x + y
    assert r[0][1] == (x, -10, 10) or (y, -10, 10)
    assert r[0][2] == (y, -10, 10) or (x, -10, 10)
    assert r[0][1] != r[0][2]
    assert r[0][3] == "x + y"

    # single expression, custom range and label
    args = _plot_sympify((x + y, (x, -2, 2), "test"))
    r = _check_arguments(args, 1, 2)
    assert isinstance(r, (list, tuple, Tuple)) and len(r) == 1
    assert len(r[0]) == 4
    assert r[0][0] == x + y
    assert r[0][1] == (x, -2, 2) or (y, -10, 10)
    assert r[0][2] == (y, -10, 10) or (x, -2, 2)
    assert r[0][1] != r[0][2]
    assert r[0][3] == "test"

    args = _plot_sympify((x + y, (x, -2, 2), (y, -4, 4), "test"))
    r = _check_arguments(args, 1, 2)
    assert isinstance(r, (list, tuple, Tuple)) and len(r) == 1
    assert r[0] == (x + y, (x, -2, 2), (y, -4, 4), "test")

    # multiple expressions
    args = _plot_sympify((x + y, x * y))
    r = _check_arguments(args, 1, 2)
    assert isinstance(r, (list, tuple, Tuple)) and len(r) == 2
    assert len(r[0]) == 4
    assert len(r[1]) == 4
    assert r[0][0] == x + y
    assert r[0][1] == (x, -10, 10) or (y, -10, 10)
    assert r[0][2] == (y, -10, 10) or (x, -10, 10)
    assert r[0][1] != r[0][2]
    assert r[0][3] == "x + y"
    assert r[1][0] == x * y
    assert r[1][1] == (x, -10, 10) or (y, -10, 10)
    assert r[1][2] == (y, -10, 10) or (x, -10, 10)
    assert r[1][1] != r[0][2]
    assert r[1][3] == "x*y"

    # multiple expressions, same custom ranges
    args = _plot_sympify((x + y, x * y, (x, -2, 2), (y, -4, 4)))
    r = _check_arguments(args, 1, 2)
    assert isinstance(r, (list, tuple, Tuple)) and len(r) == 2
    assert r[0] == (x + y, (x, -2, 2), (y, -4, 4), "x + y")
    assert r[1] == (x * y, (x, -2, 2), (y, -4, 4), "x*y")

    # multiple expressions, custom ranges and labels
    args = _plot_sympify([(x + y, (x, -2, 2), (y, -4, 4)),
                          (x * y, (x, -3, 3), (y, -6, 6), "test")])
    r = _check_arguments(args, 1, 2)
    assert isinstance(r, (list, tuple, Tuple)) and len(r) == 2
    assert r[0] == (x + y, (x, -2, 2), (y, -4, 4), "x + y")
    assert r[1] == (x * y, (x, -3, 3), (y, -6, 6), "test")

    ### Test arguments for plot3d_parametric_surface()

    # single parametric expression
    args = _plot_sympify((x + y, cos(x + y), sin(x + y)))
    r = _check_arguments(args, 3, 2)
    assert isinstance(r, (list, tuple, Tuple)) and len(r) == 1
    assert len(r[0]) == 6
    assert r[0][0] == x + y
    assert r[0][1] == cos(x + y)
    assert r[0][2] == sin(x + y)
    assert r[0][3] == (x, -10, 10) or (y, -10, 10)
    assert r[0][4] == (y, -10, 10) or (x, -10, 10)
    assert r[0][3] != r[0][4]
    assert r[0][5] == "(x + y, cos(x + y), sin(x + y))"

    # single parametric expression, custom ranges and labels
    args = _plot_sympify(
        (x + y, cos(x + y), sin(x + y), (x, -2, 2), (y, -4, 4), "test"))
    r = _check_arguments(args, 3, 2)
    assert isinstance(r, (list, tuple, Tuple)) and len(r) == 1
    assert r[0] == (x + y, cos(x + y), sin(x + y), (x, -2, 2), (y, -4, 4),
                    "test")

    # multiple parametric expressions
    args = _plot_sympify([(x + y, cos(x + y), sin(x + y)),
                          (x - y, cos(x - y), sin(x - y))])
    r = _check_arguments(args, 3, 2)
    assert isinstance(r, (list, tuple, Tuple)) and len(r) == 2
    assert len(r[0]) == 6
    assert len(r[1]) == 6
    assert r[0][0] == x + y
    assert r[0][1] == cos(x + y)
    assert r[0][2] == sin(x + y)
    assert r[0][3] == (x, -10, 10) or (y, -10, 10)
    assert r[0][4] == (y, -10, 10) or (x, -10, 10)
    assert r[0][3] != r[0][4]
    assert r[0][5] == "(x + y, cos(x + y), sin(x + y))"
    assert r[1][0] == x - y
    assert r[1][1] == cos(x - y)
    assert r[1][2] == sin(x - y)
    assert r[1][3] == (x, -10, 10) or (y, -10, 10)
    assert r[1][4] == (y, -10, 10) or (x, -10, 10)
    assert r[1][3] != r[0][4]
    assert r[1][5] == "(x - y, cos(x - y), sin(x - y))"

    # multiple parametric expressions, custom ranges and labels
    args = _plot_sympify([
        (x + y, cos(x + y), sin(x + y), (x, -2, 2), "test"),
        (x - y, cos(x - y), sin(x - y), (x, -3, 3), (y, -4, 4), "test2"),
    ])
    r = _check_arguments(args, 3, 2)
    assert isinstance(r, (list, tuple, Tuple)) and len(r) == 2
    assert len(r[0]) == 6
    assert r[0][0] == x + y
    assert r[0][1] == cos(x + y)
    assert r[0][2] == sin(x + y)
    assert r[0][3] == (x, -2, 2) or (y, -10, 10)
    assert r[0][4] == (y, -10, 10) or (x, -2, 2)
    assert r[0][3] != r[0][4]
    assert r[0][5] == "test"
    assert r[1] == (x - y, cos(x - y), sin(x - y), (x, -3, 3), (y, -4, 4),
                    "test2")

    ### Test arguments for plot_implicit

    # single expression with both ranges
    args = _plot_sympify((x > 0, (x, -2, 2), (y, -3, 3)))
    r = _check_arguments(args, 1, 2)
    assert isinstance(r, (list, tuple, Tuple)) and len(r) == 1
    assert len(r[0]) == 4
    assert r[0] == (x > 0, (x, -2, 2), (y, -3, 3), "x > 0")

    # single expression with one missing range
    args = _plot_sympify((x > 0, (x, -2, 2), "test"))
    r = _check_arguments(args, 1, 2)
    assert isinstance(r, (list, tuple, Tuple)) and len(r) == 1
    assert len(r[0]) == 4
    assert r[0][:2] == (x > 0, (x, -2, 2))
    assert r[0][-1] == "test"
    assert (r[0][2][1] == Integer(-10)) and (r[0][2][2] == Integer(10))

    # multiple expressions
    args = _plot_sympify([(x > 0, (x, -2, 2), (y, -3, 3)),
                          ((x > 0) & (y < 0), "test")])
    r = _check_arguments(args, 1, 2)
    assert isinstance(r, (list, tuple, Tuple)) and len(r) == 2
    assert len(r[0]) == 4
    assert r[0] == (x > 0, (x, -2, 2), (y, -3, 3), "x > 0")
    assert len(r[1]) == 4
    assert r[1][0] == ((x > 0) & (y < 0))
    assert (r[1][1] == Tuple(x, -10, 10)) or (r[1][1] == Tuple(y, -10, 10))
    assert (r[1][2] == Tuple(x, -10, 10)) or (r[1][2] == Tuple(y, -10, 10))
    assert r[1][-1] == "test"

    # incompatible free symbols between expression and ranges
    z = symbols("z")
    args = _plot_sympify((x * y > 0, (x, -2, 2), (z, -3, 3)))
    raises(ValueError, lambda: _check_arguments(args, 1, 2))
コード例 #15
0
def vector_plot(*args, show=True, **kwargs):
    """Plot a 2D or 3D vector field. By default, the aspect ratio of the plot
    is set to ``aspect="equal"``.

    Arguments
    =========
        expr : Vector, or Matrix with 2 or 3 elements, or list/tuple  with 2 or
                3 elements)
            Represent the vector to be plotted.
            Note: if a 3D vector is given with a list/tuple, it might happens
            that the internal algorithm could think of it as a range. Therefore,
            3D vectors should be given as a Matrix or as a Vector: this reduces
            ambiguities.

        ranges : 3-element tuples
            Denotes the range of the variables. For example (x, -5, 5). For 2D
            vector plots, 2 ranges should be provided. For 3D vector plots, 3
            ranges are needed.

        label : str
            The name of the vector field to be eventually shown on the legend.
            If none is provided, the string representation of the vector will
            be used.

        To specify multiple vector fields, wrap them into a tuple. Refer to the
        examples to learn more.

    Keyword Arguments
    =================

        contours_kw : dict
            A dictionary of keywords/values which is passed to the plotting
            library contour function to customize the appearance. Refer to the
            plotting library (backend) manual for more informations.

        n1, n2, n3 : int
            Number of discretization points in the x/y/z-direction respectively
            for the quivers or streamlines. Default to 25.

        n : int
            Set the same number of discretization points in all directions for
            the quivers or streamlines. It overrides n1, n2, n3. Default to 25.

        nc : int
            Number of discretization points for the scalar contour plot.
            Default to 100.

        quiver_kw : dict
            A dictionary of keywords/values which is passed to the plotting
            library quivers function to customize the appearance. Refer to the
            plotting library (backend) manual for more informations.

        scalar : boolean, Expr, None or list/tuple of 2 elements
            Represents the scalar field to be plotted in the background. Can be:
                True: plot the magnitude of the vector field.
                False/None: do not plot any scalar field.
                Expr: a symbolic expression representing the scalar field.
                List/Tuple: [scalar_expr, label], where the label will be shown
                    on the colorbar.
            Default to True.

        show : boolean
            Default to True, in which case the plot will be shown on the screen.

        slice : Plane, list, Expr
            Plot the 3D vector field over the provided slice. It can be:
                Plane: a Plane object from sympy.geometry module.
                list: a list of planes.
                Expr: a symbolic expression representing a surface.
            The number of discretization points will be `n1`, `n2`, `n3`.
            Note that:
                1. only quivers plots are supported with slices.
                2. `n3` will be used only with planes parallel to xz or yz.

        streamlines : boolean
            Whether to plot the vector field using streamlines (True) or quivers
            (False). Default to False.

        stream_kw : dict
            A dictionary of keywords/values which is passed to the backend
            streamlines-plotting function to customize the appearance. Refer to
            the backend's manual for more informations.

    Examples
    ========

    Quivers plot of a 2D vector field with a contour plot in background
    representing the vector's magnitude (a scalar field):

    .. code-block:: python
        x, y = symbols("x, y")
        vector_plot([-sin(y), cos(x)], (x, -3, 3), (y, -3, 3))


    Streamlines plot of a 2D vector field with no background scalar field:

    .. code-block:: python
        x, y = symbols("x, y")
        vector_plot([-sin(y), cos(x)], (x, -3, 3), (y, -3, 3),
                streamlines=True, scalar=None)


    Plot of two 2D vectors with background the contour plot of magnitude of the
    first vector:

    .. code-block:: python
        x, y = symbols("x, y")
        vector_plot([-sin(y), cos(x)], [y, x], n=20,
            scalar=sqrt((-sin(y))**2 + cos(x)**2), legend=True)


    3D vector field:

    .. code-block:: python
        x, y, z = symbols("x, y, z")
        vector_plot([x, y, z], (x, -10, 10), (y, -10, 10), (z, -10, 10),
                n=8)


    3D vector field with 3 orthogonal slice planes:

    .. code-block:: python
        x, y, z = symbols("x, y, z")
        vector_plot([z, y, x], (x, -10, 10), (y, -10, 10), (z, -10, 10), n=8,
            slice=[
                Plane((-10, 0, 0), (1, 0, 0)),
                Plane((0, -10, 0), (0, 2, 0)),
                Plane((0, 0, -10), (0, 0, 1)),
            ])
    """
    args = _plot_sympify(args)
    args = _preprocess(*args)

    kwargs = _set_discretization_points(kwargs, Vector3DSeries)
    # TODO: do I need these?
    if "n1" not in kwargs:
        kwargs["n1"] = 25
    if "n2" not in kwargs:
        kwargs["n2"] = 25
    if "aspect" not in kwargs.keys():
        kwargs["aspect"] = "equal"

    series = _build_series(*args, **kwargs)
    if all([isinstance(s, (Vector2DSeries, ContourSeries)) for s in series]):
        from spb.defaults import TWO_D_B

        backend = kwargs.pop("backend", TWO_D_B)
    elif all([isinstance(s, Vector3DSeries) for s in series]):
        from spb.defaults import THREE_D_B

        backend = kwargs.pop("backend", THREE_D_B)
    else:
        raise ValueError("Mixing 2D vectors with 3D vectors is not allowed.")

    p = Plot(*series, backend=backend, **kwargs)
    if show:
        p.show()
    return p