Exemple #1
0
def revolution_plot3d(curve,
                      trange,
                      phirange=None,
                      parallel_axis='z',
                      axis=(0, 0),
                      print_vector=False,
                      show_curve=False,
                      **kwds):
    r"""
    Return a plot of a revolved curve.

    There are three ways to call this function:

    - ``revolution_plot3d(f,trange)`` where `f` is a function located in the `x z` plane.

    - ``revolution_plot3d((f_x,f_z),trange)`` where `(f_x,f_z)` is a parametric curve on the `x z` plane.

    - ``revolution_plot3d((f_x,f_y,f_z),trange)`` where `(f_x,f_y,f_z)` can be any parametric curve.

    INPUT:

    - ``curve`` - A curve to be revolved, specified as a function, a 2-tuple or a 3-tuple.

    - ``trange`` - A 3-tuple `(t,t_{\min},t_{\max})` where t is the independent variable of the curve.

    - ``phirange`` - A 2-tuple of the form `(\phi_{\min},\phi_{\max})`, (default `(0,\pi)`) that specifies the angle in which the curve is to be revolved.

    - ``parallel_axis`` - A string (Either 'x', 'y', or 'z') that specifies the coordinate axis parallel to the revolution axis.

    - ``axis`` - A 2-tuple that specifies the position of the revolution axis. If parallel is:

        - 'z' - then axis is the point in which the revolution axis intersects the  `x y` plane.

        - 'x' - then axis is the point in which the revolution axis intersects the  `y z` plane.

        - 'y' - then axis is the point in which the revolution axis intersects the `x z` plane.

    - ``print_vector`` - If True, the parametrization of the surface of revolution will be printed.

    - ``show_curve`` - If True, the curve will be displayed.


    EXAMPLES:

    Let's revolve a simple function around different axes::

        sage: u = var('u')
        sage: f = u^2
        sage: revolution_plot3d(f, (u,0,2), show_curve=True, opacity=0.7).show(aspect_ratio=(1,1,1))

    .. PLOT::

        u = var('u')
        f = u**2
        P = revolution_plot3d(f, (u,0,2), show_curve=True, opacity=0.7).plot()
        sphinx_plot(P)

    If we move slightly the axis, we get a goblet-like surface::

        sage: revolution_plot3d(f, (u,0,2), axis=(1,0.2), show_curve=True, opacity=0.5).show(aspect_ratio=(1,1,1))

    .. PLOT::

        u = var('u')
        f = u**2
        P = revolution_plot3d(f, (u,0,2), axis=(1,0.2), show_curve=True, opacity=0.5).plot()
        sphinx_plot(P)

    A common problem in calculus books, find the volume within the following revolution solid::

        sage: line = u
        sage: parabola = u^2
        sage: sur1 = revolution_plot3d(line, (u,0,1), opacity=0.5, rgbcolor=(1,0.5,0), show_curve=True, parallel_axis='x')
        sage: sur2 = revolution_plot3d(parabola, (u,0,1), opacity=0.5, rgbcolor=(0,1,0), show_curve=True, parallel_axis='x')
        sage: (sur1+sur2).show()

    .. PLOT::

        u = var('u')
        line = u
        parabola = u**2
        sur1 = revolution_plot3d(line, (u,0,1), opacity=0.5, rgbcolor=(1,0.5,0), show_curve=True, parallel_axis='x')
        sur2 = revolution_plot3d(parabola, (u,0,1), opacity=0.5, rgbcolor=(0,1,0), show_curve=True, parallel_axis='x')
        P = sur1 + sur2
        sphinx_plot(P)

    Now let's revolve a parametrically defined circle. We can play with the topology of the surface by changing the axis,
    an axis in `(0,0)` (as the previous one) will produce a sphere-like surface::

        sage: u = var('u')
        sage: circle = (cos(u), sin(u))
        sage: revolution_plot3d(circle, (u,0,2*pi), axis=(0,0), show_curve=True, opacity=0.5).show(aspect_ratio=(1,1,1))

    .. PLOT::

        u = var('u')
        circle = (cos(u), sin(u))
        P = revolution_plot3d(circle, (u,0,2*pi), axis=(0,0), show_curve=True, opacity=0.5)
        sphinx_plot(P)

    An axis on `(0,y)` will produce a cylinder-like surface::

        sage: revolution_plot3d(circle, (u,0,2*pi), axis=(0,2), show_curve=True, opacity=0.5).show(aspect_ratio=(1,1,1))

    .. PLOT::

        u = var('u')
        circle = (cos(u), sin(u))
        P = revolution_plot3d(circle, (u,0,2*pi), axis=(0,2), show_curve=True, opacity=0.5)
        sphinx_plot(P)

    And any other axis will produce a torus-like surface::

        sage: revolution_plot3d(circle, (u,0,2*pi), axis=(2,0), show_curve=True, opacity=0.5).show(aspect_ratio=(1,1,1))

    .. PLOT::

        u = var('u')
        circle = (cos(u), sin(u))
        P = revolution_plot3d(circle, (u,0,2*pi), axis=(2,0), show_curve=True, opacity=0.5)
        sphinx_plot(P)

    Now, we can get another goblet-like surface by revolving a curve in 3d::

        sage: u = var('u')
        sage: curve = (u, cos(4*u), u^2)
        sage: P = revolution_plot3d(curve, (u,0,2), show_curve=True, parallel_axis='z',axis=(1,.2), opacity=0.5)
        sage: P.show(aspect_ratio=(1,1,1))

    .. PLOT::

        u = var('u')
        curve = (u, cos(4*u), u**2)
        P = revolution_plot3d(curve, (u,0,2), show_curve=True, parallel_axis='z', axis=(1,.2), opacity=0.5)
        sphinx_plot(P)

    A curvy curve with only a quarter turn::

        sage: u = var('u')
        sage: curve = (sin(3*u), .8*cos(4*u), cos(u))
        sage: revolution_plot3d(curve, (u,0,pi), (0,pi/2), show_curve=True, parallel_axis='z', opacity=0.5).show(aspect_ratio=(1,1,1),frame=False)

    .. PLOT::

        u = var('u')
        curve = (sin(3*u), .8*cos(4*u), cos(u))
        P = revolution_plot3d(curve, (u,0,pi), (0,pi/2), show_curve=True, parallel_axis='z', opacity=0.5)
        sphinx_plot(P)

    One can also color the surface using a coloring function of two
    parameters and a colormap as follows. Note that the coloring
    function must take values in the interval [0,1]. ::

        sage: u, phi = var('u,phi')
        sage: def cf(u,phi): return sin(phi+u) ^ 2
        sage: curve = (1+u^2/4, 0, u)
        sage: revolution_plot3d(curve, (u,-2,2), (0,2*pi), parallel_axis='z', color=(cf, colormaps.PiYG)).show(aspect_ratio=(1,1,1))

    .. PLOT::

        u, phi = var('u,phi')
        def cf(u, phi): return sin(phi+u) ** 2
        curve = (1+u**2/4, 0, u)
        P = revolution_plot3d(curve, (u,-2,2), (0,2*pi), parallel_axis='z', color=(cf, colormaps.PiYG))
        sphinx_plot(P)

    The first parameter of the coloring function will be identified with the
    parameter of the curve, and the second with the angle parameter.

    .. WARNING::

        This kind of coloring using a colormap can be visualized using
        Jmol, Tachyon (option ``viewer='tachyon'``) and Canvas3D
        (option ``viewer='canvas3d'`` in the notebook).

    Another colored example, illustrating that one can use (colormap, color function) instead of (color function, colormap)::

        sage: u, phi = var('u,phi')
        sage: def cf(u, phi): return float(2 * u / pi) % 1
        sage: curve = (sin(u), 0, u)
        sage: revolution_plot3d(curve, (u,0,pi), (0,2*pi), parallel_axis
        ....: ='z', color=(colormaps.brg, cf)).show(aspect_ratio=1)

    .. PLOT::

        u, phi = var('u,phi')
        def cf(u, phi): return float(2 * u / pi) % 1
        curve = (sin(u), 0, u)
        P = revolution_plot3d(curve, (u,0,pi), (0,2*pi), parallel_axis='z', color=(colormaps.brg, cf))
        sphinx_plot(P)
    """
    from sage.symbolic.ring import SR
    from sage.symbolic.constants import pi
    from sage.misc.functional import sqrt
    from sage.functions.trig import sin
    from sage.functions.trig import cos
    from sage.functions.trig import atan2

    if parallel_axis not in ['x', 'y', 'z']:
        raise ValueError("parallel_axis must be either 'x', 'y', or 'z'.")

    vart = trange[0]

    if str(vart) == 'phi':
        phi = SR.var('fi')
    else:
        phi = SR.var('phi')

    if phirange is None:  # this if-else provides a phirange
        phirange = (phi, 0, 2 * pi)
    elif len(phirange) == 3:
        phi = phirange[0]
    else:
        phirange = (phi, phirange[0], phirange[1])

    if isinstance(curve, (tuple, list)):
        #this if-else provides a vector v to be plotted
        #if curve is a tuple or a list of length 2, it is interpreted as a parametric curve
        #in the x-z plane.
        #if it is of length 3 it is interpreted as a parametric curve in 3d space

        if len(curve) == 2:
            x = curve[0]
            y = 0
            z = curve[1]
        elif len(curve) == 3:
            x = curve[0]
            y = curve[1]
            z = curve[2]
    else:
        x = vart
        y = 0
        z = curve

    phase = 0
    if parallel_axis == 'z':
        x0 = axis[0]
        y0 = axis[1]
        # (0,0) must be handled separately for the phase value
        if x0 != 0 or y0 != 0:
            phase = atan2(y - y0, x - x0)
        R = sqrt((x - x0)**2 + (y - y0)**2)
        v = (R * cos(phi + phase) + x0, R * sin(phi + phase) + y0, z)
    elif parallel_axis == 'x':
        y0 = axis[0]
        z0 = axis[1]
        # (0,0) must be handled separately for the phase value
        if z0 != 0 or y0 != 0:
            phase = atan2(z - z0, y - y0)
        R = sqrt((y - y0)**2 + (z - z0)**2)
        v = (x, R * cos(phi + phase) + y0, R * sin(phi + phase) + z0)
    elif parallel_axis == 'y':
        x0 = axis[0]
        z0 = axis[1]
        # (0,0) must be handled separately for the phase value
        if z0 != 0 or x0 != 0:
            phase = atan2(z - z0, x - x0)
        R = sqrt((x - x0)**2 + (z - z0)**2)
        v = (R * cos(phi + phase) + x0, y, R * sin(phi + phase) + z0)

    if print_vector:
        print(v)

    if show_curve:
        curveplot = parametric_plot3d((x, y, z),
                                      trange,
                                      thickness=2,
                                      rgbcolor=(1, 0, 0))
        return parametric_plot3d(v, trange, phirange, **kwds) + curveplot

    return parametric_plot3d(v, trange, phirange, **kwds)
def revolution_plot3d(curve,
                      trange,
                      phirange=None,
                      parallel_axis='z',
                      axis=(0, 0),
                      print_vector=False,
                      show_curve=False,
                      **kwds):
    """
    Return a plot of a revolved curve.

    There are three ways to call this function:

    - ``revolution_plot3d(f,trange)`` where `f` is a function located in the `x z` plane.

    - ``revolution_plot3d((f_x,f_z),trange)`` where `(f_x,f_z)` is a parametric curve on the `x z` plane.

    - ``revolution_plot3d((f_x,f_y,f_z),trange)`` where `(f_x,f_y,f_z)` can be any parametric curve.

    INPUT:

    - ``curve`` - A curve to be revolved, specified as a function, a 2-tuple or a 3-tuple.

    - ``trange`` - A 3-tuple `(t,t_{\min},t_{\max})` where t is the independent variable of the curve.

    - ``phirange`` - A 2-tuple of the form `(\phi_{\min},\phi_{\max})`, (default `(0,\pi)`) that specifies the angle in which the curve is to be revolved.

    - ``parallel_axis`` - A string (Either 'x', 'y', or 'z') that specifies the coordinate axis parallel to the revolution axis.

    - ``axis`` - A 2-tuple that specifies the position of the revolution axis. If parallel is:

        - 'z' - then axis is the point in which the revolution axis intersects the  `x y` plane.

        - 'x' - then axis is the point in which the revolution axis intersects the  `y z` plane.

        - 'y' - then axis is the point in which the revolution axis intersects the `x z` plane.

    - ``print_vector`` - If True, the parametrization of the surface of revolution will be printed.

    - ``show_curve`` - If True, the curve will be displayed.


    EXAMPLES:

    Let's revolve a simple function around different axes::

        sage: u = var('u')
        sage: f=u^2
        sage: revolution_plot3d(f,(u,0,2),show_curve=True,opacity=0.7).show(aspect_ratio=(1,1,1))

    If we move slightly the axis, we get a goblet-like surface::

        sage: revolution_plot3d(f,(u,0,2),axis=(1,0.2),show_curve=True,opacity=0.5).show(aspect_ratio=(1,1,1))

    A common problem in calculus books, find the volume within the following revolution solid::

        sage: line=u
        sage: parabola=u^2
        sage: sur1=revolution_plot3d(line,(u,0,1),opacity=0.5,rgbcolor=(1,0.5,0),show_curve=True,parallel_axis='x')
        sage: sur2=revolution_plot3d(parabola,(u,0,1),opacity=0.5,rgbcolor=(0,1,0),show_curve=True,parallel_axis='x')
        sage: (sur1+sur2).show()


    Now let's revolve a parametrically defined circle. We can play with the topology of the surface by changing the axis, an axis in `(0,0)` (as the previous one) will produce a sphere-like surface::

        sage: u = var('u')
        sage: circle=(cos(u),sin(u))
        sage: revolution_plot3d(circle,(u,0,2*pi),axis=(0,0),show_curve=True,opacity=0.5).show(aspect_ratio=(1,1,1))

    An axis on `(0,y)` will produce a cylinder-like surface::

        sage: revolution_plot3d(circle,(u,0,2*pi),axis=(0,2),show_curve=True,opacity=0.5).show(aspect_ratio=(1,1,1))

    And any other axis will produce a torus-like surface::

        sage: revolution_plot3d(circle,(u,0,2*pi),axis=(2,0),show_curve=True,opacity=0.5).show(aspect_ratio=(1,1,1))

    Now, we can get another goblet-like surface by revolving a curve in 3d::

        sage: u = var('u')
        sage: curve=(u,cos(4*u),u^2)
        sage: revolution_plot3d(curve,(u,0,2),show_curve=True,parallel_axis='z',axis=(1,.2),opacity=0.5).show(aspect_ratio=(1,1,1))

    A curvy curve with only a quarter turn::

        sage: u = var('u')
        sage: curve=(sin(3*u),.8*cos(4*u),cos(u))
        sage: revolution_plot3d(curve,(u,0,pi),(0,pi/2),show_curve=True,parallel_axis='z',opacity=0.5).show(aspect_ratio=(1,1,1),frame=False)
    """
    from sage.symbolic.ring import SR
    from sage.symbolic.constants import pi
    from sage.functions.other import sqrt
    from sage.functions.trig import sin
    from sage.functions.trig import cos
    from sage.functions.trig import atan2

    if parallel_axis not in ['x', 'y', 'z']:
        raise ValueError("parallel_axis must be either 'x', 'y', or 'z'.")

    vart = trange[0]

    if str(vart) == 'phi':
        phi = SR.var('fi')
    else:
        phi = SR.var('phi')

    if phirange is None:  #this if-else provides a phirange
        phirange = (phi, 0, 2 * pi)
    elif len(phirange) == 3:
        phi = phirange[0]
        pass
    else:
        phirange = (phi, phirange[0], phirange[1])

    if isinstance(curve, tuple) or isinstance(curve, list):
        #this if-else provides a vector v to be plotted
        #if curve is a tuple or a list of length 2, it is interpreted as a parametric curve
        #in the x-z plane.
        #if it is of length 3 it is interpreted as a parametric curve in 3d space

        if len(curve) == 2:
            x = curve[0]
            y = 0
            z = curve[1]
        elif len(curve) == 3:
            x = curve[0]
            y = curve[1]
            z = curve[2]
    else:
        x = vart
        y = 0
        z = curve

    if parallel_axis == 'z':
        x0 = axis[0]
        y0 = axis[1]
        # (0,0) must be handled separately for the phase value
        phase = 0
        if x0 != 0 or y0 != 0:
            phase = atan2((y - y0), (x - x0))
        R = sqrt((x - x0)**2 + (y - y0)**2)
        v = (R * cos(phi + phase) + x0, R * sin(phi + phase) + y0, z)
    elif parallel_axis == 'x':
        y0 = axis[0]
        z0 = axis[1]
        # (0,0) must be handled separately for the phase value
        phase = 0
        if z0 != 0 or y0 != 0:
            phase = atan2((z - z0), (y - y0))
        R = sqrt((y - y0)**2 + (z - z0)**2)
        v = (x, R * cos(phi + phase) + y0, R * sin(phi + phase) + z0)
    elif parallel_axis == 'y':
        x0 = axis[0]
        z0 = axis[1]
        # (0,0) must be handled separately for the phase value
        phase = 0
        if z0 != 0 or x0 != 0:
            phase = atan2((z - z0), (x - x0))
        R = sqrt((x - x0)**2 + (z - z0)**2)
        v = (R * cos(phi + phase) + x0, y, R * sin(phi + phase) + z0)

    if print_vector:
        print(v)
    if show_curve:
        curveplot = parametric_plot3d((x, y, z),
                                      trange,
                                      thickness=2,
                                      rgbcolor=(1, 0, 0))
        return parametric_plot3d(v, trange, phirange, **kwds) + curveplot
    return parametric_plot3d(v, trange, phirange, **kwds)
Exemple #3
0
def plot_hyperplane(hyperplane, **kwds):
    r"""
    Return the plot of a single hyperplane.

    INPUT:

    - ``**kwds`` -- plot options: see below

    OUTPUT:

    A graphics object of the plot.

    .. RUBRIC:: Plot Options

    Beside the usual plot options (enter ``plot?``), the plot command for
    hyperplanes includes the following:

    - ``hyperplane_label`` -- Boolean value or string (default: ``True``).
      If ``True``, the hyperplane is labeled with its equation, if a
      string, it is labeled by that string, otherwise it is not
      labeled.

    - ``label_color`` -- (Default: ``'black'``) Color for hyperplane_label.

    - ``label_fontsize`` -- Size for ``hyperplane_label`` font (default: 14)
      (does not work in 3d, yet).

    - ``label_offset`` -- (Default: 0-dim: 0.1, 1-dim: (0,1),
      2-dim: (0,0,0.2)) Amount by which label is offset from
      ``hyperplane.point()``.

    - ``point_size`` -- (Default: 50) Size of points in a zero-dimensional
      arrangement or of an arrangement over a finite field.

    - ``ranges`` -- Range for the parameters for the parametric plot of the
      hyperplane. If a single positive number ``r`` is given for the
      value of ``ranges``, then the ranges for all parameters are set to
      `[-r, r]`.  Otherwise, for a line in the plane, ``ranges`` has the
      form ``[a, b]`` (default: [-3,3]), and for a plane in 3-space, the
      ``ranges`` has the form ``[[a, b], [c, d]]`` (default: [[-3,3],[-3,3]]).
      (The ranges are centered around ``hyperplane.point()``.)

    EXAMPLES::

        sage: H1.<x> = HyperplaneArrangements(QQ)
        sage: a = 3*x + 4
        sage: a.plot()    # indirect doctest
        Graphics object consisting of 3 graphics primitives
        sage: a.plot(point_size=100,hyperplane_label='hello')
        Graphics object consisting of 3 graphics primitives

    
        sage: H2.<x,y> = HyperplaneArrangements(QQ)
        sage: b = 3*x + 4*y + 5
        sage: b.plot()
        Graphics object consisting of 2 graphics primitives
        sage: b.plot(ranges=(1,5),label_offset=(2,-1))
        Graphics object consisting of 2 graphics primitives
        sage: opts = {'hyperplane_label':True, 'label_color':'green',
        ....:         'label_fontsize':24, 'label_offset':(0,1.5)}
        sage: b.plot(**opts)
        Graphics object consisting of 2 graphics primitives

        sage: H3.<x,y,z> = HyperplaneArrangements(QQ)
        sage: c = 2*x + 3*y + 4*z + 5
        sage: c.plot()
        Graphics3d Object
        sage: c.plot(label_offset=(1,0,1), color='green', label_color='red', frame=False)
        Graphics3d Object
        sage: d = -3*x + 2*y + 2*z + 3
        sage: d.plot(opacity=0.8)
        Graphics3d Object
        sage: e = 4*x + 2*z + 3
        sage: e.plot(ranges=[[-1,1],[0,8]], label_offset=(2,2,1), aspect_ratio=1)
        Graphics3d Object
    """
    if hyperplane.base_ring().characteristic():
        raise NotImplementedError('base field must have characteristic zero')
    elif hyperplane.dimension() not in [
            0, 1, 2
    ]:  # dimension of hyperplane, not ambient space
        raise ValueError('can only plot hyperplanes in dimensions 1, 2, 3')
    # handle extra keywords
    if 'hyperplane_label' in kwds:
        hyp_label = kwds.pop('hyperplane_label')
        if not hyp_label:
            has_hyp_label = False
        else:
            has_hyp_label = True
    else:  # default
        hyp_label = True
        has_hyp_label = True
    if has_hyp_label:
        if hyp_label:  # then label hyperplane with its equation
            if hyperplane.dimension() == 2:  # jmol does not like latex
                label = hyperplane._repr_linear(include_zero=False)
            else:
                label = hyperplane._latex_()
        else:
            label = hyp_label  # a string
    if 'label_color' in kwds:
        label_color = kwds.pop('label_color')
    else:
        label_color = 'black'
    if 'label_fontsize' in kwds:
        label_fontsize = kwds.pop('label_fontsize')
    else:
        label_fontsize = 14
    if 'label_offset' in kwds:
        has_offset = True
        label_offset = kwds.pop('label_offset')
    else:
        has_offset = False  # give default values below
    if 'point_size' in kwds:
        pt_size = kwds.pop('point_size')
    else:
        pt_size = 50
    if 'ranges' in kwds:
        ranges_set = True
        ranges = kwds.pop('ranges')
    else:
        ranges_set = False  # give default values below
    # the extra keywords have now been handled
    # now create the plot
    if hyperplane.dimension() == 0:  # a point on a line
        x, = hyperplane.A()
        d = hyperplane.b()
        p = point((d / x, 0), size=pt_size, **kwds)
        if has_hyp_label:
            if not has_offset:
                label_offset = 0.1
            p += text(label, (d / x, label_offset),
                      color=label_color,
                      fontsize=label_fontsize)
            p += text('', (d / x, label_offset + 0.4))  # add space at top
        if 'ymax' not in kwds:
            kwds['ymax'] = 0.5
    elif hyperplane.dimension() == 1:  # a line in the plane
        pnt = hyperplane.point()
        w = hyperplane.linear_part().matrix()
        t = SR.var('t')
        if ranges_set:
            if isinstance(ranges, (list, tuple)):
                t0, t1 = ranges
            else:  # ranges should be a single positive number
                t0, t1 = -ranges, ranges
        else:  # default
            t0, t1 = -3, 3
        p = parametric_plot(pnt + t * w[0], (t, t0, t1), **kwds)
        if has_hyp_label:
            if has_offset:
                b0, b1 = label_offset
            else:
                b0, b1 = 0, 0.2
            label = text(label, (pnt[0] + b0, pnt[1] + b1),
                         color=label_color,
                         fontsize=label_fontsize)
            p += label
    elif hyperplane.dimension() == 2:  # a plane in 3-space
        pnt = hyperplane.point()
        w = hyperplane.linear_part().matrix()
        s, t = SR.var('s t')
        if ranges_set:
            if isinstance(ranges, (list, tuple)):
                s0, s1 = ranges[0]
                t0, t1 = ranges[1]
            else:  # ranges should be a single positive integers
                s0, s1 = -ranges, ranges
                t0, t1 = -ranges, ranges
        else:  # default
            s0, s1 = -3, 3
            t0, t1 = -3, 3
        p = parametric_plot3d(pnt + s * w[0] + t * w[1], (s, s0, s1),
                              (t, t0, t1), **kwds)
        if has_hyp_label:
            if has_offset:
                b0, b1, b2 = label_offset
            else:
                b0, b1, b2 = 0, 0, 0
            label = text3d(label, (pnt[0] + b0, pnt[1] + b1, pnt[2] + b2),
                           color=label_color,
                           fontsize=label_fontsize)
            p += label
    return p
Exemple #4
0
def plot_hyperplane(hyperplane, **kwds):
    r"""
    Return the plot of a single hyperplane.

    INPUT:

    - ``**kwds`` -- plot options: see below

    OUTPUT:

    A graphics object of the plot.

    .. RUBRIC:: Plot Options

    Beside the usual plot options (enter ``plot?``), the plot command for
    hyperplanes includes the following:

    - ``hyperplane_label`` -- Boolean value or string (default: ``True``).
      If ``True``, the hyperplane is labeled with its equation, if a
      string, it is labeled by that string, otherwise it is not
      labeled.

    - ``label_color`` -- (Default: ``'black'``) Color for hyperplane_label.

    - ``label_fontsize`` -- Size for ``hyperplane_label`` font (default: 14)
      (does not work in 3d, yet).

    - ``label_offset`` -- (Default: 0-dim: 0.1, 1-dim: (0,1),
      2-dim: (0,0,0.2)) Amount by which label is offset from
      ``hyperplane.point()``.

    - ``point_size`` -- (Default: 50) Size of points in a zero-dimensional
      arrangement or of an arrangement over a finite field.

    - ``ranges`` -- Range for the parameters for the parametric plot of the
      hyperplane. If a single positive number ``r`` is given for the
      value of ``ranges``, then the ranges for all parameters are set to
      `[-r, r]`.  Otherwise, for a line in the plane, ``ranges`` has the
      form ``[a, b]`` (default: [-3,3]), and for a plane in 3-space, the
      ``ranges`` has the form ``[[a, b], [c, d]]`` (default: [[-3,3],[-3,3]]).
      (The ranges are centered around ``hyperplane.point()``.)

    EXAMPLES::

        sage: H1.<x> = HyperplaneArrangements(QQ)
        sage: a = 3*x + 4
        sage: a.plot()    # indirect doctest
        Graphics object consisting of 3 graphics primitives
        sage: a.plot(point_size=100,hyperplane_label='hello')
        Graphics object consisting of 3 graphics primitives

    
        sage: H2.<x,y> = HyperplaneArrangements(QQ)
        sage: b = 3*x + 4*y + 5
        sage: b.plot()
        Graphics object consisting of 2 graphics primitives
        sage: b.plot(ranges=(1,5),label_offset=(2,-1))
        Graphics object consisting of 2 graphics primitives
        sage: opts = {'hyperplane_label':True, 'label_color':'green',
        ....:         'label_fontsize':24, 'label_offset':(0,1.5)}
        sage: b.plot(**opts)
        Graphics object consisting of 2 graphics primitives

        sage: H3.<x,y,z> = HyperplaneArrangements(QQ)
        sage: c = 2*x + 3*y + 4*z + 5
        sage: c.plot()
        Graphics3d Object
        sage: c.plot(label_offset=(1,0,1), color='green', label_color='red', frame=False)
        Graphics3d Object
        sage: d = -3*x + 2*y + 2*z + 3
        sage: d.plot(opacity=0.8)
        Graphics3d Object
        sage: e = 4*x + 2*z + 3
        sage: e.plot(ranges=[[-1,1],[0,8]], label_offset=(2,2,1), aspect_ratio=1)
        Graphics3d Object
    """
    if hyperplane.base_ring().characteristic() != 0:
        raise NotImplementedError('base field must have characteristic zero')
    elif hyperplane.dimension() not in [0, 1, 2]: # dimension of hyperplane, not ambient space
        raise ValueError('can only plot hyperplanes in dimensions 1, 2, 3')
    # handle extra keywords
    if 'hyperplane_label' in kwds:
        hyp_label = kwds.pop('hyperplane_label')
        if not hyp_label:
            has_hyp_label = False
        else:
            has_hyp_label = True
    else: # default
        hyp_label = True
        has_hyp_label = True
    if has_hyp_label:
        if hyp_label: # then label hyperplane with its equation
            if hyperplane.dimension() == 2: # jmol does not like latex
                label = hyperplane._repr_linear(include_zero=False)
            else:
                label = hyperplane._latex_()
        else:
            label = hyp_label # a string
    if 'label_color' in kwds:
        label_color = kwds.pop('label_color')
    else:
        label_color = 'black'
    if 'label_fontsize' in kwds:
        label_fontsize = kwds.pop('label_fontsize')
    else:
        label_fontsize = 14
    if 'label_offset' in kwds:
        has_offset = True
        label_offset = kwds.pop('label_offset')
    else:
        has_offset = False # give default values below
    if 'point_size' in kwds:
        pt_size = kwds.pop('point_size')
    else:
        pt_size = 50
    if 'ranges' in kwds:
        ranges_set = True
        ranges = kwds.pop('ranges')
    else:
        ranges_set = False # give default values below
    # the extra keywords have now been handled
    # now create the plot
    if hyperplane.dimension() == 0: # a point on a line
        x, = hyperplane.A() 
        d = hyperplane.b()
        p = point((d/x,0), size = pt_size, **kwds)
        if has_hyp_label:
            if not has_offset:
                label_offset = 0.1
            p += text(label, (d/x,label_offset),
                    color=label_color,fontsize=label_fontsize)
            p += text('',(d/x,label_offset+0.4)) # add space at top
        if 'ymax' not in kwds:
            kwds['ymax'] = 0.5
    elif hyperplane.dimension() == 1: # a line in the plane
        pnt = hyperplane.point()
        w = hyperplane.linear_part().matrix()
        x, y = hyperplane.A()
        d = hyperplane.b()
        t = SR.var('t')
        if ranges_set:
            if type(ranges) in [list,tuple]:
                t0, t1 = ranges
            else:  # ranges should be a single positive number
                t0, t1 = -ranges, ranges
        else: # default
            t0, t1 = -3, 3
        p = parametric_plot(pnt+t*w[0], (t,t0,t1), **kwds)
        if has_hyp_label:
            if has_offset:
                b0, b1 = label_offset
            else:
                b0, b1 = 0, 0.2
            label = text(label,(pnt[0]+b0,pnt[1]+b1),
                    color=label_color,fontsize=label_fontsize)
            p += label
    elif hyperplane.dimension() == 2: # a plane in 3-space
        pnt = hyperplane.point()
        w = hyperplane.linear_part().matrix()
        a, b, c = hyperplane.A()
        d = hyperplane.b()
        s,t = SR.var('s t')
        if ranges_set:
            if type(ranges) in [list,tuple]:
                s0, s1 = ranges[0]
                t0, t1 = ranges[1]
            else: # ranges should be a single positive integers
                s0, s1 = -ranges, ranges
                t0, t1 = -ranges, ranges
        else: # default
            s0, s1 = -3, 3
            t0, t1 = -3, 3
        p = parametric_plot3d(pnt+s*w[0]+t*w[1],(s,s0,s1),(t,t0,t1),**kwds)
        if has_hyp_label: 
            if has_offset:
                b0, b1, b2 = label_offset
            else:
                b0, b1, b2 = 0, 0, 0
            label = text3d(label,(pnt[0]+b0,pnt[1]+b1,pnt[2]+b2),
                    color=label_color,fontsize=label_fontsize)
            p += label
    return p
    radius=norm(first_vector)
    if norm(second_vector)!=radius:
        raise ValueError("Ellipse not implemented")
    first_unit_vector=first_vector/radius
    second_unit_vector=second_vector/radius
    normal_vector=second_vector-(second_vector*first_unit_vector)*first_unit_vector
    if norm(normal_vector)==0:
        print (first_point,second_point)
        return
    normal_unit_vector=normal_vector/norm(normal_vector)
    scalar_product=first_unit_vector*second_unit_vector
    if abs(scalar_product) == 1:
        raise ValueError("The points are alligned")
    angle=arccos(scalar_product)
    var('t')
    return parametric_plot3d(center+first_vector*cos(t)+radius*normal_unit_vector*sin(t),(0,angle),**kwds)
     

     
def _arc(p,q,s,**kwds):
    #rewrite this to use polar_plot and get points to do filled triangles
    from sage.misc.functional import det
    from sage.plot.line import line
    from sage.misc.functional import norm
    from sage.symbolic.all import pi
    from sage.plot.arc import arc
     
    p,q,s = map( lambda x: vector(x), [p,q,s])
     
    # to avoid running into division by 0 we set to be colinear vectors that are
    # almost colinear
Exemple #6
0
def revolution_plot3d(curve,trange,phirange=None,parallel_axis='z',axis=(0,0),print_vector=False,show_curve=False,**kwds):
    """
    Return a plot of a revolved curve.

    There are three ways to call this function:

    - ``revolution_plot3d(f,trange)`` where `f` is a function located in the `x z` plane.

    - ``revolution_plot3d((f_x,f_z),trange)`` where `(f_x,f_z)` is a parametric curve on the `x z` plane.

    - ``revolution_plot3d((f_x,f_y,f_z),trange)`` where `(f_x,f_y,f_z)` can be any parametric curve.

    INPUT:

    - ``curve`` - A curve to be revolved, specified as a function, a 2-tuple or a 3-tuple.

    - ``trange`` - A 3-tuple `(t,t_{\min},t_{\max})` where t is the independent variable of the curve.

    - ``phirange`` - A 2-tuple of the form `(\phi_{\min},\phi_{\max})`, (default `(0,\pi)`) that specifies the angle in which the curve is to be revolved.

    - ``parallel_axis`` - A string (Either 'x', 'y', or 'z') that specifies the coordinate axis parallel to the revolution axis.

    - ``axis`` - A 2-tuple that specifies the position of the revolution axis. If parallel is:

        - 'z' - then axis is the point in which the revolution axis intersects the  `x y` plane.

        - 'x' - then axis is the point in which the revolution axis intersects the  `y z` plane.

        - 'y' - then axis is the point in which the revolution axis intersects the `x z` plane.

    - ``print_vector`` - If True, the parametrization of the surface of revolution will be printed.

    - ``show_curve`` - If True, the curve will be displayed.


    EXAMPLES:

    Let's revolve a simple function around different axes::

        sage: u = var('u')
        sage: f=u^2
        sage: revolution_plot3d(f,(u,0,2),show_curve=True,opacity=0.7).show(aspect_ratio=(1,1,1))

    If we move slightly the axis, we get a goblet-like surface::

        sage: revolution_plot3d(f,(u,0,2),axis=(1,0.2),show_curve=True,opacity=0.5).show(aspect_ratio=(1,1,1))

    A common problem in calculus books, find the volume within the following revolution solid::

        sage: line=u
        sage: parabola=u^2
        sage: sur1=revolution_plot3d(line,(u,0,1),opacity=0.5,rgbcolor=(1,0.5,0),show_curve=True,parallel_axis='x')
        sage: sur2=revolution_plot3d(parabola,(u,0,1),opacity=0.5,rgbcolor=(0,1,0),show_curve=True,parallel_axis='x')
        sage: (sur1+sur2).show()


    Now let's revolve a parametrically defined circle. We can play with the topology of the surface by changing the axis, an axis in `(0,0)` (as the previous one) will produce a sphere-like surface::

        sage: u = var('u')
        sage: circle=(cos(u),sin(u))
        sage: revolution_plot3d(circle,(u,0,2*pi),axis=(0,0),show_curve=True,opacity=0.5).show(aspect_ratio=(1,1,1))

    An axis on `(0,y)` will produce a cylinder-like surface::

        sage: revolution_plot3d(circle,(u,0,2*pi),axis=(0,2),show_curve=True,opacity=0.5).show(aspect_ratio=(1,1,1))

    And any other axis will produce a torus-like surface::

        sage: revolution_plot3d(circle,(u,0,2*pi),axis=(2,0),show_curve=True,opacity=0.5).show(aspect_ratio=(1,1,1))

    Now, we can get another goblet-like surface by revolving a curve in 3d::

        sage: u = var('u')
        sage: curve=(u,cos(4*u),u^2)
        sage: revolution_plot3d(curve,(u,0,2),show_curve=True,parallel_axis='z',axis=(1,.2),opacity=0.5).show(aspect_ratio=(1,1,1))

    A curvy curve with only a quarter turn::

        sage: u = var('u')
        sage: curve=(sin(3*u),.8*cos(4*u),cos(u))
        sage: revolution_plot3d(curve,(u,0,pi),(0,pi/2),show_curve=True,parallel_axis='z',opacity=0.5).show(aspect_ratio=(1,1,1),frame=False)
    """
    from sage.symbolic.ring import var
    from sage.symbolic.constants import pi
    from sage.functions.other import sqrt
    from sage.functions.trig import sin
    from sage.functions.trig import cos
    from sage.functions.trig import atan2


    if parallel_axis not in ['x','y','z']:
        raise ValueError, "parallel_axis must be either 'x', 'y', or 'z'."

    vart=trange[0]


    if str(vart)=='phi':
        phi=var('fi')
    else:
        phi=var('phi')


    if phirange is None:#this if-else provides a phirange
        phirange=(phi,0,2*pi)
    elif len(phirange)==3:
        phi=phirange[0]
        pass
    else:
        phirange=(phi,phirange[0],phirange[1])

    if isinstance(curve,tuple) or isinstance(curve,list):
        #this if-else provides a vector v to be plotted
        #if curve is a tuple or a list of length 2, it is interpreted as a parametric curve
        #in the x-z plane.
        #if it is of length 3 it is interpreted as a parametric curve in 3d space

        if len(curve) ==2:
            x=curve[0]
            y=0
            z=curve[1]
        elif len(curve)==3:
            x=curve[0]
            y=curve[1]
            z=curve[2]
    else:
        x=vart
        y=0
        z=curve

    if parallel_axis=='z':
        x0=axis[0]
        y0=axis[1]
        # (0,0) must be handled separately for the phase value
        phase=0
        if x0!=0 or y0!=0:
            phase=atan2((y-y0),(x-x0))
        R=sqrt((x-x0)**2+(y-y0)**2)
        v=(R*cos(phi+phase)+x0,R*sin(phi+phase)+y0,z)
    elif parallel_axis=='x':
        y0=axis[0]
        z0=axis[1]
        # (0,0) must be handled separately for the phase value
        phase=0
        if z0!=0 or y0!=0:
            phase=atan2((z-z0),(y-y0))
        R=sqrt((y-y0)**2+(z-z0)**2)
        v=(x,R*cos(phi+phase)+y0,R*sin(phi+phase)+z0)
    elif parallel_axis=='y':
        x0=axis[0]
        z0=axis[1]
        # (0,0) must be handled separately for the phase value
        phase=0
        if z0!=0 or x0!=0:
            phase=atan2((z-z0),(x-x0))
        R=sqrt((x-x0)**2+(z-z0)**2)
        v=(R*cos(phi+phase)+x0,y,R*sin(phi+phase)+z0)

    if print_vector:
        print v
    if show_curve:
        curveplot=parametric_plot3d((x,y,z),trange,thickness=2,rgbcolor=(1,0,0))
        return parametric_plot3d(v,trange,phirange,**kwds)+curveplot
    return parametric_plot3d(v,trange,phirange,**kwds)
        raise ValueError("Ellipse not implemented")
    first_unit_vector = first_vector / radius
    second_unit_vector = second_vector / radius
    normal_vector = second_vector - (second_vector *
                                     first_unit_vector) * first_unit_vector
    if norm(normal_vector) == 0:
        print(first_point, second_point)
        return
    normal_unit_vector = normal_vector / norm(normal_vector)
    scalar_product = first_unit_vector * second_unit_vector
    if abs(scalar_product) == 1:
        raise ValueError("The points are alligned")
    angle = arccos(scalar_product)
    var('t')
    return parametric_plot3d(
        center + first_vector * cos(t) + radius * normal_unit_vector * sin(t),
        (0, angle), **kwds)


def _arc(p, q, s, **kwds):
    #rewrite this to use polar_plot and get points to do filled triangles
    from sage.misc.functional import det
    from sage.plot.line import line
    from sage.misc.functional import norm
    from sage.symbolic.all import pi
    from sage.plot.arc import arc

    p, q, s = map(lambda x: vector(x), [p, q, s])

    # to avoid running into division by 0 we set to be colinear vectors that are
    # almost colinear