| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233 |
- """Implicit plotting module for SymPy.
- Explanation
- ===========
- The module implements a data series called ImplicitSeries which is used by
- ``Plot`` class to plot implicit plots for different backends. The module,
- by default, implements plotting using interval arithmetic. It switches to a
- fall back algorithm if the expression cannot be plotted using interval arithmetic.
- It is also possible to specify to use the fall back algorithm for all plots.
- Boolean combinations of expressions cannot be plotted by the fall back
- algorithm.
- See Also
- ========
- sympy.plotting.plot
- References
- ==========
- .. [1] Jeffrey Allen Tupper. Reliable Two-Dimensional Graphing Methods for
- Mathematical Formulae with Two Free Variables.
- .. [2] Jeffrey Allen Tupper. Graphing Equations with Generalized Interval
- Arithmetic. Master's thesis. University of Toronto, 1996
- """
- from sympy.core.containers import Tuple
- from sympy.core.symbol import (Dummy, Symbol)
- from sympy.polys.polyutils import _sort_gens
- from sympy.plotting.series import ImplicitSeries, _set_discretization_points
- from sympy.plotting.plot import plot_factory
- from sympy.utilities.decorator import doctest_depends_on
- from sympy.utilities.iterables import flatten
- __doctest_requires__ = {'plot_implicit': ['matplotlib']}
- @doctest_depends_on(modules=('matplotlib',))
- def plot_implicit(expr, x_var=None, y_var=None, adaptive=True, depth=0,
- n=300, line_color="blue", show=True, **kwargs):
- """A plot function to plot implicit equations / inequalities.
- Arguments
- =========
- - expr : The equation / inequality that is to be plotted.
- - x_var (optional) : symbol to plot on x-axis or tuple giving symbol
- and range as ``(symbol, xmin, xmax)``
- - y_var (optional) : symbol to plot on y-axis or tuple giving symbol
- and range as ``(symbol, ymin, ymax)``
- If neither ``x_var`` nor ``y_var`` are given then the free symbols in the
- expression will be assigned in the order they are sorted.
- The following keyword arguments can also be used:
- - ``adaptive`` Boolean. The default value is set to True. It has to be
- set to False if you want to use a mesh grid.
- - ``depth`` integer. The depth of recursion for adaptive mesh grid.
- Default value is 0. Takes value in the range (0, 4).
- - ``n`` integer. The number of points if adaptive mesh grid is not
- used. Default value is 300. This keyword argument replaces ``points``,
- which should be considered deprecated.
- - ``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
- Aesthetics options:
- - ``line_color``: float or string. Specifies the color for the plot.
- See ``Plot`` to see how to set color for the plots.
- Default value is "Blue"
- plot_implicit, by default, uses interval arithmetic to plot functions. If
- the expression cannot be plotted using interval arithmetic, it defaults to
- a generating a contour using a mesh grid of fixed number of points. By
- setting adaptive to False, you can force plot_implicit to use the mesh
- grid. The mesh grid method can be effective when adaptive plotting using
- interval arithmetic, fails to plot with small line width.
- 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))
- With depth of recursion as argument:
- .. plot::
- :context: close-figs
- :format: doctest
- :include-source: True
- >>> p3 = plot_implicit(
- ... Eq(x**2 + y**2, 5), (x, -4, 4), (y, -4, 4), depth = 2)
- Using mesh grid and not using adaptive meshing:
- .. plot::
- :context: close-figs
- :format: doctest
- :include-source: True
- >>> p4 = plot_implicit(
- ... Eq(x**2 + y**2, 5), (x, -5, 5), (y, -2, 2),
- ... adaptive=False)
- Using mesh grid without using adaptive meshing with number of points
- specified:
- .. plot::
- :context: close-figs
- :format: doctest
- :include-source: True
- >>> p5 = plot_implicit(
- ... Eq(x**2 + y**2, 5), (x, -5, 5), (y, -2, 2),
- ... adaptive=False, n=400)
- Plotting regions:
- .. plot::
- :context: close-figs
- :format: doctest
- :include-source: True
- >>> p6 = plot_implicit(y > x**2)
- Plotting Using boolean conjunctions:
- .. plot::
- :context: close-figs
- :format: doctest
- :include-source: True
- >>> p7 = plot_implicit(And(y > x, y > -x))
- When plotting an expression with a single variable (y - 1, for example),
- specify the x or the y variable explicitly:
- .. plot::
- :context: close-figs
- :format: doctest
- :include-source: True
- >>> p8 = plot_implicit(y - 1, y_var=y)
- >>> p9 = plot_implicit(x - 1, x_var=x)
- """
- xyvar = [i for i in (x_var, y_var) if i is not None]
- free_symbols = expr.free_symbols
- range_symbols = Tuple(*flatten(xyvar)).free_symbols
- undeclared = free_symbols - range_symbols
- if len(free_symbols & range_symbols) > 2:
- raise NotImplementedError("Implicit plotting is not implemented for "
- "more than 2 variables")
- #Create default ranges if the range is not provided.
- default_range = Tuple(-5, 5)
- def _range_tuple(s):
- if isinstance(s, Symbol):
- return Tuple(s) + default_range
- if len(s) == 3:
- return Tuple(*s)
- raise ValueError('symbol or `(symbol, min, max)` expected but got %s' % s)
- if len(xyvar) == 0:
- xyvar = list(_sort_gens(free_symbols))
- var_start_end_x = _range_tuple(xyvar[0])
- x = var_start_end_x[0]
- if len(xyvar) != 2:
- if x in undeclared or not undeclared:
- xyvar.append(Dummy('f(%s)' % x.name))
- else:
- xyvar.append(undeclared.pop())
- var_start_end_y = _range_tuple(xyvar[1])
- kwargs = _set_discretization_points(kwargs, ImplicitSeries)
- series_argument = ImplicitSeries(
- expr, var_start_end_x, var_start_end_y,
- adaptive=adaptive, depth=depth,
- n=n, line_color=line_color)
- #set the x and y limits
- kwargs['xlim'] = tuple(float(x) for x in var_start_end_x[1:])
- kwargs['ylim'] = tuple(float(y) for y in var_start_end_y[1:])
- # set the x and y labels
- kwargs.setdefault('xlabel', var_start_end_x[0])
- kwargs.setdefault('ylabel', var_start_end_y[0])
- p = plot_factory(series_argument, **kwargs)
- if show:
- p.show()
- return p
|