︠a6ff1b15-9c34-41a5-8d7a-0bafe432b0c0is︠ def latex_integral(f, *limits): r""" Produce a `\LaTeX` expression of computing the iterated integral. .. warning:: This function tries to plow through all obstacles and, in particular, will try to use the Fundamental Theorem of Calculus even if the function is not integrable on the given interval. In this case a red question mark will appear over an equality sign: `\int_-1^1 \frac{1}{x}\, dx =^{\color{red}?} 0`. This behaviour is necessary, for example, to compute the volume of a unit sphere as a triple iterated integral with square roots in limits. INPUT: - ``f`` -- a function to integrate; - ``*limits`` -- a sequence of triples `(v, a, b)` corresponding to `\int_a^b \dots\, dv`, internal integrals must be first. OUTPUT: - a :class:`LatexExpr`. EXAMPLES:: sage: var("x, y, z") sage: latex_integral(1, (y, -sqrt(1-x^2-z^2), sqrt(1-x^2-z^2)), (x, 0, sqrt(1-z^2)), (z, -1, 1)) """ integrand = SR(f) integrals = [] differentials = [] expressions = [integrand] for v, a, b in limits: integrals.insert(0, r"\int_{%s}^{%s} " % (latex(a), latex(b))) differentials.append(r"\, d %s" % latex(v)) expressions.extend([a, b]) try: assume(a < v) assume(v < b) except ValueError: pass # We also assume that everything is nicely computable in a calculus course... w0 = SR.wild(0) w1 = SR.wild(1) while expressions: current = expressions.pop(0) if current in RDF: continue # sqrt(4-x^2) is real!!! for m in current.find(w0^w1): m = m.match(w0^w1) expressions.extend(m.values()) if m[w0] not in RDF and (m[w1] not in QQ or is_even(QQ(m[w1]).denominator())): try: assume(m[w0] > 0) except ValueError: pass result = [r"\displaystyle"] try: n = len(limits) for i in range(n): result.extend(integrals[:n-i]) s = latex(integrand) inside = 0 for c in s: if c in "([{": inside += 1 elif c in ")]}": inside -= 1 elif c in "+-" and inside == 0: s = r"\left( %s \right)" % s break result.append(s) result.extend(differentials[i:]) result.append("=") v, a, b = limits[i] try: integrand = integral(integrand, v, a, b) except (RuntimeError, ValueError): integrand = integral(integrand, v) if "integrate" in str(integrand): # Does now work well with substitution, give up. raise ValueError("cannot integrate given function") integrand = integrand.subs({v: b}) - integrand.subs({v: a}) # Use FTC, even if integrand is not integrable, but put a warning. result[-1] = r"\, {\color{red}{=^?}} \," try: integrand = integrand.simplify_full() except AttributeError: pass result.append(latex(integrand)) if integrand not in ZZ and integrand in RDF: result.append(r"\approx") result.append(latex(integrand.n())) except (AttributeError, RuntimeError, TypeError, ValueError): result.append(r"\dots ?") forget() return LatexExpr(" ".join(result)) from sage.plot.misc import setup_for_eval_on_grid def plot_vector_field3d(functions, xrange, yrange, zrange, plot_points=5, colors='jet', center_arrows=False,**kwds): try: from matplotlib.cm import get_cmap cm = get_cmap(colors) except (TypeError, ValueError): cm = None if cm is None: if isinstance(colors, (list, tuple)): from matplotlib.colors import LinearSegmentedColormap cm = LinearSegmentedColormap.from_list('mymap',colors) else: cm = lambda x: colors (ff,gg,hh), ranges = setup_for_eval_on_grid(functions, [xrange, yrange, zrange], plot_points) xpoints, ypoints, zpoints = [srange(*r, include_endpoint=True) for r in ranges] V = VectorSpace(RDF, 3) points = [V((i,j,k)) for i in xpoints for j in ypoints for k in zpoints] vectors = [V((ff(*point), gg(*point), hh(*point))) for point in points] size = 0.9 * max(r[-1] for r in ranges) norms = [sqrt(v*v) for v in vectors] max_norm = max(norms) scaled_vectors = [v/max_norm*size for v in vectors] if center_arrows: points = [p - v/2 for p, v in zip(points, scaled_vectors)] return sum([arrow3d((0,0,0), v, color=cm(n/max_norm), **kwds).translate(p) for p, v, n in zip(points, scaled_vectors, norms)]) def plot_vector_field3d_along_curve(field, curve, trange, plot_points=20, colors='jet', center_arrows=False, **kwds): r""" Plot a 3D vector field along a parametric curve `C`. INPUT: - ``field`` -- a list of three functions of `(x, y, z)` specifying the vector field; - ``curve`` -- a list of three functions of a single variable, parametric equations of `C`; - ``trange`` -- a triple `(t, start, end)`, the variable and interval of parametrization of `C`; - ``plot_points`` (default: 20) -- the number of arrows to plot `C`; - ``colors`` (default: 'jet') -- a color, list of colors (which are interpolated between), or matplotlib colormap name, giving the coloring of the arrows. If a list of colors or a colormap is given, coloring is done as a function of length of the vector - ``center_arrows`` (default: ``False``) -- if ``True``, draw the arrows centered on the points; otherwise, draw the arrows with the tails at the points; - any other keywords are passed on to the plot command for each arrow. OUTPUT: - a plot. EXAMPLES:: """ try: from matplotlib.cm import get_cmap cm = get_cmap(colors) except (TypeError, ValueError): cm = None if cm is None: if isinstance(colors, (list, tuple)): from matplotlib.colors import LinearSegmentedColormap cm = LinearSegmentedColormap.from_list('mymap',colors) else: cm = lambda x: colors curve_d = dict(zip(map(SR, "xyz"), curve)) field = [c.subs(curve_d) for c in field] (P, Q, R, x, y, z), (trange, ) = setup_for_eval_on_grid(field + list(curve), [trange], plot_points) trange = srange(*trange, include_endpoint=True) V = VectorSpace(RDF, 3) points = [V((x(t), y(t), z(t))) for t in trange] vectors = [V((P(t), Q(t), R(t))) for t in trange] size = max([max(vlist) - min(vlist) for vlist in zip(*points)]) / sqrt(plot_points) norms = [sqrt(v*v) for v in vectors] max_norm = max(norms) scaled_vectors = [v/max_norm*size for v in vectors] if center_arrows: points = [p - v/2 for p, v in zip(points, scaled_vectors)] return sum([arrow3d((0,0,0), v, color=cm(n/max_norm), **kwds).translate(p) for p, v, n in zip(points, scaled_vectors, norms)]) def plot_vector_field3d_along_surface(F, r, urange, vrange, plot_points=10, colors='jet', center_arrows=False, plot_surface=None, plot_ulines=None, plot_vlines=None, **kwds): r""" Plot a 3D vector field along a parametric curve `S`. INPUT: - ``F`` -- a list of three functions of `(x, y, z)` specifying the vector field; - ``r`` -- a list of three functions of two variables, parametric equations of `S`; - ``urange``, ``vrange`` -- triples `(u, start, end)`, `(v, start, end)`, the variables and intervals of parametrization of `S`; - ``plot_points`` (default: 10) -- the number of arrows to plot; - ``colors`` (default: 'jet') -- a color, list of colors (which are interpolated between), or matplotlib colormap name, giving the coloring of the arrows. If a list of colors or a colormap is given, coloring is done as a function of length of the vector - ``center_arrows`` (default: ``False``) -- if ``True``, draw the arrows centered on the points; otherwise, draw the arrows with the tails at the points; - any other keywords are passed on to the plot command for each arrow. OUTPUT: - a plot. EXAMPLES:: """ try: from matplotlib.cm import get_cmap cm = get_cmap(colors) except (TypeError, ValueError): cm = None if cm is None: if isinstance(colors, (list, tuple)): from matplotlib.colors import LinearSegmentedColormap cm = LinearSegmentedColormap.from_list('mymap',colors) else: cm = lambda x: colors r_d = dict(zip(map(SR, "xyz"), r)) F = [c.subs(r_d) for c in F] (P, Q, R, x, y, z), ranges = setup_for_eval_on_grid(F + list(r), [urange, vrange], plot_points) urange, vrange = [srange(*range, include_endpoint=True) for range in ranges] V = VectorSpace(RDF, 3) points = [V((x(u, v), y(u, v), z(u, v))) for u in urange for v in vrange] vectors = [V((P(u, v), Q(u, v), R(u, v))) for u in urange for v in vrange] # NaN is just impossible to detect due to RDF(NaN) == 123!!! vectors = [v if "NaN" not in str(v) else V.zero() for v in vectors] size = max([max(vlist) - min(vlist) for vlist in zip(*points)]) / max(flatten([plot_points])) norms = [sqrt(v*v) for v in vectors] max_norm = max(norms) scaled_vectors = [v/max_norm*size for v in vectors] if center_arrows: points = [p - v/2 for p, v in zip(points, scaled_vectors)] result = sum([arrow3d((0,0,0), v, color=cm(n/max_norm), **kwds).translate(p) for p, v, n in zip(points, scaled_vectors, norms)]) options = plot_surface if isinstance(plot_surface, dict) else dict() if plot_surface is not None: result += parametric_plot_3d((x, y, z), urange, vrange, **plot_surface) options = plot_ulines if isinstance(plot_ulines, dict) else dict() if plot_ulines is not None: for U in urange: result += parametric_plot3d([fast_float(c.subs(u=U), "v") for c in r], (vrange[0], vrange[-1]), **plot_ulines) options = plot_vlines if isinstance(plot_vlines, dict) else dict() if plot_vlines is not None: for V in vrange: result += parametric_plot3d([fast_float(c.subs(v=V), "u") for c in r], (urange[0], urange[-1]), **plot_vlines) return result def add_axes(p): r""" """ bb = p.bounding_box() for i, v in enumerate("XYZ"): start = min(bb[0][i], 0) end = max(bb[1][i], 0) length = end - start p += line([[0]*i+[start-0.08*length]+[0]*(2-i), [0]*i+[end+0.08*length]+[0]*(2-i)], thickness=3, color="brown") p += text3d(v, [0]*i+[end+0.1*length]+[0]*(2-i)) return p t, u, v, x, y, z = map(SR.var, "tuvxyz") def to_value(l): return map(SR, map(str, l[0])) html(r"""
Plot vector field $\vec{F}(x,y,z)$ | |
$\vec{i} +$ $\vec{j} +$ $\vec{k}$ | |
Box: $\leq x \leq$ $,\quad$ $\leq y \leq$ $,\quad$ $\leq z \leq$ | |
Plot parametric curve $C$ given by $\vec{r}(t)$ for $\leq t \leq$ | |
$\vec{i} +$ $\vec{j} +$ $\vec{k}$ | |
Plot parametric surface $S$ given by $\vec{r}(u, v)$ for $\leq u \leq$ $,\quad$ $\leq v \leq$ | |
$\vec{i} +$ $\vec{j} +$ $\vec{k}$ |
\n | Plot vector field $\\vec{F}(x,y,z)$ | \n
\n | $\\vec{i} +$ $\\vec{j} +$ $\\vec{k}$ | \n
\n | \n Box:\n $\\leq x \\leq$ $,\\quad$\n $\\leq y \\leq$ $,\\quad$\n $\\leq z \\leq$ \n | \n
\n | Plot parametric curve $C$ given by $\\vec{r}(t)$ for\n $\\leq t \\leq$ | \n
\n | $\\vec{i} +$ $\\vec{j} +$ $\\vec{k}$ | \n
\n | Plot parametric surface $S$ given by $\\vec{r}(u, v)$ for\n $\\leq u \\leq$ $,\\quad$\n $\\leq v \\leq$ | \n
\n | $\\vec{i} +$ $\\vec{j} +$ $\\vec{k}$ | \n