def legend_3d(hyperplane_arrangement, hyperplane_colors, length):
    r"""
    Create plot of a 3d legend for an arrangement of planes in 3-space.  The
    ``length`` parameter determines whether short or long labels are used in
    the legend.

    INPUT:

    - ``hyperplane_arrangement`` -- a hyperplane arrangement
    
    - ``hyperplane_colors`` -- list of colors

    - ``length`` -- either ``'short'`` or ``'long'``

    OUTPUT:

    - A graphics object.

    EXAMPLES::

        sage: a = hyperplane_arrangements.semiorder(3)
        sage: from sage.geometry.hyperplane_arrangement.plot import legend_3d
        sage: legend_3d(a, colors.values()[:6],length='long')

        sage: b = hyperplane_arrangements.semiorder(4)
        sage: c = b.essentialization()
        sage: legend_3d(c, colors.values()[:12], length='long')

        sage: legend_3d(c, colors.values()[:12], length='short')

        sage: p = legend_3d(c, colors.values()[:12], length='short')
        sage: p.set_legend_options(ncol=4)
        sage: type(p)
        <class 'sage.plot.graphics.Graphics'>
    """
    if hyperplane_arrangement.dimension() != 3:
        raise ValueError('arrangements must be in 3-space')
    hyps = hyperplane_arrangement.hyperplanes()
    N = len(hyperplane_arrangement)
    if length == 'short':
        labels = ['  ' + str(i) for i in range(N)]
    else:
        labels = [
            '  ' + hyps[i]._repr_linear(include_zero=False) for i in range(N)
        ]
    p = Graphics()
    for i in range(N):
        p += line([(0, 0), (0, 0)],
                  color=hyperplane_colors[i],
                  thickness=8,
                  legend_label=labels[i],
                  axes=False)
    p.set_legend_options(title='Hyperplanes',
                         loc='center',
                         labelspacing=0.4,
                         fancybox=True,
                         font_size='x-large',
                         ncol=2)
    p.legend(True)
    return p
Exemple #2
0
    def plot_n_cylinders(self, n, labels=True):
        r"""
        EXAMPLES::

            sage: from slabbe.markov_transformation import markov_transformations
            sage: T = markov_transformations.Selmer()
            sage: G = T.plot_n_cylinders(3)

        TESTS::

            sage: G = T.plot_n_cylinders(0)
        """
        from sage.plot.graphics import Graphics
        from sage.plot.polygon import polygon
        from sage.plot.text import text
        M3to2 = projection_matrix(3, 2)
        G = Graphics()
        for w, cyl in self.n_cylinders_iterator(n):
            columns = cyl.columns()
            G += polygon((M3to2 * col / col.norm(1) for col in columns),
                         fill=False)
            if labels:
                sum_cols = sum(columns)
                G += text("{}".format(w), M3to2 * sum_cols / sum_cols.norm(1))
        return G
Exemple #3
0
    def plot(self, **options):
        r"""
        Plot this cylinder in coordinates used by a graphical surface. This
        plots this cylinder as a union of subpolygons. Only the intersections
        with polygons visible in the graphical surface are shown.

        Parameters other than `graphical_surface` are passed to `polygon2d`
        which is called to render the polygons.

        Parameters
        ----------
        graphical_surface : a GraphicalSurface
            If not provided or `None`, the plot method uses the default graphical
            surface for the surface.
        """
        if "graphical_surface" in options and options[
                "graphical_surface"] is not None:
            gs = options["graphical_surface"]
            assert gs.get_surface(
            ) == self._s, "Graphical surface for the wrong surface."
            del options["graphical_surface"]
        else:
            gs = self._s.graphical_surface()
        plt = Graphics()
        for l, p in self.polygons():
            if gs.is_visible(l):
                gp = gs.graphical_polygon(l)
                t = gp.transformation()
                pp = t(p)
                poly = polygon2d(pp.vertices(), **options)
                plt += poly.plot()
        return plt
Exemple #4
0
def plot_error_function(model_filename, N, x0, Tfrac=0.8):
    """
    Plot the estimated error of the linearized ODE as a function of time.

    INPUT:

    - ``model_filename`` -- string containing the model in text format

    - ``N`` -- truncation order

    - ``x0`` -- initial point, a list

    - ``Tfrac`` -- (optional, default: `0.8`): fraction of the convergence radius,
      to specify the plotting range in the time axis

    NOTE:

    This function calls ``error_function`` for the error computations.
    """
    from sage.plot.graphics import Graphics
    from sage.plot.plot import plot
    from sage.plot.line import line

    [Ts, eps] = error_function(model_filename, N, x0)
    P = Graphics()
    P = plot(eps, 0, Ts * Tfrac, axes_labels=["$t$", r"$\mathcal{E}(t)$"])
    P += line([[Ts, 0], [Ts, eps(t=Ts * Tfrac)]],
              linestyle='dotted',
              color='black')

    return P
    def plot(self, **kwargs):
        """
        Plot this Newton polygon.

        .. NOTE::

            All usual rendering options (color, thickness, etc.) are available.

        EXAMPLES:

            sage: from sage.geometry.newton_polygon import NewtonPolygon
            sage: NP = NewtonPolygon([ (0,0), (1,1), (2,6) ])
            sage: polygon = NP.plot()
        """
        vertices = self.vertices()
        if len(vertices) == 0:
            from sage.plot.graphics import Graphics
            return Graphics()
        else:
            from sage.plot.line import line
            (xstart, ystart) = vertices[0]
            (xend, yend) = vertices[-1]
            if self.last_slope() is Infinity:
                return line([(xstart, ystart+1), (xstart,ystart+0.5)], linestyle="--", **kwargs) \
                     + line([(xstart, ystart+0.5)] + vertices + [(xend, yend+0.5)], **kwargs) \
                     + line([(xend, yend+0.5), (xend, yend+1)], linestyle="--", **kwargs)
            else:
                return line([(xstart, ystart+1), (xstart,ystart+0.5)], linestyle="--", **kwargs) \
                     + line([(xstart, ystart+0.5)] + vertices + [(xend+0.5, yend + 0.5*self.last_slope())], **kwargs) \
                     + line([(xend+0.5, yend + 0.5*self.last_slope()), (xend+1, yend+self.last_slope())], linestyle="--", **kwargs)
    def plot2d(self, depth=None):
        # FIXME: refactor this before publishing
        from sage.plot.line import line
        from sage.plot.graphics import Graphics
        if self._n != 2:
            raise ValueError("Can only 2d plot fans.")
        if depth == None:
            depth = self._depth
        if not self.is_finite() and depth == infinity:
            raise ValueError(
                "For infinite algebras you must specify the depth.")

        colors = dict([(0, 'red'), (1, 'green')])
        G = Graphics()
        for i in range(2):
            orbit = self.ith_orbit(i, depth=depth)
            for j in orbit:
                G += line([(0, 0), vector(orbit[j])],
                          color=colors[i],
                          thickness=0.5,
                          zorder=2 * j + 1)

        G.set_aspect_ratio(1)
        G._show_axes = False
        return G
Exemple #7
0
def circle_image(A, B):
    G = Graphics()
    G += circle((0, 0), 1, color='grey')
    from collections import defaultdict
    tmp = defaultdict(int)
    for a in A:
        for j in range(a):
            if gcd(j, a) == 1:
                rational = Rational(j) / Rational(a)
                tmp[(rational.numerator(), rational.denominator())] += 1

    for b in B:
        for j in range(b):
            if gcd(j, b) == 1:
                rational = Rational(j) / Rational(b)
                tmp[(rational.numerator(), rational.denominator())] -= 1
    C = ComplexField()
    for val in tmp:
        if tmp[val] > 0:
            G += text(str(tmp[val]),
                      exp(C(-.2 + 2 * 3.14159 * I * val[0] / val[1])),
                      fontsize=30,
                      axes=False,
                      color="green")
        if tmp[val] < 0:
            G += text(str(abs(tmp[val])),
                      exp(C(.2 + 2 * 3.14159 * I * val[0] / val[1])),
                      fontsize=30,
                      axes=False,
                      color="blue")
    return G
Exemple #8
0
def bar_chart(datalist, **options):
    """
    A bar chart of (currently) one list of numerical data.
    Support for more data lists in progress.

    EXAMPLES:

    A bar_chart with blue bars::

        sage: bar_chart([1,2,3,4])
        Graphics object consisting of 1 graphics primitive

    A bar_chart with thinner bars::

        sage: bar_chart([x^2 for x in range(1,20)], width=0.2)
        Graphics object consisting of 1 graphics primitive

    A bar_chart with negative values and red bars::

        sage: bar_chart([-3,5,-6,11], rgbcolor=(1,0,0))
        Graphics object consisting of 1 graphics primitive

    A bar chart with a legend (it's possible, not necessarily useful)::

        sage: bar_chart([-1,1,-1,1], legend_label='wave')
        Graphics object consisting of 1 graphics primitive

    Extra options will get passed on to show(), as long as they are valid::

        sage: bar_chart([-2,8,-7,3], rgbcolor=(1,0,0), axes=False)
        Graphics object consisting of 1 graphics primitive
        sage: bar_chart([-2,8,-7,3], rgbcolor=(1,0,0)).show(axes=False) # These are equivalent
    """
    dl = len(datalist)
    #if dl > 1:
    #    print "WARNING, currently only 1 data set allowed"
    #    datalist = datalist[0]
    if dl == 3:
        datalist = datalist + [0]
    #bardata = []
    #cnt = 1
    #for pnts in datalist:
    #ind = [i+cnt/dl for i in range(len(pnts))]
    #bardata.append([ind, pnts, xrange, yrange])
    #cnt += 1

    g = Graphics()
    g._set_extra_kwds(Graphics._extract_kwds_for_show(options))
    #TODO: improve below for multiple data sets!
    #cnt = 1
    #for ind, pnts, xrange, yrange in bardata:
    #options={'rgbcolor':hue(cnt/dl),'width':0.5/dl}
    #    g._bar_chart(ind, pnts, xrange, yrange, options=options)
    #    cnt += 1
    #else:
    ind = list(range(len(datalist)))
    g.add_primitive(BarChart(ind, datalist, options=options))
    if options['legend_label']:
        g.legend(True)
    return g
Exemple #9
0
def piecewise_constant_image(A, B):
    # Jumps up and down going around circle, not used
    v = circle_drops(A, B)
    G = Graphics()
    w = ((Rational(i) / len(v), j) for i, j in enumerate(v))
    for p0, p1 in w:
        G += line([(p0, p1), (p0 + Rational(1) / len(w), p1)])
    return G
Exemple #10
0
def piecewise_linear_image(A,B):
    # Jumps up and down going around circle, not used
    v = circle_drops(A,B)
    G = Graphics()
    w = [(Rational(i)/len(v), j) for i,j in enumerate(v)]
    for pt in w:
        G += line([(pt[0],pt[1]),(pt[0]+Rational(1)/len(w),pt[1])])
    return G
Exemple #11
0
    def bezier_path(self):
        """
        Return ``self`` as a Bezier path.

        This is needed to concatenate arcs, in order to
        create hyperbolic polygons.

        EXAMPLES::

            sage: from sage.plot.arc import Arc
            sage: op = {'alpha':1,'thickness':1,'rgbcolor':'blue','zorder':0,
            ....:     'linestyle':'--'}
            sage: Arc(2,3,2.2,2.2,0,2,3,op).bezier_path()
            Graphics object consisting of 1 graphics primitive

            sage: a = arc((0,0),2,1,0,(pi/5,pi/2+pi/12), linestyle="--", color="red")
            sage: b = a[0].bezier_path()
            sage: b[0]
            Bezier path from (1.133..., 0.8237...) to (-0.2655..., 0.9911...)
        """
        from sage.plot.bezier_path import BezierPath
        from sage.plot.graphics import Graphics
        from matplotlib.path import Path
        import numpy as np
        ma = self._matplotlib_arc()

        def theta_stretch(theta, scale):
            theta = np.deg2rad(theta)
            x = np.cos(theta)
            y = np.sin(theta)
            return np.rad2deg(np.arctan2(scale * y, x))

        theta1 = theta_stretch(ma.theta1, ma.width / ma.height)
        theta2 = theta_stretch(ma.theta2, ma.width / ma.height)

        pa = ma
        pa._path = Path.arc(theta1, theta2)
        transform = pa.get_transform().get_matrix()
        cA, cC, cE = transform[0]
        cB, cD, cF = transform[1]
        points = []
        for u in pa._path.vertices:
            x, y = list(u)
            points += [(cA * x + cC * y + cE, cB * x + cD * y + cF)]
        cutlist = [points[0:4]]
        N = 4
        while N < len(points):
            cutlist += [points[N:N + 3]]
            N += 3
        g = Graphics()
        opt = self.options()
        opt['fill'] = False
        g.add_primitive(BezierPath(cutlist, opt))
        return g
Exemple #12
0
 def plot(self, pointsize=20):
     from sage.plot.graphics import Graphics
     G = Graphics()
     m = len(self._scales)
     for i, (name, scale) in enumerate(zip(self._scale_names,
                                           self._scales)):
         G += list_plot(scale,
                        color=hue(1. * i / m),
                        legend_label=name,
                        pointsize=pointsize)
     return G
    def plot3d(self, depth=None):
        # FIXME: refactor this before publishing
        from sage.plot.graphics import Graphics
        from sage.plot.point import point
        from sage.misc.flatten import flatten
        from sage.plot.plot3d.shapes2 import sphere
        if self._n != 3:
            raise ValueError("Can only 3d plot fans.")
        if depth == None:
            depth = self._depth
        if not self.is_finite() and depth == infinity:
            raise ValueError(
                "For infinite algebras you must specify the depth.")

        colors = dict([(0, 'red'), (1, 'green'), (2, 'blue'), (3, 'cyan')])
        G = Graphics()

        roots = self.d_vectors(depth=depth)
        compatible = []
        while roots:
            x = roots.pop()
            for y in roots:
                if self.compatibility_degree(x, y) == 0:
                    compatible.append((x, y))
        for (u, v) in compatible:
            G += _arc3d((_normalize(vector(u)), _normalize(vector(v))),
                        thickness=0.5,
                        color='black')

        for i in range(3):
            orbit = self.ith_orbit(i, depth=depth)
            for j in orbit:
                G += point(_normalize(vector(orbit[j])),
                           color=colors[i],
                           size=10,
                           zorder=len(G.all))

        if self.is_affine():
            tube_vectors = map(vector, flatten(self.affine_tubes()))
            tube_vectors = map(_normalize, tube_vectors)
            for v in tube_vectors:
                G += point(v, color=colors[3], size=10, zorder=len(G.all))
            G += _arc3d((tube_vectors[0], tube_vectors[1]),
                        thickness=5,
                        color='gray',
                        zorder=0)

        G += sphere((0, 0, 0), opacity=0.1, zorder=0)
        G._extra_kwds['frame'] = False
        G._extra_kwds['aspect_ratio'] = 1
        return G
Exemple #14
0
    def plot_n_matrices_eigenvectors(self, n, side='right', color_index=0, draw_line=False):
        r"""
        INPUT:

        - ``n`` -- integer, length
        - ``side`` -- ``'left'`` or ``'right'``, drawing left or right
          eigenvectors
        - ``color_index`` -- 0 for first letter, -1 for last letter
        - ``draw_line`` -- boolean

        EXAMPLES::

            sage: from slabbe.matrix_cocycle import cocycles
            sage: ARP = cocycles.ARP()
            sage: G = ARP.plot_n_matrices_eigenvectors(2)
        """
        from sage.plot.graphics import Graphics
        from sage.plot.point import point
        from sage.plot.line import line
        from sage.plot.text import text
        from sage.plot.colors import hue
        from sage.modules.free_module_element import vector
        from matrices import M3to2
        R = self.n_matrices_eigenvectors(n)
        L = [(w, M3to2*(a/sum(a)), M3to2*(b/sum(b))) for (w,a,b) in R]
        G = Graphics()
        alphabet = self._language._alphabet
        color_ = dict( (letter, hue(i/float(len(alphabet)))) for i,letter in
                enumerate(alphabet))
        for letter in alphabet:
            L_filtered = [(w,p1,p2) for (w,p1,p2) in L if w[color_index] == letter]
            words,rights,lefts = zip(*L_filtered)
            if side == 'right':
                G += point(rights, color=color_[letter], legend_label=letter)
            elif side == 'left':
                G += point(lefts,  color=color_[letter], legend_label=letter)
            else:
                raise ValueError("side(=%s) should be left or right" % side)

        if draw_line:
            for (a,b) in L:
                G += line([a,b], color='black', linestyle=":")
        G += line([M3to2*vector(a) for a in [(1,0,0), (0,1,0), (0,0,1), (1,0,0)]]) 
        title = "%s eigenvectors, colored by letter w[%s] of cylinder w" % (side, color_index)
        G += text(title, (0.5, 1.05), axis_coords=True)
        G.axes(False)
        return G
Exemple #15
0
    def plot(self, geosub, color=None):
        r"""
        EXAMPLES::

            sage: from EkEkstar import kFace, kPatch, GeoSub
            sage: sub = {1:[1,2], 2:[1,3], 3:[1]}
            sage: geosub = GeoSub(sub,2, dual=True)
            sage: P = kPatch([kFace((0,0,0),(1,2),dual=True),
            ....:             kFace((0,0,1),(1,3),dual=True),
            ....:             kFace((0,1,0),(2,1),dual=True),
            ....:             kFace((0,0,0),(3,1),dual=True)])
            sage: _ = P.plot(geosub)
        """
        G = Graphics()
        for face, m in self:
            G += face._plot(geosub, color)
        G.set_aspect_ratio(1)
        return G
Exemple #16
0
    def plot_n_cylinders(self, n, labels=True):
        r"""
        EXAMPLES::

            sage: from slabbe.matrix_cocycle import cocycles
            sage: C = cocycles.Sorted_ARP()
            sage: G = C.plot_n_cylinders(3)
        """
        from sage.plot.graphics import Graphics
        from sage.plot.polygon import polygon
        from sage.plot.text import text
        from matrices import M3to2
        G = Graphics()
        for w,cyl in self.n_cylinders_iterator(n):
            columns = cyl.columns()
            G += polygon((M3to2*col/col.norm(1) for col in columns), fill=False) 
            if labels:
                sum_cols = sum(columns)
                G += text("{}".format(w), M3to2*sum_cols/sum_cols.norm(1))
        return G
Exemple #17
0
    def plot(self, m, pointsize=100, thickness=3, axes=False):
        r"""
        Return 2d graphics object contained in the primal box [-m,m]^d.

        INPUT:

        - ``pointsize``, integer (default:``100``),
        - ``thickness``, integer (default:``3``),
        - ``axes``, bool (default:``False``),

        EXAMPLES::

            sage: from slabbe import BondPercolationSample
            sage: S = BondPercolationSample(0.5,2)
            sage: S.plot(2)           # optional long

        It works in 3d!!::

            sage: S = BondPercolationSample(0.5,3)
            sage: S.plot(3, pointsize=10, thickness=1)     # optional long
            Graphics3d Object

        """
        s = ""
        s += "\\begin{tikzpicture}\n"
        s += "[inner sep=0pt,thick,\n"
        s += "reddot/.style={fill=red,draw=red,circle,minimum size=5pt}]\n"
        s += "\\clip %s rectangle %s;\n" % ((-m - .4, -m - .4),
                                            (m + .4, m + .4))
        G = Graphics()
        for u in self.cluster_in_box(m + 1):
            G += point(u, color='blue', size=pointsize)
        for (u, v) in self.edges_in_box(m + 1):
            G += line((u, v), thickness=thickness, alpha=0.8)
        G += text("p=%.3f" % self._p, (0.5, 1.03),
                  axis_coords=True,
                  color='black')
        G += circle((0, 0), 0.5, color='red', thickness=thickness)
        if self._dimension == 2:
            G.axes(axes)
        return G
Exemple #18
0
    def bezier_path(self):
        """
        Return ``self`` as a Bezier path.

        This is needed to concatenate arcs, in order to
        create hyperbolic polygons.

        EXAMPLES::

            sage: from sage.plot.arc import Arc
            sage: op = {'alpha':1,'thickness':1,'rgbcolor':'blue','zorder':0,
            ....:     'linestyle':'--'}
            sage: Arc(2,3,2.2,2.2,0,2,3,op).bezier_path()
            Graphics object consisting of 1 graphics primitive

            sage: a = arc((0,0),2,1,0,(pi/5,pi/2+pi/12), linestyle="--", color="red")
            sage: b = a[0].bezier_path()
            sage: b[0]
            Bezier path from (1.618..., 0.5877...) to (-0.5176..., 0.9659...)
        """
        from sage.plot.bezier_path import BezierPath
        from sage.plot.graphics import Graphics
        ma = self._matplotlib_arc()
        transform = ma.get_transform().get_matrix()
        cA, cC, cE = transform[0]
        cB, cD, cF = transform[1]
        points = []
        for u in ma._path.vertices:
            x, y = list(u)
            points += [(cA * x + cC * y + cE, cB * x + cD * y + cF)]
        cutlist = [points[0:4]]
        N = 4
        while N < len(points):
            cutlist += [points[N:N + 3]]
            N += 3
        g = Graphics()
        opt = self.options()
        opt['fill'] = False
        g.add_primitive(BezierPath(cutlist, opt))
        return g
Exemple #19
0
def render_2d(projection, point_opts={}, line_opts={}, polygon_opts={}):
    """
    Return 2d rendering of the projection of a polyhedron into
    2-dimensional ambient space.

    EXAMPLES::

        sage: p1 = Polyhedron(vertices=[[1,1]], rays=[[1,1]])
        sage: q1 = p1.projection()
        sage: p2 = Polyhedron(vertices=[[1,0], [0,1], [0,0]])
        sage: q2 = p2.projection()
        sage: p3 = Polyhedron(vertices=[[1,2]])
        sage: q3 = p3.projection()
        sage: p4 = Polyhedron(vertices=[[2,0]], rays=[[1,-1]], lines=[[1,1]])
        sage: q4 = p4.projection()
        sage: q1.show() + q2.show() + q3.show() + q4.show()
        sage: from sage.geometry.polyhedron.plot import render_2d
        sage: q = render_2d(p1.projection())
        sage: q._objects
        [Point set defined by 1 point(s),
         Arrow from (1.0,1.0) to (2.0,2.0),
         Polygon defined by 3 points]
    """
    if is_Polyhedron(projection):
        projection = Projection(projection)
    from sage.plot.graphics import Graphics
    plt = Graphics()
    if isinstance(point_opts, dict):
        point_opts.setdefault('zorder', 2)
        point_opts.setdefault('pointsize', 10)
        plt += projection.render_points_2d(**point_opts)
    if isinstance(line_opts, dict):
        line_opts.setdefault('zorder', 1)
        plt += projection.render_outline_2d(**line_opts)
    if isinstance(polygon_opts, dict):
        polygon_opts.setdefault('zorder', 0)
        plt += projection.render_fill_2d(**polygon_opts)
    return plt
Exemple #20
0
 def make_chart(self, region=None):
     G = Graphics()
     smin, smax, nmin, nmax = [], [], [], []
     for d in self.chartgens(region):
         x, y = self.get_coords(d)
         G += point2d((x, y), zorder=10)
         smin.append(y)
         smax.append(y)
         nmin.append(x)
         nmax.append(x)
         smin = [
             min(smin),
         ]
         smax = [
             max(smax),
         ]
         nmin = [
             min(nmin),
         ]
         nmax = [
             max(nmax),
         ]
     for l in self.chartlines():
         try:
             pts, lineargs = self.lineinfo[l["line"]]
             x1, y1 = self.get_coords(self.geninfo(int(l["src"])))
             x2, y2 = self.get_coords(self.geninfo(int(l["tar"])))
             G += line2d([(x1, y1), (x2, y2)], **lineargs)
         except:
             print("line not understood:", l)
     off = 0.5
     G.ymin(smin[0] - off)
     G.ymax(smax[0] + off)
     G.xmin(nmin[0] - off)
     G.xmax(nmax[0] + off)
     return G
Exemple #21
0
def circle_image(A, B):
    G = Graphics()
    G += circle((0, 0), 1, color='black', thickness=3)
    G += circle(
        (0, 0), 1.4, color='black', alpha=0
    )  # This adds an invisible framing circle to the plot, which protects the aspect ratio from being skewed.
    from collections import defaultdict
    tmp = defaultdict(int)
    for a in A:
        for j in range(a):
            if gcd(j, a) == 1:
                rational = Rational(j) / Rational(a)
                tmp[(rational.numerator(), rational.denominator())] += 1

    for b in B:
        for j in range(b):
            if gcd(j, b) == 1:
                rational = Rational(j) / Rational(b)
                tmp[(rational.numerator(), rational.denominator())] -= 1
    C = ComplexField()
    color1 = (41 / 255, 95 / 255, 45 / 255)
    color2 = (0 / 255, 0 / 255, 150 / 255)
    for val in tmp:
        if tmp[val] > 0:
            G += text(str(tmp[val]),
                      exp(C(-.2 + 2 * 3.14159 * I * val[0] / val[1])),
                      fontsize=30,
                      axes=False,
                      color=color1)
        if tmp[val] < 0:
            G += text(str(abs(tmp[val])),
                      exp(C(.2 + 2 * 3.14159 * I * val[0] / val[1])),
                      fontsize=30,
                      axes=False,
                      color=color2)
    return G
Exemple #22
0
    def plot(self, edge_labels=False, polygon_labels=False):
        from sage.plot.graphics import Graphics
        surface = self._surface
        polygons = surface.polygons()

        if not polygons.is_finite():
            raise NotImplementedError(
                "no implementation for surface built from infinitely many polygons"
            )

        if self._pos is None:
            self._set_positions()
        if self._edge_labels is None:
            self._set_edge_labels()

        G = Graphics()
        for a in polygons.keys():
            p = polygons[a]
            v = p.vertices(translation=self._pos[a])
            G += p.plot(translation=self._pos[a])

            if edge_labels:
                for i in xrange(p.num_edges()):
                    G += text(str(self._edge_labels[a, i]),
                              (v[i] + v[(i + 1) % p.num_edges()]) / 2,
                              color='black')

        # then we possibly plot the lable inside each polygon
        if len(self._index_set) != 1:
            for a in polygons.keys():
                p = polygons[a]
                if polygon_labels:
                    m = sum(
                        p.vertices(translation=self._pos[a])) / p.num_edges()
                    G += text(str(a), m, color='black')
        return G
Exemple #23
0
def arc(center, r1, r2=None, angle=0.0, sector=(0.0, 2 * pi), **options):
    r"""
    An arc (that is a portion of a circle or an ellipse)

    Type ``arc.options`` to see all options.

    INPUT:

    - ``center`` - 2-tuple of real numbers - position of the center.

    - ``r1``, ``r2`` - positive real numbers - radii of the ellipse. If only ``r1``
      is set, then the two radii are supposed to be equal and this function returns
      an arc of circle.

    - ``angle`` - real number - angle between the horizontal and the axis that
      corresponds to ``r1``.

    - ``sector`` - 2-tuple (default: (0,2*pi))- angles sector in which the arc will
      be drawn.

    OPTIONS:

    - ``alpha`` - float (default: 1) - transparency

    - ``thickness`` - float (default: 1) - thickness of the arc

    - ``color``, ``rgbcolor`` - string or 2-tuple (default: 'blue') - the color
      of the arc

    - ``linestyle`` - string (default: ``'solid'``) - The style of the line,
      which is one of ``'dashed'``, ``'dotted'``, ``'solid'``, ``'dashdot'``,
      or ``'--'``, ``':'``, ``'-'``, ``'-.'``, respectively.

    EXAMPLES:

    Plot an arc of circle centered at (0,0) with radius 1 in the sector
    `(\pi/4,3*\pi/4)`::

        sage: arc((0,0), 1, sector=(pi/4,3*pi/4))
        Graphics object consisting of 1 graphics primitive

    Plot an arc of an ellipse between the angles 0 and `\pi/2`::

        sage: arc((2,3), 2, 1, sector=(0,pi/2))
        Graphics object consisting of 1 graphics primitive

    Plot an arc of a rotated ellipse between the angles 0 and `\pi/2`::

        sage: arc((2,3), 2, 1, angle=pi/5, sector=(0,pi/2))
        Graphics object consisting of 1 graphics primitive

    Plot an arc of an ellipse in red with a dashed linestyle::

        sage: arc((0,0), 2, 1, 0, (0,pi/2), linestyle="dashed", color="red")
        Graphics object consisting of 1 graphics primitive
        sage: arc((0,0), 2, 1, 0, (0,pi/2), linestyle="--", color="red")
        Graphics object consisting of 1 graphics primitive

    The default aspect ratio for arcs is 1.0::

        sage: arc((0,0), 1, sector=(pi/4,3*pi/4)).aspect_ratio()
        1.0

    It is not possible to draw arcs in 3D::

        sage: A = arc((0,0,0), 1)
        Traceback (most recent call last):
        ...
        NotImplementedError
    """
    from sage.plot.all import Graphics

    # Reset aspect_ratio to 'automatic' in case scale is 'semilog[xy]'.
    # Otherwise matplotlib complains.
    scale = options.get('scale', None)
    if isinstance(scale, (list, tuple)):
        scale = scale[0]
    if scale == 'semilogy' or scale == 'semilogx':
        options['aspect_ratio'] = 'automatic'

    if len(center) == 2:
        if r2 is None:
            r2 = r1
        g = Graphics()
        g._set_extra_kwds(Graphics._extract_kwds_for_show(options))
        if len(sector) != 2:
            raise ValueError("the sector must consist of two angles")
        g.add_primitive(
            Arc(center[0], center[1], r1, r2, angle, sector[0], sector[1],
                options))
        return g
    elif len(center) == 3:
        raise NotImplementedError
Exemple #24
0
    def plot(self, color='sign'):
        """
        Return a plot of ``self``.

        INPUT:

        - ``color`` -- can be any of the following:

          * ``4`` - use 4 colors: black, red, blue, and green with each
            corresponding to up, right, down, and left respectively
          * ``2`` - use 2 colors: red for horizontal, blue for vertical arrows
          * ``'sign'`` - use red for right and down arrows, blue for left
            and up arrows
          * a list of 4 colors for each direction
          * a function which takes a direction and a boolean corresponding
            to the sign

        EXAMPLES::

            sage: M = SixVertexModel(2, boundary_conditions='ice')
            sage: print(M[0].plot().description())
            Arrow from (-1.0,0.0) to (0.0,0.0)
            Arrow from (-1.0,1.0) to (0.0,1.0)
            Arrow from (0.0,0.0) to (0.0,-1.0)
            Arrow from (0.0,0.0) to (1.0,0.0)
            Arrow from (0.0,1.0) to (0.0,0.0)
            Arrow from (0.0,1.0) to (0.0,2.0)
            Arrow from (1.0,0.0) to (1.0,-1.0)
            Arrow from (1.0,0.0) to (1.0,1.0)
            Arrow from (1.0,1.0) to (0.0,1.0)
            Arrow from (1.0,1.0) to (1.0,2.0)
            Arrow from (2.0,0.0) to (1.0,0.0)
            Arrow from (2.0,1.0) to (1.0,1.0)
        """
        from sage.plot.graphics import Graphics
        from sage.plot.arrow import arrow

        if color == 4:
            color_list = ['black', 'red', 'blue', 'green']
            cfunc = lambda d,pm: color_list[d]
        elif color == 2:
            cfunc = lambda d,pm: 'red' if d % 2 == 0 else 'blue'
        elif color == 1 or color is None:
            cfunc = lambda d,pm: 'black'
        elif color == 'sign':
            cfunc = lambda d,pm: 'red' if pm else 'blue' # RD are True
        elif isinstance(color, (list, tuple)):
            cfunc = lambda d,pm: color[d]
        else:
            cfunc = color

        G = Graphics()
        for j,row in enumerate(reversed(self)):
            for i,entry in enumerate(row):
                if entry == 0: # LR
                    G += arrow((i,j+1), (i,j), color=cfunc(2, True))
                    G += arrow((i,j), (i+1,j), color=cfunc(1, True))
                    if j == 0:
                        G += arrow((i,j-1), (i,j), color=cfunc(0, False))
                    if i == 0:
                        G += arrow((i,j), (i-1,j), color=cfunc(3, False))
                elif entry == 1: # LU
                    G += arrow((i,j), (i,j+1), color=cfunc(0, False))
                    G += arrow((i+1,j), (i,j), color=cfunc(3, False))
                    if j == 0:
                        G += arrow((i,j-1), (i,j), color=cfunc(0, False))
                    if i == 0:
                        G += arrow((i,j), (i-1,j), color=cfunc(3, False))
                elif entry == 2: # LD
                    G += arrow((i,j+1), (i,j), color=cfunc(2, True))
                    G += arrow((i+1,j), (i,j), color=cfunc(3, False))
                    if j == 0:
                        G += arrow((i,j), (i,j-1), color=cfunc(2, True))
                    if i == 0:
                        G += arrow((i,j), (i-1,j), color=cfunc(3, False))
                elif entry == 3: # UD
                    G += arrow((i,j), (i,j+1), color=cfunc(0, False))
                    G += arrow((i+1,j), (i,j), color=cfunc(3, False))
                    if j == 0:
                        G += arrow((i,j), (i,j-1), color=cfunc(2, True))
                    if i == 0:
                        G += arrow((i-1,j), (i,j), color=cfunc(1, True))
                elif entry == 4: # UR
                    G += arrow((i,j), (i,j+1), color=cfunc(0, False))
                    G += arrow((i,j), (i+1,j), color=cfunc(1, True))
                    if j == 0:
                        G += arrow((i,j-1), (i,j), color=cfunc(0, False))
                    if i == 0:
                        G += arrow((i-1,j), (i,j), color=cfunc(1, True))
                elif entry == 5: # RD
                    G += arrow((i,j+1), (i,j), color=cfunc(2, True))
                    G += arrow((i,j), (i+1,j), color=cfunc(1, True))
                    if j == 0:
                        G += arrow((i,j), (i,j-1), color=cfunc(2, True))
                    if i == 0:
                        G += arrow((i-1,j), (i,j), color=cfunc(1, True))
        G.axes(False)
        return G
Exemple #25
0
    def _graphics(self, plot_curve, ambient_coords, thickness=1,
                  aspect_ratio='automatic', color='red', style='-',
                  label_axes=True):
        r"""
        Plot a 2D or 3D curve in a Cartesian graph with axes labeled by
        the ambient coordinates; it is invoked by the methods
        :meth:`plot` of
        :class:`~sage.manifolds.differentiable.curve.DifferentiableCurve`,
        and its subclasses
        (:class:`~sage.manifolds.differentiable.integrated_curve.IntegratedCurve`,
        :class:`~sage.manifolds.differentiable.integrated_curve.IntegratedAutoparallelCurve`,
        and
        :class:`~sage.manifolds.differentiable.integrated_curve.IntegratedGeodesic`).

        TESTS::

            sage: M = Manifold(2, 'R^2')
            sage: X.<x,y> = M.chart()
            sage: R.<t> = RealLine()
            sage: c = M.curve([cos(t), sin(t)], (t, 0, 2*pi), name='c')
            sage: graph = c._graphics([[1,2], [3,4]], [x,y])
            sage: graph._objects[0].xdata == [1,3]
            True
            sage: graph._objects[0].ydata == [2,4]
            True
            sage: graph._objects[0]._options['thickness'] == 1
            True
            sage: graph._extra_kwds['aspect_ratio'] == 'automatic'
            True
            sage: graph._objects[0]._options['rgbcolor'] == 'red'
            True
            sage: graph._objects[0]._options['linestyle'] == '-'
            True
            sage: l = [r'$'+latex(x)+r'$', r'$'+latex(y)+r'$']
            sage: graph._extra_kwds['axes_labels'] == l
            True

        """
        from sage.plot.graphics import Graphics
        from sage.plot.line import line
        from sage.manifolds.utilities import set_axes_labels

        #
        # The plot
        #
        n_pc = len(ambient_coords)
        resu = Graphics()
        resu += line(plot_curve, color=color, linestyle=style,
                     thickness=thickness)
        if n_pc == 2:  # 2D graphic
            resu.set_aspect_ratio(aspect_ratio)
            if label_axes:
                # We update the dictionary _extra_kwds (options to be passed
                # to show()), instead of using the method
                # Graphics.axes_labels() since the latter is not robust w.r.t.
                # graph addition
                resu._extra_kwds['axes_labels'] = [r'$'+latex(pc)+r'$'
                                                   for pc in ambient_coords]
        else: # 3D graphic
            if aspect_ratio == 'automatic':
                aspect_ratio = 1
            resu.aspect_ratio(aspect_ratio)
            if label_axes:
                labels = [str(pc) for pc in ambient_coords]
                resu = set_axes_labels(resu, *labels)
        return resu
Exemple #26
0
    def plot(self,
             chart=None,
             ambient_coords=None,
             mapping=None,
             chart_domain=None,
             fixed_coords=None,
             ranges=None,
             max_value=8,
             nb_values=None,
             steps=None,
             scale=1,
             color='blue',
             parameters=None,
             label_axes=True,
             **extra_options):
        r"""
        Plot the vector field in a Cartesian graph based on the coordinates
        of some ambient chart.

        The vector field is drawn in terms of two (2D graphics) or three
        (3D graphics) coordinates of a given chart, called hereafter the
        *ambient chart*.
        The vector field's base points `p` (or their images `\Phi(p)` by some
        differentiable mapping `\Phi`) must lie in the ambient chart's domain.

        INPUT:

        - ``chart`` -- (default: ``None``) the ambient chart (see above); if
          ``None``, the default chart of the vector field's domain is used
        - ``ambient_coords`` -- (default: ``None``) tuple containing the 2 or 3
          coordinates of the ambient chart in terms of which the plot is
          performed; if ``None``, all the coordinates of the ambient chart are
          considered
        - ``mapping`` -- (default: ``None``) differentiable mapping `\Phi`
          (instance of
          :class:`~sage.geometry.manifolds.diffmapping.DiffMapping`)
          providing the link between the vector field's domain and
          the ambient chart ``chart``; if ``None``, the identity mapping is
          assumed
        - ``chart_domain`` -- (default: ``None``) chart on the vector
          field's domain to define the points at which vector arrows are to be
          plotted; if ``None``, the default chart of the vector field's domain
          is used
        - ``fixed_coords`` -- (default: ``None``) dictionary with keys the
          coordinates of ``chart_domain`` that are kept fixed and with values
          the value of these coordinates; if ``None``, all the coordinates of
          ``chart_domain`` are used
        - ``ranges`` -- (default: ``None``) dictionary with keys the
          coordinates of ``chart_domain`` to be used and values
          tuples ``(x_min,x_max)`` specifying the
          coordinate range for the plot; if ``None``, the entire coordinate
          range declared during the construction of ``chart_domain`` is
          considered (with ``-Infinity`` replaced by ``-max_value`` and
          ``+Infinity`` by ``max_value``)
        - ``max_value`` -- (default: 8) numerical value substituted to
          ``+Infinity`` if the latter is the upper bound of the range of a
          coordinate for which the plot is performed over the entire coordinate
          range (i.e. for which no specific plot range has been set in
          ``ranges``); similarly ``-max_value`` is the numerical valued
          substituted for ``-Infinity``
        - ``nb_values`` -- (default: ``None``) either an integer or a dictionary
          with keys the coordinates of ``chart_domain`` to be used and values
          the number of values of the coordinate for sampling
          the part of the vector field's domain involved in the plot ; if
          ``nb_values`` is a single integer, it represents the number of
          values for all coordinates; if ``nb_values`` is ``None``, it is set
          to 9 for a 2D plot and to 5 for a 3D plot
        - ``steps`` -- (default: ``None``) dictionary with keys the coordinates
          of ``chart_domain`` to be used and values the step between each
          constant value of the coordinate; if ``None``, the step is computed
          from the coordinate range (specified in ``ranges``) and ``nb_values``.
          On the contrary, if the step is provided for some coordinate, the
          corresponding number of values is deduced from it and the coordinate
          range.
        - ``scale`` -- (default: 1) value by which the lengths of the arrows
          representing the vectors is multiplied
        - ``color`` -- (default: 'blue') color of the arrows representing the
          vectors
        - ``parameters`` -- (default: ``None``) dictionary giving the numerical
          values of the parameters that may appear in the coordinate expression
          of the vector field (see example below)
        - ``label_axes`` -- (default: ``True``) boolean determining whether the
          labels of the coordinate axes of ``chart`` shall be added to the
          graph; can be set to ``False`` if the graph is 3D and must be
          superposed with another graph.
        - ``**extra_options`` -- extra options for the arrow plot, like
          ``linestyle``, ``width`` or ``arrowsize`` (see
          :func:`~sage.plot.arrow.arrow2d` and
          :func:`~sage.plot.plot3d.shapes.arrow3d` for details)

        OUTPUT:

        - a graphic object, either an instance of
          :class:`~sage.plot.graphics.Graphics` for a 2D plot (i.e. based on
          2 coordinates of ``chart``) or an instance of
          :class:`~sage.plot.plot3d.base.Graphics3d` for a 3D plot (i.e.
          based on 3 coordinates of ``chart``)

        EXAMPLES:

        Plot of a vector field on a 2-dimensional manifold::

            sage: Manifold._clear_cache_() # for doctests only
            sage: M = Manifold(2, 'M')
            sage: X.<x,y> = M.chart()
            sage: v = M.vector_field(name='v')
            sage: v[:] = -y, x ; v.display()
            v = -y d/dx + x d/dy
            sage: v.plot()
            Graphics object consisting of 80 graphics primitives

        Plot with various options::

            sage: v.plot(scale=0.5, color='green', linestyle='--', width=1, arrowsize=6)
            Graphics object consisting of 80 graphics primitives
            sage: v.plot(max_value=4, nb_values=5, scale=0.5)
            Graphics object consisting of 24 graphics primitives

        Plots along a line of fixed coordinate::

            sage: v.plot(fixed_coords={x: -2})
            Graphics object consisting of 9 graphics primitives
            sage: v.plot(fixed_coords={y: 1})
            Graphics object consisting of 9 graphics primitives

        Let us now consider a vector field on a 4-dimensional manifold::

            sage: Manifold._clear_cache_() # for doctests only
            sage: M = Manifold(4, 'M')
            sage: X.<t,x,y,z> = M.chart()
            sage: v = M.vector_field(name='v')
            sage: v[:] = (t/8)^2, -t*y/4, t*x/4, t*z/4 ; v.display()
            v = 1/64*t^2 d/dt - 1/4*t*y d/dx + 1/4*t*x d/dy + 1/4*t*z d/dz

        We cannot make a 4D plot directly::

            sage: v.plot()
            Traceback (most recent call last):
            ...
            ValueError: the number of ambient coordinates must be either 2 or 3, not 4

        Rather, we have to select some coordinates for the plot, via
        the argument ``ambient_coords``. For instance, for a 3D plot::

            sage: v.plot(ambient_coords=(x, y, z), fixed_coords={t: 1})
            Graphics3d Object
            sage: v.plot(ambient_coords=(x, y, t), fixed_coords={z: 0},
            ....:        ranges={x: (-2,2), y: (-2,2), t: (-1, 4)}, nb_values=4)
            Graphics3d Object

        or, for a 2D plot::

            sage: v.plot(ambient_coords=(x, y), fixed_coords={t: 1, z: 0})
            Graphics object consisting of 80 graphics primitives
            sage: v.plot(ambient_coords=(x, t), fixed_coords={y: 1, z: 0})
            Graphics object consisting of 72 graphics primitives

        An example of plot via a differential mapping: plot of a vector field
        tangent to a 2-sphere viewed in `\RR^3`::

            sage: S2 = Manifold(2, 'S^2')
            sage: U = S2.open_subset('U') # the open set covered by spherical coord.
            sage: XS.<th,ph> = U.chart(r'th:(0,pi):\theta ph:(0,2*pi):\phi')
            sage: R3 = Manifold(3, 'R^3')
            sage: X3.<x,y,z> = R3.chart()
            sage: F = S2.diff_mapping(R3, {(XS, X3): [sin(th)*cos(ph),
            ....:                     sin(th)*sin(ph), cos(th)]}, name='F')
            sage: F.display() # the standard embedding of S^2 into R^3
            F: S^2 --> R^3
            on U: (th, ph) |--> (x, y, z) = (cos(ph)*sin(th), sin(ph)*sin(th), cos(th))
            sage: v = XS.frame()[1] ; v
            vector field 'd/dph' on the open subset 'U' of the 2-dimensional manifold 'S^2'
            sage: graph_v = v.plot(chart=X3, mapping=F, label_axes=False)
            sage: graph_S2 = XS.plot(chart=X3, mapping=F, nb_values=9)
            sage: show(graph_v + graph_S2)

        """
        from sage.rings.infinity import Infinity
        from sage.misc.functional import numerical_approx
        from sage.misc.latex import latex
        from sage.plot.graphics import Graphics
        from sage.geometry.manifolds.chart import Chart
        from sage.geometry.manifolds.utilities import set_axes_labels
        #
        # 1/ Treatment of input parameters
        #    -----------------------------
        if chart is None:
            chart = self._domain.default_chart()
        elif not isinstance(chart, Chart):
            raise TypeError("{} is not a chart".format(chart))
        if chart_domain is None:
            chart_domain = self._domain.default_chart()
        elif not isinstance(chart_domain, Chart):
            raise TypeError("{} is not a chart".format(chart_domain))
        elif not chart_domain.domain().is_subset(self._domain):
            raise ValueError("The domain of {} is not ".format(chart_domain) +
                             "included in the domain of {}".format(self))
        if fixed_coords is None:
            coords = chart_domain._xx
        else:
            fixed_coord_list = fixed_coords.keys()
            coords = []
            for coord in chart_domain._xx:
                if coord not in fixed_coord_list:
                    coords.append(coord)
            coords = tuple(coords)
        if ambient_coords is None:
            ambient_coords = chart[:]
        elif not isinstance(ambient_coords, tuple):
            ambient_coords = tuple(ambient_coords)
        nca = len(ambient_coords)
        if nca != 2 and nca != 3:
            raise ValueError("the number of ambient coordinates must be " +
                             "either 2 or 3, not {}".format(nca))
        if ranges is None:
            ranges = {}
        ranges0 = {}
        for coord in coords:
            if coord in ranges:
                ranges0[coord] = (numerical_approx(ranges[coord][0]),
                                  numerical_approx(ranges[coord][1]))
            else:
                bounds = chart_domain._bounds[chart_domain[:].index(coord)]
                if bounds[0][0] == -Infinity:
                    xmin = numerical_approx(-max_value)
                elif bounds[0][1]:
                    xmin = numerical_approx(bounds[0][0])
                else:
                    xmin = numerical_approx(bounds[0][0] + 1.e-3)
                if bounds[1][0] == Infinity:
                    xmax = numerical_approx(max_value)
                elif bounds[1][1]:
                    xmax = numerical_approx(bounds[1][0])
                else:
                    xmax = numerical_approx(bounds[1][0] - 1.e-3)
                ranges0[coord] = (xmin, xmax)
        ranges = ranges0
        if nb_values is None:
            if nca == 2:  # 2D plot
                nb_values = 9
            else:  # 3D plot
                nb_values = 5
        if not isinstance(nb_values, dict):
            nb_values0 = {}
            for coord in coords:
                nb_values0[coord] = nb_values
            nb_values = nb_values0
        if steps is None:
            steps = {}
        for coord in coords:
            if coord not in steps:
                steps[coord] = (ranges[coord][1] - ranges[coord][0])/ \
                               (nb_values[coord]-1)
            else:
                nb_values[coord] = 1 + int(
                    (ranges[coord][1] - ranges[coord][0]) / steps[coord])
        #
        # 2/ Plots
        #    -----
        dom = chart_domain.domain()
        nc = len(chart_domain[:])
        ncp = len(coords)
        xx = [0] * nc
        if fixed_coords is not None:
            if len(fixed_coords) != nc - ncp:
                raise ValueError("Bad number of fixed coordinates.")
            for fc, val in fixed_coords.iteritems():
                xx[chart_domain[:].index(fc)] = val
        index_p = [chart_domain[:].index(cd) for cd in coords]
        resu = Graphics()
        ind = [0] * ncp
        ind_max = [0] * ncp
        ind_max[0] = nb_values[coords[0]]
        xmin = [ranges[cd][0] for cd in coords]
        step_tab = [steps[cd] for cd in coords]
        while ind != ind_max:
            for i in range(ncp):
                xx[index_p[i]] = xmin[i] + ind[i] * step_tab[i]
            if chart_domain.valid_coordinates(*xx,
                                              tolerance=1e-13,
                                              parameters=parameters):
                point = dom(xx, chart=chart_domain)
                resu += self.at(point).plot(chart=chart,
                                            ambient_coords=ambient_coords,
                                            mapping=mapping,
                                            scale=scale,
                                            color=color,
                                            print_label=False,
                                            parameters=parameters,
                                            **extra_options)
            # Next index:
            ret = 1
            for pos in range(ncp - 1, -1, -1):
                imax = nb_values[coords[pos]] - 1
                if ind[pos] != imax:
                    ind[pos] += ret
                    ret = 0
                elif ret == 1:
                    if pos == 0:
                        ind[pos] = imax + 1  # end point reached
                    else:
                        ind[pos] = 0
                        ret = 1
        if label_axes:
            if nca == 2:  # 2D graphic
                # We update the dictionary _extra_kwds (options to be passed
                # to show()), instead of using the method
                # Graphics.axes_labels() since the latter is not robust w.r.t.
                # graph addition
                resu._extra_kwds['axes_labels'] = [
                    r'$' + latex(ac) + r'$' for ac in ambient_coords
                ]
            else:  # 3D graphic
                labels = [str(ac) for ac in ambient_coords]
                resu = set_axes_labels(resu, *labels)
        return resu
Exemple #27
0
    def plot(self):
        r"""
        Return a graphical object of the Fully Packed Loop

        EXAMPLES:

        Here is the fully packed loop for

        .. MATH::

            \begin{pmatrix} 0&1&1 \\ 1&-1&1 \\ 0&1&0 \end{pmatrix}:

        .. PLOT::
            :width: 200 px

            A = AlternatingSignMatrix([[0, 1, 0], [1, -1, 1], [0, 1, 0]])
            fpl = FullyPackedLoop(A)
            p = fpl.plot()
            sphinx_plot(p)

        Here is how Sage represents this::

            sage: A = AlternatingSignMatrix([[0, 1, 0], [1, -1, 1], [0, 1, 0]])
            sage: fpl = FullyPackedLoop(A)
            sage: print(fpl.plot().description())
            Line defined by 2 points:       [(-1.0, 1.0), (0.0, 1.0)]
            Line defined by 2 points:       [(0.0, 0.0), (0.0, -1.0)]
            Line defined by 2 points:       [(0.0, 0.0), (1.0, 0.0)]
            Line defined by 2 points:       [(0.0, 2.0), (0.0, 3.0)]
            Line defined by 2 points:       [(0.0, 2.0), (0.0, 3.0)]
            Line defined by 2 points:       [(0.0, 2.0), (1.0, 2.0)]
            Line defined by 2 points:       [(1.0, 1.0), (0.0, 1.0)]
            Line defined by 2 points:       [(1.0, 1.0), (2.0, 1.0)]
            Line defined by 2 points:       [(2.0, 0.0), (1.0, 0.0)]
            Line defined by 2 points:       [(2.0, 0.0), (2.0, -1.0)]
            Line defined by 2 points:       [(2.0, 2.0), (1.0, 2.0)]
            Line defined by 2 points:       [(2.0, 2.0), (2.0, 3.0)]
            Line defined by 2 points:       [(2.0, 2.0), (2.0, 3.0)]
            Line defined by 2 points:       [(3.0, 1.0), (2.0, 1.0)]
            Line defined by 2 points:       [(3.0, 1.0), (2.0, 1.0)]

        Here are the other 3 by 3 Alternating Sign Matrices and their corresponding
        fully packed loops:

        .. MATH::

            A = \begin{pmatrix} 1&0&0 \\ 0&1&0 \\ 0&0&1 \\ \end{pmatrix}

        gives:

        .. PLOT::
            :width: 200 px

            A = AlternatingSignMatrix([[1, 0, 0], [0, 1, 0], [0, 0, 1]])
            fpl = FullyPackedLoop(A)
            p = fpl.plot()
            sphinx_plot(p)

        .. MATH::

            A = \begin{pmatrix} 1&0&0 \\ 0&0&1 \\ 0&1&0 \\ \end{pmatrix}

        gives:

        .. PLOT::
            :width: 200 px

            A = AlternatingSignMatrix([[1, 0, 0], [0, 0, 1], [0, 1, 0]])
            fpl = FullyPackedLoop(A)
            p = fpl.plot()
            sphinx_plot(p)

        .. MATH::

            A = \begin{pmatrix} 0&1&0\\ 1&0&0\\ 0&0&1\\ \end{pmatrix}

        gives:

        .. PLOT::
            :width: 200 px

            A = AlternatingSignMatrix([[0, 1, 0], [1, 0, 0], [0, 0, 1]])
            fpl = FullyPackedLoop(A)
            p = fpl.plot()
            sphinx_plot(p)

        .. MATH::

            A = \begin{pmatrix} 0&1&0\\ 0&0&1\\ 1&0&0\\ \end{pmatrix}

        gives:

        .. PLOT::
            :width: 200 px

            A = AlternatingSignMatrix([[0, 1, 0], [0, 0, 1], [1, 0, 0]])
            fpl = FullyPackedLoop(A)
            p = fpl.plot()
            sphinx_plot(p)

        .. MATH::

            A = \begin{pmatrix} 0&0&1\\ 1&0&0\\ 0&1&0\\ \end{pmatrix}

        gives:

        .. PLOT::
            :width: 200 px

            A = AlternatingSignMatrix([[0, 0, 1], [1, 0, 0], [0, 1, 0]])
            fpl = FullyPackedLoop(A)
            p = fpl.plot()
            sphinx_plot(p)

        .. MATH::

            A = \begin{pmatrix} 0&0&1\\ 0&1&0\\ 1&0&0\\ \end{pmatrix}

        gives:

        .. PLOT::
            :width: 200 px

            A = AlternatingSignMatrix([[0, 0, 1], [0, 1, 0], [1, 0, 0]])
            fpl = FullyPackedLoop(A)
            p = fpl.plot()
            sphinx_plot(p)

        EXAMPLES::

            sage: A = AlternatingSignMatrix([[0, 1, 0, 0], [1, -1, 0, 1], \
            [0, 1, 0, 0],[0, 0, 1, 0]])
            sage: fpl = FullyPackedLoop(A)
            sage: print(fpl.plot().description())
            Line defined by 2 points:       [(-1.0, 0.0), (0.0, 0.0)]
            Line defined by 2 points:       [(-1.0, 2.0), (0.0, 2.0)]
            Line defined by 2 points:       [(0.0, 1.0), (0.0, 0.0)]
            Line defined by 2 points:       [(0.0, 1.0), (1.0, 1.0)]
            Line defined by 2 points:       [(0.0, 3.0), (0.0, 4.0)]
            Line defined by 2 points:       [(0.0, 3.0), (0.0, 4.0)]
            Line defined by 2 points:       [(0.0, 3.0), (1.0, 3.0)]
            Line defined by 2 points:       [(1.0, 0.0), (1.0, -1.0)]
            Line defined by 2 points:       [(1.0, 0.0), (2.0, 0.0)]
            Line defined by 2 points:       [(1.0, 2.0), (0.0, 2.0)]
            Line defined by 2 points:       [(1.0, 2.0), (2.0, 2.0)]
            Line defined by 2 points:       [(2.0, 1.0), (1.0, 1.0)]
            Line defined by 2 points:       [(2.0, 1.0), (2.0, 2.0)]
            Line defined by 2 points:       [(2.0, 3.0), (1.0, 3.0)]
            Line defined by 2 points:       [(2.0, 3.0), (2.0, 4.0)]
            Line defined by 2 points:       [(2.0, 3.0), (2.0, 4.0)]
            Line defined by 2 points:       [(3.0, 0.0), (2.0, 0.0)]
            Line defined by 2 points:       [(3.0, 0.0), (3.0, -1.0)]
            Line defined by 2 points:       [(3.0, 2.0), (3.0, 1.0)]
            Line defined by 2 points:       [(3.0, 2.0), (3.0, 3.0)]
            Line defined by 2 points:       [(4.0, 1.0), (3.0, 1.0)]
            Line defined by 2 points:       [(4.0, 1.0), (3.0, 1.0)]
            Line defined by 2 points:       [(4.0, 3.0), (3.0, 3.0)]
            Line defined by 2 points:       [(4.0, 3.0), (3.0, 3.0)]

        Here is the plot:

        .. PLOT::
            :width: 300 px

            A = AlternatingSignMatrix([[0, 1, 0, 0], [1, -1, 0, 1], [0, 1, 0, 0],[0, 0, 1, 0]])
            fpl = FullyPackedLoop(A)
            p = fpl.plot()
            sphinx_plot(p)

        """
        G = Graphics()
        n=len(self._six_vertex_model)-1
        for j,row in enumerate(reversed(self._six_vertex_model)):
            for i,entry in enumerate(row):
                if i == 0 and (i+j+n+1) % 2 ==0:
                    G+= line([(i-1,j),(i,j)])
                if i == n and (i+j+n+1) % 2 ==0:
                    G+= line([(i+1,j),(i,j)])
                if j == 0 and (i+j+n) % 2 ==0:
                    G+= line([(i,j),(i,j-1)])
                if j == n and (i+j+n) % 2 ==0:
                    G+= line([(i,j),(i,j+1)])
                if entry == 0: # LR
                    if (i+j+n) % 2==0:
                        G += line([(i,j), (i+1,j)])
                    else:
                        G += line([(i,j),(i,j+1)])
                elif entry == 1: # LU
                    if (i+j+n) % 2 ==0:
                        G += line([(i,j), (i,j+1)])
                    else:
                        G += line([(i+1,j), (i,j)])
                elif entry == 2: # LD
                    if (i+j+n) % 2 == 0:
                        pass
                    else:
                        G += line([(i,j+1), (i,j)])
                        G += line([(i+1,j), (i,j)])
                elif entry == 3: # UD
                    if (i+j+n) % 2 == 0:
                        G += line([(i,j), (i,j+1)])
                    else:
                        G += line([(i+1,j), (i,j)])
                elif entry == 4: # UR
                    if (i+j+n) % 2 ==0:
                        G += line([(i,j), (i,j+1)])
                        G += line([(i,j), (i+1,j)])
                    else:
                        pass
                elif entry == 5: # RD
                    if (i+j+n) % 2 ==0:
                        G += line([(i,j), (i+1,j)])
                    else:
                        G += line([(i,j+1), (i,j)])
        G.axes(False)
        return G
Exemple #28
0
    def plot(self,
             chart=None,
             ambient_coords=None,
             mapping=None,
             prange=None,
             include_end_point=(True, True),
             end_point_offset=(0.001, 0.001),
             parameters=None,
             color='red',
             style='-',
             label_axes=True,
             **kwds):
        r"""
        Plot the current curve in a Cartesian graph based on the
        coordinates of some ambient chart.

        The curve is drawn in terms of two (2D graphics) or three (3D graphics)
        coordinates of a given chart, called hereafter the *ambient chart*.
        The ambient chart's domain must overlap with the curve's codomain or
        with the codomain of the composite curve `\Phi\circ c`, where `c` is
        the current curve and `\Phi` some manifold differential map (argument
        ``mapping`` below).

        INPUT:

        - ``chart`` -- (default: ``None``) the ambient chart (see above);
          if ``None``, the default chart of the codomain of the curve (or of
          the curve composed with `\Phi`) is used

        - ``ambient_coords`` -- (default: ``None``) tuple containing the 2
          or 3 coordinates of the ambient chart in terms of which the plot
          is performed; if ``None``, all the coordinates of the ambient chart
          are considered

        - ``mapping`` -- (default: ``None``) differentiable mapping `\Phi`
          (instance of
          :class:`~sage.manifolds.differentiable.diff_map.DiffMap`)
          providing the link between the curve and the ambient chart ``chart``
          (cf. above); if ``None``, the ambient chart is supposed to be defined
          on the codomain of the curve.

        - ``prange`` -- (default: ``None``) range of the curve parameter for
          the plot; if ``None``, the entire parameter range declared during the
          curve construction is considered (with -Infinity
          replaced by ``-max_range`` and +Infinity by ``max_range``)

        - ``include_end_point`` -- (default: ``(True, True)``) determines
          whether the end points of ``prange`` are included in the plot

        - ``end_point_offset`` -- (default: ``(0.001, 0.001)``) offsets from
          the end points when they are not included in the plot: if
          ``include_end_point[0] == False``, the minimal value of the curve
          parameter used for the plot is ``prange[0] + end_point_offset[0]``,
          while if ``include_end_point[1] == False``, the maximal value is
          ``prange[1] - end_point_offset[1]``.

        - ``max_range`` -- (default: 8) numerical value substituted to
          +Infinity if the latter is the upper bound of the parameter range;
          similarly ``-max_range`` is the numerical valued substituted for
          -Infinity

        - ``parameters`` -- (default: ``None``) dictionary giving the numerical
          values of the parameters that may appear in the coordinate expression
          of the curve

        - ``color`` -- (default: 'red') color of the drawn curve

        - ``style`` -- (default: '-') color of the drawn curve; NB: ``style``
          is effective only for 2D plots

        - ``thickness`` -- (default: 1) thickness of the drawn curve

        - ``plot_points`` -- (default: 75) number of points to plot the curve

        - ``label_axes`` -- (default: ``True``) boolean determining whether the
          labels of the coordinate axes of ``chart`` shall be added to the
          graph; can be set to ``False`` if the graph is 3D and must be
          superposed with another graph.

        - ``aspect_ratio`` -- (default: ``'automatic'``) aspect ratio of the
          plot; the default value (``'automatic'``) applies only for 2D plots;
          for 3D plots, the default value is ``1`` instead

        OUTPUT:

        - a graphic object, either an instance of
          :class:`~sage.plot.graphics.Graphics` for a 2D plot (i.e. based on
          2 coordinates of ``chart``) or an instance of
          :class:`~sage.plot.plot3d.base.Graphics3d` for a 3D plot (i.e.
          based on 3 coordinates of ``chart``)

        EXAMPLES:

        Plot of the lemniscate of Gerono::

            sage: R2 = Manifold(2, 'R^2')
            sage: X.<x,y> = R2.chart()
            sage: R.<t> = RealLine()
            sage: c = R2.curve([sin(t), sin(2*t)/2], (t, 0, 2*pi), name='c')
            sage: c.plot()  # 2D plot
            Graphics object consisting of 1 graphics primitive

        .. PLOT::

            R2 = Manifold(2, 'R^2')
            X = R2.chart('x y')
            t = RealLine().canonical_coordinate()
            c = R2.curve([sin(t), sin(2*t)/2], (t, 0, 2*pi), name='c')
            g = c.plot()
            sphinx_plot(g)

        Plot for a subinterval of the curve's domain::

            sage: c.plot(prange=(0,pi))
            Graphics object consisting of 1 graphics primitive

        .. PLOT::

            R2 = Manifold(2, 'R^2')
            X = R2.chart('x y')
            t = RealLine().canonical_coordinate()
            c = R2.curve([sin(t), sin(2*t)/2], (t, 0, 2*pi), name='c')
            g = c.plot(prange=(0,pi))
            sphinx_plot(g)

        Plot with various options::

            sage: c.plot(color='green', style=':', thickness=3, aspect_ratio=1)
            Graphics object consisting of 1 graphics primitive

        .. PLOT::

            R2 = Manifold(2, 'R^2')
            X = R2.chart('x y')
            t = RealLine().canonical_coordinate()
            c = R2.curve([sin(t), sin(2*t)/2], (t, 0, 2*pi), name='c')
            g = c.plot(color='green', style=':', thickness=3, aspect_ratio=1)
            sphinx_plot(g)

        Plot via a mapping to another manifold: loxodrome of a sphere viewed
        in `\RR^3`::

            sage: S2 = Manifold(2, 'S^2')
            sage: U = S2.open_subset('U')
            sage: XS.<th,ph> = U.chart(r'th:(0,pi):\theta ph:(0,2*pi):\phi')
            sage: R3 = Manifold(3, 'R^3')
            sage: X3.<x,y,z> = R3.chart()
            sage: F = S2.diff_map(R3, {(XS, X3): [sin(th)*cos(ph),
            ....:                      sin(th)*sin(ph), cos(th)]}, name='F')
            sage: F.display()
            F: S^2 --> R^3
            on U: (th, ph) |--> (x, y, z) = (cos(ph)*sin(th), sin(ph)*sin(th), cos(th))
            sage: c = S2.curve([2*atan(exp(-t/10)), t], (t, -oo, +oo), name='c')
            sage: graph_c = c.plot(mapping=F, max_range=40,
            ....:                  plot_points=200, thickness=2, label_axes=False)  # 3D plot
            sage: graph_S2 = XS.plot(X3, mapping=F, number_values=11, color='black') # plot of the sphere
            sage: show(graph_c + graph_S2) # the loxodrome + the sphere

        .. PLOT::

            S2 = Manifold(2, 'S^2')
            U = S2.open_subset('U')
            XS = U.chart(r'th:(0,pi):\theta ph:(0,2*pi):\phi')
            th, ph = XS[:]
            R3 = Manifold(3, 'R^3')
            X3 = R3.chart('x y z')
            F = S2.diff_map(R3, {(XS, X3): [sin(th)*cos(ph), sin(th)*sin(ph),
                                            cos(th)]}, name='F')
            t = RealLine().canonical_coordinate()
            c = S2.curve([2*atan(exp(-t/10)), t], (t, -oo, +oo), name='c')
            graph_c = c.plot(mapping=F, max_range=40, plot_points=200,
                             thickness=2, label_axes=False)
            graph_S2 = XS.plot(X3, mapping=F, number_values=11, color='black')
            sphinx_plot(graph_c + graph_S2)

        Example of use of the argument ``parameters``: we define a curve with
        some symbolic parameters ``a`` and ``b``::

            sage: a, b = var('a b')
            sage: c = R2.curve([a*cos(t) + b, a*sin(t)], (t, 0, 2*pi), name='c')

        To make a plot, we set spectific values for ``a`` and ``b`` by means
        of the Python dictionary ``parameters``::

            sage: c.plot(parameters={a: 2, b: -3}, aspect_ratio=1)
            Graphics object consisting of 1 graphics primitive

        .. PLOT::

            R2 = Manifold(2, 'R^2')
            X = R2.chart('x y')
            t = RealLine().canonical_coordinate()
            a, b = var('a b')
            c = R2.curve([a*cos(t) + b, a*sin(t)], (t, 0, 2*pi), name='c')
            g = c.plot(parameters={a: 2, b: -3}, aspect_ratio=1)
            sphinx_plot(g)

        """
        from sage.rings.infinity import Infinity
        from sage.misc.functional import numerical_approx
        from sage.plot.graphics import Graphics
        from sage.plot.line import line
        from sage.manifolds.chart import RealChart
        from sage.manifolds.utilities import set_axes_labels
        #
        # Get the @options from kwds
        #
        thickness = kwds.pop('thickness')
        plot_points = kwds.pop('plot_points')
        max_range = kwds.pop('max_range')
        aspect_ratio = kwds.pop('aspect_ratio')
        #
        # The "effective" curve to be plotted
        #
        if mapping is None:
            eff_curve = self
        else:
            eff_curve = mapping.restrict(self.codomain()) * self
        #
        # The chart w.r.t. which the curve is plotted
        #
        if chart is None:
            chart = eff_curve._codomain.default_chart()
        elif not isinstance(chart, RealChart):
            raise TypeError("{} is not a real chart".format(chart))
        #
        # Coordinates of the above chart w.r.t. which the curve is plotted
        #
        if ambient_coords is None:
            ambient_coords = chart[:]  # all chart coordinates are used
        n_pc = len(ambient_coords)
        if n_pc != 2 and n_pc != 3:
            raise ValueError("the number of coordinates involved in the " +
                             "plot must be either 2 or 3, not {}".format(n_pc))
        # indices of plot coordinates
        ind_pc = [chart[:].index(pc) for pc in ambient_coords]
        #
        # Parameter range for the plot
        #
        if prange is None:
            prange = (self._domain.lower_bound(), self._domain.upper_bound())
        elif not isinstance(prange, (tuple, list)):
            raise TypeError("{} is neither a tuple nor a list".format(prange))
        elif len(prange) != 2:
            raise ValueError("the argument prange must be a tuple/list " +
                             "of 2 elements")
        tmin = prange[0]
        tmax = prange[1]
        if tmin == -Infinity:
            tmin = -max_range
        elif not include_end_point[0]:
            tmin = tmin + end_point_offset[0]
        if tmax == Infinity:
            tmax = max_range
        elif not include_end_point[1]:
            tmax = tmax - end_point_offset[1]
        tmin = numerical_approx(tmin)
        tmax = numerical_approx(tmax)
        #
        # The coordinate expression of the effective curve
        #
        canon_chart = self._domain.canonical_chart()
        transf = None
        for chart_pair in eff_curve._coord_expression:
            if chart_pair == (canon_chart, chart):
                transf = eff_curve._coord_expression[chart_pair]
                break
        else:
            # Search for a subchart
            for chart_pair in eff_curve._coord_expression:
                for schart in chart._subcharts:
                    if chart_pair == (canon_chart, schart):
                        transf = eff_curve._coord_expression[chart_pair]
        if transf is None:
            raise ValueError("No expression has been found for " +
                             "{} in terms of {}".format(self, chart))
        #
        # List of points for the plot curve
        #
        plot_curve = []
        dt = (tmax - tmin) / (plot_points - 1)
        t = tmin
        if parameters is None:
            for i in range(plot_points):
                x = transf(t, simplify=False)
                plot_curve.append([numerical_approx(x[j]) for j in ind_pc])
                t += dt
        else:
            for i in range(plot_points):
                x = transf(t, simplify=False)
                plot_curve.append([
                    numerical_approx(x[j].substitute(parameters))
                    for j in ind_pc
                ])
                t += dt
        #
        # The plot
        #
        resu = Graphics()
        resu += line(plot_curve,
                     color=color,
                     linestyle=style,
                     thickness=thickness)
        if n_pc == 2:  # 2D graphic
            resu.set_aspect_ratio(aspect_ratio)
            if label_axes:
                # We update the dictionary _extra_kwds (options to be passed
                # to show()), instead of using the method
                # Graphics.axes_labels() since the latter is not robust w.r.t.
                # graph addition
                resu._extra_kwds['axes_labels'] = [
                    r'$' + latex(pc) + r'$' for pc in ambient_coords
                ]
        else:  # 3D graphic
            if aspect_ratio == 'automatic':
                aspect_ratio = 1
            resu.aspect_ratio(aspect_ratio)
            if label_axes:
                labels = [str(pc) for pc in ambient_coords]
                resu = set_axes_labels(resu, *labels)
        return resu
Exemple #29
0
def plot(hyperplane_arrangement, **kwds):
    r"""
    Return a plot of the hyperplane arrangement.  

    If the arrangement is in 4 dimensions but inessential, a plot of
    the essentialization is returned.

    .. NOTE::

        This function is available as the
        :meth:`~sage.geometry.hyperplane_arrangement.arrangement.HyperplaneArrangementElement.plot`
        method of hyperplane arrangements. You should not call this
        function directly, only through the method.

    INPUT:

    - ``hyperplane_arrangement`` -- the hyperplane arrangement to plot

    - ``**kwds`` -- plot options: see
      :mod:`sage.geometry.hyperplane_arrangement.plot`.

    OUTPUT:
    
    A graphics object of the plot.

    EXAMPLES::

        sage: B = hyperplane_arrangements.semiorder(4)
        sage: B.plot()
        Displaying the essentialization.
        Graphics3d Object
    """
    N = len(hyperplane_arrangement)
    dim = hyperplane_arrangement.dimension()
    if hyperplane_arrangement.base_ring().characteristic() != 0:
        raise NotImplementedError('must be a field of characteristic 0')
    elif dim == 4:
        if not hyperplane_arrangement.is_essential():
            print('Displaying the essentialization.')
            hyperplane_arrangement = hyperplane_arrangement.essentialization()
    elif dim not in [1, 2, 3]:  # revise to handle 4d
        return  # silently
    # handle extra keywords
    if 'hyperplane_colors' in kwds:
        hyp_colors = kwds.pop('hyperplane_colors')
        if not isinstance(hyp_colors,
                          list):  # we assume its a single color then
            hyp_colors = [hyp_colors] * N
    else:
        HSV_tuples = [(i * 1.0 / N, 0.8, 0.9) for i in range(N)]
        hyp_colors = [hsv_to_rgb(*x) for x in HSV_tuples]
    if 'hyperplane_labels' in kwds:
        hyp_labels = kwds.pop('hyperplane_labels')
        has_hyp_label = True
        if not isinstance(hyp_labels, list):  # we assume its a boolean then
            hyp_labels = [hyp_labels] * N
        relabeled = []
        for i in range(N):
            if hyp_labels[i] in [True, 'long']:
                relabeled.append(True)
            else:
                relabeled.append(str(i))
        hyp_labels = relabeled
    else:
        has_hyp_label = False
    if 'label_colors' in kwds:
        label_colors = kwds.pop('label_colors')
        has_label_color = True
        if not isinstance(label_colors,
                          list):  # we assume its a single color then
            label_colors = [label_colors] * N
    else:
        has_label_color = False
    if 'label_fontsize' in kwds:
        label_fontsize = kwds.pop('label_fontsize')
        has_label_fontsize = True
        if not isinstance(label_fontsize,
                          list):  # we assume its a single size then
            label_fontsize = [label_fontsize] * N
    else:
        has_label_fontsize = False
    if 'label_offsets' in kwds:
        has_offsets = True
        offsets = kwds.pop('label_offsets')
    else:
        has_offsets = False  # give default values below
    hyperplane_legend = kwds.pop('hyperplane_legend',
                                 'long' if dim < 3 else False)
    if 'hyperplane_opacities' in kwds:
        hyperplane_opacities = kwds.pop('hyperplane_opacities')
        has_opacity = True
        if not isinstance(hyperplane_opacities,
                          list):  # we assume a single number then
            hyperplane_opacities = [hyperplane_opacities] * N
    else:
        has_opacity = False
    point_sizes = kwds.pop('point_sizes', 50)
    if not isinstance(point_sizes, list):
        point_sizes = [point_sizes] * N
    if 'ranges' in kwds:
        ranges_set = True
        ranges = kwds.pop('ranges')
        if not type(ranges) in [list, tuple]:  # ranges is a single number
            ranges = [ranges] * N
        # So ranges is some type of list.
        elif dim == 2:  # arrangement of lines in the plane
            if not type(ranges[0]) in [list, tuple]:  # a single interval
                ranges = [ranges] * N
        elif dim == 3:  # arrangement of planes in 3-space
            if not type(ranges[0][0]) in [list, tuple]:
                ranges = [ranges] * N
        elif dim not in [2, 3]:  # ranges is not an option unless dim is 2 or 3
            ranges_set = False
        else:  # a list of intervals, one for each hyperplane is given
            pass  # ranges does not need to be modified
    else:
        ranges_set = False  # give default values below
    # the extra keywords have now been handled
    # now handle the legend
    if dim in [1, 2]:  # points on a line or lines in the plane
        if hyperplane_legend in [True, 'long']:
            hyps = hyperplane_arrangement.hyperplanes()
            legend_labels = [hyps[i]._latex_() for i in range(N)]
        elif hyperplane_legend == 'short':
            legend_labels = [str(i) for i in range(N)]
    else:  # dim==3,  arrangement of planes in 3-space
        if hyperplane_legend in [True, 'long']:
            legend3d = legend_3d(hyperplane_arrangement, hyp_colors, 'long')
        elif hyperplane_legend == 'short':
            legend3d = legend_3d(hyperplane_arrangement, hyp_colors, 'short')
    ## done handling the legend
    ## now create the plot
    p = Graphics()
    for i in range(N):
        newk = copy(kwds)
        if has_hyp_label:
            newk['hyperplane_label'] = hyp_labels[i]
            if has_offsets:
                if not isinstance(offsets, list):
                    newk['label_offset'] = offsets
                else:
                    newk['label_offset'] = offsets[i]
        else:
            newk['hyperplane_label'] = False
        if has_label_color:
            newk['label_color'] = label_colors[i]
        if has_label_fontsize:
            newk['label_fontsize'] = label_fontsize[i]
        if has_opacity:
            newk['opacity'] = hyperplane_opacities[i]
        if dim == 1:
            newk['point_size'] = point_sizes[i]
        if dim in [1, 2] and hyperplane_legend:  # more options than T/F
            newk['legend_label'] = legend_labels[i]
        if ranges_set:
            newk['ranges'] = ranges[i]
        p += plot_hyperplane(hyperplane_arrangement[i],
                             rgbcolor=hyp_colors[i],
                             **newk)
    if dim == 1:
        if hyperplane_legend:  # there are more options than T/F
            p.legend(True)
        return p
    elif dim == 2:
        if hyperplane_legend:  # there are more options than T/F
            p.legend(True)
        return p
    else:  # dim==3
        if hyperplane_legend:  # there are more options than T/F
            return p, legend3d
        else:
            return p
Exemple #30
0
    def plot(self,
             chart=None,
             ambient_coords=None,
             mapping=None,
             color='blue',
             print_label=True,
             label=None,
             label_color=None,
             fontsize=10,
             label_offset=0.1,
             parameters=None,
             **extra_options):
        r"""
        Plot the vector in a Cartesian graph based on the coordinates of some
        ambient chart.

        The vector is drawn in terms of two (2D graphics) or three (3D graphics)
        coordinates of a given chart, called hereafter the *ambient chart*.
        The vector's base point `p` (or its image `\Phi(p)` by some
        differentiable mapping `\Phi`) must lie in the ambient chart's domain.
        If `\Phi` is different from the identity mapping, the vector
        actually depicted is `\mathrm{d}\Phi_p(v)`, where `v` is the current
        vector (``self``) (see the example of a vector tangent to the
        2-sphere below, where `\Phi: S^2 \to \RR^3`).

        INPUT:

        - ``chart`` -- (default: ``None``) the ambient chart (see above); if
          ``None``, it is set to the default chart of the open set containing
          the point at which the vector (or the vector image via the
          differential `\mathrm{d}\Phi_p` of ``mapping``) is defined

        - ``ambient_coords`` -- (default: ``None``) tuple containing the 2
          or 3 coordinates of the ambient chart in terms of which the plot
          is performed; if ``None``, all the coordinates of the ambient
          chart are considered

        - ``mapping`` -- (default: ``None``)
          :class:`~sage.manifolds.differentiable.diff_map.DiffMap`;
          differentiable mapping `\Phi` providing the link between the
          point `p` at which the vector is defined and the ambient chart
          ``chart``: the domain of ``chart`` must contain `\Phi(p)`;
          if ``None``, the identity mapping is assumed

        - ``scale`` -- (default: 1) value by which the length of the arrow
          representing the vector is multiplied

        - ``color`` -- (default: 'blue') color of the arrow representing the
          vector

        - ``print_label`` -- (boolean; default: ``True``) determines whether a
          label is printed next to the arrow representing the vector

        - ``label`` -- (string; default: ``None``) label printed next to the
          arrow representing the vector; if ``None``, the vector's symbol is
          used, if any

        - ``label_color`` -- (default: ``None``) color to print the label;
          if ``None``, the value of ``color`` is used

        - ``fontsize`` -- (default: 10) size of the font used to print the
          label

        - ``label_offset`` -- (default: 0.1) determines the separation between
          the vector arrow and the label

        - ``parameters`` -- (default: ``None``) dictionary giving the numerical
          values of the parameters that may appear in the coordinate expression
          of ``self`` (see example below)

        - ``**extra_options`` -- extra options for the arrow plot, like
          ``linestyle``, ``width`` or ``arrowsize`` (see
          :func:`~sage.plot.arrow.arrow2d` and
          :func:`~sage.plot.plot3d.shapes.arrow3d` for details)

        OUTPUT:

        - a graphic object, either an instance of
          :class:`~sage.plot.graphics.Graphics` for a 2D plot (i.e. based on
          2 coordinates of ``chart``) or an instance of
          :class:`~sage.plot.plot3d.base.Graphics3d` for a 3D plot (i.e.
          based on 3 coordinates of ``chart``)

        EXAMPLES:

        Vector tangent to a 2-dimensional manifold::

            sage: M = Manifold(2, 'M')
            sage: X.<x,y> = M.chart()
            sage: p = M((2,2), name='p')
            sage: Tp = M.tangent_space(p)
            sage: v = Tp((2, 1), name='v') ; v
            Tangent vector v at Point p on the 2-dimensional differentiable
             manifold M

        Plot of the vector alone (arrow + label)::

            sage: v.plot()
            Graphics object consisting of 2 graphics primitives

        Plot atop of the chart grid::

            sage: X.plot() + v.plot()
            Graphics object consisting of 20 graphics primitives

        .. PLOT::

            M = Manifold(2, 'M')
            X = M.chart('x y'); x, y = X[:]
            p = M((2,2), name='p'); Tp = M.tangent_space(p)
            v = Tp((2, 1), name='v')
            g = X.plot() + v.plot()
            sphinx_plot(g)

        Plots with various options::

            sage: X.plot() + v.plot(color='green', scale=2, label='V')
            Graphics object consisting of 20 graphics primitives

        .. PLOT::

            M = Manifold(2, 'M')
            X = M.chart('x y'); x, y = X[:]
            p = M((2,2), name='p'); Tp = M.tangent_space(p)
            v = Tp((2, 1), name='v')
            g = X.plot() + v.plot(color='green', scale=2, label='V')
            sphinx_plot(g)

        ::

            sage: X.plot() + v.plot(print_label=False)
            Graphics object consisting of 19 graphics primitives

        .. PLOT::

            M = Manifold(2, 'M')
            X = M.chart('x y'); x, y = X[:]
            p = M((2,2), name='p'); Tp = M.tangent_space(p)
            v = Tp((2, 1), name='v')
            g = X.plot() + v.plot(print_label=False)
            sphinx_plot(g)

        ::

            sage: X.plot() + v.plot(color='green', label_color='black',
            ....:                   fontsize=20, label_offset=0.2)
            Graphics object consisting of 20 graphics primitives

        .. PLOT::

            M = Manifold(2, 'M')
            X = M.chart('x y'); x, y = X[:]
            p = M((2,2), name='p'); Tp = M.tangent_space(p)
            v = Tp((2, 1), name='v')
            g = X.plot() + v.plot(color='green', label_color='black', fontsize=20, label_offset=0.2)
            sphinx_plot(g)

        ::

            sage: X.plot() + v.plot(linestyle=':', width=4, arrowsize=8,
            ....:                   fontsize=20)
            Graphics object consisting of 20 graphics primitives

        .. PLOT::

            M = Manifold(2, 'M')
            X = M.chart('x y'); x, y = X[:]
            p = M((2,2), name='p'); Tp = M.tangent_space(p)
            v = Tp((2, 1), name='v')
            g = X.plot() + v.plot(linestyle=':', width=4, arrowsize=8, fontsize=20)
            sphinx_plot(g)

        Plot with specific values of some free parameters::

            sage: var('a b')
            (a, b)
            sage: v = Tp((1+a, -b^2), name='v') ; v.display()
            v = (a + 1) d/dx - b^2 d/dy
            sage: X.plot() + v.plot(parameters={a: -2, b: 3})
            Graphics object consisting of 20 graphics primitives

        Special case of the zero vector::

            sage: v = Tp.zero() ; v
            Tangent vector zero at Point p on the 2-dimensional differentiable
             manifold M
            sage: X.plot() + v.plot()
            Graphics object consisting of 19 graphics primitives

        Vector tangent to a 4-dimensional manifold::

            sage: M = Manifold(4, 'M')
            sage: X.<t,x,y,z> = M.chart()
            sage: p = M((0,1,2,3), name='p')
            sage: Tp = M.tangent_space(p)
            sage: v = Tp((5,4,3,2), name='v') ; v
            Tangent vector v at Point p on the 4-dimensional differentiable
             manifold M

        We cannot make a 4D plot directly::

            sage: v.plot()
            Traceback (most recent call last):
            ...
            ValueError: the number of coordinates involved in the plot must
             be either 2 or 3, not 4

        Rather, we have to select some chart coordinates for the plot, via
        the argument ``ambient_coords``. For instance, for a 2-dimensional
        plot in terms of the coordinates `(x, y)`::

            sage: v.plot(ambient_coords=(x,y))
            Graphics object consisting of 2 graphics primitives

        .. PLOT::

            M = Manifold(4, 'M')
            X = M.chart('t x y z'); t,x,y,z = X[:]
            p = M((0,1,2,3), name='p'); Tp = M.tangent_space(p)
            v = Tp((5,4,3,2), name='v')
            g = X.plot(ambient_coords=(x,y)) + v.plot(ambient_coords=(x,y))
            sphinx_plot(g)

        This plot involves only the components `v^x` and `v^y` of `v`.
        Similarly, for a 3-dimensional plot in terms of the coordinates
        `(t, x, y)`::

            sage: g = v.plot(ambient_coords=(t,x,z))
            sage: print(g)
            Graphics3d Object

        This plot involves only the components `v^t`,  `v^x` and `v^z` of `v`.
        A nice 3D view atop the coordinate grid is obtained via::

            sage: (X.plot(ambient_coords=(t,x,z))  # long time
            ....:  + v.plot(ambient_coords=(t,x,z),
            ....:           label_offset=0.5, width=6))
            Graphics3d Object

        .. PLOT::

            M = Manifold(4, 'M')
            X = M.chart('t x y z'); t,x,y,z = X[:]
            p = M((0,1,2,3), name='p'); Tp = M.tangent_space(p)
            v = Tp((5,4,3,2), name='v')
            g = X.plot(ambient_coords=(t,x,z)) + v.plot(ambient_coords=(t,x,z),
                       label_offset=0.5, width=6)
            sphinx_plot(g)

        An example of plot via a differential mapping: plot of a vector tangent
        to a 2-sphere viewed in `\RR^3`::

            sage: S2 = Manifold(2, 'S^2')
            sage: U = S2.open_subset('U') # the open set covered by spherical coord.
            sage: XS.<th,ph> = U.chart(r'th:(0,pi):\theta ph:(0,2*pi):\phi')
            sage: R3 = Manifold(3, 'R^3')
            sage: X3.<x,y,z> = R3.chart()
            sage: F = S2.diff_map(R3, {(XS, X3): [sin(th)*cos(ph),
            ....:                                 sin(th)*sin(ph),
            ....:                                 cos(th)]}, name='F')
            sage: F.display() # the standard embedding of S^2 into R^3
            F: S^2 --> R^3
            on U: (th, ph) |--> (x, y, z) = (cos(ph)*sin(th), sin(ph)*sin(th), cos(th))
            sage: p = U.point((pi/4, 7*pi/4), name='p')
            sage: v = XS.frame()[1].at(p) ; v  # the coordinate vector d/dphi at p
            Tangent vector d/dph at Point p on the 2-dimensional differentiable
             manifold S^2
            sage: graph_v = v.plot(mapping=F)
            sage: graph_S2 = XS.plot(chart=X3, mapping=F, number_values=9)  # long time
            sage: graph_v + graph_S2  # long time
            Graphics3d Object

        .. PLOT::

            S2 = Manifold(2, 'S^2')
            U = S2.open_subset('U')
            XS = U.chart(r'th:(0,pi):\theta ph:(0,2*pi):\phi')
            th, ph = XS[:]
            R3 = Manifold(3, 'R^3')
            X3 = R3.chart('x y z')
            F = S2.diff_map(R3, {(XS, X3): [sin(th)*cos(ph), sin(th)*sin(ph),
                                            cos(th)]}, name='F')
            p = U.point((pi/4, 7*pi/4), name='p')
            v = XS.frame()[1].at(p)
            graph_v = v.plot(mapping=F)
            graph_S2 = XS.plot(chart=X3, mapping=F, number_values=9)
            sphinx_plot(graph_v + graph_S2)

        """
        from sage.plot.arrow import arrow2d
        from sage.plot.text import text
        from sage.plot.graphics import Graphics
        from sage.plot.plot3d.shapes import arrow3d
        from sage.plot.plot3d.shapes2 import text3d
        from sage.misc.functional import numerical_approx
        from sage.manifolds.differentiable.chart import DiffChart

        scale = extra_options.pop("scale")

        #
        # The "effective" vector to be plotted
        #
        if mapping is None:
            eff_vector = self
            base_point = self._point
        else:
            #!# check
            # For efficiency, the method FiniteRankFreeModuleMorphism._call_()
            # is called instead of FiniteRankFreeModuleMorphism.__call__()
            eff_vector = mapping.differential(self._point)._call_(self)
            base_point = mapping(self._point)
        #
        # The chart w.r.t. which the vector is plotted
        #
        if chart is None:
            chart = base_point.parent().default_chart()
        elif not isinstance(chart, DiffChart):
            raise TypeError("{} is not a chart".format(chart))
        #
        # Coordinates of the above chart w.r.t. which the vector is plotted
        #
        if ambient_coords is None:
            ambient_coords = chart[:]  # all chart coordinates are used
        n_pc = len(ambient_coords)
        if n_pc != 2 and n_pc != 3:
            raise ValueError("the number of coordinates involved in the " +
                             "plot must be either 2 or 3, not {}".format(n_pc))
        # indices coordinates involved in the plot:
        ind_pc = [chart[:].index(pc) for pc in ambient_coords]
        #
        # Components of the vector w.r.t. the chart frame
        #
        basis = chart.frame().at(base_point)
        vcomp = eff_vector.comp(basis=basis)[:]
        xp = base_point.coord(chart=chart)
        #
        # The arrow
        #
        resu = Graphics()
        if parameters is None:
            coord_tail = [numerical_approx(xp[i]) for i in ind_pc]
            coord_head = [
                numerical_approx(xp[i] + scale * vcomp[i]) for i in ind_pc
            ]
        else:
            coord_tail = [
                numerical_approx(xp[i].substitute(parameters)) for i in ind_pc
            ]
            coord_head = [
                numerical_approx(
                    (xp[i] + scale * vcomp[i]).substitute(parameters))
                for i in ind_pc
            ]
        if coord_head != coord_tail:
            if n_pc == 2:
                resu += arrow2d(tailpoint=coord_tail,
                                headpoint=coord_head,
                                color=color,
                                **extra_options)
            else:
                resu += arrow3d(coord_tail,
                                coord_head,
                                color=color,
                                **extra_options)
        #
        # The label
        #
        if print_label:
            if label is None:
                if n_pc == 2 and self._latex_name is not None:
                    label = r'$' + self._latex_name + r'$'
                if n_pc == 3 and self._name is not None:
                    label = self._name
            if label is not None:
                xlab = [xh + label_offset for xh in coord_head]
                if label_color is None:
                    label_color = color
                if n_pc == 2:
                    resu += text(label,
                                 xlab,
                                 fontsize=fontsize,
                                 color=label_color)
                else:
                    resu += text3d(label,
                                   xlab,
                                   fontsize=fontsize,
                                   color=label_color)
        return resu