Beispiel #1
0
def my_hyperbolic_triangle(a, b, c, **options):
    """
    Return a hyperbolic triangle in the complex hyperbolic plane with points
    (a, b, c). Type ``?hyperbolic_triangle`` to see all options.

    INPUT:

    - ``a, b, c`` - complex numbers in the upper half complex plane

    OPTIONS:
    
    - ``alpha`` - default: 1
       
    - ``fill`` - default: False

    - ``thickness`` - default: 1

    - ``rgbcolor`` - default: 'blue'

    - ``linestyle`` - default: 'solid'

    EXAMPLES:

    Show a hyperbolic triangle with coordinates 0, `1/2+i\sqrt{3}/2` and
    `-1/2+i\sqrt{3}/2`::
    
         sage: hyperbolic_triangle(0, -1/2+I*sqrt(3)/2, 1/2+I*sqrt(3)/2)

    A hyperbolic triangle with coordinates 0, 1 and 2+i::
    
         sage: hyperbolic_triangle(0, 1, 2+i, fill=true, rgbcolor='red')
    """
    from sage.plot.all import Graphics
    g = Graphics()
    g._set_extra_kwds(g._extract_kwds_for_show(options))
    model = options['model']
    npts = options.get('npts',10)
    sides = options.pop('sides',[1,2,3]) ## Which of the sides we will draw.
    verbose = options.get('verbose',0)
    options.pop('model',None); options.pop('method',None)
    if model=="D":
        #g.add_primitive(HyperbolicTriangleDisc(a, b, c, **options))
        #print "options=",options
        options['sides']=sides
        H = HyperbolicTriangleDisc(a, b, c, **options)
        g += H()
    else:
        options.pop('npts',None)
        if sides == [1,2,3]:
            if verbose>0:
                print "adding HyperbolicTriangle({0}, {1}, {2},options={3})".format(a,b,c,options)
            options.pop('verbose',0)
            g.add_primitive(HyperbolicTriangle(a, b, c, options))
        else:
            options['sides']=sides
            if verbose>0:
                print "adding MyHyperbolicTriangle({0}, {1}, {2},options={3})".format(a,b,c,options)
            g.add_primitive(MyHyperbolicTriangle(a, b, c, options))                           
    g.set_aspect_ratio(1)
    return g
Beispiel #2
0
 def newton_plot(self):
     S = [QQ(s) for s in self.slopes]
     C = Counter(S)
     pts = [(0,0)]
     x = y = 0
     for s in sorted(C):
         c = C[s]
         x += c
         y += c*s
         pts.append((x,y))
     L = Graphics()
     L += line([(0,0),(0,y+0.2)],color="grey")
     for i in range(1,y+1):
         L += line([(0,i),(0.06,i)],color="grey")
     for i in range(1,C[0]):
         L += line([(i,0),(i,0.06)],color="grey")
     for i in range(len(pts)-1):
         P = pts[i]
         Q = pts[i+1]
         for x in range(P[0],Q[0]+1):
             L += line([(x,P[1]),(x,P[1] + (x-P[0])*(Q[1]-P[1])/(Q[0]-P[0]))],color="grey")
         for y in range(P[1],Q[1]):
             L += line([(P[0] + (y-P[1])*(Q[0]-P[0])/(Q[1]-P[1]),y),(Q[0],y)],color="grey")
     L += line(pts, thickness = 2)
     L.axes(False)
     L.set_aspect_ratio(1)
     return encode_plot(L, pad=0, pad_inches=0, bbox_inches='tight')
Beispiel #3
0
    def __init__(self, A, B, C,**options):
        """
            Initialize HyperbolicTriangle under the map (z-z0)/(z-\bar(z0)):

        Examples::
        
            sage: from sage.plot.hyperbolic_triangle import HyperbolicTriangle
            sage: print HyperbolicTriangle(0, 1/2, I, {})
            Hyperbolic triangle (0.000000000000000, 0.500000000000000, 1.00000000000000*I)
        """
        A, B, C = (CC(A), CC(B), CC(C))
        self.path = []
        self._graphics = Graphics()
        Z0 = options['center'] #.get('center',C(0,1))
        self._z0=CC(Z0); self._z0bar=CC(Z0).conjugate()        
        self._hyperbolic_arc_d(A, B, True);
        self._hyperbolic_arc_d(B, C);
        self._hyperbolic_arc_d(C, A);
        #BezierPath.__init__(self, self.path, options)
        options.pop('center',None)
        if options=={} or options==None:
            self._options = {}
        else:
            self._options = options
        #super(HyperbolicTriangleDisc,self).__init__(options)
        self.A, self.B, self.C = (A, B, C)
Beispiel #4
0
def hyperbolic_polygon(pts, **options):
    r"""
    Return a hyperbolic polygon in the hyperbolic plane with vertices ``pts``.

    Type ``?hyperbolic_polygon`` to see all options.

    INPUT:

    - ``pts`` -- a list or tuple of complex numbers

    OPTIONS:

    - ``alpha`` -- default: 1

    - ``fill`` -- default: ``False``

    - ``thickness`` -- default: 1

    - ``rgbcolor`` -- default: ``'blue'``

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

    EXAMPLES:

    Show a hyperbolic polygon with coordinates `-1`, `3i`, `2+2i`, `1+i`::

        sage: hyperbolic_polygon([-1,3*I,2+2*I,1+I])
        Graphics object consisting of 1 graphics primitive

    .. PLOT::

        P = hyperbolic_polygon([-1,3*I,2+2*I,1+I])
        sphinx_plot(P)

    With more options::

        sage: hyperbolic_polygon([-1,3*I,2+2*I,1+I], fill=True, color='red')
        Graphics object consisting of 1 graphics primitive

    .. PLOT::

        P = hyperbolic_polygon([-1,3*I,2+2*I,1+I], fill=True, color='red')
        sphinx_plot(P)

    """
    from sage.plot.all import Graphics
    g = Graphics()
    g._set_extra_kwds(g._extract_kwds_for_show(options))
    g.add_primitive(HyperbolicPolygon(pts, options))
    g.set_aspect_ratio(1)
    return g
Beispiel #5
0
    def show3d(self, size=0.85):
        r"""
        Return the solution as a 3D Graphic object.

        OUTPUT:

            3D Graphic Object

        EXAMPLES::

            sage: from sage.games.quantumino import QuantuminoSolver
            sage: s = next(QuantuminoSolver(0).solve())    # not tested (1.5s)
            sage: G = s.show3d()                            # not tested (<1s)
            sage: type(G)                                   # not tested
            <class 'sage.plot.plot3d.base.Graphics3dGroup'>

        To remove the frame::

            sage: G.show(frame=False) # not tested

        To see the solution with Tachyon viewer::

            sage: G.show(viewer='tachyon', frame=False) # not tested
        """
        G = Graphics()
        for p in self:
            G += p.show3d(size=size)
        aside_pento = self._aside.canonical() + (2,-4,0)
        G += aside_pento.show3d(size=size)

        # the box to fill
        half_box = tuple(a/2 for a in self._box)
        b = cube(color='gray',opacity=0.2).scale(self._box).translate(half_box)
        b = b.translate((0, -.5, -.5))
        G += b

        # hack to set the aspect ratio to 1
        a,b = G.bounding_box()
        a,b = map(vector, (a,b))
        G.frame_aspect_ratio(tuple(b-a))

        return G
Beispiel #6
0
def show_pentaminos(box=(5,8,2)):
    r"""
    Show the 17 3-D pentaminos included in the game and the `5 \times 8
    \times 2` box where 16 of them must fit.

    INPUT:

    - ``box`` -- tuple of size three (optional, default: ``(5,8,2)``),
      size of the box

    OUTPUT:

    3D Graphic object

    EXAMPLES::

        sage: from sage.games.quantumino import show_pentaminos
        sage: show_pentaminos()    # not tested (1s)

    To remove the frame do::

        sage: show_pentaminos().show(frame=False)  # not tested (1s)
    """
    G = Graphics()
    for i, p in enumerate(pentaminos):
        x = 4 * (i % 4)
        y = 4 * (i // 4)
        q = p + (x, y, 0)
        G += q.show3d()
        G += text3d(str(i), (x, y, 2))
    G += cube(color='gray',opacity=0.5).scale(box).translate((17, 6, 0))

    # hack to set the aspect ratio to 1
    a, b = G.bounding_box()
    a, b = map(vector, (a, b))
    G.frame_aspect_ratio(tuple(b - a))

    return G
Beispiel #7
0
def hyperbolic_arc(a, b, **options):
    """
    Plot an arc from a to b in hyperbolic geometry in the complex upper
    half plane.

    INPUT:

    - ``a, b`` - complex numbers in the upper half complex plane
      connected bye the arc

    OPTIONS:

    - ``alpha`` - default: 1

    - ``thickness`` - default: 1

    - ``rgbcolor`` - default: 'blue'

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

    Examples:

    Show a hyperbolic arc from 0 to 1::

         sage: hyperbolic_arc(0, 1)
         Graphics object consisting of 1 graphics primitive

    Show a hyperbolic arc from 1/2 to `i` with a red thick line::

         sage: hyperbolic_arc(1/2, I, color='red', thickness=2)
         Graphics object consisting of 1 graphics primitive

    Show a hyperbolic arc form `i` to `2 i` with dashed line::

         sage: hyperbolic_arc(I, 2*I, linestyle='dashed')
         Graphics object consisting of 1 graphics primitive
         sage: hyperbolic_arc(I, 2*I, linestyle='--')
         Graphics object consisting of 1 graphics primitive
    """
    from sage.plot.all import Graphics
    g = Graphics()
    g._set_extra_kwds(g._extract_kwds_for_show(options))
    g.add_primitive(HyperbolicArc(a, b, options))
    g.set_aspect_ratio(1)
    return g
Beispiel #8
0
    def show3d(self, size=0.85):
        r"""
        Return the solution as a 3D Graphic object.

        OUTPUT:

            3D Graphic Object

        EXAMPLES::

            sage: from sage.games.quantumino import QuantuminoSolver
            sage: s = QuantuminoSolver(0).solve().next()    # not tested (1.5s)
            sage: G = s.show3d()                            # not tested (<1s)
            sage: type(G)                                   # not tested
            <class 'sage.plot.plot3d.base.Graphics3dGroup'>

        To remove the frame::

            sage: G.show(frame=False) # not tested

        To see the solution with Tachyon viewer::

            sage: G.show(viewer='tachyon', frame=False) # not tested
        """
        G = Graphics()
        for p in self:
            G += p.show3d(size=size)
        aside_pento = self._aside.canonical() + (2.5*size/0.75,-4*size/0.75,0)
        G += aside_pento.show3d(size=size)

        # hack to set the aspect ratio to 1
        a,b = G.bounding_box()
        a,b = map(vector, (a,b))
        G.frame_aspect_ratio(tuple(b-a))

        return G
Beispiel #9
0
def my_hyperbolic_triangle(a, b, c, **options):
    """
    Return a hyperbolic triangle in the complex hyperbolic plane with points
    (a, b, c). Type ``?hyperbolic_triangle`` to see all options.

    INPUT:

    - ``a, b, c`` - complex numbers in the upper half complex plane

    OPTIONS:
    
    - ``alpha`` - default: 1
       
    - ``fill`` - default: False

    - ``thickness`` - default: 1

    - ``rgbcolor`` - default: 'blue'

    - ``linestyle`` - default: 'solid'

    EXAMPLES:

    Show a hyperbolic triangle with coordinates 0, `1/2+i\sqrt{3}/2` and
    `-1/2+i\sqrt{3}/2`::
    
         sage: hyperbolic_triangle(0, -1/2+I*sqrt(3)/2, 1/2+I*sqrt(3)/2)

    A hyperbolic triangle with coordinates 0, 1 and 2+i::
    
         sage: hyperbolic_triangle(0, 1, 2+i, fill=true, rgbcolor='red')
    """
    from sage.plot.all import Graphics
    g = Graphics()
    g._set_extra_kwds(g._extract_kwds_for_show(options))
    model = options['model']
    options.pop('model',None); options.pop('method',None)
    if model=="D":
        #g.add_primitive(HyperbolicTriangleDisc(a, b, c, **options))
        H = HyperbolicTriangleDisc(a, b, c, **options)
        g += H()
    else:
        g.add_primitive(HyperbolicTriangle(a, b, c, options))
    g.set_aspect_ratio(1)
    return g
Beispiel #10
0
def scatter_plot(datalist, **options):
    """
    Returns a Graphics object of a scatter plot containing all points in
    the datalist.  Type ``scatter_plot.options`` to see all available
    plotting options.

    INPUT:

    - ``datalist`` -- a list of tuples ``(x,y)``

    - ``alpha`` -- default: 1

    - ``markersize`` -- default: 50

    - ``marker``  - The style of the markers (default ``"o"``), which is one of
       - ``"None"`` or ``" "`` or ``""`` (nothing)
       - ``","`` (pixel), ``"."`` (point)
       - ``"_"`` (horizontal line), ``"|"`` (vertical line)
       - ``"o"`` (circle), ``"p"`` (pentagon), ``"s"`` (square), ``"x"`` (x), ``"+"`` (plus), ``"*"`` (star)
       - ``"D"`` (diamond), ``"d"`` (thin diamond)
       - ``"H"`` (hexagon), ``"h"`` (alternative hexagon)
       - ``"<"`` (triangle left), ``">"`` (triangle right), ``"^"`` (triangle up), ``"v"`` (triangle down)
       - ``"1"`` (tri down), ``"2"`` (tri up), ``"3"`` (tri left), ``"4"`` (tri right)
       - ``0`` (tick left), ``1`` (tick right), ``2`` (tick up), ``3`` (tick down)
       - ``4`` (caret left), ``5`` (caret right), ``6`` (caret up), ``7`` (caret down)
       - ``"$...$"`` (math TeX string)

    - ``facecolor`` -- default: ``'#fec7b8'``

    - ``edgecolor`` -- default: ``'black'``

    - ``zorder`` -- default: 5

    EXAMPLES::

        sage: scatter_plot([[0,1],[2,2],[4.3,1.1]], marker='s')

    Extra options will get passed on to :meth:`~Graphics.show`, as long as they are valid::

        sage: scatter_plot([(0, 0), (1, 1)], markersize=100, facecolor='green', ymax=100)
        sage: scatter_plot([(0, 0), (1, 1)], markersize=100, facecolor='green').show(ymax=100) # These are equivalent
    """
    import numpy
    from sage.plot.all import Graphics
    g = Graphics()
    g._set_extra_kwds(Graphics._extract_kwds_for_show(options))
    data = numpy.array(datalist, dtype='float')
    if len(data) != 0:
        xdata = data[:,0]
        ydata = data[:,1]
        g.add_primitive(ScatterPlot(xdata, ydata, options=options))
    return g
Beispiel #11
0
def hyperbolic_arc(a, b, **options):
    """
    Plot an arc from a to b in hyperbolic geometry in the complex upper
    half plane.

    INPUT:

    - ``a, b`` - complex numbers in the upper half complex plane
      connected bye the arc

    OPTIONS:

    - ``alpha`` - default: 1

    - ``thickness`` - default: 1

    - ``rgbcolor`` - default: 'blue'

    - ``linestyle`` - default: 'solid'

    Examples:

    Show a hyperbolic arc from 0 to 1::

         sage: hyperbolic_arc(0, 1)

    Show a hyperbolic arc from 1/2 to `i` with a red thick line::

         sage: hyperbolic_arc(1/2, I, color='red', thickness=2)

    Show a hyperbolic arc form `i` to `2 i` with dashed line::

         sage: hyperbolic_arc(I, 2*I, linestyle='dashed')
    """
    from sage.plot.all import Graphics
    g = Graphics()
    g._set_extra_kwds(g._extract_kwds_for_show(options))
    g.add_primitive(HyperbolicArc(a, b, options))
    g.set_aspect_ratio(1)
    return g
Beispiel #12
0
def hyperbolic_triangle(a, b, c, **options):
    """
    Return a hyperbolic triangle in the complex hyperbolic plane with points
    (a, b, c). Type ``?hyperbolic_triangle`` to see all options.

    INPUT:

    - ``a, b, c`` - complex numbers in the upper half complex plane

    OPTIONS:

    - ``alpha`` - default: 1

    - ``fill`` - default: False

    - ``thickness`` - default: 1

    - ``rgbcolor`` - default: 'blue'

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

    EXAMPLES:

    Show a hyperbolic triangle with coordinates 0, `1/2+i\sqrt{3}/2` and
    `-1/2+i\sqrt{3}/2`::

         sage: hyperbolic_triangle(0, -1/2+I*sqrt(3)/2, 1/2+I*sqrt(3)/2)

    A hyperbolic triangle with coordinates 0, 1 and 2+i and a dashed line::

         sage: hyperbolic_triangle(0, 1, 2+i, fill=true, rgbcolor='red', linestyle='--')
    """
    from sage.plot.all import Graphics
    g = Graphics()
    g._set_extra_kwds(g._extract_kwds_for_show(options))
    g.add_primitive(HyperbolicTriangle(a, b, c, options))
    g.set_aspect_ratio(1)
    return g
Beispiel #13
0
def scatter_plot(datalist, **options):
    """
    Returns a Graphics object of a scatter plot containing all points in
    the datalist.  Type ``scatter_plot.options`` to see all available
    plotting options.

    INPUT:

    - ``datalist`` -- a list of tuples ``(x,y)``

    - ``alpha`` -- default: 1

    - ``markersize`` -- default: 50

    - ``marker``  - The style of the markers (default ``"o"``). See the
      documentation of :func:`plot` for the full list of markers.

    - ``facecolor`` -- default: ``'#fec7b8'``

    - ``edgecolor`` -- default: ``'black'``

    - ``zorder`` -- default: 5

    EXAMPLES::

        sage: scatter_plot([[0,1],[2,2],[4.3,1.1]], marker='s')
        Graphics object consisting of 1 graphics primitive

    Extra options will get passed on to :meth:`~Graphics.show`, as long as they are valid::

        sage: scatter_plot([(0, 0), (1, 1)], markersize=100, facecolor='green', ymax=100)
        Graphics object consisting of 1 graphics primitive
        sage: scatter_plot([(0, 0), (1, 1)], markersize=100, facecolor='green').show(ymax=100) # These are equivalent
    """
    import numpy
    from sage.plot.all import Graphics
    g = Graphics()
    g._set_extra_kwds(Graphics._extract_kwds_for_show(options))
    data = numpy.array(datalist, dtype='float')
    if len(data) != 0:
        xdata = data[:,0]
        ydata = data[:,1]
        g.add_primitive(ScatterPlot(xdata, ydata, options=options))
    return g
Beispiel #14
0
def bezier_path(path, **options):
    """
    Returns a Graphics object of a Bezier path corresponding to the
    path parameter.  The path is a list of curves, and each curve is
    a list of points.  Each point is a tuple ``(x,y)``.

    The first curve contains the endpoints as the first and last point
    in the list.  All other curves assume a starting point given by the
    last entry in the preceding list, and take the last point in the list
    as their opposite endpoint.  A curve can have 0, 1 or 2 control points
    listed between the endpoints.  In the input example for path below,
    the first and second curves have 2 control points, the third has one,
    and the fourth has no control points:

    path = [[p1, c1, c2, p2], [c3, c4, p3], [c5, p4], [p5], ...]

    In the case of no control points, a straight line will be drawn
    between the two endpoints.  If one control point is supplied, then
    the curve at each of the endpoints will be tangent to the line from
    that endpoint to the control point.  Similarly, in the case of two
    control points, at each endpoint the curve will be tangent to the line
    connecting that endpoint with the control point immediately after or
    immediately preceding it in the list.

    .. PLOT::

        p1 = (0,0)
        c1 = (1,1)
        c2 = (1.5,0.5)
        p2 = (4,-1)
        c3 = (3.5,0)
        c4 = (2,1)
        p3 = (0,2)
        c5 = (0.5,3)
        p4 = (1.5,2)
        p5 = (0,4)
        path = [[p1, c1, c2, p2], [c3, c4, p3], [c5, p4], [p5]]
        P = bezier_path(path)
        P += line([p1,c1], color="red", linestyle="dashed")
        P += line([p2,c2], color="red", linestyle="dashed")
        P += line([p2,c3], color="red", linestyle="dashed")
        P += line([p3,c4], color="red", linestyle="dashed")
        P += line([p3,c5], color="red", linestyle="dashed")
        P += text("c1", c1, horizontal_alignment='left')
        P += text("c2", c2, horizontal_alignment='right')
        P += text("c3", c3, horizontal_alignment='left', vertical_alignment='bottom')
        P += text("c4", c4, horizontal_alignment='left')
        P += text("c5", c5, horizontal_alignment='left')
        P += text("p1", p1, horizontal_alignment='left', vertical_alignment='top')
        P += text("p2", p2, horizontal_alignment='left')
        P += text("p3", p3, horizontal_alignment='right', vertical_alignment='top')
        P += text("p4", p4, horizontal_alignment='left')
        P += text("p5", p5, horizontal_alignment='left', vertical_alignment='bottom')
        P += point([c1, c2, c3, c4, c5])
        sphinx_plot(P)

    So in our example above, the curve between p1 and p2 is tangent to the
    line through p1 and c1 at p1, and tangent to the line through p2 and c2
    at p2.  Similarly, the curve between p2 and p3 is tangent to line(p2,c3)
    at p2 and tangent to line(p3,c4) at p3.  Curve(p3,p4) is tangent to
    line(p3,c5) at p3 and tangent to line(p4,c5) at p4.  Curve(p4,p5) is a
    straight line.

    INPUT:

    - ``path`` -- a list of lists of tuples (see above)
    - ``alpha`` -- default: 1
    - ``fill`` -- default: False
    - ``thickness`` -- default: 1
    - ``linestyle`` -- default: ``'solid'``, The style of the line, which is one
       of ``'dashed'``, ``'dotted'``, ``'solid'``, ``'dashdot'``, or ``'--'``,
       ``':'``, ``'-'``, ``'-.'``, respectively.
    - ``rgbcolor`` -- default: (0,0,0)
    - ``zorder`` -- the layer in which to draw

    EXAMPLES::

        sage: path = [[(0,0),(.5,.1),(.75,3),(1,0)],[(.5,1),(.5,0)],[(.2,.5)]]
        sage: b = bezier_path(path, linestyle='dashed', rgbcolor='green')
        sage: b
        Graphics object consisting of 1 graphics primitive

    .. PLOT::

        path = [[(0,0),(.5,.1),(.75,3),(1,0)],[(.5,1),(.5,0)],[(.2,.5)]]
        b = bezier_path(path, linestyle='dashed', rgbcolor='green')
        sphinx_plot(b)

    To construct a simple curve, create a list containing a single list::

        sage: path = [[(0,0),(.5,1),(1,0)]]
        sage: curve = bezier_path(path, linestyle='dashed', rgbcolor='green')
        sage: curve
        Graphics object consisting of 1 graphics primitive

    .. PLOT::

        path = [[(0,0),(.5,1),(1,0)]]
        curve = bezier_path(path, linestyle='dashed', rgbcolor='green')
        sphinx_plot(curve)

    Extra options will get passed on to :meth:`~Graphics.show`, as long as they are valid::

        sage: bezier_path([[(0,1),(.5,0),(1,1)]], fontsize=50)
        Graphics object consisting of 1 graphics primitive
        sage: bezier_path([[(0,1),(.5,0),(1,1)]]).show(fontsize=50) # These are equivalent

    .. PLOT::

        sphinx_plot(bezier_path([[(0,1),(.5,0),(1,1)]], fontsize=50))

    TESTS:

    We shouldn't modify our argument, :trac:`13822`::

        sage: bp = [[(1,1),(2,3),(3,3)], [(4,4),(5,5)]]
        sage: foo = bezier_path(bp)
        sage: bp
        [[(1, 1), (2, 3), (3, 3)], [(4, 4), (5, 5)]]

    """
    from sage.plot.all import Graphics
    g = Graphics()
    g._set_extra_kwds(g._extract_kwds_for_show(options))
    g.add_primitive(BezierPath(path, options))
    return g
Beispiel #15
0
def draw_funddom_d(coset_reps, format="MP", z0=I, verbose=0):
    r""" Draw a fundamental domain for self in the circle model
    INPUT:
    - ''format''  -- (default 'Disp') How to present the f.d.
    =  'S'  -- Display directly on the screen
    - z0          -- (default I) the upper-half plane is mapped to the disk by z-->(z-z0)/(z-z0.conjugate())
    EXAMPLES::
        

    sage: G=MySubgroup(Gamma0(3))
    sage: G._draw_funddom_d()
        
    """
    # The fundamental domain consists of copies of the standard fundamental domain
    pi = RR.pi()
    from sage.plot.plot import (Graphics, line)
    g = Graphics()
    bdcirc = _circ_arc(0, 2 * pi, 0, 1, 1000)
    g = g + bdcirc
    # Corners
    x1 = -RR(0.5)
    y1 = RR(sqrt(3) / 2)
    x2 = RR(0.5)
    y2 = RR(sqrt(3) / 2)
    z_inf = 1
    l1 = _geodesic_between_two_points_d(x1, y1, x1, infinity)
    l2 = _geodesic_between_two_points_d(x2, y2, x2, infinity)
    c0 = _geodesic_between_two_points_d(x1, y1, x2, y2)
    tri = c0 + l1 + l2
    g = g + tri
    for A in coset_reps:
        a, b, c, d = A
        if a == 1 and b == 0 and c == 0 and d == 1:
            continue
        if a < 0:
            a = -a
            b = -b
            c = -c
            d = -d
        if verbose > 0:
            print("a,b,c,d={0},{1},{2},{3}".format(a, b, c, d))
        if c == 0:  # then this is easier
            l1 = _geodesic_between_two_points_d(x1 + b, y1, x1 + b, infinity)
            l2 = _geodesic_between_two_points_d(x2 + b, y2, x2 + b, infinity)
            c0 = _geodesic_between_two_points_d(x1 + b, y1, x2 + b, y2)
            # c0=line(L0); l1=line(L1); l2=line(L2); l3=line(L3)
            tri = c0 + l1 + l2
            g = g + tri
        else:
            den = (c * x1 + d)**2 + c**2 * y1**2
            x1_t = (a * c * (x1**2 + y1**2) +
                    (a * d + b * c) * x1 + b * d) / den
            y1_t = y1 / den
            den = (c * x2 + d)**2 + c**2 * y2**2
            x2_t = (a * c * (x2**2 + y2**2) +
                    (a * d + b * c) * x2 + b * d) / den
            y2_t = y2 / den
            inf_t = a / c
            if verbose > 0:
                print("x1_t=", x1_t)
                print("y1_t=", y1_t)
                print("x2_t=", x2_t)
                print("y2_t=", y2_t)
                print("inf_t=", inf_t)
            c0 = _geodesic_between_two_points_d(x1_t, y1_t, x2_t, y2_t)
            c1 = _geodesic_between_two_points_d(x1_t, y1_t, inf_t, 1.0)
            c2 = _geodesic_between_two_points_d(x2_t, y2_t, inf_t, 1.0)
            tri = c0 + c1 + c2
            g = g + tri
    g.xmax(1)
    g.ymax(1)
    g.xmin(-1)
    g.ymin(-1)
    g.set_aspect_ratio(1)
    return g
Beispiel #16
0
def streamline_plot(f_g, xrange, yrange, **options):
    r"""
    Return a streamline plot in a vector field.

    ``streamline_plot`` can take either one or two functions. Consider
    two variables `x` and `y`.

    If given two functions `(f(x,y), g(x,y))`, then this function plots
    streamlines in the vector field over the specified ranges with ``xrange``
    being of `x`, denoted by ``xvar`` below, between ``xmin`` and ``xmax``,
    and ``yrange`` similarly (see below). ::

        streamline_plot((f, g), (xvar, xmin, xmax), (yvar, ymin, ymax))

    Similarly, if given one function `f(x, y)`, then this function plots
    streamlines in the slope field `dy/dx = f(x,y)` over the specified
    ranges as given above.

    PLOT OPTIONS:

    - ``plot_points`` -- (default: 200) the minimal number of plot points

    - ``density`` -- float (default: 1.); controls the closeness of
      streamlines

    - ``start_points`` -- (optional) list of coordinates of starting
      points for the streamlines; coordinate pairs can be tuples or lists

    EXAMPLES:

    Plot some vector fields involving `\sin` and `\cos`::

        sage: x, y = var('x y')
        sage: streamline_plot((sin(x), cos(y)), (x,-3,3), (y,-3,3))
        Graphics object consisting of 1 graphics primitive

    .. PLOT::

        x, y = var('x y')
        g = streamline_plot((sin(x), cos(y)), (x,-3,3), (y,-3,3))
        sphinx_plot(g)

    ::

        sage: streamline_plot((y, (cos(x)-2) * sin(x)), (x,-pi,pi), (y,-pi,pi))
        Graphics object consisting of 1 graphics primitive

    .. PLOT::

        x, y = var('x y')
        g = streamline_plot((y, (cos(x)-2) * sin(x)), (x,-pi,pi), (y,-pi,pi))
        sphinx_plot(g)

    We increase the density of the plot::

        sage: streamline_plot((y, (cos(x)-2) * sin(x)), (x,-pi,pi), (y,-pi,pi), density=2)
        Graphics object consisting of 1 graphics primitive

    .. PLOT::

        x, y = var('x y')
        g = streamline_plot((y, (cos(x)-2) * sin(x)), (x,-pi,pi), (y,-pi,pi), density=2)
        sphinx_plot(g)

    We ignore function values that are infinite or NaN::

        sage: x, y = var('x y')
        sage: streamline_plot((-x/sqrt(x^2+y^2), -y/sqrt(x^2+y^2)), (x,-10,10), (y,-10,10))
        Graphics object consisting of 1 graphics primitive

    .. PLOT::

        x, y = var('x y')
        g = streamline_plot((-x/sqrt(x**2+y**2), -y/sqrt(x**2+y**2)), (x,-10,10), (y,-10,10))
        sphinx_plot(g)

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

        sage: streamline_plot((x, y), (x,-2,2), (y,-2,2), xmax=10)
        Graphics object consisting of 1 graphics primitive
        sage: streamline_plot((x, y), (x,-2,2), (y,-2,2)).show(xmax=10) # These are equivalent

    .. PLOT::

        x, y = var('x y')
        g = streamline_plot((x, y), (x,-2,2), (y,-2,2), xmax=10)
        sphinx_plot(g)

    We can also construct streamlines in a slope field::

        sage: x, y = var('x y')
        sage: streamline_plot((x + y) / sqrt(x^2 + y^2), (x,-3,3), (y,-3,3))
        Graphics object consisting of 1 graphics primitive

    .. PLOT::

        x, y = var('x y')
        g = streamline_plot((x + y) / sqrt(x**2 + y**2), (x,-3,3), (y,-3,3))
        sphinx_plot(g)

    We choose some particular points the streamlines pass through::

        sage: pts = [[1, 1], [-2, 2], [1, -3/2]]
        sage: g = streamline_plot((x + y) / sqrt(x^2 + y^2), (x,-3,3), (y,-3,3), start_points=pts)
        sage: g += point(pts, color='red')
        sage: g
        Graphics object consisting of 2 graphics primitives

    .. PLOT::

        x, y = var('x y')
        pts = [[1, 1], [-2, 2], [1, -3/2]]
        g = streamline_plot((x + y) / sqrt(x**2 + y**2), (x,-3,3), (y,-3,3), start_points=pts)
        g += point(pts, color='red')
        sphinx_plot(g)

    .. NOTE::

        Streamlines currently pass close to ``start_points`` but do
        not necessarily pass directly through them. That is part of
        the behavior of matplotlib, not an error on your part.

    """
    # Parse the function input
    if isinstance(f_g, (list, tuple)):
        (f, g) = f_g
    else:
        from sage.functions.all import sqrt
        from inspect import isfunction
        if isfunction(f_g):
            f = lambda x, y: 1 / sqrt(f_g(x, y)**2 + 1)
            g = lambda x, y: f_g(x, y) * f(x, y)
        else:
            f = 1 / sqrt(f_g**2 + 1)
            g = f_g * f

    from sage.plot.all import Graphics
    from sage.plot.misc import setup_for_eval_on_grid
    z, ranges = setup_for_eval_on_grid([f, g], [xrange, yrange],
                                       options['plot_points'])
    f, g = z

    # The density values must be floats
    if isinstance(options['density'], (list, tuple)):
        options['density'] = [float(x) for x in options['density']]
    else:
        options['density'] = float(options['density'])

    xpos_array, ypos_array, xvec_array, yvec_array = [], [], [], []
    for x in xsrange(*ranges[0], include_endpoint=True):
        xpos_array.append(x)
    for y in xsrange(*ranges[1], include_endpoint=True):
        ypos_array.append(y)
        xvec_row, yvec_row = [], []
        for x in xsrange(*ranges[0], include_endpoint=True):
            xvec_row.append(f(x, y))
            yvec_row.append(g(x, y))
        xvec_array.append(xvec_row)
        yvec_array.append(yvec_row)

    import numpy
    xpos_array = numpy.array(xpos_array, dtype=float)
    ypos_array = numpy.array(ypos_array, dtype=float)
    xvec_array = numpy.ma.masked_invalid(numpy.array(xvec_array, dtype=float))
    yvec_array = numpy.ma.masked_invalid(numpy.array(yvec_array, dtype=float))

    if 'start_points' in options:
        xstart_array, ystart_array = [], []
        for point in options['start_points']:
            xstart_array.append(point[0])
            ystart_array.append(point[1])
        options['start_points'] = numpy.array([xstart_array, ystart_array]).T

    g = Graphics()
    g._set_extra_kwds(Graphics._extract_kwds_for_show(options))
    g.add_primitive(
        StreamlinePlot(xpos_array, ypos_array, xvec_array, yvec_array,
                       options))
    return g
Beispiel #17
0
def bezier_path(path, **options):
    """
    Returns a Graphics object of a Bezier path corresponding to the
    path parameter.  The path is a list of curves, and each curve is
    a list of points.  Each point is a tuple ``(x,y)``.

    The first curve contains the endpoints as the first and last point
    in the list.  All other curves assume a starting point given by the
    last entry in the preceding list, and take the last point in the list
    as their opposite endpoint.  A curve can have 0, 1 or 2 control points
    listed between the endpoints.  In the input example for path below,
    the first and second curves have 2 control points, the third has one,
    and the fourth has no control points:

    path = [[p1, c1, c2, p2], [c3, c4, p3], [c5, p4], [p5], ...]

    In the case of no control points, a straight line will be drawn
    between the two endpoints.  If one control point is supplied, then
    the curve at each of the endpoints will be tangent to the line from
    that endpoint to the control point.  Similarly, in the case of two
    control points, at each endpoint the curve will be tangent to the line
    connecting that endpoint with the control point immediately after or
    immediately preceding it in the list.

    So in our example above, the curve between p1 and p2 is tangent to the
    line through p1 and c1 at p1, and tangent to the line through p2 and c2
    at p2.  Similarly, the curve between p2 and p3 is tangent to line(p2,c3)
    at p2 and tangent to line(p3,c4) at p3.  Curve(p3,p4) is tangent to
    line(p3,c5) at p3 and tangent to line(p4,c5) at p4.  Curve(p4,p5) is a
    straight line.

    INPUT:

    - ``path`` -- a list of lists of tuples (see above)
    - ``alpha`` -- default: 1
    - ``fill`` -- default: False
    - ``thickness`` -- default: 1
    - ``linestyle`` -- default: 'solid'
    - ``rbgcolor`` -- default: (0,0,0)
    - ``zorder`` -- the layer in which to draw

    EXAMPLES::

        sage: path = [[(0,0),(.5,.1),(.75,3),(1,0)],[(.5,1),(.5,0)],[(.2,.5)]]
        sage: b = bezier_path(path, linestyle='dashed', rgbcolor='green')
        sage: b

    To construct a simple curve, create a list containing a single list::

        sage: path = [[(0,0),(.5,1),(1,0)]]
        sage: curve = bezier_path(path, linestyle='dashed', rgbcolor='green')
        sage: curve

    Extra options will get passed on to :meth:`~Graphics.show`, as long as they are valid::

        sage: bezier_path([[(0,1),(.5,0),(1,1)]], fontsize=50)
        sage: bezier_path([[(0,1),(.5,0),(1,1)]]).show(fontsize=50) # These are equivalent
    """
    from sage.plot.all import Graphics
    g = Graphics()
    g._set_extra_kwds(g._extract_kwds_for_show(options))
    g.add_primitive(BezierPath(path, options))
    return g
Beispiel #18
0
def draw_funddom_d(coset_reps,format="MP",z0=I,verbose=0):
    r""" Draw a fundamental domain for self in the circle model
    INPUT:
    - ''format''  -- (default 'Disp') How to present the f.d.
    =  'S'  -- Display directly on the screen
    - z0          -- (default I) the upper-half plane is mapped to the disk by z-->(z-z0)/(z-z0.conjugate())
    EXAMPLES::
        

    sage: G=MySubgroup(Gamma0(3))
    sage: G._draw_funddom_d()
        
    """
    # The fundamental domain consists of copies of the standard fundamental domain
    pi=RR.pi()
    from sage.plot.plot import (Graphics,line)
    g=Graphics()
    bdcirc=_circ_arc(0 ,2 *pi,0 ,1 ,1000 )
    g=g+bdcirc
    # Corners
    x1=-RR(0.5); y1=RR(sqrt(3 )/2)
    x2=RR(0.5); y2=RR(sqrt(3 )/2)
    z_inf=1 
    l1 = _geodesic_between_two_points_d(x1,y1,x1,infinity)
    l2 = _geodesic_between_two_points_d(x2,y2,x2,infinity)
    c0 = _geodesic_between_two_points_d(x1,y1,x2,y2)
    tri=c0+l1+l2
    g=g+tri
    for A in coset_reps:
        a,b,c,d=A
        if a==1  and b==0  and c==0  and d==1:
            continue
        if a<0:
            a=-a; b=-b; c=-c; d=-d 
        if verbose>0:
                print "a,b,c,d=",a,b,c,d
        if c==0: # then this is easier
            l1 = _geodesic_between_two_points_d(x1+b,y1,x1+b,infinity)
            l2 = _geodesic_between_two_points_d(x2+b,y2,x2+b,infinity)
            c0 = _geodesic_between_two_points_d(x1+b,y1,x2+b,y2)
            # c0=line(L0); l1=line(L1); l2=line(L2); l3=line(L3)
            tri=c0+l1+l2
            g=g+tri
        else:
            den=(c*x1+d)**2 +c**2 *y1**2 
            x1_t=(a*c*(x1**2 +y1**2 )+(a*d+b*c)*x1+b*d)/den
            y1_t=y1/den
            den=(c*x2+d)**2 +c**2 *y2**2 
            x2_t=(a*c*(x2**2 +y2**2 )+(a*d+b*c)*x2+b*d)/den
            y2_t=y2/den            
            inf_t=a/c
            if verbose>0:
                    print "x1_t=",x1_t
                    print "y1_t=",y1_t
                    print "x2_t=",x2_t
                    print "y2_t=",y2_t
                    print "inf_t=",inf_t
            c0=_geodesic_between_two_points_d(x1_t,y1_t,x2_t,y2_t)
            c1=_geodesic_between_two_points_d(x1_t,y1_t,inf_t,1.0 )
            c2=_geodesic_between_two_points_d(x2_t,y2_t,inf_t,1.0 )
            tri=c0+c1+c2
            g=g+tri
    g.xmax(1 )
    g.ymax(1 )
    g.xmin(-1 )
    g.ymin(-1 )
    g.set_aspect_ratio(1 )
    return g
Beispiel #19
0
def region_plot(f, xrange, yrange, plot_points, incol, outcol, bordercol, borderstyle, borderwidth,**options):
    r"""
    ``region_plot`` takes a boolean function of two variables, `f(x,y)`
    and plots the region where f is True over the specified
    ``xrange`` and ``yrange`` as demonstrated below.

    ``region_plot(f, (xmin, xmax), (ymin, ymax), ...)``

    INPUT:

    - ``f`` -- a boolean function of two variables

    - ``(xmin, xmax)`` -- 2-tuple, the range of ``x`` values OR 3-tuple
      ``(x,xmin,xmax)``

    - ``(ymin, ymax)`` -- 2-tuple, the range of ``y`` values OR 3-tuple
      ``(y,ymin,ymax)``

    - ``plot_points``  -- integer (default: 100); number of points to plot
      in each direction of the grid

    - ``incol`` -- a color (default: ``'blue'``), the color inside the region

    - ``outcol`` -- a color (default: ``'white'``), the color of the outside
      of the region

    If any of these options are specified, the border will be shown as indicated,
    otherwise it is only implicit (with color ``incol``) as the border of the
    inside of the region.

     - ``bordercol`` -- a color (default: ``None``), the color of the border
       (``'black'`` if ``borderwidth`` or ``borderstyle`` is specified but not ``bordercol``)

    - ``borderstyle``  -- string (default: 'solid'), one of ``'solid'``,
      ``'dashed'``, ``'dotted'``, ``'dashdot'``, respectively ``'-'``,
      ``'--'``, ``':'``, ``'-.'``.

    - ``borderwidth``  -- integer (default: None), the width of the border in pixels

    - ``legend_label`` -- the label for this item in the legend

    - ``base`` - (default: 10) the base of the logarithm if
      a logarithmic scale is set. This must be greater than 1. The base
      can be also given as a list or tuple ``(basex, basey)``.
      ``basex`` sets the base of the logarithm along the horizontal
      axis and ``basey`` sets the base along the vertical axis.

    - ``scale`` -- (default: ``"linear"``) string. The scale of the axes.
      Possible values are ``"linear"``, ``"loglog"``, ``"semilogx"``,
      ``"semilogy"``.

      The scale can be also be given as single argument that is a list
      or tuple ``(scale, base)`` or ``(scale, basex, basey)``.

      The ``"loglog"`` scale sets both the horizontal and vertical axes to
      logarithmic scale. The ``"semilogx"`` scale sets the horizontal axis
      to logarithmic scale. The ``"semilogy"`` scale sets the vertical axis
      to logarithmic scale. The ``"linear"`` scale is the default value
      when :class:`~sage.plot.graphics.Graphics` is initialized.


    EXAMPLES:

    Here we plot a simple function of two variables::

        sage: x,y = var('x,y')
        sage: region_plot(cos(x^2+y^2) <= 0, (x, -3, 3), (y, -3, 3))

    Here we play with the colors::

        sage: region_plot(x^2+y^3 < 2, (x, -2, 2), (y, -2, 2), incol='lightblue', bordercol='gray')

    An even more complicated plot, with dashed borders::

        sage: region_plot(sin(x)*sin(y) >= 1/4, (x,-10,10), (y,-10,10), incol='yellow', bordercol='black', borderstyle='dashed', plot_points=250)

    A disk centered at the origin::

        sage: region_plot(x^2+y^2<1, (x,-1,1), (y,-1,1))

    A plot with more than one condition (all conditions must be true for the statement to be true)::

        sage: region_plot([x^2+y^2<1, x<y], (x,-2,2), (y,-2,2))

    Since it doesn't look very good, let's increase ``plot_points``::

        sage: region_plot([x^2+y^2<1, x<y], (x,-2,2), (y,-2,2), plot_points=400)

    To get plots where only one condition needs to be true, use a function.
    Using lambda functions, we definitely need the extra ``plot_points``::

        sage: region_plot(lambda x,y: x^2+y^2<1 or x<y, (x,-2,2), (y,-2,2), plot_points=400)

    The first quadrant of the unit circle::

        sage: region_plot([y>0, x>0, x^2+y^2<1], (x,-1.1, 1.1), (y,-1.1, 1.1), plot_points = 400)

    Here is another plot, with a huge border::

        sage: region_plot(x*(x-1)*(x+1)+y^2<0, (x, -3, 2), (y, -3, 3), incol='lightblue', bordercol='gray', borderwidth=10, plot_points=50)

    If we want to keep only the region where x is positive::

        sage: region_plot([x*(x-1)*(x+1)+y^2<0, x>-1], (x, -3, 2), (y, -3, 3), incol='lightblue', plot_points=50)

    Here we have a cut circle::

        sage: region_plot([x^2+y^2<4, x>-1], (x, -2, 2), (y, -2, 2), incol='lightblue', bordercol='gray', plot_points=200)

    The first variable range corresponds to the horizontal axis and
    the second variable range corresponds to the vertical axis::

        sage: s,t=var('s,t')
        sage: region_plot(s>0,(t,-2,2),(s,-2,2))

    ::

        sage: region_plot(s>0,(s,-2,2),(t,-2,2))

    An example of a region plot in 'loglog' scale::

        sage: region_plot(x^2+y^2<100, (x,1,10), (y,1,10), scale='loglog')

    """

    from sage.plot.all import Graphics
    from sage.plot.misc import setup_for_eval_on_grid
    import numpy

    if not isinstance(f, (list, tuple)):
        f = [f]

    f = [equify(g) for g in f]

    g, ranges = setup_for_eval_on_grid(f, [xrange, yrange], plot_points)
    xrange,yrange=[r[:2] for r in ranges]

    xy_data_arrays = numpy.asarray([[[func(x, y) for x in xsrange(*ranges[0], include_endpoint=True)]
                                     for y in xsrange(*ranges[1], include_endpoint=True)]
                                    for func in g],dtype=float)
    xy_data_array=numpy.abs(xy_data_arrays.prod(axis=0))
    # Now we need to set entries to negative iff all
    # functions were negative at that point.
    neg_indices = (xy_data_arrays<0).all(axis=0)
    xy_data_array[neg_indices]=-xy_data_array[neg_indices]

    from matplotlib.colors import ListedColormap
    incol = rgbcolor(incol)
    outcol = rgbcolor(outcol)
    cmap = ListedColormap([incol, outcol])
    cmap.set_over(outcol)
    cmap.set_under(incol)

    g = 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'

    g._set_extra_kwds(Graphics._extract_kwds_for_show(options, ignore=['xmin', 'xmax']))
    g.add_primitive(ContourPlot(xy_data_array, xrange,yrange,
                                dict(contours=[-1e307, 0, 1e307], cmap=cmap, fill=True, **options)))

    if bordercol or borderstyle or borderwidth:
        cmap = [rgbcolor(bordercol)] if bordercol else ['black']
        linestyles = [borderstyle] if borderstyle else None
        linewidths = [borderwidth] if borderwidth else None
        g.add_primitive(ContourPlot(xy_data_array, xrange, yrange,
                                    dict(linestyles=linestyles, linewidths=linewidths,
                                         contours=[0], cmap=[bordercol], fill=False, **options)))

    return g
Beispiel #20
0
    def plot_walls(self, walls):
        r"""
        Plot ``walls``, i.e. 2-d cones, and their labels.

        Ray generators must be specified during construction or using
        :meth:`set_rays` before calling this method and these specified
        ray generators will be used in conjunction with
        :meth:`~sage.geometry.cone.ConvexRationalPolyhedralCone.ambient_ray_indices`
        of ``walls``.

        INPUT:

        - ``walls`` -- a list of 2-d cones.

        OUTPUT:

        - a plot.

        EXAMPLES::

            sage: quadrant = Cone([(1,0), (0,1)])
            sage: from sage.geometry.toric_plotter import ToricPlotter
            sage: tp = ToricPlotter(dict(), 2, quadrant.rays())
            sage: print tp.plot_walls([quadrant])
            Graphics object consisting of 2 graphics primitives
            
        Let's also check that the truncating polyhedron is functioning
        correctly::
        
            sage: tp = ToricPlotter({"mode": "box"}, 2, quadrant.rays())
            sage: print tp.plot_walls([quadrant])
            Graphics object consisting of 2 graphics primitives
        """
        result = Graphics()
        if not walls or not self.show_walls:
            return result
        rays = self.rays
        extra_options = self.extra_options
        mode = self.mode
        alpha = self.wall_alpha
        colors = color_list(self.wall_color, len(walls))
        zorder = self.wall_zorder
        if mode == "box":
            if self.dimension <= 2:
                ieqs = [(self.xmax, -1, 0), (- self.xmin, 1, 0),
                        (self.ymax, 0, -1), (- self.ymin, 0, 1)]
            else:
                ieqs = [(self.xmax, -1, 0, 0), (- self.xmin, 1, 0, 0),
                        (self.ymax, 0, -1, 0), (- self.ymin, 0, 1, 0),
                        (self.zmax, 0, 0, -1), (- self.zmin, 0, 0, 1)]
            box = Polyhedron(ieqs=ieqs, base_ring=RDF)
            for wall, color in zip(walls, colors):
                result += box.intersection(wall.polyhedron()).render_solid(
                    alpha=alpha, color=color, zorder=zorder, **extra_options)
        elif mode == "generators":
            origin = self.origin
            for wall, color in zip(walls, colors):
                vertices = [rays[i] for i in wall.ambient_ray_indices()]
                vertices.append(origin)
                result += Polyhedron(vertices=vertices, base_ring=RDF).render_solid(
                    alpha=alpha, color=color, zorder=zorder, **extra_options)
        label_sectors = []
        round = mode == "round"
        for wall, color in zip(walls, colors):
            S = wall.linear_subspace()
            lsd = S.dimension()
            if lsd == 0:    # Strictly convex wall
                r1, r2 = (rays[i] for i in wall.ambient_ray_indices())
            elif lsd == 1:  # wall is a half-plane
                for i, ray in zip(wall.ambient_ray_indices(), wall.rays()):
                    if ray in S:
                        r1 = rays[i]
                    else:
                        r2 = rays[i]
                if round:
                    # Plot one "extra" sector
                    result += sector(- r1, r2,
                      alpha=alpha, color=color, zorder=zorder, **extra_options)
            else:           # wall is a plane
                r1, r2 = S.basis()
                r1 = vector(RDF, r1)
                r1 = r1 / r1.norm() * self.radius
                r2 = vector(RDF, r2)
                r2 = r2 / r2.norm() * self.radius
                if round:
                    # Plot three "extra" sectors
                    result += sector(r1, - r2,
                      alpha=alpha, color=color, zorder=zorder, **extra_options)
                    result += sector(- r1, r2,
                      alpha=alpha, color=color, zorder=zorder, **extra_options)
                    result += sector(- r1, - r2,
                      alpha=alpha, color=color, zorder=zorder, **extra_options)
            label_sectors.append([r1, r2])
            if round:
                result += sector(r1, r2,
                    alpha=alpha, color=color, zorder=zorder, **extra_options)
        result += self.plot_labels(self.wall_label,
                    [sum(label_sector) / 3 for label_sector in label_sectors])
        return result
Beispiel #21
0
def bezier_path(path, **options):
    """
    Returns a Graphics object of a Bezier path corresponding to the
    path parameter.  The path is a list of curves, and each curve is
    a list of points.  Each point is a tuple ``(x,y)``.
    
    The first curve contains the endpoints as the first and last point 
    in the list.  All other curves assume a starting point given by the
    last entry in the preceding list, and take the last point in the list
    as their opposite endpoint.  A curve can have 0, 1 or 2 control points
    listed between the endpoints.  In the input example for path below, 
    the first and second curves have 2 control points, the third has one,
    and the fourth has no control points:    
    
    path = [[p1, c1, c2, p2], [c3, c4, p3], [c5, p4], [p5], ...]
    
    In the case of no control points, a straight line will be drawn
    between the two endpoints.  If one control point is supplied, then 
    the curve at each of the endpoints will be tangent to the line from
    that endpoint to the control point.  Similarly, in the case of two 
    control points, at each endpoint the curve will be tangent to the line
    connecting that endpoint with the control point immediately after or
    immediately preceding it in the list.
    
    So in our example above, the curve between p1 and p2 is tangent to the
    line through p1 and c1 at p1, and tangent to the line through p2 and c2
    at p2.  Similarly, the curve between p2 and p3 is tangent to line(p2,c3)
    at p2 and tangent to line(p3,c4) at p3.  Curve(p3,p4) is tangent to 
    line(p3,c5) at p3 and tangent to line(p4,c5) at p4.  Curve(p4,p5) is a
    straight line.
    
    INPUT:

    - ``path`` -- a list of lists of tuples (see above)
    - ``alpha`` -- default: 1
    - ``fill`` -- default: False
    - ``thickness`` -- default: 1
    - ``linestyle`` -- default: 'solid'
    - ``rbgcolor`` -- default: (0,0,0)
    - ``zorder`` -- the layer in which to draw
        
    EXAMPLES::

        sage: path = [[(0,0),(.5,.1),(.75,3),(1,0)],[(.5,1),(.5,0)],[(.2,.5)]]
        sage: b = bezier_path(path, linestyle='dashed', rgbcolor='green')
        sage: b

    To construct a simple curve, create a list containing a single list::
        
        sage: path = [[(0,0),(.5,1),(1,0)]]
        sage: curve = bezier_path(path, linestyle='dashed', rgbcolor='green')
        sage: curve

    Extra options will get passed on to :meth:`~Graphics.show`, as long as they are valid::

        sage: bezier_path([[(0,1),(.5,0),(1,1)]], fontsize=50)
        sage: bezier_path([[(0,1),(.5,0),(1,1)]]).show(fontsize=50) # These are equivalent
    """
    from sage.plot.all import Graphics
    g = Graphics()
    g._set_extra_kwds(g._extract_kwds_for_show(options))
    g.add_primitive(BezierPath(path, options))
    return g
Beispiel #22
0
def matrix_plot(mat, **options):
    r"""
    A plot of a given matrix or 2D array.

    If the matrix is dense, each matrix element is given a different
    color value depending on its relative size compared to the other
    elements in the matrix.  If the matrix is sparse, colors only
    indicate whether an element is nonzero or zero, so the plot
    represents the sparsity pattern of the matrix.

    The tick marks drawn on the frame axes denote the row numbers
    (vertical ticks) and the column numbers (horizontal ticks) of the
    matrix.

    INPUT:

    - ``mat`` - a 2D matrix or array

    The following input must all be passed in as named parameters, if
    default not used:

    - ``cmap`` - a colormap (default: 'gray'), the name of
      a predefined colormap, a list of colors,
      or an instance of a matplotlib Colormap.
      Type: ``import matplotlib.cm; matplotlib.cm.datad.keys()``
      for available colormap names.

    - ``colorbar`` -- boolean (default: False) Show a colorbar or not (dense matrices only).

      The following options are used to adjust the style and placement
      of colorbars.  They have no effect if a colorbar is not shown.

      - ``colorbar_orientation`` -- string (default: 'vertical'),
        controls placement of the colorbar, can be either 'vertical'
        or 'horizontal'

      - ``colorbar_format`` -- a format string, this is used to format
        the colorbar labels.

      - ``colorbar_options`` -- a dictionary of options for the matplotlib
        colorbar API.  Documentation for the :mod:`matplotlib.colorbar` module
        has details.

    - ``norm`` - If None (default), the value range is scaled to the interval
      [0,1].  If 'value', then the actual value is used with no
      scaling.  A :class:`matplotlib.colors.Normalize` instance may
      also passed.

    - ``vmin`` - The minimum value (values below this are set to this value)

    - ``vmax`` - The maximum value (values above this are set to this value)

    - ``origin`` - If 'upper' (default), the first row of the matrix
      is on the top of the graph.  If 'lower', the first row is on the
      bottom of the graph.

    - ``subdivisions`` - If True, plot the subdivisions of the matrix as lines.

    - ``subdivision_boundaries`` - a list of lists in the form
      ``[row_subdivisions, column_subdivisions]``, which specifies
      the row and column subdivisions to use.  If not specified,
      defaults to the matrix subdivisions

    - ``subdivision_style`` - a dictionary of properties passed
      on to the :func:`~sage.plot.line.line2d` command for plotting
      subdivisions.  If this is a two-element list or tuple, then it
      specifies the styles of row and column divisions, respectively.

    EXAMPLES:

    A matrix over `\ZZ` colored with different grey levels::

        sage: matrix_plot(matrix([[1,3,5,1],[2,4,5,6],[1,3,5,7]]))

    Here we make a random matrix over `\RR` and use ``cmap='hsv'``
    to color the matrix elements different RGB colors::

        sage: matrix_plot(random_matrix(RDF, 50), cmap='hsv')

    By default, entries are scaled to the interval [0,1] before
    determining colors from the color map.  That means the two plots
    below are the same::

        sage: P = matrix_plot(matrix(2,[1,1,3,3]))
        sage: Q = matrix_plot(matrix(2,[2,2,3,3]))
        sage: P; Q

    However, we can specify which values scale to 0 or 1 with the
    ``vmin`` and ``vmax`` parameters (values outside the range are
    clipped).  The two plots below are now distinguished::

        sage: P = matrix_plot(matrix(2,[1,1,3,3]), vmin=0, vmax=3, colorbar=True)
        sage: Q = matrix_plot(matrix(2,[2,2,3,3]), vmin=0, vmax=3, colorbar=True)
        sage: P; Q

    We can also specify a norm function of 'value', which means that
    there is no scaling performed::

        sage: matrix_plot(random_matrix(ZZ,10)*.05, norm='value', colorbar=True)

    Matrix subdivisions can be plotted as well::

        sage: m=random_matrix(RR,10)
        sage: m.subdivide([2,4],[6,8])
        sage: matrix_plot(m, subdivisions=True, subdivision_style=dict(color='red',thickness=3))

    You can also specify your own subdivisions and separate styles
    for row or column subdivisions::

        sage: m=random_matrix(RR,10)
        sage: matrix_plot(m, subdivisions=True, subdivision_boundaries=[[2,4],[6,8]], subdivision_style=[dict(color='red',thickness=3),dict(linestyle='--',thickness=6)])

    Generally matrices are plotted with the (0,0) entry in the upper
    left.  However, sometimes if we are plotting an image, we'd like
    the (0,0) entry to be in the lower left.  We can do that with the
    ``origin`` argument::

        sage: matrix_plot(identity_matrix(100), origin='lower')

    Another random plot, but over `\GF{389}`::

        sage: m = random_matrix(GF(389), 10)
        sage: matrix_plot(m, cmap='Oranges')

    It also works if you lift it to the polynomial ring::

        sage: matrix_plot(m.change_ring(GF(389)['x']), cmap='Oranges')

    We have several options for colorbars::

        sage: matrix_plot(random_matrix(RDF, 50), colorbar=True, colorbar_orientation='horizontal')

    ::

        sage: matrix_plot(random_matrix(RDF, 50), colorbar=True, colorbar_format='%.3f')

    The length of a color bar and the length of the adjacent
    matrix plot dimension may be quite different.  This example
    shows how to adjust the length of the colorbar by passing a
    dictionary of options to the matplotlib colorbar routines.  ::

        sage: m = random_matrix(ZZ, 40, 80, x=-10, y=10)
        sage: m.plot(colorbar=True, colorbar_orientation='vertical',
        ...          colorbar_options={'shrink':0.50})

    Here we plot a random sparse matrix::

        sage: sparse = matrix(dict([((randint(0, 10), randint(0, 10)), 1) for i in xrange(100)]))
        sage: matrix_plot(sparse)

    ::

        sage: A=random_matrix(ZZ,100000,density=.00001,sparse=True)
        sage: matrix_plot(A,marker=',')

    As with dense matrices, sparse matrix entries are automatically
    converted to floating point numbers before plotting.  Thus the
    following works::

        sage: b=random_matrix(GF(2),200,sparse=True,density=0.01)
        sage: matrix_plot(b)

    While this returns an error::

        sage: b=random_matrix(CDF,200,sparse=True,density=0.01)
        sage: matrix_plot(b)
        Traceback (most recent call last):
        ...
        ValueError: can not convert entries to floating point numbers

    To plot the absolute value of a complex matrix, use the
    ``apply_map`` method::

        sage: b=random_matrix(CDF,200,sparse=True,density=0.01)
        sage: matrix_plot(b.apply_map(abs))

    Plotting lists of lists also works::

        sage: matrix_plot([[1,3,5,1],[2,4,5,6],[1,3,5,7]])

    As does plotting of NumPy arrays::

        sage: import numpy
        sage: matrix_plot(numpy.random.rand(10, 10))

    A plot title can be added to the matrix plot.::

        sage: matrix_plot(identity_matrix(50), origin='lower', title='not identity')

    The title position is adjusted upwards if the ``origin`` keyword is set
    to ``"upper"`` (this is the default).::

        sage: matrix_plot(identity_matrix(50), title='identity')

    TESTS::

        sage: P.<t> = RR[]
        sage: matrix_plot(random_matrix(P, 3, 3))
        Traceback (most recent call last):
        ...
        TypeError: cannot coerce nonconstant polynomial to float

    ::

        sage: matrix_plot([1,2,3])
        Traceback (most recent call last):
        ...
        TypeError: mat must be a Matrix or a two dimensional array

    ::

        sage: matrix_plot([[sin(x), cos(x)], [1, 0]])
        Traceback (most recent call last):
        ...
        TypeError: mat must be a Matrix or a two dimensional array

    Test that sparse matrices also work with subdivisions::

        sage: matrix_plot(sparse, subdivisions=True, subdivision_boundaries=[[2,4],[6,8]])
    """
    import numpy as np
    import scipy.sparse as scipysparse
    from sage.plot.all import Graphics
    from sage.matrix.matrix import is_Matrix
    from sage.rings.all import RDF
    orig_mat = mat
    if is_Matrix(mat):
        sparse = mat.is_sparse()
        if sparse:
            entries = list(mat._dict().items())
            try:
                data = np.asarray([d for _, d in entries], dtype=float)
            except Exception:
                raise ValueError(
                    "can not convert entries to floating point numbers")
            positions = np.asarray([[row for (row, col), _ in entries],
                                    [col for (row, col), _ in entries]],
                                   dtype=int)
            mat = scipysparse.coo_matrix((data, positions),
                                         shape=(mat.nrows(), mat.ncols()))
        else:
            mat = mat.change_ring(RDF).numpy()
    elif hasattr(mat, 'tocoo'):
        sparse = True
    else:
        sparse = False

    try:
        if sparse:
            xy_data_array = mat
        else:
            xy_data_array = np.asarray(mat, dtype=float)
    except TypeError:
        raise TypeError("mat must be a Matrix or a two dimensional array")
    except ValueError:
        raise ValueError("can not convert entries to floating point numbers")

    if len(xy_data_array.shape) < 2:
        raise TypeError("mat must be a Matrix or a two dimensional array")

    xrange = (0, xy_data_array.shape[1])
    yrange = (0, xy_data_array.shape[0])

    if options['subdivisions'] and options['subdivision_options'][
            'boundaries'] is None:
        options['subdivision_options'][
            'boundaries'] = orig_mat.get_subdivisions()

    # Custom position the title. Otherwise it overlaps with tick labels
    if options['origin'] == 'upper' and 'title_pos' not in options:
        options['title_pos'] = (0.5, 1.05)

    g = Graphics()
    g._set_extra_kwds(Graphics._extract_kwds_for_show(options))
    g.add_primitive(MatrixPlot(xy_data_array, xrange, yrange, options))
    return g
Beispiel #23
0
def text(string, xy, **options):
    r"""
    Returns a 2D text graphics object at the point `(x,y)`.

    Type ``text.options`` for a dictionary of options for 2D text.

    2D OPTIONS:

    - ``fontsize`` - How big the text is. Either an integer that
      specifies the size in points or a string which specifies a size (one of
      'xx-small', 'x-small', 'small', 'medium', 'large', 'x-large', 'xx-large')

    - ``fontstyle`` - A string either 'normal', 'italic' or 'oblique'

    - ``fontweight`` - A numeric value in the range 0-1000 or a string (one of
      'ultralight', 'light', 'normal', 'regular', 'book',' 'medium', 'roman',
      'semibold', 'demibold', 'demi', 'bold', 'heavy', 'extra bold', 'black')

    - ``rgbcolor`` - The color as an RGB tuple

    - ``hue`` - The color given as a hue

    - ``alpha`` - A float (0.0 transparent through 1.0 opaque)

    - ``background_color`` - The background color

    - ``rotation`` - How to rotate the text: angle in degrees, vertical, horizontal

    - ``vertical_alignment`` - How to align vertically: top, center, bottom

    - ``horizontal_alignment`` - How to align horizontally: left, center, right

    - ``zorder`` - The layer level in which to draw

    - ``clip`` - (default: False) Whether to clip or not

    - ``axis_coords`` - (default: False) If True, use axis coordinates, so that
      (0,0) is the lower left and (1,1) upper right, regardless of the x and y
      range of plotted values.

    - ``bounding_box`` - A dictionary specifying a bounding box. Currently the text location.

    EXAMPLES::

        sage: text("Sage graphics are really neat because they use matplotlib!", (2,12))
        Graphics object consisting of 1 graphics primitive

    .. PLOT::

        t = "Sage graphics are really neat because they use matplotlib!"
        sphinx_plot(text(t,(2,12)))

    Larger font, bold, colored red and transparent text::

        sage: text("I had a dream!", (2,12), alpha=0.3, fontsize='large', fontweight='bold', color='red')
        Graphics object consisting of 1 graphics primitive

    .. PLOT::

        sphinx_plot(text("I had a dream!", (2,12), alpha=0.3, fontsize='large', fontweight='bold', color='red'))

    By setting ``horizontal_alignment`` to 'left' the text is guaranteed to be
    in the lower left no matter what::

        sage: text("I got a horse and he lives in a tree", (0,0), axis_coords=True, horizontal_alignment='left')
        Graphics object consisting of 1 graphics primitive

    .. PLOT::

        t = "I got a horse and he lives in a tree"
        sphinx_plot(text(t, (0,0), axis_coords=True, horizontal_alignment='left'))

    Various rotations::

        sage: text("noitator", (0,0), rotation=45.0, horizontal_alignment='left', vertical_alignment='bottom')
        Graphics object consisting of 1 graphics primitive

    .. PLOT::

        sphinx_plot(text("noitator", (0,0), rotation=45.0, horizontal_alignment='left', vertical_alignment='bottom'))

    ::

        sage: text("Sage is really neat!!",(0,0), rotation="vertical")
        Graphics object consisting of 1 graphics primitive

    .. PLOT::

        sphinx_plot(text("Sage is really neat!!",(0,0), rotation="vertical"))

    You can also align text differently::

        sage: t1 = text("Hello",(1,1), vertical_alignment="top")
        sage: t2 = text("World", (1,0.5), horizontal_alignment="left")
        sage: t1 + t2   # render the sum
        Graphics object consisting of 2 graphics primitives

    .. PLOT::

        t1 = text("Hello",(1,1), vertical_alignment="top")
        t2 = text("World", (1,0.5), horizontal_alignment="left")
        sphinx_plot(t1 + t2)

    You can save text as part of PDF output::

        sage: text("sage", (0,0), rgbcolor=(0,0,0)).save(os.path.join(SAGE_TMP, 'a.pdf'))

    Some examples of bounding box::

        sage: bbox = {'boxstyle':"rarrow,pad=0.3", 'fc':"cyan", 'ec':"b", 'lw':2}
        sage: text("I feel good", (1,2), bounding_box=bbox)
        Graphics object consisting of 1 graphics primitive

    .. PLOT::

         bbox = {'boxstyle':"rarrow,pad=0.3", 'fc':"cyan", 'ec':"b", 'lw':2}
         sphinx_plot(text("I feel good", (1,2), bounding_box=bbox))

    ::

        sage: text("So good", (0,0), bounding_box={'boxstyle':'round', 'fc':'w'})
        Graphics object consisting of 1 graphics primitive

    .. PLOT::

        bbox = {'boxstyle':'round', 'fc':'w'}
        sphinx_plot(text("So good", (0,0), bounding_box=bbox))

    The possible options of the bounding box are 'boxstyle' (one of 'larrow',
    'rarrow', 'round', 'round4', 'roundtooth', 'sawtooth', 'square'), 'fc' or
    'facecolor', 'ec' or 'edgecolor', 'ha' or 'horizontalalignment', 'va' or
    'verticalalignment', 'lw' or 'linewidth'.

    A text with a background color::

        sage: text("So good", (-2,2), background_color='red')
        Graphics object consisting of 1 graphics primitive

    .. PLOT::

        sphinx_plot(text("So good", (-2,2), background_color='red'))

    Text must be 2D (use the text3d command for 3D text)::

        sage: t = text("hi",(1,2,3))
        Traceback (most recent call last):
        ...
        ValueError: use text3d instead for text in 3d
        sage: t = text3d("hi",(1,2,3))

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

        sage: text("MATH IS AWESOME", (0, 0), fontsize=40, axes=False)
        Graphics object consisting of 1 graphics primitive
        sage: text("MATH IS AWESOME", (0, 0), fontsize=40).show(axes=False) # These are equivalent
    """
    try:
        x, y = xy
    except ValueError:
        if isinstance(xy, (list, tuple)) and len(xy) == 3:
            raise ValueError("use text3d instead for text in 3d")
        raise
    from sage.plot.all import Graphics
    options['rgbcolor'] = to_mpl_color(options['rgbcolor'])
    point = (float(x), float(y))
    g = Graphics()
    g._set_extra_kwds(
        Graphics._extract_kwds_for_show(options, ignore='fontsize'))
    g.add_primitive(Text(string, point, options))
    return g
Beispiel #24
0
def circle(center, radius, **options):
    """
    Return a circle at a point center = `(x,y)` (or `(x,y,z)` and 
    parallel to the `xy`-plane) with radius = `r`.  Type 
    ``circle.options`` to see all options.
    
    OPTIONS:

    - ``alpha`` - default: 1

    - ``fill`` - default: False

    - ``thickness`` - default: 1

    - ``linestyle`` - default: 'solid' (2D plotting only)

    - ``edgecolor`` - default: 'blue' (2D plotting only)

    - ``facecolor`` - default: 'blue' (2D plotting only, useful only
      if ``fill=True``)

    - ``rgbcolor`` - 2D or 3D plotting.  This option overrides
      ``edgecolor`` and ``facecolor`` for 2D plotting.

    - ``legend_label`` - the label for this item in the legend

    EXAMPLES:

    The default color is blue, but this is easy to change::

        sage: c = circle((1,1), 1)
        sage: c

    ::

        sage: c = circle((1,1), 1, rgbcolor=(1,0,0))
        sage: c

    We can also use this command to plot three-dimensional circles parallel
    to the `xy`-plane::

        sage: c = circle((1,1,3), 1, rgbcolor=(1,0,0))
        sage: c
        sage: type(c)
        <class 'sage.plot.plot3d.base.TransformGroup'>

    To correct the aspect ratio of certain graphics, it is necessary
    to show with a ``figsize`` of square dimensions::

        sage: c.show(figsize=[5,5],xmin=-1,xmax=3,ymin=-1,ymax=3)

    Here we make a more complicated plot, with many circles of different colors::

        sage: g = Graphics()
        sage: step=6; ocur=1/5; paths=16;
        sage: PI = math.pi    # numerical for speed -- fine for graphics
        sage: for r in range(1,paths+1):
        ...       for x,y in [((r+ocur)*math.cos(n), (r+ocur)*math.sin(n)) for n in srange(0, 2*PI+PI/step, PI/step)]:
        ...           g += circle((x,y), ocur, rgbcolor=hue(r/paths))
        ...       rnext = (r+1)^2
        ...       ocur = (rnext-r)-ocur
        ...
        sage: g.show(xmin=-(paths+1)^2, xmax=(paths+1)^2, ymin=-(paths+1)^2, ymax=(paths+1)^2, figsize=[6,6])

    Note that the ``rgbcolor`` option overrides the other coloring options.
    This produces red fill in a blue circle::

        sage: circle((2,3), 1, fill=True, edgecolor='blue')

    This produces an all-green filled circle::

        sage: circle((2,3), 1, fill=True, edgecolor='blue', rgbcolor='green')

    The option ``hue`` overrides *all* other options, so be careful with its use.
    This produces a purplish filled circle::

        sage: circle((2,3), 1, fill=True, edgecolor='blue', rgbcolor='green', hue=.8)

    And a circle with a legend::

        sage: circle((4,5), 1, rgbcolor='yellow', fill=True, legend_label='the sun').show(xmin=0, ymin=0)

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

        sage: circle((0, 0), 2, figsize=[10,10]) # That circle is huge!

    ::

        sage: circle((0, 0), 2).show(figsize=[10,10]) # These are equivalent

    TESTS:

    We cannot currently plot circles in more than three dimensions::

        sage: circle((1,1,1,1), 1, rgbcolor=(1,0,0))
        Traceback (most recent call last):
        ...
        ValueError: The center of a plotted circle should have two or three coordinates.

    The default aspect ratio for a circle is 1.0::

        sage: P = circle((1,1), 1)
        sage: P.aspect_ratio()
        1.0
    """
    from sage.plot.all import Graphics
    g = Graphics()
    g._set_extra_kwds(Graphics._extract_kwds_for_show(options))
    g.add_primitive(Circle(center[0], center[1], radius, options))
    if options['legend_label']:
        g.legend(True)
    if len(center) == 2:
        return g
    elif len(center) == 3:
        return g[0].plot3d(z=center[2])
    else:
        raise ValueError, 'The center of a plotted circle should have two or three coordinates.'
Beispiel #25
0
def line2d(points, **options):
    r"""
    Create the line through the given list of points.

    INPUT:

    -  ``points`` - either a single point (as a tuple), a list of
       points, a single complex number, or a list of complex numbers.

    Type ``line2d.options`` for a dictionary of the default options for
    lines.  You can change this to change the defaults for all future
    lines.  Use ``line2d.reset()`` to reset to the default options.

    INPUT:

    - ``alpha`` -- How transparent the line is

    - ``thickness`` -- How thick the line is

    - ``rgbcolor`` -- The color as an RGB tuple

    - ``hue`` -- The color given as a hue

    - ``legend_color`` -- The color of the text in the legend

    - ``legend_label`` -- the label for this item in the legend


    Any MATPLOTLIB line option may also be passed in.  E.g.,

    - ``linestyle`` - (default: "-") The style of the line, which is one of
       - ``"-"`` or ``"solid"``
       - ``"--"`` or ``"dashed"``
       - ``"-."`` or ``"dash dot"``
       - ``":"`` or ``"dotted"``
       - ``"None"`` or ``" "`` or ``""`` (nothing)

       The linestyle can also be prefixed with a drawing style (e.g., ``"steps--"``)

       - ``"default"`` (connect the points with straight lines)
       - ``"steps"`` or ``"steps-pre"`` (step function; horizontal
         line is to the left of point)
       - ``"steps-mid"`` (step function; points are in the middle of
         horizontal lines)
       - ``"steps-post"`` (step function; horizontal line is to the
         right of point)

    - ``marker``  - The style of the markers, which is one of
       - ``"None"`` or ``" "`` or ``""`` (nothing) -- default
       - ``","`` (pixel), ``"."`` (point)
       - ``"_"`` (horizontal line), ``"|"`` (vertical line)
       - ``"o"`` (circle), ``"p"`` (pentagon), ``"s"`` (square), ``"x"`` (x), ``"+"`` (plus), ``"*"`` (star)
       - ``"D"`` (diamond), ``"d"`` (thin diamond)
       - ``"H"`` (hexagon), ``"h"`` (alternative hexagon)
       - ``"<"`` (triangle left), ``">"`` (triangle right), ``"^"`` (triangle up), ``"v"`` (triangle down)
       - ``"1"`` (tri down), ``"2"`` (tri up), ``"3"`` (tri left), ``"4"`` (tri right)
       - ``0`` (tick left), ``1`` (tick right), ``2`` (tick up), ``3`` (tick down)
       - ``4`` (caret left), ``5`` (caret right), ``6`` (caret up), ``7`` (caret down)
       - ``"$...$"`` (math TeX string)

    - ``markersize`` -- the size of the marker in points

    - ``markeredgecolor`` -- the color of the marker edge

    - ``markerfacecolor`` -- the color of the marker face

    - ``markeredgewidth`` -- the size of the marker edge in points

    EXAMPLES:

    A line with no points or one point::

        sage: line([])      #returns an empty plot
        sage: import numpy; line(numpy.array([]))
        sage: line([(1,1)])

    A line with numpy arrays::

        sage: line(numpy.array([[1,2], [3,4]]))

    A line with a legend::

        sage: line([(0,0),(1,1)], legend_label='line')

    Lines with different colors in the legend text::

        sage: p1 = line([(0,0),(1,1)], legend_label='line')
        sage: p2 = line([(1,1),(2,4)], legend_label='squared', legend_color='red')
        sage: p1 + p2

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

        sage: line([(0,1), (3,4)], figsize=[10, 2])
        sage: line([(0,1), (3,4)]).show(figsize=[10, 2]) # These are equivalent

    We can also use a logarithmic scale if the data will support it::

        sage: line([(1,2),(2,4),(3,4),(4,8),(4.5,32)],scale='loglog',base=2)

    Many more examples below!

    A blue conchoid of Nicomedes::

        sage: L = [[1+5*cos(pi/2+pi*i/100), tan(pi/2+pi*i/100)*(1+5*cos(pi/2+pi*i/100))] for i in range(1,100)]
        sage: line(L, rgbcolor=(1/4,1/8,3/4))

    A line with 2 complex points::

        sage: i = CC.0
        sage: line([1+i, 2+3*i])

    A blue hypotrochoid (3 leaves)::

        sage: n = 4; h = 3; b = 2
        sage: L = [[n*cos(pi*i/100)+h*cos((n/b)*pi*i/100),n*sin(pi*i/100)-h*sin((n/b)*pi*i/100)] for i in range(200)]
        sage: line(L, rgbcolor=(1/4,1/4,3/4))

    A blue hypotrochoid (4 leaves)::

        sage: n = 6; h = 5; b = 2
        sage: L = [[n*cos(pi*i/100)+h*cos((n/b)*pi*i/100),n*sin(pi*i/100)-h*sin((n/b)*pi*i/100)] for i in range(200)]
        sage: line(L, rgbcolor=(1/4,1/4,3/4))

    A red limacon of Pascal::

        sage: L = [[sin(pi*i/100)+sin(pi*i/50),-(1+cos(pi*i/100)+cos(pi*i/50))] for i in range(-100,101)]
        sage: line(L, rgbcolor=(1,1/4,1/2))

    A light green trisectrix of Maclaurin::

        sage: L = [[2*(1-4*cos(-pi/2+pi*i/100)^2),10*tan(-pi/2+pi*i/100)*(1-4*cos(-pi/2+pi*i/100)^2)] for i in range(1,100)]
        sage: line(L, rgbcolor=(1/4,1,1/8))

    A green lemniscate of Bernoulli::

        sage: cosines = [cos(-pi/2+pi*i/100) for i in range(201)]
        sage: v = [(1/c, tan(-pi/2+pi*i/100)) for i,c in enumerate(cosines) if c != 0]
        sage: L = [(a/(a^2+b^2), b/(a^2+b^2)) for a,b in v]
        sage: line(L, rgbcolor=(1/4,3/4,1/8))

    A red plot of the Jacobi elliptic function `\text{sn}(x,2)`, `-3 < x < 3`::

        sage: L = [(i/100.0, jacobi('sn', i/100.0 ,2.0)) for i in range(-300,300,30)]
        sage: line(L, rgbcolor=(3/4,1/4,1/8))

    A red plot of `J`-Bessel function `J_2(x)`, `0 < x < 10`::

        sage: L = [(i/10.0, bessel_J(2,i/10.0)) for i in range(100)]
        sage: line(L, rgbcolor=(3/4,1/4,5/8))


    A purple plot of the Riemann zeta function `\zeta(1/2 + it)`, `0 < t < 30`::

        sage: i = CDF.gen()
        sage: v = [zeta(0.5 + n/10 * i) for n in range(300)]
        sage: L = [(z.real(), z.imag()) for z in v]
        sage: line(L, rgbcolor=(3/4,1/2,5/8))

    A purple plot of the Hasse-Weil `L`-function `L(E, 1 + it)`, `-1 < t < 10`::

        sage: E = EllipticCurve('37a')
        sage: vals = E.lseries().values_along_line(1-I, 1+10*I, 100) # critical line
        sage: L = [(z[1].real(), z[1].imag()) for z in vals]
        sage: line(L, rgbcolor=(3/4,1/2,5/8))

    A red, blue, and green "cool cat"::

        sage: G = plot(-cos(x), -2, 2, thickness=5, rgbcolor=(0.5,1,0.5))
        sage: P = polygon([[1,2], [5,6], [5,0]], rgbcolor=(1,0,0))
        sage: Q = polygon([(-x,y) for x,y in P[0]], rgbcolor=(0,0,1))
        sage: G + P + Q   # show the plot

    TESTS:

    Check that :trac:`13690` is fixed. The legend label should have circles
    as markers.::

        sage: line(enumerate(range(2)), marker='o', legend_label='circle')

    """
    from sage.plot.all import Graphics
    from sage.plot.plot import xydata_from_point_list
    from sage.rings.all import CC, CDF
    if points in CC or points in CDF:
        pass
    else:
        try:
            if not points:
                return Graphics()
        except ValueError: # numpy raises a ValueError if not empty
            pass
    xdata, ydata = xydata_from_point_list(points)
    g = Graphics()
    g._set_extra_kwds(Graphics._extract_kwds_for_show(options))
    g.add_primitive(Line(xdata, ydata, options))
    if options['legend_label']:
        g.legend(True)
        g._legend_colors = [options['legend_color']]
    return g
Beispiel #26
0
    from sage.plot.misc import setup_for_eval_on_grid
    z, ranges = setup_for_eval_on_grid([f,g], [xrange, yrange], options['plot_points'])
    f,g = z

    xpos_array, ypos_array, xvec_array, yvec_array = [],[],[],[]
    for x in xsrange(*ranges[0], include_endpoint=True):
        for y in xsrange(*ranges[1], include_endpoint=True):
            xpos_array.append(x)
            ypos_array.append(y)
            xvec_array.append(f(x,y))
            yvec_array.append(g(x,y))

    import numpy
    xvec_array = numpy.ma.masked_invalid(numpy.array(xvec_array, dtype=float))
    yvec_array = numpy.ma.masked_invalid(numpy.array(yvec_array, dtype=float))
    g = Graphics()
    g._set_extra_kwds(Graphics._extract_kwds_for_show(options))
    g.add_primitive(PlotField(xpos_array, ypos_array, xvec_array, yvec_array, options))
    return g

def plot_slope_field(f, xrange, yrange, **kwds):
    r"""
    ``plot_slope_field`` takes a function of two variables xvar and yvar
    (for instance, if the variables are `x` and `y`, take `f(x,y)`), and at
    representative points `(x_i,y_i)` between xmin, xmax, and ymin, ymax
    respectively, plots a line with slope `f(x_i,y_i)` (see below).

    ``plot_slope_field(f, (xvar, xmin, xmax), (yvar, ymin, ymax))``

    EXAMPLES: 
Beispiel #27
0
def ellipse(center, r1, r2, angle=0, **options):
    """
    Return an ellipse centered at a point center = ``(x,y)`` with radii =
    ``r1,r2`` and angle ``angle``.  Type ``ellipse.options`` to see all
    options.

    INPUT:

    - ``center`` - 2-tuple of real numbers - coordinates of the center

    - ``r1``, ``r2`` - positive real numbers - the radii of the ellipse

    - ``angle`` - real number (default: 0) - the angle between the first axis
      and the horizontal
    
    OPTIONS:

    - ``alpha`` - default: 1 - transparency

    - ``fill`` - default: False - whether to fill the ellipse or not

    - ``thickness`` - default: 1 - thickness of the line

    - ``rgbcolor`` - default: (0,0,0) - color of the ellipse 
      (overwrites ``edgecolor`` and ``facecolor``)

    - ``linestyle`` - default: 'solid'

    - ``edgecolor`` - default: 'black' - color of the contour

    - ``facecolor`` - default: 'red' - color of the filling

    EXAMPLES:

    An ellipse centered at (0,0) with major and minor axes of lengths 2 and 1::

        sage: ellipse((0,0),2,1)

    More complicated examples with tilted axes and drawing options::

        sage: ellipse((0,0),3,1,pi/6,fill=True,alpha=0.3)

    ::

        sage: ellipse((0,0),3,1,pi/6,fill=True,edgecolor='blue',facecolor='red')

    The default aspect ratio for ellipses is 1.0::

        sage: ellipse((0,0),2,1).aspect_ratio()
        1.0

    One cannot yet plot ellipses in 3D::

        sage: ellipse((0,0,0),2,1)
        Traceback (most recent call last):
        ...
        NotImplementedError: plotting ellipse in 3D is not implemented
    """
    from sage.plot.all import Graphics
    g = Graphics()
    g._set_extra_kwds(Graphics._extract_kwds_for_show(options))
    g.add_primitive(Ellipse(center[0],center[1],r1,r2,angle,options))
    if len(center)==2:
        return g
    elif len(center)==3:
        raise NotImplementedError, "plotting ellipse in 3D is not implemented"
Beispiel #28
0
def point2d(points, **options):
    r"""
    A point of size ``size`` defined by point = `(x,y)`.

    INPUT:

    -  ``points`` - either a single point (as a tuple), a list of
       points, a single complex number, or a list of complex numbers.
    - ``alpha`` -- How transparent the point is.
    - ``faceted`` -- If True color the edge of the point. (only for 2D plots)
    - ``hue`` -- The color given as a hue.
    - ``legend_color`` -- The color of the legend text
    - ``legend_label`` -- The label for this item in the legend.
    - ``marker`` -- the marker symbol for 2D plots only (see documentation of
      :func:`plot` for details)
    - ``markeredgecolor`` -- the color of the marker edge (only for 2D plots)
    - ``rgbcolor`` -- The color as an RGB tuple.
    - ``size`` -- How big the point is (i.e., area in points^2=(1/72 inch)^2).
    - ``zorder`` -- The layer level in which to draw

    EXAMPLES:

    A purple point from a single tuple or coordinates::

        sage: point((0.5, 0.5), rgbcolor=hue(0.75))
        Graphics object consisting of 1 graphics primitive

    Points with customized markers and edge colors::

        sage: r = [(random(), random()) for _ in range(10)]
        sage: point(r, marker='d', markeredgecolor='red', size=20)
        Graphics object consisting of 1 graphics primitive

    Passing an empty list returns an empty plot::

        sage: point([])
        Graphics object consisting of 0 graphics primitives
        sage: import numpy; point(numpy.array([]))
        Graphics object consisting of 0 graphics primitives

    If you need a 2D point to live in 3-space later, this is possible::

        sage: A=point((1,1))
        sage: a=A[0];a
        Point set defined by 1 point(s)
        sage: b=a.plot3d(z=3)

    This is also true with multiple points::

        sage: P=point([(0,0), (1,1)])
        sage: p=P[0]
        sage: q=p.plot3d(z=[2,3])

    Here are some random larger red points, given as a list of tuples::

        sage: point(((0.5, 0.5), (1, 2), (0.5, 0.9), (-1, -1)), rgbcolor=hue(1), size=30)
        Graphics object consisting of 1 graphics primitive

    And an example with a legend::

        sage: point((0,0), rgbcolor='black', pointsize=40, legend_label='origin')
        Graphics object consisting of 1 graphics primitive

    The legend can be colored::

        sage: P = points([(0,0),(1,0)], pointsize=40, legend_label='origin', legend_color='red')
        sage: P + plot(x^2,(x,0,1), legend_label='plot', legend_color='green')
        Graphics object consisting of 2 graphics primitives

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

        sage: point([(cos(theta), sin(theta)) for theta in srange(0, 2*pi, pi/8)], frame=True)
        Graphics object consisting of 1 graphics primitive
        sage: point([(cos(theta), sin(theta)) for theta in srange(0, 2*pi, pi/8)]).show(frame=True) # These are equivalent

    For plotting data, we can use a logarithmic scale, as long as we are sure
    not to include any nonpositive points in the logarithmic direction::

        sage: point([(1,2),(2,4),(3,4),(4,8),(4.5,32)],scale='semilogy',base=2)
        Graphics object consisting of 1 graphics primitive

    Since Sage Version 4.4 (:trac:`8599`), the size of a 2d point can be
    given by the argument ``size`` instead of ``pointsize``. The argument
    ``pointsize`` is still supported::

        sage: point((3,4), size=100)
        Graphics object consisting of 1 graphics primitive

    ::

        sage: point((3,4), pointsize=100)
        Graphics object consisting of 1 graphics primitive

    We can plot a single complex number::

        sage: point(CC(1+I), pointsize=100)
        Graphics object consisting of 1 graphics primitive

    We can also plot a list of complex numbers::

        sage: point([CC(I), CC(I+1), CC(2+2*I)], pointsize=100)
        Graphics object consisting of 1 graphics primitive

    """
    from sage.plot.plot import xydata_from_point_list
    from sage.plot.all import Graphics
    from sage.rings.all import CC, CDF
    if points in CC or points in CDF:
        pass
    else:
        try:
            if not points:
                return Graphics()
        except ValueError:  # numpy raises a ValueError if not empty
            pass
    xdata, ydata = xydata_from_point_list(points)
    g = Graphics()
    g._set_extra_kwds(Graphics._extract_kwds_for_show(options))
    g.add_primitive(Point(xdata, ydata, options))
    if options['legend_label']:
        g.legend(True)
        g._legend_colors = [options['legend_color']]
    return g
Beispiel #29
0
    def __init__(self, A, B, C,**options):
        """
        Initialize HyperbolicTriangle under the map (z-z0)/(z-\bar(z0)):
        
        Examples::
        
            sage: from sage.plot.hyperbolic_triangle import HyperbolicTriangle
            sage: print HyperbolicTriangle(0, 1/2, I, {})
            Hyperbolic triangle (0.000000000000000, 0.500000000000000, 1.00000000000000*I)
        """
        A, B, C = (CC(A), CC(B), CC(C))
        self.path = []
        self._options = {}
        self._graphics = Graphics()
        self._verbose = options.pop('verbose',None)
        Z0 = options['center'] #.get('center',C(0,1))
        options.pop('center',None)
        self._npts = options.pop('npts',10)
        sides = options.pop('sides',[1,2,3])
        #options.pop('fill',None)
        self._options.update(options)
        self._z0=CC(Z0); self._z0bar=CC(Z0).conjugate()        
        verbose=self._verbose
        sides.sort()
        if sides == [1]:
            if verbose>0:
                print "Drawing A - B!"
            self._hyperbolic_arc_d(A, B, True);
        elif sides == [2]:
            if verbose>0:
                print "Drawing B - C!"                
            self._hyperbolic_arc_d(B, C, True);
        elif sides == [3]:
            if verbose>0:
                print "Drawing C - A!"                
            self._hyperbolic_arc_d(C, A, True);
        elif sides == [1,2]:
            if verbose>0:
                print "Drawing A - B! & B - C!"
            self._hyperbolic_arc_d(A, B, True);
            self._hyperbolic_arc_d(B, C,False);
        elif sides == [1,3]:
            if verbose>0:
                print "Drawing C - A! & A - B"
            self._hyperbolic_arc_d(C, A,True)
            self._hyperbolic_arc_d(A, B, False)
        elif sides == [2,3]:
            if verbose>0:
                print "Drawing B - C! & C - A"
            self._hyperbolic_arc_d(B, C,True)
            self._hyperbolic_arc_d(C, A, False)            
        else:
            self._hyperbolic_arc_d(A, B,True)            
            self._hyperbolic_arc_d(B, C,False)
            self._hyperbolic_arc_d(C, A, False)
        #self._hyperbolic_arc_d(A, B, True);
        #self._hyperbolic_arc_d(B, C);
        #self._hyperbolic_arc_d(C, A);
        #BezierPath.__init__(self, self.path, options)


        #super(HyperbolicTriangleDisc,self).__init__(options)
        self.A, self.B, self.C = (A, B, C)
Beispiel #30
0
def disk(point, radius, angle, **options):
    r"""
    A disk (that is, a sector or wedge of a circle) with center
    at a point = `(x,y)` (or `(x,y,z)` and parallel to the
    `xy`-plane) with radius = `r` spanning (in radians)
    angle=`(rad1, rad2)`.

    Type ``disk.options`` to see all options.

    EXAMPLES:

    Make some dangerous disks::

        sage: bl = disk((0.0,0.0), 1, (pi, 3*pi/2), color='yellow')
        sage: tr = disk((0.0,0.0), 1, (0, pi/2), color='yellow')
        sage: tl = disk((0.0,0.0), 1, (pi/2, pi), color='black')
        sage: br = disk((0.0,0.0), 1, (3*pi/2, 2*pi), color='black')
        sage: P  = tl+tr+bl+br
        sage: P.show(xmin=-2,xmax=2,ymin=-2,ymax=2)

    The default aspect ratio is 1.0::

        sage: disk((0.0,0.0), 1, (pi, 3*pi/2)).aspect_ratio()
        1.0

    Another example of a disk::

        sage: bl = disk((0.0,0.0), 1, (pi, 3*pi/2), rgbcolor=(1,1,0))
        sage: bl.show(figsize=[5,5])

    Note that since ``thickness`` defaults to zero, it is best to change
    that option when using ``fill=False``::

        sage: disk((2,3), 1, (pi/4,pi/3), hue=.8, alpha=.3, fill=False, thickness=2)
        Graphics object consisting of 1 graphics primitive

    The previous two examples also illustrate using ``hue`` and ``rgbcolor``
    as ways of specifying the color of the graphic.

    We can also use this command to plot three-dimensional disks parallel
    to the `xy`-plane::

        sage: d = disk((1,1,3), 1, (pi,3*pi/2), rgbcolor=(1,0,0))
        sage: d
        Graphics3d Object
        sage: type(d)
        <type 'sage.plot.plot3d.index_face_set.IndexFaceSet'>

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

        sage: disk((0, 0), 5, (0, pi/2), xmin=0, xmax=5, ymin=0, ymax=5, figsize=(2,2), rgbcolor=(1, 0, 1))
        Graphics object consisting of 1 graphics primitive
        sage: disk((0, 0), 5, (0, pi/2), rgbcolor=(1, 0, 1)).show(xmin=0, xmax=5, ymin=0, ymax=5, figsize=(2,2)) # These are equivalent

    TESTS:

    Testing that legend labels work right::

        sage: disk((2,4), 3, (pi/8, pi/4), hue=1, legend_label='disk', legend_color='blue')
        Graphics object consisting of 1 graphics primitive

    We cannot currently plot disks in more than three dimensions::

        sage: d = disk((1,1,1,1), 1, (0,pi))
        Traceback (most recent call last):
        ...
        ValueError: The center point of a plotted disk should have two or three coordinates.
    """
    from sage.plot.all import Graphics
    g = 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'

    g._set_extra_kwds(Graphics._extract_kwds_for_show(options))
    g.add_primitive(Disk(point, radius, angle, options))
    if options['legend_label']:
        g.legend(True)
        g._legend_colors = [options['legend_color']]
    if len(point) == 2:
        return g
    elif len(point) == 3:
        return g[0].plot3d(z=point[2])
    else:
        raise ValueError(
            'The center point of a plotted disk should have two or three coordinates.'
        )
Beispiel #31
0
def geomrep(M1, B1=None, lineorders1=None, pd=None, sp=False):
    """
    Return a sage graphics object containing geometric representation of
    matroid M1.

    INPUT:

    - ``M1`` -- A matroid.
    - ``B1`` -- (optional) A list of elements in ``M1.groundset()`` that
    correspond to a basis of ``M1`` and will be placed as vertices of the
    triangle in the geometric representation of ``M1``.
    - ``lineorders1`` -- (optional) A list of ordered lists of elements of
    ``M1.grondset()`` such that if a line in geometric representation is
    setwise same as any of these then points contained will be traversed in
    that order thus overriding internal order deciding heuristic.
    - ``pd`` - (optional) A dictionary mapping ground set elements to their
    (x,y) positions.
    - ``sp`` -- (optional) If True, a positioning dictionary and line orders
    will be placed in ``M._cached_info``.

    OUTPUT:

    A sage graphics object of type <class 'sage.plot.graphics.Graphics'> that
    corresponds to the geometric representation of the matroid.

    EXAMPLES::

        sage: from sage.matroids import matroids_plot_helpers
        sage: M=matroids.named_matroids.P7()
        sage: G=matroids_plot_helpers.geomrep(M)
        sage: G.show(xmin=-2, xmax=3, ymin=-2, ymax=3)
        sage: M=matroids.named_matroids.P7()
        sage: G=matroids_plot_helpers.geomrep(M,lineorders1=[['f','e','d']])
        sage: G.show(xmin=-2, xmax=3, ymin=-2, ymax=3)

    .. NOTE::

            This method does NOT do any checks.
    """
    G = Graphics()
    # create lists of loops and parallel elements and simplify given matroid
    [M, L, P] = slp(M1, pos_dict=pd, B=B1)
    if B1 is None:
        B1 = list(M.basis())
    M._cached_info = M1._cached_info

    if M.rank() == 0:
        limits = None
        loops = L
        looptext = ", ".join([str(l) for l in loops])
        rectx = -1
        recty = -1
        rectw = 0.5 + 0.4*len(loops) + 0.5  # controlled based on len(loops)
        recth = 0.6
        G += polygon2d([[rectx, recty], [rectx, recty+recth],
                        [rectx+rectw, recty+recth], [rectx+rectw, recty]],
                       color='black', fill=False, thickness=4)
        G += text(looptext, (rectx+0.5, recty+0.3), color='black',
                  fontsize=13)
        G += point((rectx+0.2, recty+0.3), color=Color('#BDBDBD'), size=300,
                   zorder=2)
        G += text('Loop(s)', (rectx+0.5+0.4*len(loops)+0.1, recty+0.3),
                  fontsize=13, color='black')
        limits = tracklims(limits, [rectx, rectx+rectw], [recty, recty+recth])
        G.axes(False)
        G.axes_range(xmin=limits[0]-0.5, xmax=limits[1]+0.5,
                     ymin=limits[2]-0.5, ymax=limits[3]+0.5)
        return G
    elif M.rank() == 1:
        if M._cached_info is not None and \
           'plot_positions' in M._cached_info.keys() and \
           M._cached_info['plot_positions'] is not None:
            pts = M._cached_info['plot_positions']
        else:
            pts = {}
            gnd = sorted(M.groundset())
        pts[gnd[0]] = (1, float(2)/3)
        G += point((1, float(2)/3), size=300, color=Color('#BDBDBD'), zorder=2)
        pt = [1, float(2)/3]
        if len(P) == 0:
            G += text(gnd[0], (float(pt[0]), float(pt[1])), color='black',
                      fontsize=13)
        pts2 = pts
        # track limits [xmin,xmax,ymin,ymax]
        pl = [list(x) for x in pts2.values()]
        lims = tracklims([None, None, None, None], [pt[0] for pt in pl],
                         [pt[1] for pt in pl])
    elif M.rank() == 2:
        nB1 = list(set(list(M.groundset())) - set(B1))
        bline = []
        for j in nB1:
            if M.is_dependent([j, B1[0], B1[1]]):
                bline.append(j)
        interval = len(bline)+1
        if M._cached_info is not None and \
           'plot_positions' in M._cached_info.keys() and \
           M._cached_info['plot_positions'] is not None:
            pts2 = M._cached_info['plot_positions']
        else:
            pts2 = {}
            pts2[B1[0]] = (0, 0)
            pts2[B1[1]] = (2, 0)
            lpt = list(pts2[B1[0]])
            rpt = list(pts2[B1[1]])
            for k in range(len(bline)):
                cc = (float(1)/interval)*(k+1)
                pts2[bline[k]] = (cc*lpt[0]+(1-cc)*rpt[0],
                                  cc*lpt[1]+(1-cc)*rpt[1])
            if sp is True:
                M._cached_info['plot_positions'] = pts2
        # track limits [xmin,xmax,ymin,ymax]
        pl = [list(x) for x in pts2.values()]
        lims = tracklims([None, None, None, None], [pt[0] for pt in pl],
                         [pt[1] for pt in pl])
        bline.extend(B1)
        ptsx, ptsy, x_i, y_i = createline(pts2, bline, lineorders1)
        lims = tracklims(lims, x_i, y_i)
        G += line(zip(x_i, y_i), color='black', thickness=3, zorder=1)
        pels = [p for p in pts2.keys() if any([M1.rank([p, q]) == 1
                for q in P])]
        allpts = [list(pts2[i]) for i in M.groundset()]
        xpts = [float(k[0]) for k in allpts]
        ypts = [float(k[1]) for k in allpts]
        G += points(zip(xpts, ypts), color=Color('#BDBDBD'), size=300,
                    zorder=2)
        for i in pts2:
            if i not in pels:
                pt = list(pts2[i])
                G += text(i, (float(pt[0]), float(pt[1])), color='black',
                          fontsize=13)
    else:
        if M._cached_info is None or \
           'plot_positions' not in M._cached_info.keys() or \
           M._cached_info['plot_positions'] is None:
            (pts, trilines,
             nontripts, curvedlines) = it(M1, B1,
                                          list(set(M.groundset())-set(B1)),
                                          list(set(L) | set(P)))
            pts2 = addnontripts([B1[0], B1[1], B1[2]], nontripts, pts)
            trilines.extend(curvedlines)
        else:
            pts2 = M._cached_info['plot_positions']
            trilines = [list(set(list(x)).difference(L | P))
                        for x in M1.flats(2)
                        if len(list(x)) >= 3]
        pl = [list(x) for x in pts2.values()]
        lims = tracklims([None, None, None, None], [pt[0] for pt in pl],
                         [pt[1] for pt in pl])
        j = 0
        for ll in trilines:
            if len(ll) >= 3:
                ptsx, ptsy, x_i, y_i = createline(pts2, ll, lineorders1)
                lims = tracklims(lims, x_i, y_i)
                G += line(zip(x_i, y_i), color='black', thickness=3, zorder=1)
        pels = [p for p in pts2.keys() if any([M1.rank([p, q]) == 1
                for q in P])]
        allpts = [list(pts2[i]) for i in M.groundset()]
        xpts = [float(k[0]) for k in allpts]
        ypts = [float(k[1]) for k in allpts]
        G += points(zip(xpts, ypts), color=Color('#BDBDBD'), size=300,
                    zorder=2)
        for i in pts2:
            if i not in pels:
                pt = list(pts2[i])
                G += text(i, (float(pt[0]), float(pt[1])), color='black',
                          fontsize=13)
        if sp is True:
            M1._cached_info['plot_positions'] = pts2
            M1._cached_info['plot_lineorders'] = lineorders1
    # deal with loops and parallel elements
    G, lims = addlp(M1, M, L, P, pts2, G, lims)
    G.axes(False)
    G.axes_range(xmin=lims[0]-0.5, xmax=lims[1]+0.5, ymin=lims[2]-0.5,
                 ymax=lims[3]+0.5)
    return G
Beispiel #32
0
def ellipse(center, r1, r2, angle=0, **options):
    """
    Return an ellipse centered at a point center = ``(x,y)`` with radii =
    ``r1,r2`` and angle ``angle``.  Type ``ellipse.options`` to see all
    options.

    INPUT:

    - ``center`` - 2-tuple of real numbers - coordinates of the center

    - ``r1``, ``r2`` - positive real numbers - the radii of the ellipse

    - ``angle`` - real number (default: 0) - the angle between the first axis
      and the horizontal

    OPTIONS:

    - ``alpha`` - default: 1 - transparency

    - ``fill`` - default: False - whether to fill the ellipse or not

    - ``thickness`` - default: 1 - thickness of the line

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

    - ``edgecolor`` - default: 'black' - color of the contour

    - ``facecolor`` - default: 'red' - color of the filling

    - ``rgbcolor`` - 2D or 3D plotting.  This option overrides
      ``edgecolor`` and ``facecolor`` for 2D plotting.

    - ``legend_label`` - the label for this item in the legend

    - ``legend_color`` - the color for the legend label

    EXAMPLES:

    An ellipse centered at (0,0) with major and minor axes of lengths 2 and 1.
    Note that the default color is blue::

        sage: ellipse((0,0),2,1)
        Graphics object consisting of 1 graphics primitive

    More complicated examples with tilted axes and drawing options::

        sage: ellipse((0,0),3,1,pi/6,fill=True,alpha=0.3,linestyle="dashed")
        Graphics object consisting of 1 graphics primitive
        sage: ellipse((0,0),3,1,pi/6,fill=True,alpha=0.3,linestyle="--")
        Graphics object consisting of 1 graphics primitive

    ::

        sage: ellipse((0,0),3,1,pi/6,fill=True,edgecolor='black',facecolor='red')
        Graphics object consisting of 1 graphics primitive

    We see that ``rgbcolor`` overrides these other options, as this plot
    is green::

        sage: ellipse((0,0),3,1,pi/6,fill=True,edgecolor='black',facecolor='red',rgbcolor='green')
        Graphics object consisting of 1 graphics primitive

    The default aspect ratio for ellipses is 1.0::

        sage: ellipse((0,0),2,1).aspect_ratio()
        1.0

    One cannot yet plot ellipses in 3D::

        sage: ellipse((0,0,0),2,1)
        Traceback (most recent call last):
        ...
        NotImplementedError: plotting ellipse in 3D is not implemented

    We can also give ellipses a legend::

        sage: ellipse((0,0),2,1,legend_label="My ellipse", legend_color='green')
        Graphics object consisting of 1 graphics primitive
    """
    from sage.plot.all import Graphics
    g = 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'

    g._set_extra_kwds(Graphics._extract_kwds_for_show(options))
    g.add_primitive(Ellipse(center[0], center[1], r1, r2, angle, options))
    if options['legend_label']:
        g.legend(True)
        g._legend_colors = [options['legend_color']]
    if len(center) == 2:
        return g
    elif len(center) == 3:
        raise NotImplementedError("plotting ellipse in 3D is not implemented")
        def plot(self, size=[[0],[0]], projection='usual', simple_roots=True, fundamental_weights=True, alcovewalks=[]):
            r"""
            Return a graphics object built from a space of weight(space/lattice).
            There is a different technic to plot if the Cartan type is affine or not.
            The graphics returned is a Graphics object.

            This function is experimental, and is subject to short term evolutions.

            EXAMPLES::

              By default, the plot returned has no axes and the ratio between axes is 1.
                sage: G = RootSystem(['C',2]).weight_lattice().plot()
                sage: G.axes(True)
                sage: G.set_aspect_ratio(2)

              For a non affine Cartan type, the plot method work for type with 2 generators,
              it will draw the hyperlane(line for this dimension) accrow the fundamentals weights.
                sage: G = RootSystem(['A',2]).weight_lattice().plot()
                sage: G = RootSystem(['B',2]).weight_lattice().plot()
                sage: G = RootSystem(['G',2]).weight_lattice().plot()

              The plot returned has a size of one fundamental polygon by default. We can
              ask plot to give a bigger plot by using the argument size
                sage: G = RootSystem(['G',2,1]).weight_space().plot(size = [[0..1],[-1..1]])
                sage: G = RootSystem(['A',2,1]).weight_space().plot(size = [[-1..1],[-1..1]])

              A very important argument is the projection which will draw the plot. There are
              some usual projections is this method. If you want to draw in the plane a very
              special Cartan type, Sage will ask you to specify the projection. The projection
              is a matrix over a ring. In practice, calcul over float is a good way to draw.
                sage: L = RootSystem(['A',2,1]).weight_space()
                sage: G = L.plot(projection=matrix(RR, [[0,0.5,-0.5],[0,0.866,0.866]]))
                sage: G = RootSystem(['C',2,1]).weight_space().plot()

              By default, the plot method draw the simple roots, this can be disabled by setting
              the argument simple_roots=False
                sage: G = RootSystem(['A',2]).weight_space().plot(simple_roots=False)

              By default, the plot method draw the fundamental weights,this can be disabled by
              setting the argument fundamental_weights=False
                sage: G = RootSystem(['A',2]).weight_space().plot(fundamental_weights=False, simple_roots=False)

              There is in a plot an argument to draw alcoves walks. The good way to do this is
              to use the crystals theory. the plot method contains only the drawing part...
                sage: L = RootSystem(['A',2,1]).weight_space()
                sage: G = L.plot(size=[[-1..1],[-1..1]],alcovewalks=[[0,2,0,1,2,1,2,0,2,1]])
            """

            from sage.plot.all import Graphics
            from sage.plot.line import line
            from cartan_type import CartanType
            from sage.matrix.constructor import matrix
            from sage.rings.all import QQ, RR
            from sage.plot.arrow import arrow
            from sage.plot.point import point

            # We begin with an empty plot G
            G = Graphics()

            ct = self.cartan_type()
            n = ct.n

            # Define a set of colors
            # TODO : Colors in option ?
            colors=[(0,1,0),(1,0,0),(0,0,1),(1,1,0),(0,1,1),(1,0,1)]

            # plot the affine types:
            if ct.is_affine():

                # Check the projection
                # TODO : try to have usual_projection for main plotable types
                if projection == 'usual':
                    if ct == CartanType(['A',2,1]):
                        projection = matrix(RR, [[0,0.5,-0.5],[0,0.866,0.866]])
                    elif ct == CartanType(['C',2,1]):
                        projection = matrix(QQ, [[0,1,1],[0,0,1]])
                    elif ct == CartanType(['G',2,1]):
                        projection = matrix(RR, [[0,0.5,0],[0,0.866,1.732]])
                    else:
                        raise 'There is no usual projection for this Cartan type, you have to give one in argument'

                assert(n + 1 == projection.ncols())
                assert(2 == projection.nrows())

                # Check the size is correct with the lattice
                assert(len(size) == n)

                # Select the center of the translated fundamental polygon to plot
                translation_factors = ct.translation_factors()
                simple_roots = self.simple_roots()
                translation_vectors = [translation_factors[i]*simple_roots[i] for i in ct.classical().index_set()]

                initial = [[]]
                for i in range(n):
                    prod_list = []
                    for elem in size[i]:
                        for partial_list in initial:
                            prod_list.append( [elem]+partial_list );
                    initial = prod_list;

                part_lattice = []
                for combinaison in prod_list:
                    elem_lattice = self.zero()
                    for i in range(n):
                        elem_lattice = elem_lattice + combinaison[i]*translation_vectors[i]
                    part_lattice.append(elem_lattice)

                # Get the vertices of the fundamental alcove
                fundamental_weights = self.fundamental_weights()
                vertices = map(lambda x: (1/x.level())*x, fundamental_weights.list())

                # Recup the group which act on the fundamental polygon
                classical = self.weyl_group().classical()

                for center in part_lattice:
                    for w in classical:
                        # for each center of polygon and each element of classical
                        # parabolic subgroup, we have to draw an alcove.

                        #first, iterate over pairs of fundamental weights, drawing lines border of polygons:
                        for i in range(1,n+1):
                            for j in range(i+1,n+1):
                                p1=projection*((w.action(vertices[i])).to_vector() + center.to_vector())
                                p2=projection*((w.action(vertices[j])).to_vector() + center.to_vector())
                                G+=line([p1,p2],rgbcolor=(0,0,0),thickness=2)

                        #next, get all lines from point to a fundamental weight, that separe different
                        #chanber in a same polygon (important: associate a color with a fundamental weight)
                        pcenter = projection*(center.to_vector())
                        for i in range(1,n+1):
                            p3=projection*((w.action(vertices[i])).to_vector() + center.to_vector())
                            G+=line([p3,pcenter], rgbcolor=colors[n-i+1])

                #Draw alcovewalks
                #FIXME : The good way to draw this is to use the alcoves walks works made in Cristals
                #The code here just draw like example and import the good things.
                rho = (1/self.rho().level())*self.rho()
                W = self.weyl_group()
                for walk in alcovewalks:
                    target = W.from_reduced_word(walk).action(rho)
                    for i in range(len(walk)):
                        walk.pop()
                        origin = W.from_reduced_word(walk).action(rho)
                        G+=arrow(projection*(origin.to_vector()),projection*(target.to_vector()), rgbcolor=(0.6,0,0.6), width=1, arrowsize=5)
                        target = origin

            else:
                # non affine plot

                # Check the projection
                # TODO : try to have usual_projection for main plotable types
                if projection == 'usual':
                    if ct == CartanType(['A',2]):
                        projection = matrix(RR, [[0.5,-0.5],[0.866,0.866]])
                    elif ct == CartanType(['B',2]):
                        projection = matrix(QQ, [[1,0],[1,1]])
                    elif ct == CartanType(['C',2]):
                        projection = matrix(QQ, [[1,1],[0,1]])
                    elif ct == CartanType(['G',2]):
                        projection = matrix(RR, [[0.5,0],[0.866,1.732]])
                    else:
                        raise 'There is no usual projection for this Cartan type, you have to give one in argument'

                # Get the fundamental weights
                fundamental_weights = self.fundamental_weights()
                WeylGroup = self.weyl_group()

                #Draw not the alcove but the cones delimited by the hyperplanes
                #The size of the line depend of the fundamental weights.
                pcenter = projection*(self.zero().to_vector())
                for w in WeylGroup:
                    for i in range(1,n+1):
                        p3=3*projection*((w.action(fundamental_weights[i])).to_vector())
                        G+=line([p3,pcenter], rgbcolor=colors[n-i+1])

            #Draw the simple roots
            if simple_roots:
                SimpleRoots = self.simple_roots()
                if ct.is_affine():
                    G+=arrow((0,0), projection*(SimpleRoots[0].to_vector()), rgbcolor=(0,0,0))
                for j in range(1,n+1):
                    G+=arrow((0,0),projection*(SimpleRoots[j].to_vector()), rgbcolor=colors[j])

            #Draw the fundamental weights
            if fundamental_weights:
                FundWeight = self.fundamental_weights()
                for j in range(1,n+1):
                    G+=point(projection*(FundWeight[j].to_vector()), rgbcolor=colors[j], pointsize=60)

            G.set_aspect_ratio(1)
            G.axes(False)
            return G
Beispiel #34
0
    def plot_two_intervals(self,
                           position=(0, 0),
                           vertical_alignment='center',
                           horizontal_alignment='left',
                           interval_height=0.1,
                           labels_height=0.05,
                           fontsize=14,
                           labels=True,
                           colors=None):
        r"""
        Returns a picture of the interval exchange transformation.

        INPUT:

        - ``position`` - a 2-uple of the position

        - ``horizontal_alignment`` - left (default), center or right

        - ``labels`` - boolean (default: True)

        - ``fontsize`` - the size of the label


        OUTPUT:

        2d plot -- a plot of the two intervals (domain and range)

        EXAMPLES::

            sage: t = iet.IntervalExchangeTransformation(('a b','b a'),[1,1])
            sage: t.plot_two_intervals()
            Graphics object consisting of 8 graphics primitives
        """
        from sage.plot.all import Graphics
        from sage.plot.plot import line2d
        from sage.plot.plot import text
        from sage.plot.colors import rainbow

        G = Graphics()

        lengths = [float(_) for _ in self._lengths]
        total_length = sum(lengths)

        if colors is None:
            colors = rainbow(len(self._permutation), 'rgbtuple')

        if horizontal_alignment == 'left':
            s = position[0]
        elif horizontal_alignment == 'center':
            s = position[0] - total_length / 2
        elif horizontal_alignment == 'right':
            s = position[0] - total_length
        else:
            raise ValueError(
                "horizontal_alignement must be left, center or right")

        top_height = position[1] + interval_height
        for i in self._permutation._intervals[0]:
            G += line2d([(s, top_height), (s + lengths[i], top_height)],
                        rgbcolor=colors[i])
            if labels:
                G += text(
                    str(self._permutation._alphabet.unrank(i)),
                    (s + float(lengths[i]) / 2, top_height + labels_height),
                    horizontal_alignment='center',
                    rgbcolor=colors[i],
                    fontsize=fontsize)

            s += lengths[i]

        if horizontal_alignment == 'left':
            s = position[0]
        elif horizontal_alignment == 'center':
            s = position[0] - total_length / 2
        elif horizontal_alignment == 'right':
            s = position[0] - total_length
        else:
            raise ValueError(
                "horizontal_alignement must be left, center or right")

        bottom_height = position[1] - interval_height
        for i in self._permutation._intervals[1]:
            G += line2d([(s, bottom_height), (s + lengths[i], bottom_height)],
                        rgbcolor=colors[i])
            if labels:
                G += text(
                    str(self._permutation._alphabet.unrank(i)),
                    (s + float(lengths[i]) / 2, bottom_height - labels_height),
                    horizontal_alignment='center',
                    rgbcolor=colors[i],
                    fontsize=fontsize)
            s += lengths[i]

        return G
Beispiel #35
0
def my_hyperbolic_triangle(a, b, c, **options):
    r"""
    Return a hyperbolic triangle in the complex hyperbolic plane with points
    (a, b, c). Type ``?hyperbolic_triangle`` to see all options.

    INPUT:

    - ``a, b, c`` - complex numbers in the upper half complex plane

    OPTIONS:
    
    - ``alpha`` - default: 1
       
    - ``fill`` - default: False

    - ``thickness`` - default: 1

    - ``rgbcolor`` - default: 'blue'

    - ``linestyle`` - default: 'solid'

    EXAMPLES:

    Show a hyperbolic triangle with coordinates 0, `1/2+i\sqrt{3}/2` and
    `-1/2+i\sqrt{3}/2`::
    
         sage: hyperbolic_triangle(0, -1/2+I*sqrt(3)/2, 1/2+I*sqrt(3)/2)

    A hyperbolic triangle with coordinates 0, 1 and 2+i::
    
         sage: hyperbolic_triangle(0, 1, 2+i, fill=true, rgbcolor='red')
    """
    g = Graphics()
    g._set_extra_kwds(g._extract_kwds_for_show(options))
    model = options['model']
    npts = options.get('npts', 10)
    sides = options.pop('sides',
                        [1, 2, 3])  ## Which of the sides we will draw.
    verbose = options.get('verbose', 0)
    options.pop('model', None)
    options.pop('method', None)
    if model == "D":
        #g.add_primitive(HyperbolicTriangleDisc(a, b, c, **options))
        #print "options=",options
        options['sides'] = sides
        H = HyperbolicTriangleDisc(a, b, c, **options)
        g += H()
    else:
        options.pop('npts', None)
        if sides == [1, 2, 3]:
            if verbose > 0:
                print("adding HyperbolicTriangle({0}, {1}, {2},options={3})".
                      format(a, b, c, options))
            options.pop('verbose', 0)
            ## check if We need my class or the original class
            g.add_primitive(HyperbolicTriangle(a, b, c, options))
        else:
            options['sides'] = sides
            if verbose > 0:
                print("adding HyperbolicTriangle({0}, {1}, {2},options={3})".
                      format(a, b, c, options))
            g.add_primitive(HyperbolicTriangle(a, b, c, options))
    g.set_aspect_ratio(1)
    return g
Beispiel #36
0
def addlp(M, M1, L, P, ptsdict, G=None, limits=None):
    """
    Return a graphics object containing loops (in inset) and parallel elements
    of matroid.

    INPUT:

    - ``M`` -- A matroid.
    - ``M1`` -- A simple matroid corresponding to ``M``.
    - ``L`` -- List of elements in ``M.groundset()`` that are loops of matroid
      ``M``.
    - ``P`` -- List of elements in ``M.groundset()`` not in
      ``M.simplify.groundset()`` or ``L``.
    - ``ptsdict`` -- A dictionary containing elements in ``M.groundset()`` not
      necessarily containing elements of ``L``.
    - ``G`` -- (optional) A sage graphics object to which loops and parallel
      elements of matroid `M` added .
    - ``limits``-- (optional) Current axes limits [xmin,xmax,ymin,ymax].

    OUTPUT:

    A 2-tuple containing:

    1. A sage graphics object containing loops and parallel elements of
       matroid ``M``
    2. axes limits array

    EXAMPLES::

        sage: from sage.matroids import matroids_plot_helpers
        sage: M=Matroid(ring=GF(2), matrix=[[1, 0, 0, 0, 1, 1, 1,0,1],
        ....: [0, 1, 0, 1, 0, 1, 1,0,0],[0, 0, 1, 1, 1, 0, 1,0,0]])
        sage: [M1,L,P]=matroids_plot_helpers.slp(M)
        sage: G,lims=matroids_plot_helpers.addlp(M,M1,L,P,{0:(0,0)})
        sage: G.show(axes=False)

    .. NOTE::

            This method does NOT do any checks.

    """
    if G is None:
        G = Graphics()
    # deal with loops
    if L:
        loops = L
        looptext = ", ".join(str(l) for l in loops)
        if limits is None:
            rectx = -1
            recty = -1
        else:
            rectx = limits[0]
            recty = limits[2] - 1
        rectw = 0.5 + 0.4 * len(loops) + 0.5  # controlled based on len(loops)
        recth = 0.6
        G += polygon2d(
            [[rectx, recty], [rectx, recty + recth],
             [rectx + rectw, recty + recth], [rectx + rectw, recty]],
            color='black',
            fill=False,
            thickness=4)
        G += text(looptext, (rectx + 0.5, recty + 0.3),
                  color='black',
                  fontsize=13)
        G += point((rectx + 0.2, recty + 0.3),
                   color=Color('#BDBDBD'),
                   size=300,
                   zorder=2)
        G += text('Loop(s)',
                  (rectx + 0.5 + 0.4 * len(loops) + 0.1, recty + 0.3),
                  fontsize=13,
                  color='black')
        limits = tracklims(limits, [rectx, rectx + rectw],
                           [recty, recty + recth])
    # deal with parallel elements
    if P:
        # create list of lists where inner lists are parallel classes
        pcls = []
        gnd = sorted(list(M1.groundset()))
        for g in gnd:
            pcl = [g]
            for p in P:
                if M.rank([g, p]) == 1:
                    pcl.extend([p])
            pcls.append(pcl)
        ext_gnd = list(M.groundset())
        for pcl in pcls:
            if len(pcl) > 1:
                basept = list(ptsdict[pcl[0]])
                if len(pcl) <= 2:
                    # add side by side
                    ptsdict[pcl[1]] = (basept[0], basept[1] - 0.13)
                    G += points(zip([basept[0]], [basept[1] - 0.13]),
                                color=Color('#BDBDBD'),
                                size=300,
                                zorder=2)
                    G += text(pcl[0], (float(basept[0]), float(basept[1])),
                              color='black',
                              fontsize=13)
                    G += text(pcl[1],
                              (float(basept[0]), float(basept[1]) - 0.13),
                              color='black',
                              fontsize=13)
                    limits = tracklims(limits, [basept[0]], [basept[1] - 0.13])
                else:
                    # add in a bracket
                    pce = sorted([str(kk) for kk in pcl])
                    l = newlabel(set(ext_gnd))
                    ext_gnd.append(l)
                    G += text(
                        l + '={ ' + ", ".join(pce) + ' }',
                        (float(basept[0]), float(basept[1] - 0.2) - 0.034),
                        color='black',
                        fontsize=13)
                    G += text(l, (float(basept[0]), float(basept[1])),
                              color='black',
                              fontsize=13)
                    limits = tracklims(limits, [basept[0]],
                                       [(basept[1] - 0.2) - 0.034])
    return G, limits
def hyperbolic_regular_polygon(sides, i_angle, center=CC(0,1), **options):
    r"""
    Return a hyperbolic regular polygon in the upper half model of
    Hyperbolic plane given the number of sides, interior angle and
    possibly a center.

    Type ``?hyperbolic_regular_polygon`` to see all options.

    INPUT:

    - ``sides`` -- number of sides of the polygon

    - ``i_angle`` -- interior angle of the polygon

    - ``center``  -- (default: `i`) hyperbolic center point
      (complex number) of the polygon

    OPTIONS:

    - ``alpha`` -- default: 1

    - ``fill`` -- default: ``False``

    - ``thickness`` -- default: 1

    - ``rgbcolor`` -- default: ``'blue'``

    - ``linestyle`` -- (default: ``'solid'``) the style of the line,
      which can be one of the following:

      * ``'dashed'`` or ``'--'``
      * ``'dotted'`` or ``':'``
      * ``'solid'`` or ``'-'``
      * ``'dashdot'`` or ``'-.'``

    EXAMPLES:

    Show a hyperbolic regular polygon with 6 sides and square angles::

        sage: g = hyperbolic_regular_polygon(6, pi/2)
        sage: g.plot()
        Graphics object consisting of 1 graphics primitive

    .. PLOT::

         g = hyperbolic_regular_polygon(6, pi/2)
         sphinx_plot(g.plot())

    With more options::

        sage: g = hyperbolic_regular_polygon(6, pi/2, center=3+2*I, fill=True, color='red')
        sage: g.plot()
        Graphics object consisting of 1 graphics primitive

    .. PLOT::

         g = hyperbolic_regular_polygon(6, pi/2, center=3+2*I, fill=True, color='red')
         sphinx_plot(g.plot())

    The code verifies is there exists a hyperbolic regular polygon
    with the given data, checking

    .. MATH::

        A(\mathcal{P}) = \pi(s-2) - s \cdot \alpha > 0,

    where `s` is ``sides`` and `\alpha` is ``i_angle`. This raises an error if
    the ``i_angle`` is less than the minimum to generate a compact polygon::

        sage: hyperbolic_regular_polygon(4, pi/2)
        Traceback (most recent call last):
        ...
        ValueError: there exists no hyperbolic regular compact polygon,
         for sides=4 the interior angle must be less than 1/2*pi

    It is an error to give a center outside the upper half plane in
    this model::

        sage: from sage.plot.hyperbolic_regular_polygon import hyperbolic_regular_polygon
        sage: hyperbolic_regular_polygon(4, pi/4, 1-I)
        Traceback (most recent call last):
        ...
        ValueError: center: 1.00000000000000 - 1.00000000000000*I is not
         a valid point in the upper half plane model of the hyperbolic plane
    """
    g = Graphics()
    g._set_extra_kwds(g._extract_kwds_for_show(options))
    g.add_primitive(HyperbolicRegularPolygon(sides, i_angle, center, options))
    g.set_aspect_ratio(1)
    return g
Beispiel #38
0
def geomrep(M1, B1=None, lineorders1=None, pd=None, sp=False):
    """
    Return a sage graphics object containing geometric representation of
    matroid M1.

    INPUT:

    - ``M1`` -- A matroid.
    - ``B1`` -- (optional) A list of elements in ``M1.groundset()`` that
      correspond to a basis of ``M1`` and will be placed as vertices of the
      triangle in the geometric representation of ``M1``.
    - ``lineorders1`` -- (optional) A list of ordered lists of elements of
      ``M1.groundset()`` such that if a line in geometric representation is
      setwise same as any of these then points contained will be traversed in
      that order thus overriding internal order deciding heuristic.
    - ``pd`` - (optional) A dictionary mapping ground set elements to their
      (x,y) positions.
    - ``sp`` -- (optional) If True, a positioning dictionary and line orders
      will be placed in ``M._cached_info``.

    OUTPUT:

    A sage graphics object of type <class 'sage.plot.graphics.Graphics'> that
    corresponds to the geometric representation of the matroid.

    EXAMPLES::

        sage: from sage.matroids import matroids_plot_helpers
        sage: M=matroids.named_matroids.P7()
        sage: G=matroids_plot_helpers.geomrep(M)
        sage: G.show(xmin=-2, xmax=3, ymin=-2, ymax=3)
        sage: M=matroids.named_matroids.P7()
        sage: G=matroids_plot_helpers.geomrep(M,lineorders1=[['f','e','d']])
        sage: G.show(xmin=-2, xmax=3, ymin=-2, ymax=3)

    .. NOTE::

            This method does NOT do any checks.
    """
    G = Graphics()
    # create lists of loops and parallel elements and simplify given matroid
    [M, L, P] = slp(M1, pos_dict=pd, B=B1)
    if B1 is None:
        B1 = list(M.basis())
    M._cached_info = M1._cached_info

    if M.rank() == 0:
        limits = None
        loops = L
        looptext = ", ".join([str(l) for l in loops])
        rectx = -1
        recty = -1
        rectw = 0.5 + 0.4 * len(loops) + 0.5  # controlled based on len(loops)
        recth = 0.6
        G += polygon2d(
            [[rectx, recty], [rectx, recty + recth],
             [rectx + rectw, recty + recth], [rectx + rectw, recty]],
            color='black',
            fill=False,
            thickness=4)
        G += text(looptext, (rectx + 0.5, recty + 0.3),
                  color='black',
                  fontsize=13)
        G += point((rectx + 0.2, recty + 0.3),
                   color=Color('#BDBDBD'),
                   size=300,
                   zorder=2)
        G += text('Loop(s)',
                  (rectx + 0.5 + 0.4 * len(loops) + 0.1, recty + 0.3),
                  fontsize=13,
                  color='black')
        limits = tracklims(limits, [rectx, rectx + rectw],
                           [recty, recty + recth])
        G.axes(False)
        G.axes_range(xmin=limits[0] - 0.5,
                     xmax=limits[1] + 0.5,
                     ymin=limits[2] - 0.5,
                     ymax=limits[3] + 0.5)
        return G
    elif M.rank() == 1:
        if M._cached_info is not None and \
           'plot_positions' in M._cached_info.keys() and \
           M._cached_info['plot_positions'] is not None:
            pts = M._cached_info['plot_positions']
        else:
            pts = {}
            gnd = sorted(M.groundset())
        pts[gnd[0]] = (1, float(2) / 3)
        G += point((1, float(2) / 3),
                   size=300,
                   color=Color('#BDBDBD'),
                   zorder=2)
        pt = [1, float(2) / 3]
        if not P:
            G += text(gnd[0], (float(pt[0]), float(pt[1])),
                      color='black',
                      fontsize=13)
        pts2 = pts
        # track limits [xmin,xmax,ymin,ymax]
        pl = [list(x) for x in pts2.values()]
        lims = tracklims([None, None, None, None], [pnt[0] for pnt in pl],
                         [pnt[1] for pnt in pl])
    elif M.rank() == 2:
        nB1 = list(set(list(M.groundset())) - set(B1))
        bline = []
        for j in nB1:
            if M.is_dependent([j, B1[0], B1[1]]):
                bline.append(j)
        interval = len(bline) + 1
        if M._cached_info is not None and \
           'plot_positions' in M._cached_info.keys() and \
           M._cached_info['plot_positions'] is not None:
            pts2 = M._cached_info['plot_positions']
        else:
            pts2 = {}
            pts2[B1[0]] = (0, 0)
            pts2[B1[1]] = (2, 0)
            lpt = list(pts2[B1[0]])
            rpt = list(pts2[B1[1]])
            for k in range(len(bline)):
                cc = (float(1) / interval) * (k + 1)
                pts2[bline[k]] = (cc * lpt[0] + (1 - cc) * rpt[0],
                                  cc * lpt[1] + (1 - cc) * rpt[1])
            if sp:
                M._cached_info['plot_positions'] = pts2
        # track limits [xmin,xmax,ymin,ymax]
        pl = [list(x) for x in pts2.values()]
        lims = tracklims([None, None, None, None], [pt[0] for pt in pl],
                         [pt[1] for pt in pl])
        bline.extend(B1)
        ptsx, ptsy, x_i, y_i = createline(pts2, bline, lineorders1)
        lims = tracklims(lims, x_i, y_i)
        G += line(zip(x_i, y_i), color='black', thickness=3, zorder=1)
        pels = [p for p in pts2 if any(M1.rank([p, q]) == 1 for q in P)]
        allpts = [list(pts2[i]) for i in M.groundset()]
        xpts = [float(k[0]) for k in allpts]
        ypts = [float(k[1]) for k in allpts]
        G += points(zip(xpts, ypts),
                    color=Color('#BDBDBD'),
                    size=300,
                    zorder=2)
        for i in pts2:
            if i not in pels:
                pt = list(pts2[i])
                G += text(i, (float(pt[0]), float(pt[1])),
                          color='black',
                          fontsize=13)
    else:
        if M._cached_info is None or \
           'plot_positions' not in M._cached_info.keys() or \
           M._cached_info['plot_positions'] is None:
            (pts, trilines, nontripts,
             curvedlines) = it(M1, B1, list(set(M.groundset()) - set(B1)),
                               list(set(L) | set(P)))
            pts2 = addnontripts([B1[0], B1[1], B1[2]], nontripts, pts)
            trilines.extend(curvedlines)
        else:
            pts2 = M._cached_info['plot_positions']
            trilines = [
                list(set(list(x)).difference(L | P)) for x in M1.flats(2)
                if len(list(x)) >= 3
            ]
        pl = [list(x) for x in pts2.values()]
        lims = tracklims([None, None, None, None], [pt[0] for pt in pl],
                         [pt[1] for pt in pl])
        j = 0
        for ll in trilines:
            if len(ll) >= 3:
                ptsx, ptsy, x_i, y_i = createline(pts2, ll, lineorders1)
                lims = tracklims(lims, x_i, y_i)
                G += line(zip(x_i, y_i), color='black', thickness=3, zorder=1)
        pels = [p for p in pts2 if any(M1.rank([p, q]) == 1 for q in P)]
        allpts = [list(pts2[i]) for i in M.groundset()]
        xpts = [float(k[0]) for k in allpts]
        ypts = [float(k[1]) for k in allpts]
        G += points(zip(xpts, ypts),
                    color=Color('#BDBDBD'),
                    size=300,
                    zorder=2)
        for i in pts2:
            if i not in pels:
                pt = list(pts2[i])
                G += text(i, (float(pt[0]), float(pt[1])),
                          color='black',
                          fontsize=13)
        if sp:
            M1._cached_info['plot_positions'] = pts2
            M1._cached_info['plot_lineorders'] = lineorders1
    # deal with loops and parallel elements
    G, lims = addlp(M1, M, L, P, pts2, G, lims)
    G.axes(False)
    G.axes_range(xmin=lims[0] - 0.5,
                 xmax=lims[1] + 0.5,
                 ymin=lims[2] - 0.5,
                 ymax=lims[3] + 0.5)
    return G
Beispiel #39
0
def matrix_plot(mat, **options):
    r"""
    A plot of a given matrix or 2D array.

    If the matrix is dense, each matrix element is given a different
    color value depending on its relative size compared to the other
    elements in the matrix.  If the matrix is sparse, colors only
    indicate whether an element is nonzero or zero, so the plot
    represents the sparsity pattern of the matrix.

    The tick marks drawn on the frame axes denote the row numbers
    (vertical ticks) and the column numbers (horizontal ticks) of the
    matrix.

    INPUT:

    - ``mat`` - a 2D matrix or array

    The following input must all be passed in as named parameters, if
    default not used:

    - ``cmap`` - a colormap (default: 'gray'), the name of
      a predefined colormap, a list of colors,
      or an instance of a matplotlib Colormap.
      Type: ``import matplotlib.cm; matplotlib.cm.datad.keys()``
      for available colormap names.

    - ``colorbar`` -- boolean (default: False) Show a colorbar or not (dense matrices only).

      The following options are used to adjust the style and placement
      of colorbars.  They have no effect if a colorbar is not shown.

      - ``colorbar_orientation`` -- string (default: 'vertical'),
        controls placement of the colorbar, can be either 'vertical'
        or 'horizontal'

      - ``colorbar_format`` -- a format string, this is used to format
        the colorbar labels.

      - ``colorbar_options`` -- a dictionary of options for the matplotlib
        colorbar API.  Documentation for the :mod:`matplotlib.colorbar` module
        has details.

    - ``norm`` - If None (default), the value range is scaled to the interval
      [0,1].  If 'value', then the actual value is used with no
      scaling.  A :class:`matplotlib.colors.Normalize` instance may
      also passed.

    - ``vmin`` - The minimum value (values below this are set to this value)

    - ``vmax`` - The maximum value (values above this are set to this value)

    - ``origin`` - If 'upper' (default), the first row of the matrix
      is on the top of the graph.  If 'lower', the first row is on the
      bottom of the graph.

    - ``subdivisions`` - If True, plot the subdivisions of the matrix as lines.

    - ``subdivision_boundaries`` - a list of lists in the form
      ``[row_subdivisions, column_subdivisions]``, which specifies
      the row and column subdivisions to use.  If not specified,
      defaults to the matrix subdivisions

    - ``subdivision_style`` - a dictionary of properties passed
      on to the :func:`~sage.plot.line.line2d` command for plotting
      subdivisions.  If this is a two-element list or tuple, then it
      specifies the styles of row and column divisions, respectively.

    EXAMPLES:

    A matrix over `\ZZ` colored with different grey levels::

        sage: matrix_plot(matrix([[1,3,5,1],[2,4,5,6],[1,3,5,7]]))
        Graphics object consisting of 1 graphics primitive

    Here we make a random matrix over `\RR` and use ``cmap='hsv'``
    to color the matrix elements different RGB colors::

        sage: matrix_plot(random_matrix(RDF, 50), cmap='hsv')
        Graphics object consisting of 1 graphics primitive

    By default, entries are scaled to the interval [0,1] before
    determining colors from the color map.  That means the two plots
    below are the same::

        sage: P = matrix_plot(matrix(2,[1,1,3,3]))
        sage: Q = matrix_plot(matrix(2,[2,2,3,3]))
        sage: P; Q
        Graphics object consisting of 1 graphics primitive
        Graphics object consisting of 1 graphics primitive

    However, we can specify which values scale to 0 or 1 with the
    ``vmin`` and ``vmax`` parameters (values outside the range are
    clipped).  The two plots below are now distinguished::

        sage: P = matrix_plot(matrix(2,[1,1,3,3]), vmin=0, vmax=3, colorbar=True)
        sage: Q = matrix_plot(matrix(2,[2,2,3,3]), vmin=0, vmax=3, colorbar=True)
        sage: P; Q
        Graphics object consisting of 1 graphics primitive
        Graphics object consisting of 1 graphics primitive

    We can also specify a norm function of 'value', which means that
    there is no scaling performed::

        sage: matrix_plot(random_matrix(ZZ,10)*.05, norm='value', colorbar=True)
        Graphics object consisting of 1 graphics primitive

    Matrix subdivisions can be plotted as well::

        sage: m=random_matrix(RR,10)
        sage: m.subdivide([2,4],[6,8])
        sage: matrix_plot(m, subdivisions=True, subdivision_style=dict(color='red',thickness=3))
        Graphics object consisting of 1 graphics primitive

    You can also specify your own subdivisions and separate styles
    for row or column subdivisions::

        sage: m=random_matrix(RR,10)
        sage: matrix_plot(m, subdivisions=True, subdivision_boundaries=[[2,4],[6,8]], subdivision_style=[dict(color='red',thickness=3),dict(linestyle='--',thickness=6)])
        Graphics object consisting of 1 graphics primitive

    Generally matrices are plotted with the (0,0) entry in the upper
    left.  However, sometimes if we are plotting an image, we'd like
    the (0,0) entry to be in the lower left.  We can do that with the
    ``origin`` argument::

        sage: matrix_plot(identity_matrix(100), origin='lower')
        Graphics object consisting of 1 graphics primitive

    Another random plot, but over `\GF{389}`::

        sage: m = random_matrix(GF(389), 10)
        sage: matrix_plot(m, cmap='Oranges')
        Graphics object consisting of 1 graphics primitive

    It also works if you lift it to the polynomial ring::

        sage: matrix_plot(m.change_ring(GF(389)['x']), cmap='Oranges')
        Graphics object consisting of 1 graphics primitive

    We have several options for colorbars::

        sage: matrix_plot(random_matrix(RDF, 50), colorbar=True, colorbar_orientation='horizontal')
        Graphics object consisting of 1 graphics primitive

    ::

        sage: matrix_plot(random_matrix(RDF, 50), colorbar=True, colorbar_format='%.3f')
        Graphics object consisting of 1 graphics primitive

    The length of a color bar and the length of the adjacent
    matrix plot dimension may be quite different.  This example
    shows how to adjust the length of the colorbar by passing a
    dictionary of options to the matplotlib colorbar routines.  ::

        sage: m = random_matrix(ZZ, 40, 80, x=-10, y=10)
        sage: m.plot(colorbar=True, colorbar_orientation='vertical',
        ....:        colorbar_options={'shrink':0.50})
        Graphics object consisting of 1 graphics primitive

    Here we plot a random sparse matrix::

        sage: sparse = matrix(dict([((randint(0, 10), randint(0, 10)), 1) for i in xrange(100)]))
        sage: matrix_plot(sparse)
        Graphics object consisting of 1 graphics primitive

    ::

        sage: A=random_matrix(ZZ,100000,density=.00001,sparse=True)
        sage: matrix_plot(A,marker=',')
        Graphics object consisting of 1 graphics primitive

    As with dense matrices, sparse matrix entries are automatically
    converted to floating point numbers before plotting.  Thus the
    following works::

        sage: b=random_matrix(GF(2),200,sparse=True,density=0.01)
        sage: matrix_plot(b)
        Graphics object consisting of 1 graphics primitive

    While this returns an error::

        sage: b=random_matrix(CDF,200,sparse=True,density=0.01)
        sage: matrix_plot(b)
        Traceback (most recent call last):
        ...
        ValueError: can not convert entries to floating point numbers

    To plot the absolute value of a complex matrix, use the
    ``apply_map`` method::

        sage: b=random_matrix(CDF,200,sparse=True,density=0.01)
        sage: matrix_plot(b.apply_map(abs))
        Graphics object consisting of 1 graphics primitive

    Plotting lists of lists also works::

        sage: matrix_plot([[1,3,5,1],[2,4,5,6],[1,3,5,7]])
        Graphics object consisting of 1 graphics primitive

    As does plotting of NumPy arrays::

        sage: import numpy
        sage: matrix_plot(numpy.random.rand(10, 10))
        Graphics object consisting of 1 graphics primitive

    A plot title can be added to the matrix plot.::

        sage: matrix_plot(identity_matrix(50), origin='lower', title='not identity')
        Graphics object consisting of 1 graphics primitive

    The title position is adjusted upwards if the ``origin`` keyword is set
    to ``"upper"`` (this is the default).::

        sage: matrix_plot(identity_matrix(50), title='identity')
        Graphics object consisting of 1 graphics primitive

    TESTS::

        sage: P.<t> = RR[]
        sage: matrix_plot(random_matrix(P, 3, 3))
        Traceback (most recent call last):
        ...
        TypeError: cannot coerce nonconstant polynomial to float

    ::

        sage: matrix_plot([1,2,3])
        Traceback (most recent call last):
        ...
        TypeError: mat must be a Matrix or a two dimensional array

    ::

        sage: matrix_plot([[sin(x), cos(x)], [1, 0]])
        Traceback (most recent call last):
        ...
        TypeError: mat must be a Matrix or a two dimensional array

    Test that sparse matrices also work with subdivisions::

        sage: matrix_plot(sparse, subdivisions=True, subdivision_boundaries=[[2,4],[6,8]])
        Graphics object consisting of 1 graphics primitive

    Test that matrix plots have aspect ratio one (see :trac:`15315`)::

        sage: P = matrix_plot(random_matrix(RDF, 5))
        sage: P.aspect_ratio()
        1
    """
    import numpy as np
    import scipy.sparse as scipysparse
    from sage.plot.all import Graphics
    from sage.matrix.matrix import is_Matrix
    from sage.rings.all import RDF
    orig_mat=mat
    if is_Matrix(mat):
        sparse = mat.is_sparse()
        if sparse:
            entries = list(mat._dict().items())
            try:
                data = np.asarray([d for _,d in entries], dtype=float)
            except Exception:
                raise ValueError("can not convert entries to floating point numbers")
            positions = np.asarray([[row for (row,col),_ in entries],
                                    [col for (row,col),_ in entries]], dtype=int)
            mat = scipysparse.coo_matrix((data,positions), shape=(mat.nrows(), mat.ncols()))
        else:
            mat = mat.change_ring(RDF).numpy()
    elif hasattr(mat, 'tocoo'):
        sparse = True
    else:
        sparse = False


    try:
        if sparse:
            xy_data_array = mat
        else:
            xy_data_array = np.asarray(mat, dtype = float)
    except TypeError:
        raise TypeError("mat must be a Matrix or a two dimensional array")
    except ValueError:
        raise ValueError("can not convert entries to floating point numbers")

    if len(xy_data_array.shape) < 2:
        raise TypeError("mat must be a Matrix or a two dimensional array")

    xrange = (0, xy_data_array.shape[1])
    yrange = (0, xy_data_array.shape[0])

    if options['subdivisions'] and options['subdivision_options']['boundaries'] is None:
        options['subdivision_options']['boundaries']=orig_mat.get_subdivisions()

    # Custom position the title. Otherwise it overlaps with tick labels
    if options['origin'] == 'upper' and 'title_pos' not in options:
        options['title_pos'] = (0.5, 1.05)

    g = Graphics()
    g._set_extra_kwds(Graphics._extract_kwds_for_show(options))
    g.add_primitive(MatrixPlot(xy_data_array, xrange, yrange, options))
    return g
Beispiel #40
0
def polygon2d(points, **options):
    r"""
    Returns a 2-dimensional polygon defined by ``points``.

    Type ``polygon2d.options`` for a dictionary of the default
    options for polygons.  You can change this to change the
    defaults for all future polygons.  Use ``polygon2d.reset()``
    to reset to the default options.

    EXAMPLES:

    We create a purple-ish polygon::

        sage: polygon2d([[1,2], [5,6], [5,0]], rgbcolor=(1,0,1))
        Graphics object consisting of 1 graphics primitive

    By default, polygons are filled in, but we can make them
    without a fill as well::

        sage: polygon2d([[1,2], [5,6], [5,0]], fill=False)
        Graphics object consisting of 1 graphics primitive

    In either case, the thickness of the border can be controlled::

        sage: polygon2d([[1,2], [5,6], [5,0]], fill=False, thickness=4, color='orange')
        Graphics object consisting of 1 graphics primitive

    For filled polygons, one can use different colors for the border
    and the interior as follows::

        sage: L = [[0,0]]+[[i/100, 1.1+cos(i/20)] for i in range(100)]+[[1,0]]
        sage: polygon2d(L, color="limegreen", edgecolor="black", axes=False)
        Graphics object consisting of 1 graphics primitive

    Some modern art -- a random polygon, with legend::

        sage: v = [(randrange(-5,5), randrange(-5,5)) for _ in range(10)]
        sage: polygon2d(v, legend_label='some form')
        Graphics object consisting of 1 graphics primitive

    A purple hexagon::

        sage: L = [[cos(pi*i/3),sin(pi*i/3)] for i in range(6)]
        sage: polygon2d(L, rgbcolor=(1,0,1))
        Graphics object consisting of 1 graphics primitive

    A green deltoid::

        sage: L = [[-1+cos(pi*i/100)*(1+cos(pi*i/100)),2*sin(pi*i/100)*(1-cos(pi*i/100))] for i in range(200)]
        sage: polygon2d(L, rgbcolor=(1/8,3/4,1/2))
        Graphics object consisting of 1 graphics primitive

    A blue hypotrochoid::

        sage: L = [[6*cos(pi*i/100)+5*cos((6/2)*pi*i/100),6*sin(pi*i/100)-5*sin((6/2)*pi*i/100)] for i in range(200)]
        sage: polygon2d(L, rgbcolor=(1/8,1/4,1/2))
        Graphics object consisting of 1 graphics primitive

    Another one::

        sage: n = 4; h = 5; b = 2
        sage: L = [[n*cos(pi*i/100)+h*cos((n/b)*pi*i/100),n*sin(pi*i/100)-h*sin((n/b)*pi*i/100)] for i in range(200)]
        sage: polygon2d(L, rgbcolor=(1/8,1/4,3/4))
        Graphics object consisting of 1 graphics primitive

    A purple epicycloid::

        sage: m = 9; b = 1
        sage: L = [[m*cos(pi*i/100)+b*cos((m/b)*pi*i/100),m*sin(pi*i/100)-b*sin((m/b)*pi*i/100)] for i in range(200)]
        sage: polygon2d(L, rgbcolor=(7/8,1/4,3/4))
        Graphics object consisting of 1 graphics primitive

    A brown astroid::

        sage: L = [[cos(pi*i/100)^3,sin(pi*i/100)^3] for i in range(200)]
        sage: polygon2d(L, rgbcolor=(3/4,1/4,1/4))
        Graphics object consisting of 1 graphics primitive

    And, my favorite, a greenish blob::

        sage: L = [[cos(pi*i/100)*(1+cos(pi*i/50)), sin(pi*i/100)*(1+sin(pi*i/50))] for i in range(200)]
        sage: polygon2d(L, rgbcolor=(1/8, 3/4, 1/2))
        Graphics object consisting of 1 graphics primitive

    This one is for my wife::

        sage: L = [[sin(pi*i/100)+sin(pi*i/50),-(1+cos(pi*i/100)+cos(pi*i/50))] for i in range(-100,100)]
        sage: polygon2d(L, rgbcolor=(1,1/4,1/2))
        Graphics object consisting of 1 graphics primitive

    One can do the same one with a colored legend label::

        sage: polygon2d(L, color='red', legend_label='For you!', legend_color='red')
        Graphics object consisting of 1 graphics primitive

    Polygons have a default aspect ratio of 1.0::

        sage: polygon2d([[1,2], [5,6], [5,0]]).aspect_ratio()
        1.0

    AUTHORS:

    - David Joyner (2006-04-14): the long list of examples above.

    """
    from sage.plot.plot import xydata_from_point_list
    from sage.plot.all import Graphics
    if options["thickness"] is None:   # If the user did not specify thickness
        if options["fill"] and options["edgecolor"] is None:
            # If the user chose fill
            options["thickness"] = 0
        else:
            options["thickness"] = 1
    xdata, ydata = xydata_from_point_list(points)
    g = 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'

    g._set_extra_kwds(Graphics._extract_kwds_for_show(options))
    g.add_primitive(Polygon(xdata, ydata, options))
    if options['legend_label']:
        g.legend(True)
        g._legend_colors = [options['legend_color']]
    return g
Beispiel #41
0
    from sage.plot.misc import setup_for_eval_on_grid
    z, ranges = setup_for_eval_on_grid([f,g], [xrange, yrange], options['plot_points'])
    f,g = z

    xpos_array, ypos_array, xvec_array, yvec_array = [],[],[],[]
    for x in xsrange(*ranges[0], include_endpoint=True):
        for y in xsrange(*ranges[1], include_endpoint=True):
            xpos_array.append(x)
            ypos_array.append(y)
            xvec_array.append(f(x,y))
            yvec_array.append(g(x,y))

    import numpy
    xvec_array = numpy.ma.masked_invalid(numpy.array(xvec_array, dtype=float))
    yvec_array = numpy.ma.masked_invalid(numpy.array(yvec_array, dtype=float))
    g = Graphics()
    g._set_extra_kwds(Graphics._extract_kwds_for_show(options))
    g.add_primitive(PlotField(xpos_array, ypos_array, xvec_array, yvec_array, options))
    return g

def plot_slope_field(f, xrange, yrange, **kwds):
    r"""
    ``plot_slope_field`` takes a function of two variables xvar and yvar
    (for instance, if the variables are `x` and `y`, take `f(x,y)`), and at
    representative points `(x_i,y_i)` between xmin, xmax, and ymin, ymax
    respectively, plots a line with slope `f(x_i,y_i)` (see below).

    ``plot_slope_field(f, (xvar, xmin, xmax), (yvar, ymin, ymax))``

    EXAMPLES:
Beispiel #42
0
    def plot(self, **kwds):
        """
        Returns a graphics object representing the (di)graph.

        INPUT:

        The options accepted by this method are to be found in the documentation
        of the :mod:`sage.graphs.graph_plot` module, and the
        :meth:`~sage.plot.graphics.Graphics.show` method.

        .. NOTE::

            See :mod:`the module's documentation <sage.graphs.graph_plot>` for
            information on default values of this method.

        We can specify some pretty precise plotting of familiar graphs::

            sage: from math import sin, cos, pi
            sage: P = graphs.PetersenGraph()
            sage: d = {'#FF0000':[0,5], '#FF9900':[1,6], '#FFFF00':[2,7], '#00FF00':[3,8], '#0000FF':[4,9]}
            sage: pos_dict = {}
            sage: for i in range(5):
            ...    x = float(cos(pi/2 + ((2*pi)/5)*i))
            ...    y = float(sin(pi/2 + ((2*pi)/5)*i))
            ...    pos_dict[i] = [x,y]
            ...
            sage: for i in range(10)[5:]:
            ...    x = float(0.5*cos(pi/2 + ((2*pi)/5)*i))
            ...    y = float(0.5*sin(pi/2 + ((2*pi)/5)*i))
            ...    pos_dict[i] = [x,y]
            ...
            sage: pl = P.graphplot(pos=pos_dict, vertex_colors=d)
            sage: pl.show()

        Here are some more common graphs with typical options::

            sage: C = graphs.CubeGraph(8)
            sage: P = C.graphplot(vertex_labels=False, vertex_size=0, graph_border=True)
            sage: P.show()

            sage: G = graphs.HeawoodGraph().copy(sparse=True)
            sage: for u,v,l in G.edges():
            ...    G.set_edge_label(u,v,'(' + str(u) + ',' + str(v) + ')')
            sage: G.graphplot(edge_labels=True).show()

        The options for plotting also work with directed graphs::

            sage: D = DiGraph( { 0: [1, 10, 19], 1: [8, 2], 2: [3, 6], 3: [19, 4], 4: [17, 5], 5: [6, 15], 6: [7], 7: [8, 14], 8: [9], 9: [10, 13], 10: [11], 11: [12, 18], 12: [16, 13], 13: [14], 14: [15], 15: [16], 16: [17], 17: [18], 18: [19], 19: []}, implementation='networkx' )
            sage: for u,v,l in D.edges():
            ...    D.set_edge_label(u,v,'(' + str(u) + ',' + str(v) + ')')
            sage: D.graphplot(edge_labels=True, layout='circular').show()

        This example shows off the coloring of edges::

            sage: from sage.plot.colors import rainbow
            sage: C = graphs.CubeGraph(5)
            sage: R = rainbow(5)
            sage: edge_colors = {}
            sage: for i in range(5):
            ...    edge_colors[R[i]] = []
            sage: for u,v,l in C.edges():
            ...    for i in range(5):
            ...        if u[i] != v[i]:
            ...            edge_colors[R[i]].append((u,v,l))
            sage: C.graphplot(vertex_labels=False, vertex_size=0, edge_colors=edge_colors).show()


        With the ``partition`` option, we can separate out same-color groups
        of vertices::

            sage: D = graphs.DodecahedralGraph()
            sage: Pi = [[6,5,15,14,7],[16,13,8,2,4],[12,17,9,3,1],[0,19,18,10,11]]
            sage: D.show(partition=Pi)

        Loops are also plotted correctly::

            sage: G = graphs.PetersenGraph()
            sage: G.allow_loops(True)
            sage: G.add_edge(0,0)
            sage: G.show()

        ::

            sage: D = DiGraph({0:[0,1], 1:[2], 2:[3]}, loops=True)
            sage: D.show()
            sage: D.show(edge_colors={(0,1,0):[(0,1,None),(1,2,None)],(0,0,0):[(2,3,None)]})

        More options::

            sage: pos = {0:[0.0, 1.5], 1:[-0.8, 0.3], 2:[-0.6, -0.8], 3:[0.6, -0.8], 4:[0.8, 0.3]}
            sage: g = Graph({0:[1], 1:[2], 2:[3], 3:[4], 4:[0]})
            sage: g.graphplot(pos=pos, layout='spring', iterations=0).plot()

            sage: G = Graph()
            sage: P = G.graphplot().plot()
            sage: P.axes()
            False
            sage: G = DiGraph()
            sage: P = G.graphplot().plot()
            sage: P.axes()
            False

        We can plot multiple graphs::

            sage: T = list(graphs.trees(7))
            sage: t = T[3]
            sage: t.graphplot(heights={0:[0], 1:[4,5,1], 2:[2], 3:[3,6]}).plot()

        ::

            sage: T = list(graphs.trees(7))
            sage: t = T[3]
            sage: t.graphplot(heights={0:[0], 1:[4,5,1], 2:[2], 3:[3,6]}).plot()
            sage: t.set_edge_label(0,1,-7)
            sage: t.set_edge_label(0,5,3)
            sage: t.set_edge_label(0,5,99)
            sage: t.set_edge_label(1,2,1000)
            sage: t.set_edge_label(3,2,'spam')
            sage: t.set_edge_label(2,6,3/2)
            sage: t.set_edge_label(0,4,66)
            sage: t.graphplot(heights={0:[0], 1:[4,5,1], 2:[2], 3:[3,6]}, edge_labels=True).plot()

        ::

            sage: T = list(graphs.trees(7))
            sage: t = T[3]
            sage: t.graphplot(layout='tree').show()

        The tree layout is also useful::

            sage: t = DiGraph('JCC???@A??GO??CO??GO??')
            sage: t.graphplot(layout='tree', tree_root=0, tree_orientation="up").show()

        More examples::

            sage: D = DiGraph({0:[1,2,3], 2:[1,4], 3:[0]})
            sage: D.graphplot().show()

            sage: D = DiGraph(multiedges=True, sparse=True)
            sage: for i in range(5):
            ...     D.add_edge((i,i+1,'a'))
            ...     D.add_edge((i,i-1,'b'))
            sage: D.graphplot(edge_labels=True,edge_colors=D._color_by_label()).plot()

            sage: g = Graph({}, loops=True, multiedges=True, sparse=True)
            sage: g.add_edges([(0,0,'a'),(0,0,'b'),(0,1,'c'),(0,1,'d'),
            ...     (0,1,'e'),(0,1,'f'),(0,1,'f'),(2,1,'g'),(2,2,'h')])
            sage: g.graphplot(edge_labels=True, color_by_label=True, edge_style='dashed').plot()

        The ``edge_style`` option may be provided in the short format too::

            sage: g.graphplot(edge_labels=True, color_by_label=True, edge_style='--').plot()

        TESTS:

        Make sure that show options work with plot also::

            sage: g = Graph({})
            sage: g.plot(title='empty graph', axes=True)

        Check for invalid inputs::

            sage: p = graphs.PetersenGraph().plot(egabrag='garbage')
            Traceback (most recent call last):
            ...
            ValueError: Invalid input 'egabrag=garbage'

        """
        G = Graphics()
        options = self._options.copy()
        options.update(kwds)
        G._set_extra_kwds(Graphics._extract_kwds_for_show(options))

        # Check the arguments
        for o in options:
            if o not in graphplot_options and o not in G._extra_kwds:
                raise ValueError("Invalid input '{}={}'".format(o, options[o]))

        for comp in self._plot_components.values():
            if not isinstance(comp, list):
                G += comp
            else:
                for item in comp:
                    G += item

        G.set_axes_range(*(self._graph._layout_bounding_box(self._pos)))
        if self._options['graph_border']:
            xmin = G.xmin()
            xmax = G.xmax()
            ymin = G.ymin()
            ymax = G.ymax()
            dx = (xmax - xmin) / 10.0
            dy = (ymax - ymin) / 10.0
            border = (line([(xmin - dx, ymin - dy), (xmin - dx, ymax + dy),
                            (xmax + dx, ymax + dy), (xmax + dx, ymin - dy),
                            (xmin - dx, ymin - dy)],
                           thickness=1.3))
            border.axes_range(xmin=(xmin - dx),
                              xmax=(xmax + dx),
                              ymin=(ymin - dy),
                              ymax=(ymax + dy))
            G += border
        G.set_aspect_ratio(1)
        G.axes(False)
        G._extra_kwds['axes_pad'] = .05
        return G
Beispiel #43
0
def matrix_plot(mat, xrange=None, yrange=None, **options):
    r"""
    A plot of a given matrix or 2D array.

    If the matrix is sparse, colors only indicate whether an element is
    nonzero or zero, so the plot represents the sparsity pattern of the
    matrix.

    If the matrix is dense, each matrix element is given a different
    color value depending on its relative size compared to the other
    elements in the matrix.

    The default is for the lowest number to be black and the highest
    number to be white in a greyscale pattern; see the information about
    normalizing below. To reverse this, use ``cmap='Greys'``.

    The tick marks drawn on the frame axes denote the row numbers
    (vertical ticks) and the column numbers (horizontal ticks) of the
    matrix.

    INPUT:

    - ``mat`` - a 2D matrix or array

    - ``xrange`` - (default: None) tuple of the horizontal extent
      ``(xmin, xmax)`` of the bounding box in which to draw the matrix.  The
      image is stretched individually along x and y to fill the box.

      If None, the extent is determined by the following conditions.  Matrix
      entries have unit size in data coordinates.  Their centers are on integer
      coordinates, and their center coordinates range from 0 to columns-1
      horizontally and from 0 to rows-1 vertically.

      If the matrix is sparse, this keyword is ignored.

    - ``yrange`` - (default: None) tuple of the vertical extent
      ``(ymin, ymax)`` of the bounding box in which to draw the matrix.
      See ``xrange`` for details.

    The following input must all be passed in as named parameters, if
    default not used:

    - ``cmap`` - a colormap (default: 'Greys'), the name of a predefined
      colormap, a list of colors, or an instance of a matplotlib Colormap.

      The list of predefined color maps can be visualized in `matplotlib's
      documentation
      <https://matplotlib.org/examples/color/colormaps_reference.html>`__. You
      can also type ``import matplotlib.cm; matplotlib.cm.datad.keys()`` to list
      their names.

    - ``colorbar`` -- boolean (default: False) Show a colorbar or not (dense matrices only).

      The following options are used to adjust the style and placement
      of colorbars.  They have no effect if a colorbar is not shown.

      - ``colorbar_orientation`` -- string (default: 'vertical'),
        controls placement of the colorbar, can be either 'vertical'
        or 'horizontal'

      - ``colorbar_format`` -- a format string, this is used to format
        the colorbar labels.

      - ``colorbar_options`` -- a dictionary of options for the matplotlib
        colorbar API.  Documentation for the :mod:`matplotlib.colorbar` module
        has details.

    - ``norm`` - If None (default), the value range is scaled to the interval
      [0,1].  If 'value', then the actual value is used with no
      scaling.  A :class:`matplotlib.colors.Normalize` instance may
      also passed.

    - ``vmin`` - The minimum value (values below this are set to this value)

    - ``vmax`` - The maximum value (values above this are set to this value)

    - ``flip_y`` - (default: True) boolean.  If False, the first row of the
      matrix is on the bottom of the graph.  Otherwise, the first row is on the
      top of the graph.

    - ``subdivisions`` - If True, plot the subdivisions of the matrix as lines.

    - ``subdivision_boundaries`` - a list of lists in the form
      ``[row_subdivisions, column_subdivisions]``, which specifies
      the row and column subdivisions to use.  If not specified,
      defaults to the matrix subdivisions

    - ``subdivision_style`` - a dictionary of properties passed
      on to the :func:`~sage.plot.line.line2d` command for plotting
      subdivisions.  If this is a two-element list or tuple, then it
      specifies the styles of row and column divisions, respectively.

    EXAMPLES:

    A matrix over `\ZZ` colored with different grey levels::

        sage: matrix_plot(matrix([[1,3,5,1],[2,4,5,6],[1,3,5,7]]))
        Graphics object consisting of 1 graphics primitive

    .. PLOT::

        P = matrix_plot(matrix([[1,3,5,1],[2,4,5,6],[1,3,5,7]]))
        sphinx_plot(P)

    Here we make a random matrix over `\RR` and use ``cmap='hsv'``
    to color the matrix elements different RGB colors::

        sage: matrix_plot(random_matrix(RDF, 50), cmap='hsv')
        Graphics object consisting of 1 graphics primitive

    By default, entries are scaled to the interval [0,1] before
    determining colors from the color map.  That means the two plots
    below are the same::

        sage: P = matrix_plot(matrix(2,[1,1,3,3]))
        sage: Q = matrix_plot(matrix(2,[2,2,3,3]))
        sage: P; Q
        Graphics object consisting of 1 graphics primitive
        Graphics object consisting of 1 graphics primitive

    However, we can specify which values scale to 0 or 1 with the
    ``vmin`` and ``vmax`` parameters (values outside the range are
    clipped).  The two plots below are now distinguished::

        sage: P = matrix_plot(matrix(2,[1,1,3,3]), vmin=0, vmax=3, colorbar=True)
        sage: Q = matrix_plot(matrix(2,[2,2,3,3]), vmin=0, vmax=3, colorbar=True)
        sage: P; Q
        Graphics object consisting of 1 graphics primitive
        Graphics object consisting of 1 graphics primitive

    We can also specify a norm function of 'value', which means that
    there is no scaling performed::

        sage: matrix_plot(random_matrix(ZZ,10)*.05, norm='value', colorbar=True)
        Graphics object consisting of 1 graphics primitive

    Matrix subdivisions can be plotted as well::

        sage: m=random_matrix(RR,10)
        sage: m.subdivide([2,4],[6,8])
        sage: matrix_plot(m, subdivisions=True, subdivision_style=dict(color='red',thickness=3))
        Graphics object consisting of 1 graphics primitive

    You can also specify your own subdivisions and separate styles
    for row or column subdivisions::

        sage: m=random_matrix(RR,10)
        sage: matrix_plot(m, subdivisions=True, subdivision_boundaries=[[2,4],[6,8]], subdivision_style=[dict(color='red',thickness=3),dict(linestyle='--',thickness=6)])
        Graphics object consisting of 1 graphics primitive

    Generally matrices are plotted with the (0,0) entry in the upper
    left.  However, sometimes if we are plotting an image, we'd like
    the (0,0) entry to be in the lower left.  We can do that with the
    ``flip_y`` argument::

        sage: matrix_plot(identity_matrix(100), flip_y=False)
        Graphics object consisting of 1 graphics primitive

    A custom bounding box in which to draw the matrix can be specified using
    the ``xrange`` and ``yrange`` arguments::

        sage: P = matrix_plot(identity_matrix(10), xrange=(0, pi), yrange=(-pi, 0))
        sage: P
        Graphics object consisting of 1 graphics primitive
        sage: P.get_minmax_data()
        {'xmax': 3.14159..., 'xmin': 0.0, 'ymax': 0.0, 'ymin': -3.14159...}

    If the horizontal and vertical dimension of the image are very different,
    the default ``aspect_ratio=1`` may be unsuitable and can be changed to
    ``automatic``::

        sage: matrix_plot(random_matrix(RDF, 2, 2), (-100, 100), (0, 1),
        ....:             aspect_ratio='automatic')
        Graphics object consisting of 1 graphics primitive

    Another random plot, but over `\GF{389}`::

        sage: m = random_matrix(GF(389), 10)
        sage: matrix_plot(m, cmap='Oranges')
        Graphics object consisting of 1 graphics primitive

    It also works if you lift it to the polynomial ring::

        sage: matrix_plot(m.change_ring(GF(389)['x']), cmap='Oranges')
        Graphics object consisting of 1 graphics primitive

    We have several options for colorbars::

        sage: matrix_plot(random_matrix(RDF, 50), colorbar=True, colorbar_orientation='horizontal')
        Graphics object consisting of 1 graphics primitive

    ::

        sage: matrix_plot(random_matrix(RDF, 50), colorbar=True, colorbar_format='%.3f')
        Graphics object consisting of 1 graphics primitive

    The length of a color bar and the length of the adjacent
    matrix plot dimension may be quite different.  This example
    shows how to adjust the length of the colorbar by passing a
    dictionary of options to the matplotlib colorbar routines.  ::

        sage: m = random_matrix(ZZ, 40, 80, x=-10, y=10)
        sage: m.plot(colorbar=True, colorbar_orientation='vertical',
        ....:        colorbar_options={'shrink':0.50})
        Graphics object consisting of 1 graphics primitive

    Here we plot a random sparse matrix::

        sage: sparse = matrix(dict([((randint(0, 10), randint(0, 10)), 1) for i in range(100)]))
        sage: matrix_plot(sparse)
        Graphics object consisting of 1 graphics primitive

    ::

        sage: A=random_matrix(ZZ,100000,density=.00001,sparse=True)
        sage: matrix_plot(A,marker=',')
        Graphics object consisting of 1 graphics primitive

    As with dense matrices, sparse matrix entries are automatically
    converted to floating point numbers before plotting.  Thus the
    following works::

        sage: b=random_matrix(GF(2),200,sparse=True,density=0.01)
        sage: matrix_plot(b)
        Graphics object consisting of 1 graphics primitive

    While this returns an error::

        sage: b=random_matrix(CDF,200,sparse=True,density=0.01)
        sage: matrix_plot(b)
        Traceback (most recent call last):
        ...
        ValueError: cannot convert entries to floating point numbers

    To plot the absolute value of a complex matrix, use the
    ``apply_map`` method::

        sage: b=random_matrix(CDF,200,sparse=True,density=0.01)
        sage: matrix_plot(b.apply_map(abs))
        Graphics object consisting of 1 graphics primitive

    Plotting lists of lists also works::

        sage: matrix_plot([[1,3,5,1],[2,4,5,6],[1,3,5,7]])
        Graphics object consisting of 1 graphics primitive

    As does plotting of NumPy arrays::

        sage: import numpy
        sage: matrix_plot(numpy.random.rand(10, 10))
        Graphics object consisting of 1 graphics primitive

    A plot title can be added to the matrix plot.::

        sage: matrix_plot(identity_matrix(50), flip_y=False, title='not identity')
        Graphics object consisting of 1 graphics primitive

    The title position is adjusted upwards if the ``flip_y`` keyword is set
    to True (this is the default).::

        sage: matrix_plot(identity_matrix(50), title='identity')
        Graphics object consisting of 1 graphics primitive

    TESTS::

        sage: P.<t> = RR[]
        sage: matrix_plot(random_matrix(P, 3, 3))
        Traceback (most recent call last):
        ...
        TypeError: cannot convert nonconstant polynomial

    ::

        sage: matrix_plot([1,2,3])
        Traceback (most recent call last):
        ...
        TypeError: mat must be a Matrix or a two dimensional array

    ::

        sage: matrix_plot([[sin(x), cos(x)], [1, 0]])
        Traceback (most recent call last):
        ...
        TypeError: mat must be a Matrix or a two dimensional array

    Test that sparse matrices also work with subdivisions::

        sage: matrix_plot(sparse, subdivisions=True, subdivision_boundaries=[[2,4],[6,8]])
        Graphics object consisting of 1 graphics primitive

    Test that matrix plots have aspect ratio one (see :trac:`15315`)::

        sage: P = matrix_plot(random_matrix(RDF, 5))
        sage: P.aspect_ratio()
        1

    The origin keyword is deprecated::

        sage: matrix_plot(identity_matrix(100), origin='lower')
        doctest:...: DeprecationWarning: the option 'origin' is replaced by 'flip_y'
        See https://trac.sagemath.org/27891 for details.
        Graphics object consisting of 1 graphics primitive
    """
    if 'origin' in options:
        from sage.misc.superseded import deprecation
        deprecation(27891, "the option 'origin' is replaced by 'flip_y'")
        options['flip_y'] = (options['origin'] != 'lower')
        del options['origin']

    import numpy as np
    import scipy.sparse as scipysparse
    from sage.plot.all import Graphics
    from sage.structure.element import is_Matrix
    from sage.rings.all import RDF
    orig_mat = mat
    if is_Matrix(mat):
        sparse = mat.is_sparse()
        if sparse:
            entries = list(mat._dict().items())
            try:
                data = np.asarray([d for _, d in entries], dtype=float)
            except Exception:
                raise ValueError(
                    "cannot convert entries to floating point numbers")
            positions = np.asarray([[row for (row, col), _ in entries],
                                    [col for (row, col), _ in entries]],
                                   dtype=int)
            mat = scipysparse.coo_matrix((data, positions),
                                         shape=(mat.nrows(), mat.ncols()))
        else:
            mat = mat.change_ring(RDF).numpy()
    elif hasattr(mat, 'tocoo'):
        sparse = True
    else:
        sparse = False

    try:
        if sparse:
            xy_data_array = mat
        else:
            xy_data_array = np.asarray(mat, dtype=float)
    except TypeError:
        raise TypeError("mat must be a Matrix or a two dimensional array")
    except ValueError:
        raise ValueError("cannot convert entries to floating point numbers")

    if len(xy_data_array.shape) < 2:
        raise TypeError("mat must be a Matrix or a two dimensional array")

    # Sparse matrices are not plotted with imshow, so extent is not supported,
    # hence we ignore custom bounds.
    if sparse:
        xrange = None
        yrange = None
    if xrange:
        xrange = tuple(float(v) for v in xrange)
    if yrange:
        yrange = tuple(float(v) for v in yrange)

    if options['subdivisions'] and options['subdivision_options'][
            'boundaries'] is None:
        options['subdivision_options'][
            'boundaries'] = orig_mat.get_subdivisions()

    # Custom position the title. Otherwise it overlaps with tick labels
    if options['flip_y'] and 'title_pos' not in options:
        options['title_pos'] = (0.5, 1.05)

    g = Graphics()
    g._set_extra_kwds(Graphics._extract_kwds_for_show(options))
    # Keep flip_y for _render_on_subplot
    options['flip_y'] = g._extra_kwds['flip_y']
    g.add_primitive(MatrixPlot(xy_data_array, xrange, yrange, options))
    return g
        def plot(self,
                 size=[[0], [0]],
                 projection='usual',
                 simple_roots=True,
                 fundamental_weights=True,
                 alcovewalks=[]):
            r"""
            Return a graphics object built from a space of weight(space/lattice).
            There is a different technic to plot if the Cartan type is affine or not.
            The graphics returned is a Graphics object.

            This function is experimental, and is subject to short term evolutions.

            EXAMPLES::

              By default, the plot returned has no axes and the ratio between axes is 1.
                sage: G = RootSystem(['C',2]).weight_lattice().plot()
                sage: G.axes(True)
                sage: G.set_aspect_ratio(2)

              For a non affine Cartan type, the plot method work for type with 2 generators,
              it will draw the hyperlane(line for this dimension) accrow the fundamentals weights.
                sage: G = RootSystem(['A',2]).weight_lattice().plot()
                sage: G = RootSystem(['B',2]).weight_lattice().plot()
                sage: G = RootSystem(['G',2]).weight_lattice().plot()

              The plot returned has a size of one fundamental polygon by default. We can
              ask plot to give a bigger plot by using the argument size
                sage: G = RootSystem(['G',2,1]).weight_space().plot(size = [[0..1],[-1..1]])
                sage: G = RootSystem(['A',2,1]).weight_space().plot(size = [[-1..1],[-1..1]])

              A very important argument is the projection which will draw the plot. There are
              some usual projections is this method. If you want to draw in the plane a very
              special Cartan type, Sage will ask you to specify the projection. The projection
              is a matrix over a ring. In practice, calcul over float is a good way to draw.
                sage: L = RootSystem(['A',2,1]).weight_space()
                sage: G = L.plot(projection=matrix(RR, [[0,0.5,-0.5],[0,0.866,0.866]]))
                sage: G = RootSystem(['C',2,1]).weight_space().plot()

              By default, the plot method draw the simple roots, this can be disabled by setting
              the argument simple_roots=False
                sage: G = RootSystem(['A',2]).weight_space().plot(simple_roots=False)

              By default, the plot method draw the fundamental weights,this can be disabled by
              setting the argument fundamental_weights=False
                sage: G = RootSystem(['A',2]).weight_space().plot(fundamental_weights=False, simple_roots=False)

              There is in a plot an argument to draw alcoves walks. The good way to do this is
              to use the crystals theory. the plot method contains only the drawing part...
                sage: L = RootSystem(['A',2,1]).weight_space()
                sage: G = L.plot(size=[[-1..1],[-1..1]],alcovewalks=[[0,2,0,1,2,1,2,0,2,1]])
            """

            from sage.plot.all import Graphics
            from sage.plot.line import line
            from cartan_type import CartanType
            from sage.matrix.constructor import matrix
            from sage.rings.all import QQ, RR
            from sage.plot.arrow import arrow
            from sage.plot.point import point

            # We begin with an empty plot G
            G = Graphics()

            ct = self.cartan_type()
            n = ct.n

            # Define a set of colors
            # TODO : Colors in option ?
            colors = [(0, 1, 0), (1, 0, 0), (0, 0, 1), (1, 1, 0), (0, 1, 1),
                      (1, 0, 1)]

            # plot the affine types:
            if ct.is_affine():

                # Check the projection
                # TODO : try to have usual_projection for main plotable types
                if projection == 'usual':
                    if ct == CartanType(['A', 2, 1]):
                        projection = matrix(
                            RR, [[0, 0.5, -0.5], [0, 0.866, 0.866]])
                    elif ct == CartanType(['C', 2, 1]):
                        projection = matrix(QQ, [[0, 1, 1], [0, 0, 1]])
                    elif ct == CartanType(['G', 2, 1]):
                        projection = matrix(RR,
                                            [[0, 0.5, 0], [0, 0.866, 1.732]])
                    else:
                        raise 'There is no usual projection for this Cartan type, you have to give one in argument'

                assert (n + 1 == projection.ncols())
                assert (2 == projection.nrows())

                # Check the size is correct with the lattice
                assert (len(size) == n)

                # Select the center of the translated fundamental polygon to plot
                translation_factors = ct.translation_factors()
                simple_roots = self.simple_roots()
                translation_vectors = [
                    translation_factors[i] * simple_roots[i]
                    for i in ct.classical().index_set()
                ]

                initial = [[]]
                for i in range(n):
                    prod_list = []
                    for elem in size[i]:
                        for partial_list in initial:
                            prod_list.append([elem] + partial_list)
                    initial = prod_list

                part_lattice = []
                for combinaison in prod_list:
                    elem_lattice = self.zero()
                    for i in range(n):
                        elem_lattice = elem_lattice + combinaison[
                            i] * translation_vectors[i]
                    part_lattice.append(elem_lattice)

                # Get the vertices of the fundamental alcove
                fundamental_weights = self.fundamental_weights()
                vertices = map(lambda x: (1 / x.level()) * x,
                               fundamental_weights.list())

                # Recup the group which act on the fundamental polygon
                classical = self.weyl_group().classical()

                for center in part_lattice:
                    for w in classical:
                        # for each center of polygon and each element of classical
                        # parabolic subgroup, we have to draw an alcove.

                        #first, iterate over pairs of fundamental weights, drawing lines border of polygons:
                        for i in range(1, n + 1):
                            for j in range(i + 1, n + 1):
                                p1 = projection * (
                                    (w.action(vertices[i])).to_vector() +
                                    center.to_vector())
                                p2 = projection * (
                                    (w.action(vertices[j])).to_vector() +
                                    center.to_vector())
                                G += line([p1, p2],
                                          rgbcolor=(0, 0, 0),
                                          thickness=2)

                        #next, get all lines from point to a fundamental weight, that separe different
                        #chanber in a same polygon (important: associate a color with a fundamental weight)
                        pcenter = projection * (center.to_vector())
                        for i in range(1, n + 1):
                            p3 = projection * (
                                (w.action(vertices[i])).to_vector() +
                                center.to_vector())
                            G += line([p3, pcenter],
                                      rgbcolor=colors[n - i + 1])

                #Draw alcovewalks
                #FIXME : The good way to draw this is to use the alcoves walks works made in Cristals
                #The code here just draw like example and import the good things.
                rho = (1 / self.rho().level()) * self.rho()
                W = self.weyl_group()
                for walk in alcovewalks:
                    target = W.from_reduced_word(walk).action(rho)
                    for i in range(len(walk)):
                        walk.pop()
                        origin = W.from_reduced_word(walk).action(rho)
                        G += arrow(projection * (origin.to_vector()),
                                   projection * (target.to_vector()),
                                   rgbcolor=(0.6, 0, 0.6),
                                   width=1,
                                   arrowsize=5)
                        target = origin

            else:
                # non affine plot

                # Check the projection
                # TODO : try to have usual_projection for main plotable types
                if projection == 'usual':
                    if ct == CartanType(['A', 2]):
                        projection = matrix(RR, [[0.5, -0.5], [0.866, 0.866]])
                    elif ct == CartanType(['B', 2]):
                        projection = matrix(QQ, [[1, 0], [1, 1]])
                    elif ct == CartanType(['C', 2]):
                        projection = matrix(QQ, [[1, 1], [0, 1]])
                    elif ct == CartanType(['G', 2]):
                        projection = matrix(RR, [[0.5, 0], [0.866, 1.732]])
                    else:
                        raise 'There is no usual projection for this Cartan type, you have to give one in argument'

                # Get the fundamental weights
                fundamental_weights = self.fundamental_weights()
                WeylGroup = self.weyl_group()

                #Draw not the alcove but the cones delimited by the hyperplanes
                #The size of the line depend of the fundamental weights.
                pcenter = projection * (self.zero().to_vector())
                for w in WeylGroup:
                    for i in range(1, n + 1):
                        p3 = 3 * projection * (
                            (w.action(fundamental_weights[i])).to_vector())
                        G += line([p3, pcenter], rgbcolor=colors[n - i + 1])

            #Draw the simple roots
            if simple_roots:
                SimpleRoots = self.simple_roots()
                if ct.is_affine():
                    G += arrow((0, 0),
                               projection * (SimpleRoots[0].to_vector()),
                               rgbcolor=(0, 0, 0))
                for j in range(1, n + 1):
                    G += arrow((0, 0),
                               projection * (SimpleRoots[j].to_vector()),
                               rgbcolor=colors[j])

            #Draw the fundamental weights
            if fundamental_weights:
                FundWeight = self.fundamental_weights()
                for j in range(1, n + 1):
                    G += point(projection * (FundWeight[j].to_vector()),
                               rgbcolor=colors[j],
                               pointsize=60)

            G.set_aspect_ratio(1)
            G.axes(False)
            return G
Beispiel #45
0
def contour_plot(f, xrange, yrange, **options):
    r"""
    ``contour_plot`` takes a function of two variables, `f(x,y)`
    and plots contour lines of the function over the specified
    ``xrange`` and ``yrange`` as demonstrated below.

    ``contour_plot(f, (xmin, xmax), (ymin, ymax), ...)``

    INPUT:

    - ``f`` -- a function of two variables

    - ``(xmin, xmax)`` -- 2-tuple, the range of ``x`` values OR 3-tuple
      ``(x,xmin,xmax)``

    - ``(ymin, ymax)`` -- 2-tuple, the range of ``y`` values OR 3-tuple
      ``(y,ymin,ymax)``

    The following inputs must all be passed in as named parameters:

    - ``plot_points``  -- integer (default: 100); number of points to plot
      in each direction of the grid.  For old computers, 25 is fine, but
      should not be used to verify specific intersection points.

    - ``fill`` -- bool (default: ``True``), whether to color in the area
      between contour lines

    - ``cmap`` -- a colormap (default: ``'gray'``), the name of
      a predefined colormap, a list of colors or an instance of a matplotlib
      Colormap. Type: ``import matplotlib.cm; matplotlib.cm.datad.keys()``
      for available colormap names.

    - ``contours`` -- integer or list of numbers (default: ``None``):
      If a list of numbers is given, then this specifies the contour levels
      to use.  If an integer is given, then this many contour lines are
      used, but the exact levels are determined automatically. If ``None``
      is passed (or the option is not given), then the number of contour
      lines is determined automatically, and is usually about 5.

    - ``linewidths`` -- integer or list of integer (default: None), if
      a single integer all levels will be of the width given,
      otherwise the levels will be plotted with the width in the order
      given.  If the list is shorter than the number of contours, then
      the widths will be repeated cyclically.

    - ``linestyles`` -- string or list of strings (default: None), the
      style of the lines to be plotted, one of: ``"solid"``, ``"dashed"``,
      ``"dashdot"``, ``"dotted"``, respectively ``"-"``, ``"--"``,
      ``"-."``, ``":"``.  If the list is shorter than the number of
      contours, then the styles will be repeated cyclically.

    - ``labels`` -- boolean (default: False) Show level labels or not.

      The following options are to adjust the style and placement of
      labels, they have no effect if no labels are shown.

      - ``label_fontsize`` -- integer (default: 9), the font size of the labels.

      - ``label_colors`` -- string or sequence of colors (default:
        None) If a string, gives the name of a single color with which
        to draw all labels.  If a sequence, gives the colors of the
        labels.  A color is a string giving the name of one or a
        3-tuple of floats.

      - ``label_inline`` -- boolean (default: False if fill is True,
        otherwise True), controls whether the underlying contour is
        removed or not.

      - ``label_inline_spacing`` -- integer (default: 3), When inline,
        this is the amount of contour that is removed from each side,
        in pixels.

      - ``label_fmt`` -- a format string (default: "%1.2f"), this is
        used to get the label text from the level.  This can also be a
        dictionary with the contour levels as keys and corresponding
        text string labels as values.  It can also be any callable which
        returns a string when called with a numeric contour level.

    - ``colorbar`` -- boolean (default: False) Show a colorbar or not.

      The following options are to adjust the style and placement of
      colorbars.  They have no effect if a colorbar is not shown.

      - ``colorbar_orientation`` -- string (default: 'vertical'),
        controls placement of the colorbar, can be either 'vertical'
        or 'horizontal'

      - ``colorbar_format`` -- a format string, this is used to format
        the colorbar labels.

      - ``colorbar_spacing`` -- string (default: 'proportional').  If
        'proportional', make the contour divisions proportional to
        values.  If 'uniform', space the colorbar divisions uniformly,
        without regard for numeric values.

    - ``legend_label`` -- the label for this item in the legend

    -  ``region`` - (default: None) If region is given, it must be a function
        of two variables. Only segments of the surface where region(x,y) returns a
        number >0 will be included in the plot.

    EXAMPLES:

    Here we plot a simple function of two variables.  Note that
    since the input function is an expression, we need to explicitly
    declare the variables in 3-tuples for the range::

        sage: x,y = var('x,y')
        sage: contour_plot(cos(x^2+y^2), (x, -4, 4), (y, -4, 4))

    Here we change the ranges and add some options::

        sage: x,y = var('x,y')
        sage: contour_plot((x^2)*cos(x*y), (x, -10, 5), (y, -5, 5), fill=False, plot_points=150)

    An even more complicated plot::

        sage: x,y = var('x,y')
        sage: contour_plot(sin(x^2 + y^2)*cos(x)*sin(y), (x, -4, 4), (y, -4, 4),plot_points=150)

    Some elliptic curves, but with symbolic endpoints.  In the first
    example, the plot is rotated 90 degrees because we switch the
    variables `x`, `y`::

        sage: x,y = var('x,y')
        sage: contour_plot(y^2 + 1 - x^3 - x, (y,-pi,pi), (x,-pi,pi))

    ::

        sage: contour_plot(y^2 + 1 - x^3 - x, (x,-pi,pi), (y,-pi,pi))

    We can play with the contour levels::

        sage: x,y = var('x,y')
        sage: f(x,y) = x^2 + y^2
        sage: contour_plot(f, (-2, 2), (-2, 2))

    ::

        sage: contour_plot(f, (-2, 2), (-2, 2), contours=2, cmap=[(1,0,0), (0,1,0), (0,0,1)])

    ::

        sage: contour_plot(f, (-2, 2), (-2, 2), contours=(0.1, 1.0, 1.2, 1.4), cmap='hsv')

    ::

        sage: contour_plot(f, (-2, 2), (-2, 2), contours=(1.0,), fill=False)

    ::

        sage: contour_plot(x-y^2,(x,-5,5),(y,-3,3),contours=[-4,0,1])

    We can change the style of the lines::

        sage: contour_plot(f, (-2,2), (-2,2), fill=False, linewidths=10)

    ::

        sage: contour_plot(f, (-2,2), (-2,2), fill=False, linestyles='dashdot')

    ::

        sage: P=contour_plot(x^2-y^2,(x,-3,3),(y,-3,3),contours=[0,1,2,3,4],\
        ...    linewidths=[1,5],linestyles=['solid','dashed'],fill=False)
        sage: P

    ::

        sage: P=contour_plot(x^2-y^2,(x,-3,3),(y,-3,3),contours=[0,1,2,3,4],\
        ...    linewidths=[1,5],linestyles=['solid','dashed'])
        sage: P

        sage: P=contour_plot(x^2-y^2,(x,-3,3),(y,-3,3),contours=[0,1,2,3,4],\
        ...    linewidths=[1,5],linestyles=['-',':'])
        sage: P

    We can add labels and play with them::

        sage: contour_plot(y^2 + 1 - x^3 - x, (x,-pi,pi), (y,-pi,pi),  fill=False, cmap='hsv', labels=True)

    ::

        sage: P=contour_plot(y^2 + 1 - x^3 - x, (x,-pi,pi), (y,-pi,pi), fill=False, cmap='hsv',\
        ...     labels=True, label_fmt="%1.0f", label_colors='black')
        sage: P

    ::

        sage: P=contour_plot(y^2 + 1 - x^3 - x, (x,-pi,pi), (y,-pi,pi), fill=False, cmap='hsv',labels=True,\
        ...    contours=[-4,0,4],  label_fmt={-4:"low", 0:"medium", 4: "hi"}, label_colors='black')
        sage: P

    ::

        sage: P=contour_plot(y^2 + 1 - x^3 - x, (x,-pi,pi), (y,-pi,pi), fill=False, cmap='hsv',labels=True,\
        ...    contours=[-4,0,4],  label_fmt=lambda x: "$z=%s$"%x, label_colors='black', label_inline=True, \
        ...    label_fontsize=12)
        sage: P

    ::

        sage: P=contour_plot(y^2 + 1 - x^3 - x, (x,-pi,pi), (y,-pi,pi), \
        ...    fill=False, cmap='hsv', labels=True, label_fontsize=18)
        sage: P

    ::

        sage: P=contour_plot(y^2 + 1 - x^3 - x, (x,-pi,pi), (y,-pi,pi), \
        ...    fill=False, cmap='hsv', labels=True, label_inline_spacing=1)
        sage: P

    ::

        sage: P= contour_plot(y^2 + 1 - x^3 - x, (x,-pi,pi), (y,-pi,pi), \
        ...    fill=False, cmap='hsv', labels=True, label_inline=False)
        sage: P

    We can change the color of the labels if so desired::

        sage: contour_plot(f, (-2,2), (-2,2), labels=True, label_colors='red')

    We can add a colorbar as well::

        sage: f(x,y)=x^2-y^2
        sage: contour_plot(f, (x,-3,3), (y,-3,3), colorbar=True)

    ::

        sage: contour_plot(f, (x,-3,3), (y,-3,3), colorbar=True,colorbar_orientation='horizontal')

    ::

        sage: contour_plot(f, (x,-3,3), (y,-3,3), contours=[-2,-1,4],colorbar=True)

    ::

        sage: contour_plot(f, (x,-3,3), (y,-3,3), contours=[-2,-1,4],colorbar=True,colorbar_spacing='uniform')

    ::

        sage: contour_plot(f, (x,-3,3), (y,-3,3), contours=[0,2,3,6],colorbar=True,colorbar_format='%.3f')

    ::

        sage: contour_plot(f, (x,-3,3), (y,-3,3), labels=True,label_colors='red',contours=[0,2,3,6],colorbar=True)

    ::

        sage: contour_plot(f, (x,-3,3), (y,-3,3), cmap='winter', contours=20, fill=False, colorbar=True)

    This should plot concentric circles centered at the origin::

        sage: x,y = var('x,y')
        sage: contour_plot(x^2+y^2-2,(x,-1,1), (y,-1,1))

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

        sage: f(x, y) = cos(x) + sin(y)
        sage: contour_plot(f, (0, pi), (0, pi), axes=True)

    One can also plot over a reduced region::

        sage: contour_plot(x**2-y**2, (x,-2, 2), (y,-2, 2),region=x-y,plot_points=300)

    ::

        sage: contour_plot(f, (0, pi), (0, pi)).show(axes=True) # These are equivalent

    Note that with ``fill=False`` and grayscale contours, there is the
    possibility of confusion between the contours and the axes, so use
    ``fill=False`` together with ``axes=True`` with caution::

        sage: contour_plot(f, (-pi, pi), (-pi, pi), fill=False, axes=True)

    TESTS:

    To check that ticket 5221 is fixed, note that this has three curves, not two::

        sage: x,y = var('x,y')
        sage: contour_plot(x-y^2,(x,-5,5),(y,-3,3),contours=[-4,-2,0], fill=False)
    """
    from sage.plot.all import Graphics
    from sage.plot.misc import setup_for_eval_on_grid

    region = options.pop('region')
    ev = [f] if region is None else [f,region]

    F, ranges = setup_for_eval_on_grid(ev, [xrange, yrange], options['plot_points'])
    g = F[0]
    xrange,yrange=[r[:2] for r in ranges]

    xy_data_array = [[g(x, y) for x in xsrange(*ranges[0], include_endpoint=True)]
                              for y in xsrange(*ranges[1], include_endpoint=True)]

    if region is not None:
        import numpy

        xy_data_array = numpy.ma.asarray(xy_data_array,dtype=float)

        m = F[1]

        mask = numpy.asarray([[m(x, y)<=0 for x in xsrange(*ranges[0], include_endpoint=True)]
                                          for y in xsrange(*ranges[1], include_endpoint=True)],dtype=bool)

        xy_data_array[mask] = numpy.ma.masked

    g = 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'

    g._set_extra_kwds(Graphics._extract_kwds_for_show(options, ignore=['xmin', 'xmax']))
    g.add_primitive(ContourPlot(xy_data_array, xrange, yrange, options))
    return g
Beispiel #46
0
def line2d(points, **options):
    r"""
    Create the line through the given list of points.

    INPUT:

    -  ``points`` - either a single point (as a tuple), a list of
       points, a single complex number, or a list of complex numbers.

    Type ``line2d.options`` for a dictionary of the default options for
    lines.  You can change this to change the defaults for all future
    lines.  Use ``line2d.reset()`` to reset to the default options.

    INPUT:

    - ``alpha`` -- How transparent the line is

    - ``thickness`` -- How thick the line is

    - ``rgbcolor`` -- The color as an RGB tuple

    - ``hue`` -- The color given as a hue

    - ``legend_color`` -- The color of the text in the legend

    - ``legend_label`` -- the label for this item in the legend


    Any MATPLOTLIB line option may also be passed in.  E.g.,

    - ``linestyle`` - (default: "-") The style of the line, which is one of
       - ``"-"`` or ``"solid"``
       - ``"--"`` or ``"dashed"``
       - ``"-."`` or ``"dash dot"``
       - ``":"`` or ``"dotted"``
       - ``"None"`` or ``" "`` or ``""`` (nothing)

       The linestyle can also be prefixed with a drawing style (e.g., ``"steps--"``)

       - ``"default"`` (connect the points with straight lines)
       - ``"steps"`` or ``"steps-pre"`` (step function; horizontal
         line is to the left of point)
       - ``"steps-mid"`` (step function; points are in the middle of
         horizontal lines)
       - ``"steps-post"`` (step function; horizontal line is to the
         right of point)

    - ``marker``  - The style of the markers, which is one of
       - ``"None"`` or ``" "`` or ``""`` (nothing) -- default
       - ``","`` (pixel), ``"."`` (point)
       - ``"_"`` (horizontal line), ``"|"`` (vertical line)
       - ``"o"`` (circle), ``"p"`` (pentagon), ``"s"`` (square), ``"x"`` (x), ``"+"`` (plus), ``"*"`` (star)
       - ``"D"`` (diamond), ``"d"`` (thin diamond)
       - ``"H"`` (hexagon), ``"h"`` (alternative hexagon)
       - ``"<"`` (triangle left), ``">"`` (triangle right), ``"^"`` (triangle up), ``"v"`` (triangle down)
       - ``"1"`` (tri down), ``"2"`` (tri up), ``"3"`` (tri left), ``"4"`` (tri right)
       - ``0`` (tick left), ``1`` (tick right), ``2`` (tick up), ``3`` (tick down)
       - ``4`` (caret left), ``5`` (caret right), ``6`` (caret up), ``7`` (caret down)
       - ``"$...$"`` (math TeX string)

    - ``markersize`` -- the size of the marker in points

    - ``markeredgecolor`` -- the color of the marker edge

    - ``markerfacecolor`` -- the color of the marker face

    - ``markeredgewidth`` -- the size of the marker edge in points

    EXAMPLES:

    A line with no points or one point::

        sage: line([])      #returns an empty plot
        Graphics object consisting of 0 graphics primitives
        sage: import numpy; line(numpy.array([]))
        Graphics object consisting of 0 graphics primitives
        sage: line([(1,1)])
        Graphics object consisting of 1 graphics primitive

    A line with numpy arrays::

        sage: line(numpy.array([[1,2], [3,4]]))
        Graphics object consisting of 1 graphics primitive

    A line with a legend::

        sage: line([(0,0),(1,1)], legend_label='line')
        Graphics object consisting of 1 graphics primitive

    Lines with different colors in the legend text::

        sage: p1 = line([(0,0),(1,1)], legend_label='line')
        sage: p2 = line([(1,1),(2,4)], legend_label='squared', legend_color='red')
        sage: p1 + p2
        Graphics object consisting of 2 graphics primitives

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

        sage: line([(0,1), (3,4)], figsize=[10, 2])
        Graphics object consisting of 1 graphics primitive
        sage: line([(0,1), (3,4)]).show(figsize=[10, 2]) # These are equivalent

    We can also use a logarithmic scale if the data will support it::

        sage: line([(1,2),(2,4),(3,4),(4,8),(4.5,32)],scale='loglog',base=2)
        Graphics object consisting of 1 graphics primitive

    Many more examples below!

    A blue conchoid of Nicomedes::

        sage: L = [[1+5*cos(pi/2+pi*i/100), tan(pi/2+pi*i/100)*(1+5*cos(pi/2+pi*i/100))] for i in range(1,100)]
        sage: line(L, rgbcolor=(1/4,1/8,3/4))
        Graphics object consisting of 1 graphics primitive

    A line with 2 complex points::

        sage: i = CC.0
        sage: line([1+i, 2+3*i])
        Graphics object consisting of 1 graphics primitive

    A blue hypotrochoid (3 leaves)::

        sage: n = 4; h = 3; b = 2
        sage: L = [[n*cos(pi*i/100)+h*cos((n/b)*pi*i/100),n*sin(pi*i/100)-h*sin((n/b)*pi*i/100)] for i in range(200)]
        sage: line(L, rgbcolor=(1/4,1/4,3/4))
        Graphics object consisting of 1 graphics primitive

    A blue hypotrochoid (4 leaves)::

        sage: n = 6; h = 5; b = 2
        sage: L = [[n*cos(pi*i/100)+h*cos((n/b)*pi*i/100),n*sin(pi*i/100)-h*sin((n/b)*pi*i/100)] for i in range(200)]
        sage: line(L, rgbcolor=(1/4,1/4,3/4))
        Graphics object consisting of 1 graphics primitive

    A red limacon of Pascal::

        sage: L = [[sin(pi*i/100)+sin(pi*i/50),-(1+cos(pi*i/100)+cos(pi*i/50))] for i in range(-100,101)]
        sage: line(L, rgbcolor=(1,1/4,1/2))
        Graphics object consisting of 1 graphics primitive

    A light green trisectrix of Maclaurin::

        sage: L = [[2*(1-4*cos(-pi/2+pi*i/100)^2),10*tan(-pi/2+pi*i/100)*(1-4*cos(-pi/2+pi*i/100)^2)] for i in range(1,100)]
        sage: line(L, rgbcolor=(1/4,1,1/8))
        Graphics object consisting of 1 graphics primitive

    A green lemniscate of Bernoulli::

        sage: cosines = [cos(-pi/2+pi*i/100) for i in range(201)]
        sage: v = [(1/c, tan(-pi/2+pi*i/100)) for i,c in enumerate(cosines) if c != 0]
        sage: L = [(a/(a^2+b^2), b/(a^2+b^2)) for a,b in v]
        sage: line(L, rgbcolor=(1/4,3/4,1/8))
        Graphics object consisting of 1 graphics primitive

    A red plot of the Jacobi elliptic function `\text{sn}(x,2)`, `-3 < x < 3`::

        sage: L = [(i/100.0, real_part(jacobi('sn', i/100.0, 2.0))) for i in
        ....:      range(-300, 300, 30)]
        sage: line(L, rgbcolor=(3/4, 1/4, 1/8))
        Graphics object consisting of 1 graphics primitive

    A red plot of `J`-Bessel function `J_2(x)`, `0 < x < 10`::

        sage: L = [(i/10.0, bessel_J(2,i/10.0)) for i in range(100)]
        sage: line(L, rgbcolor=(3/4,1/4,5/8))
        Graphics object consisting of 1 graphics primitive


    A purple plot of the Riemann zeta function `\zeta(1/2 + it)`, `0 < t < 30`::

        sage: i = CDF.gen()
        sage: v = [zeta(0.5 + n/10 * i) for n in range(300)]
        sage: L = [(z.real(), z.imag()) for z in v]
        sage: line(L, rgbcolor=(3/4,1/2,5/8))
        Graphics object consisting of 1 graphics primitive

    A purple plot of the Hasse-Weil `L`-function `L(E, 1 + it)`, `-1 < t < 10`::

        sage: E = EllipticCurve('37a')
        sage: vals = E.lseries().values_along_line(1-I, 1+10*I, 100) # critical line
        sage: L = [(z[1].real(), z[1].imag()) for z in vals]
        sage: line(L, rgbcolor=(3/4,1/2,5/8))
        Graphics object consisting of 1 graphics primitive

    A red, blue, and green "cool cat"::

        sage: G = plot(-cos(x), -2, 2, thickness=5, rgbcolor=(0.5,1,0.5))
        sage: P = polygon([[1,2], [5,6], [5,0]], rgbcolor=(1,0,0))
        sage: Q = polygon([(-x,y) for x,y in P[0]], rgbcolor=(0,0,1))
        sage: G + P + Q   # show the plot
        Graphics object consisting of 3 graphics primitives

    TESTS:

    Check that :trac:`13690` is fixed. The legend label should have circles
    as markers.::

        sage: line(enumerate(range(2)), marker='o', legend_label='circle')
        Graphics object consisting of 1 graphics primitive

    """
    from sage.plot.all import Graphics
    from sage.plot.plot import xydata_from_point_list
    from sage.rings.all import CC, CDF
    if points in CC or points in CDF:
        pass
    else:
        try:
            if not points:
                return Graphics()
        except ValueError: # numpy raises a ValueError if not empty
            pass
    xdata, ydata = xydata_from_point_list(points)
    g = Graphics()
    g._set_extra_kwds(Graphics._extract_kwds_for_show(options))
    g.add_primitive(Line(xdata, ydata, options))
    if options['legend_label']:
        g.legend(True)
        g._legend_colors = [options['legend_color']]
    return g
Beispiel #47
0
class HyperbolicTriangleDisc(object): #]GraphicPrimitive):
    r"""
    Hyperbolic triangles in the disc model of the hyperbolic plane.
    Note that we are given coordinates in the upper half-plane and map them to the disc.
    
    """
    @options(center=CC(0,1))
    def __init__(self, A, B, C,**options):
        """
        Initialize HyperbolicTriangle under the map (z-z0)/(z-\bar(z0)):
        
        Examples::
        
            sage: from sage.plot.hyperbolic_triangle import HyperbolicTriangle
            sage: print HyperbolicTriangle(0, 1/2, I, {})
            Hyperbolic triangle (0.000000000000000, 0.500000000000000, 1.00000000000000*I)
        """
        A, B, C = (CC(A), CC(B), CC(C))
        self.path = []
        self._options = {}
        self._graphics = Graphics()
        self._verbose = options.pop('verbose',None)
        Z0 = options['center'] #.get('center',C(0,1))
        options.pop('center',None)
        self._npts = options.pop('npts',10)
        sides = options.pop('sides',[1,2,3])
        #options.pop('fill',None)
        self._options.update(options)
        self._z0=CC(Z0); self._z0bar=CC(Z0).conjugate()        
        verbose=self._verbose
        sides.sort()
        if sides == [1]:
            if verbose>0:
                print "Drawing A - B!"
            self._hyperbolic_arc_d(A, B, True);
        elif sides == [2]:
            if verbose>0:
                print "Drawing B - C!"                
            self._hyperbolic_arc_d(B, C, True);
        elif sides == [3]:
            if verbose>0:
                print "Drawing C - A!"                
            self._hyperbolic_arc_d(C, A, True);
        elif sides == [1,2]:
            if verbose>0:
                print "Drawing A - B! & B - C!"
            self._hyperbolic_arc_d(A, B, True);
            self._hyperbolic_arc_d(B, C,False);
        elif sides == [1,3]:
            if verbose>0:
                print "Drawing C - A! & A - B"
            self._hyperbolic_arc_d(C, A,True)
            self._hyperbolic_arc_d(A, B, False)
        elif sides == [2,3]:
            if verbose>0:
                print "Drawing B - C! & C - A"
            self._hyperbolic_arc_d(B, C,True)
            self._hyperbolic_arc_d(C, A, False)            
        else:
            self._hyperbolic_arc_d(A, B,True)            
            self._hyperbolic_arc_d(B, C,False)
            self._hyperbolic_arc_d(C, A, False)
        #self._hyperbolic_arc_d(A, B, True);
        #self._hyperbolic_arc_d(B, C);
        #self._hyperbolic_arc_d(C, A);
        #BezierPath.__init__(self, self.path, options)


        #super(HyperbolicTriangleDisc,self).__init__(options)
        self.A, self.B, self.C = (A, B, C)

    def _cayley_transform(self,z):
        #print "z=",z,z==infyinity,type(z),type(infinity)
        if z==infinity or z==CC(infinity):
            return CC(1,0)
        return (CC(z)-self._z0)/(CC(z)-self._z0bar)

    def _hyperbolic_arc_d(self, z0, z3, first=False):
        """
        Function to construct Bezier path as an approximation to
        the hyperbolic arc between the complex numbers z0 and z3 in the
        hyperbolic plane.
        """

        w0 = self._cayley_transform(z0)
        w3 = self._cayley_transform(z3)
        if self._verbose>0:
            print "in plane z0,z3=",z0,z3
            print "in disc: ",w0,w3
        npts = self._npts
        if z0 == infinity or z0==CC(infinity):
            zm = [z3 + CC(0,j+0.5) for j in range(npts-2)]
            wm = [self._cayley_transform(x) for x in zm]
            pts = [w3]
            pts.extend(wm)
            pts.append(w0)
            opt = self._options
            opt['fill']=False
            self._graphics.add_primitive(BezierPath([[(x.real(),x.imag()) for x in pts ]],opt))
            return 
        if z3 == infinity  or z3==CC(infinity):
            zm = [z0 + CC(0,j+0.5) for j in range(npts-2)]
            wm = [self._cayley_transform(x) for x in zm]
            pts = [w0]
            pts.extend(wm)
            pts.append(w3)
            opt = self._options
            opt['fill']=False
            self._graphics.add_primitive(BezierPath([[(x.real(),x.imag()) for x in pts ]],opt))
            #self._graphics.add_primitive(Line([w1.real(),w2.real()],[w1.imag(),w2.imag()],self._options))
            #self.path.append([(0,w0.imag()),CC(0,y), (0,w3.imag())])
            return
        x0=z0.real(); y0 = z0.imag()
        x3=z3.real(); y3 = z3.imag()
        if y0 == 0 and y3 == 0:
            p = (z0.real()+z3.real())/2
            r = abs(z0-p)
            zm = CC(p, r)
            self._hyperbolic_arc_d(z0, zm, first)
            self._hyperbolic_arc_d(zm, z3)
            return                   
        else:
            if abs(x0-x3)<1e-10:  ## on the same vertical line
                xmid = (x0+x3)*0.5; h = y3-y0
                zm = [ CC(xmid,y0+t*h/(npts-1)) for t in range(npts) ]
            else:
                p = RR((x0+x3)*(x3-x0)+(y0+y3)*(y3-y0))/(2*(x3-x0)) 
                r = RR((p - x0)**2 + y0**2).sqrt()  # radius of the circle in H
                zm = ((z0+z3)/2-p)/abs((z0+z3)/2-p)*r+p  # midpoint (at least approximately) of geodesic between z0 and z3
                t0 = CC(z0 - p).argument()
                t3 = CC(z3 - p).argument()
                if self._verbose>1:
                    print "x0,x3=",x0,x3
                    print "t0,t3=",t0,t3
                    print "r=",r
                    print "opt=",self._options
                if x0 <= x3:
                    zm = [p + r*CC(0,(t0+t*(t3-t0)/(npts-1))).exp() for t in range(npts)]
                else:
                    zm = [p + r*CC(0,(t0+t*(t3-t0)/(npts-1))).exp() for t in range(npts)]            
                #print "zm=",zm
                #zm.insert(0,z0)
                #zm.append(z3)
            pts = [self._cayley_transform(x) for x in zm]
            opt = self._options
            opt['fill']=False
            #w0 = self._cayley_transform(z0)
            #w3 = self._cayley_transform(z3)

            if self._verbose>2:
                print "pts=",pts
            self._graphics.add_primitive(BezierPath([[(x.real(),x.imag()) for x in pts ]],opt))
            return 
            #print "z0_test=",(p+r*exp(t0*I))
                #print "z3_test=",(p+r*exp(t3*I))
#t = (8*zm-4*(z0+z3)).imag()/3/(z3-z0).real()
            # I have no idea what these points should represent....
            #z1 = z0 + t*CC(z0.imag(), (p-z0.real()))
            #z2 = z3 - t*CC(z3.imag(), (p-z3.real()))
            wm = [self._cayley_transform(x) for x in zm]
            pp = self._cayley_transform(CC(p,0))
            w1 = self._cayley_transform(z0)
            w2 = self._cayley_transform(z3)
            c = self._cayley_transform(CC(p,0)) # center of circle on the unit disk.
            if self._verbose>2:
                print "p,r=",p,r     
                print "zm=",zm
                #print "t=",t
                #print "tt=",(8*zm-4*(z0+z3)).imag()/3/(z3-z0).real()

                print "C(c)=",pp
                print "C(zm)=",wm
                print "C(z0)=",w1
                print "C(z3)=",w2
                #print "z2=",z2
            
            r = abs(w1-c) # radius
            t0 = CC(w0 - pp).argument()
            t3 = CC(w3 - pp).argument()
            t = abs(t0-t3)
        if self._verbose>0:
            print "adding a:rc ",zm.real(),zm.imag(),r,r,t,t0,t3
        self._graphics.add_primitive(Line([w1.real(),w2.real(),wm.real()],[w1.imag(),w2.imag(),wm.imag()],{'thickness':2,'alpha':1,
                                                                                       'rgbcolor':'blue',
                                                                                                         'legend_label':""}))
        self._graphics.add_primitive(Point([w1.real(),w2.real(),wm.real()],[w1.imag(),w2.imag(),wm.imag()],{'size':10,'alpha':1,
                                                                                                            'faceted':True,
                                                                                                            'rgbcolor':'red',
                                                                                                            'legend_label':""}))
        
        #self._graphics.add_primitive(Arc(pp.real(),pp.imag(),r,r,t,t0,t3,self._options))
        #self._graphics. Arc(zm.real(),zm.imag(),r,r,abs(t),-abs(t),abs(t),self._options)

    def __call__(self):
        return self._graphics
Beispiel #48
0
def ellipse(center, r1, r2, angle=0, **options):
    """
    Return an ellipse centered at a point center = ``(x,y)`` with radii =
    ``r1,r2`` and angle ``angle``.  Type ``ellipse.options`` to see all
    options.

    INPUT:

    - ``center`` - 2-tuple of real numbers - coordinates of the center

    - ``r1``, ``r2`` - positive real numbers - the radii of the ellipse

    - ``angle`` - real number (default: 0) - the angle between the first axis
      and the horizontal
    
    OPTIONS:

    - ``alpha`` - default: 1 - transparency

    - ``fill`` - default: False - whether to fill the ellipse or not

    - ``thickness`` - default: 1 - thickness of the line

    - ``linestyle`` - default: 'solid'

    - ``edgecolor`` - default: 'black' - color of the contour

    - ``facecolor`` - default: 'red' - color of the filling

    - ``rgbcolor`` - 2D or 3D plotting.  This option overrides
      ``edgecolor`` and ``facecolor`` for 2D plotting.

    EXAMPLES:

    An ellipse centered at (0,0) with major and minor axes of lengths 2 and 1.
    Note that the default color is blue::

        sage: ellipse((0,0),2,1)

    More complicated examples with tilted axes and drawing options::

        sage: ellipse((0,0),3,1,pi/6,fill=True,alpha=0.3,linestyle="dashed")

    ::

        sage: ellipse((0,0),3,1,pi/6,fill=True,edgecolor='black',facecolor='red')

    We see that ``rgbcolor`` overrides these other options, as this plot
    is green::

        sage: ellipse((0,0),3,1,pi/6,fill=True,edgecolor='black',facecolor='red',rgbcolor='green')

    The default aspect ratio for ellipses is 1.0::

        sage: ellipse((0,0),2,1).aspect_ratio()
        1.0

    One cannot yet plot ellipses in 3D::

        sage: ellipse((0,0,0),2,1)
        Traceback (most recent call last):
        ...
        NotImplementedError: plotting ellipse in 3D is not implemented
    """
    from sage.plot.all import Graphics
    g = Graphics()
    g._set_extra_kwds(Graphics._extract_kwds_for_show(options))
    g.add_primitive(Ellipse(center[0], center[1], r1, r2, angle, options))
    if options['legend_label']:
        g.legend(True)
    if len(center) == 2:
        return g
    elif len(center) == 3:
        raise NotImplementedError, "plotting ellipse in 3D is not implemented"
Beispiel #49
0
def circle(center, radius, **options):
    """
    Return a circle at a point center = `(x,y)` (or `(x,y,z)` and
    parallel to the `xy`-plane) with radius = `r`.  Type
    ``circle.options`` to see all options.

    OPTIONS:

    - ``alpha`` - default: 1

    - ``fill`` - default: False

    - ``thickness`` - default: 1

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

    - ``edgecolor`` - default: 'blue' (2D plotting only)

    - ``facecolor`` - default: 'blue' (2D plotting only, useful only
      if ``fill=True``)

    - ``rgbcolor`` - 2D or 3D plotting.  This option overrides
      ``edgecolor`` and ``facecolor`` for 2D plotting.

    - ``legend_label`` - the label for this item in the legend

    - ``legend_color`` - the color for the legend label

    EXAMPLES:

    The default color is blue, the default linestyle is solid, but this is easy to change::

        sage: c = circle((1,1), 1)
        sage: c
        Graphics object consisting of 1 graphics primitive

    .. PLOT::

        sphinx_plot(circle((1,1), 1))

    ::

        sage: c = circle((1,1), 1, rgbcolor=(1,0,0), linestyle='-.')
        sage: c
        Graphics object consisting of 1 graphics primitive

    .. PLOT::

        c = circle((1,1), 1, rgbcolor=(1,0,0), linestyle='-.')
        sphinx_plot(c)

    We can also use this command to plot three-dimensional circles parallel
    to the `xy`-plane::

        sage: c = circle((1,1,3), 1, rgbcolor=(1,0,0))
        sage: c
        Graphics3d Object
        sage: type(c)
        <class 'sage.plot.plot3d.base.TransformGroup'>

    .. PLOT::

        c = circle((1,1,3), 1, rgbcolor=(1,0,0))
        sphinx_plot(c)

    To correct the aspect ratio of certain graphics, it is necessary
    to show with a ``figsize`` of square dimensions::

        sage: c.show(figsize=[5,5],xmin=-1,xmax=3,ymin=-1,ymax=3)

    Here we make a more complicated plot, with many circles of different colors::

        sage: g = Graphics()
        sage: step=6; ocur=1/5; paths=16;
        sage: PI = math.pi    # numerical for speed -- fine for graphics
        sage: for r in range(1,paths+1):
        ....:     for x,y in [((r+ocur)*math.cos(n), (r+ocur)*math.sin(n)) for n in srange(0, 2*PI+PI/step, PI/step)]:
        ....:         g += circle((x,y), ocur, rgbcolor=hue(r/paths))
        ....:     rnext = (r+1)^2
        ....:     ocur = (rnext-r)-ocur
        sage: g.show(xmin=-(paths+1)^2, xmax=(paths+1)^2, ymin=-(paths+1)^2, ymax=(paths+1)^2, figsize=[6,6])

    .. PLOT::

        g = Graphics()
        step=6; ocur=1/5; paths=16;
        PI = math.pi    # numerical for speed -- fine for graphics
        for r in range(1,paths+1):
             for x,y in [((r+ocur)*math.cos(n), (r+ocur)*math.sin(n)) for n in srange(0, 2*PI+PI/step, PI/step)]:
                 g += circle((x,y), ocur, rgbcolor=hue(r*1.0/paths))
             rnext = (r+1)**2
             ocur = (rnext-r)-ocur
        g.set_axes_range(-(paths+1)**2,(paths+1)**2,-(paths+1)**2,(paths+1)**2)
        sphinx_plot(g)

    Note that the ``rgbcolor`` option overrides the other coloring options.
    This produces red fill in a blue circle::

        sage: circle((2,3), 1, fill=True, edgecolor='blue', facecolor='red')
        Graphics object consisting of 1 graphics primitive

    .. PLOT::

        sphinx_plot(circle((2,3), 1, fill=True, edgecolor='blue', facecolor='red'))

    This produces an all-green filled circle::

        sage: circle((2,3), 1, fill=True, edgecolor='blue', rgbcolor='green')
        Graphics object consisting of 1 graphics primitive

    .. PLOT::

        sphinx_plot(circle((2,3), 1, fill=True, edgecolor='blue', rgbcolor='green'))

    The option ``hue`` overrides *all* other options, so be careful with its use.
    This produces a purplish filled circle::

        sage: circle((2,3), 1, fill=True, edgecolor='blue', rgbcolor='green', hue=.8)
        Graphics object consisting of 1 graphics primitive

    .. PLOT::

        C = circle((2,3), 1, fill=True, edgecolor='blue', rgbcolor='green', hue=.8)
        sphinx_plot(C)

    And circles with legends::

        sage: circle((4,5), 1, rgbcolor='yellow', fill=True, legend_label='the sun').show(xmin=0, ymin=0)

    .. PLOT::

        C = circle((4,5), 1, rgbcolor='yellow', fill=True, legend_label='the sun')
        C.set_axes_range(xmin=0, ymin=0)
        sphinx_plot(C)

    ::

        sage: circle((4,5), 1, legend_label='the sun', legend_color='yellow').show(xmin=0, ymin=0)

    .. PLOT::

        C = circle((4,5), 1, legend_label='the sun', legend_color='yellow')
        C.set_axes_range(xmin=0, ymin=0)
        sphinx_plot(C)

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

        sage: circle((0, 0), 2, figsize=[10,10]) # That circle is huge!
        Graphics object consisting of 1 graphics primitive

    ::

        sage: circle((0, 0), 2).show(figsize=[10,10]) # These are equivalent

    TESTS:

    We cannot currently plot circles in more than three dimensions::

        sage: circle((1,1,1,1), 1, rgbcolor=(1,0,0))
        Traceback (most recent call last):
        ...
        ValueError: The center of a plotted circle should have two or three coordinates.

    The default aspect ratio for a circle is 1.0::

        sage: P = circle((1,1), 1)
        sage: P.aspect_ratio()
        1.0
    """
    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'

    g = Graphics()
    g._set_extra_kwds(Graphics._extract_kwds_for_show(options))
    g.add_primitive(Circle(center[0], center[1], radius, options))
    if options['legend_label']:
        g.legend(True)
        g._legend_colors = [options['legend_color']]
    if len(center) == 2:
        return g
    elif len(center) == 3:
        return g[0].plot3d(z=center[2])
    else:
        raise ValueError(
            'The center of a plotted circle should have two or three coordinates.'
        )
Beispiel #50
0
def text(string, xy, **options):
    r"""
    Returns a 2D text graphics object at the point `(x,y)`.

    Type ``text.options`` for a dictionary of options for 2D text.

    2D OPTIONS:

    - ``fontsize`` - How big the text is

    - ``rgbcolor`` - The color as an RGB tuple

    - ``hue`` - The color given as a hue

    - ``rotation`` - How to rotate the text: angle in degrees, vertical, horizontal

    - ``vertical_alignment`` - How to align vertically: top, center, bottom

    - ``horizontal_alignment`` - How to align horizontally: left, center, right

    - ``axis_coords`` - (default: False) if True, use axis coordinates, so that
      (0,0) is the lower left and (1,1) upper right, regardless of the x and y
      range of plotted values.

    EXAMPLES::

        sage: text("Sage is really neat!!",(2,12))

    The same text in larger font and colored red::

        sage: text("Sage is really neat!!",(2,12),fontsize=20,rgbcolor=(1,0,0))

    Same text but guaranteed to be in the lower left no matter what::

        sage: text("Sage is really neat!!",(0,0), axis_coords=True, horizontal_alignment='left')

    Same text rotated around the left, bottom corner of the text::

        sage: text("Sage is really neat!!",(0,0), rotation=45.0, horizontal_alignment='left', vertical_alignment='bottom')

    Same text oriented vertically::

        sage: text("Sage is really neat!!",(0,0), rotation="vertical")

    You can also align text differently::

        sage: t1 = text("Hello",(1,1), vertical_alignment="top")
        sage: t2 = text("World", (1,0.5), horizontal_alignment="left")
        sage: t1 + t2   # render the sum

    You can save text as part of PDF output::

        sage: text("sage", (0,0), rgbcolor=(0,0,0)).save(os.path.join(SAGE_TMP, 'a.pdf'))

    Text must be 2D (use the text3d command for 3D text)::

        sage: t = text("hi",(1,2,3))
        Traceback (most recent call last):
        ...
        ValueError: use text3d instead for text in 3d
        sage: t = text3d("hi",(1,2,3))

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

        sage: text("MATH IS AWESOME", (0, 0), fontsize=40, axes=False)
        sage: text("MATH IS AWESOME", (0, 0), fontsize=40).show(axes=False) # These are equivalent
    """
    try:
        x, y = xy
    except ValueError:
        if isinstance(xy, (list, tuple)) and len(xy) == 3:
            raise ValueError, "use text3d instead for text in 3d"
        raise
    from sage.plot.all import Graphics
    options['rgbcolor'] = to_mpl_color(options['rgbcolor'])
    point = (float(x), float(y))
    g = Graphics()
    g._set_extra_kwds(
        Graphics._extract_kwds_for_show(options, ignore='fontsize'))
    g.add_primitive(Text(string, point, options))
    return g
Beispiel #51
0
    def plot(self, **kwds):
        """
        Returns a graphics object representing the (di)graph.
        
        INPUT:
            - pos -- an optional positioning dictionary
            - layout -- what kind of layout to use, takes precedence over pos

              - 'circular' -- plots the graph with vertices evenly distributed
                on a circle
              - 'spring' -- uses the traditional spring layout, using the
                graph's current positions as initial positions
              - 'tree' -- the (di)graph must be a tree. One can specify the root
                of the tree using the keyword tree_root, otherwise a root
                will be selected at random. Then the tree will be plotted in
                levels, depending on minimum distance for the root.
            - vertex_labels -- whether to print vertex labels
              edge_labels -- whether to print edge labels. By default, False,
              but if True, the result of str(l) is printed on the edge for
              each label l. Labels equal to None are not printed (to set edge
              labels, see set_edge_label).
            - vertex_size -- size of vertices displayed
            - vertex_shape -- the shape to draw the vertices (Not available for
              multiedge digraphs.
            - graph_border -- whether to include a box around the graph
            - vertex_colors -- optional dictionary to specify vertex colors: each
              key is a color recognizable by matplotlib, and each corresponding
              entry is a list of vertices. If a vertex is not listed, it looks
              invisible on the resulting plot (it doesn't get drawn).
            - edge_colors -- a dictionary specifying edge colors: each key is a
              color recognized by matplotlib, and each entry is a list of edges.
            - partition -- a partition of the vertex set. if specified, plot will
              show each cell in a different color. vertex_colors takes precedence.
            - talk -- if true, prints large vertices with white backgrounds so that
              labels are legible on slides
            - iterations -- how many iterations of the spring layout algorithm to
              go through, if applicable
            - color_by_label -- if True, color edges by their labels
            - heights -- if specified, this is a dictionary from a set of
              floating point heights to a set of vertices
            - edge_style -- keyword arguments passed into the
              edge-drawing routine.  This currently only works for
              directed graphs, since we pass off the undirected graph to
              networkx
            - tree_root -- a vertex of the tree to be used as the root for
              the layout="tree" option. If no root is specified, then one
              is chosen at random. Ignored unless layout='tree'. 
            - tree_orientation -- "up" or "down" (default is "down"). 
              If "up" (resp., "down"), then the root of the tree will
              appear on the bottom (resp., top) and the tree will grow
              upwards (resp. downwards). Ignored unless layout='tree'.
            - save_pos -- save position computed during plotting

        EXAMPLES::

            sage: from sage.graphs.graph_plot import graphplot_options
            sage: list(sorted(graphplot_options.iteritems()))
            [('by_component', 'Whether to do the spring layout by connected component -- a boolean.'),
             ('color_by_label', 'Whether or not to color the edges by their label values.'),
             ('dim', 'The dimension of the layout -- 2 or 3.'),
             ('dist', 'The distance between multiedges.'),
             ('edge_color', 'The default color for edges.'),
             ('edge_colors', 'Dictionary of edge coloring.'),
             ('edge_labels', 'Whether or not to draw edge labels.'),
             ('edge_style', 'The linestyle of the edges-- one of "solid", "dashed", "dotted", dashdot".'),
             ('graph_border', 'Whether or not to draw a frame around the graph.'),
             ('heights', 'A dictionary mapping heights to the list of vertices at this height.'),
             ('iterations', 'The number of times to execute the spring layout algorithm.'),
             ('layout', 'A layout algorithm -- one of "acyclic", "circular", "ranked", "graphviz", "planar", "spring", or "tree".'),
             ('loop_size', 'The radius of the smallest loop.'),
             ('max_dist', 'The max distance range to allow multiedges.'),
             ('partition', 'A partition of the vertex set.  (Draws each cell of vertices in a different color).'),
             ('pos', 'The position dictionary of vertices'),
             ('prog', 'Which graphviz layout program to use -- one of "circo", "dot", "fdp", "neato", or "twopi".'),
             ('save_pos', 'Whether or not to save the computed position for the graph.'),
             ('spring', 'Use spring layout to finalize the current layout.'),
             ('talk', 'Whether to display the vertices in talk mode (larger and white)'),
             ('tree_orientation', 'The direction of tree branches -- "up" or "down".'),
             ('tree_root', 'A vertex designation for drawing trees.'),
             ('vertex_colors', 'Dictionary of vertex coloring.'),
             ('vertex_labels', 'Whether or not to draw vertex labels.'),
             ('vertex_shape', 'The shape to draw the vertices, Currently unavailable for Multi-edged DiGraphs.'),
             ('vertex_size', 'The size to draw the vertices.')]

            sage: from math import sin, cos, pi
            sage: P = graphs.PetersenGraph()
            sage: d = {'#FF0000':[0,5], '#FF9900':[1,6], '#FFFF00':[2,7], '#00FF00':[3,8], '#0000FF':[4,9]}
            sage: pos_dict = {}
            sage: for i in range(5):
            ...    x = float(cos(pi/2 + ((2*pi)/5)*i))
            ...    y = float(sin(pi/2 + ((2*pi)/5)*i))
            ...    pos_dict[i] = [x,y]
            ...
            sage: for i in range(10)[5:]:
            ...    x = float(0.5*cos(pi/2 + ((2*pi)/5)*i))
            ...    y = float(0.5*sin(pi/2 + ((2*pi)/5)*i))
            ...    pos_dict[i] = [x,y]
            ...
            sage: pl = P.graphplot(pos=pos_dict, vertex_colors=d)
            sage: pl.show()
            
            sage: C = graphs.CubeGraph(8)
            sage: P = C.graphplot(vertex_labels=False, vertex_size=0, graph_border=True)
            sage: P.show()
            
            sage: G = graphs.HeawoodGraph().copy(sparse=True)
            sage: for u,v,l in G.edges():
            ...    G.set_edge_label(u,v,'(' + str(u) + ',' + str(v) + ')')
            sage: G.graphplot(edge_labels=True).show()
            
            sage: D = DiGraph( { 0: [1, 10, 19], 1: [8, 2], 2: [3, 6], 3: [19, 4], 4: [17, 5], 5: [6, 15], 6: [7], 7: [8, 14], 8: [9], 9: [10, 13], 10: [11], 11: [12, 18], 12: [16, 13], 13: [14], 14: [15], 15: [16], 16: [17], 17: [18], 18: [19], 19: []}, implementation='networkx' )
            sage: for u,v,l in D.edges():
            ...    D.set_edge_label(u,v,'(' + str(u) + ',' + str(v) + ')')
            sage: D.graphplot(edge_labels=True, layout='circular').show()

            sage: from sage.plot.colors import rainbow
            sage: C = graphs.CubeGraph(5)
            sage: R = rainbow(5)
            sage: edge_colors = {}
            sage: for i in range(5):
            ...    edge_colors[R[i]] = []
            sage: for u,v,l in C.edges():
            ...    for i in range(5):
            ...        if u[i] != v[i]:
            ...            edge_colors[R[i]].append((u,v,l))
            sage: C.graphplot(vertex_labels=False, vertex_size=0, edge_colors=edge_colors).show()

            sage: D = graphs.DodecahedralGraph()
            sage: Pi = [[6,5,15,14,7],[16,13,8,2,4],[12,17,9,3,1],[0,19,18,10,11]]
            sage: D.show(partition=Pi)

            sage: G = graphs.PetersenGraph()
            sage: G.allow_loops(True)
            sage: G.add_edge(0,0)
            sage: G.show()

            sage: D = DiGraph({0:[0,1], 1:[2], 2:[3]}, loops=True)
            sage: D.show()
            sage: D.show(edge_colors={(0,1,0):[(0,1,None),(1,2,None)],(0,0,0):[(2,3,None)]}) 

            sage: pos = {0:[0.0, 1.5], 1:[-0.8, 0.3], 2:[-0.6, -0.8], 3:[0.6, -0.8], 4:[0.8, 0.3]}
            sage: g = Graph({0:[1], 1:[2], 2:[3], 3:[4], 4:[0]})
            sage: g.graphplot(pos=pos, layout='spring', iterations=0).plot()

            sage: G = Graph()
            sage: P = G.graphplot().plot()
            sage: P.axes()
            False
            sage: G = DiGraph()
            sage: P = G.graphplot().plot()
            sage: P.axes()
            False

            sage: T = list(graphs.trees(7))
            sage: t = T[3]
            sage: t.graphplot(heights={0:[0], 1:[4,5,1], 2:[2], 3:[3,6]}).plot()

            sage: T = list(graphs.trees(7))
            sage: t = T[3]
            sage: t.graphplot(heights={0:[0], 1:[4,5,1], 2:[2], 3:[3,6]}).plot()
            sage: t.set_edge_label(0,1,-7)
            sage: t.set_edge_label(0,5,3)
            sage: t.set_edge_label(0,5,99)
            sage: t.set_edge_label(1,2,1000)
            sage: t.set_edge_label(3,2,'spam')
            sage: t.set_edge_label(2,6,3/2)
            sage: t.set_edge_label(0,4,66)
            sage: t.graphplot(heights={0:[0], 1:[4,5,1], 2:[2], 3:[3,6]}, edge_labels=True).plot()

            sage: T = list(graphs.trees(7))
            sage: t = T[3]
            sage: t.graphplot(layout='tree').show()

            sage: t = DiGraph('JCC???@A??GO??CO??GO??')
            sage: t.graphplot(layout='tree', tree_root=0, tree_orientation="up").show()

            sage: D = DiGraph({0:[1,2,3], 2:[1,4], 3:[0]})
            sage: D.graphplot().show()
            
            sage: D = DiGraph(multiedges=True, sparse=True)
            sage: for i in range(5):
            ...     D.add_edge((i,i+1,'a'))
            ...     D.add_edge((i,i-1,'b'))
            sage: D.graphplot(edge_labels=True,edge_colors=D._color_by_label()).plot()
            
            sage: g = Graph({}, loops=True, multiedges=True, sparse=True)
            sage: g.add_edges([(0,0,'a'),(0,0,'b'),(0,1,'c'),(0,1,'d'),
            ...     (0,1,'e'),(0,1,'f'),(0,1,'f'),(2,1,'g'),(2,2,'h')])
            sage: g.graphplot(edge_labels=True, color_by_label=True, edge_style='dashed').plot()
        """
        G = Graphics()
        for comp in self._plot_components.values():
            if not isinstance(comp, list):
                G += comp
            else:
                for item in comp:
                    G += item
        G.set_axes_range(*(self._graph._layout_bounding_box(self._pos)))
        if self._options['graph_border']:
            xmin = G.xmin()
            xmax = G.xmax()
            ymin = G.ymin()
            ymax = G.ymax()
            dx = (xmax-xmin)/10.0
            dy = (ymax-ymin)/10.0
            border = (line([( xmin - dx, ymin - dy), ( xmin - dx, ymax + dy ), ( xmax + dx, ymax + dy ), ( xmax + dx, ymin - dy ), ( xmin - dx, ymin - dy )], thickness=1.3))
            border.axes_range(xmin = (xmin - dx), xmax = (xmax + dx), ymin = (ymin - dy), ymax = (ymax + dy))
            G += border
        G.set_aspect_ratio(1)
        G.axes(False)
        G._extra_kwds['axes_pad']=.05
        return G
Beispiel #52
0
def density_plot(f, xrange, yrange, **options):
    r"""
    ``density_plot`` takes a function of two variables, `f(x,y)`
    and plots the height of of the function over the specified
    ``xrange`` and ``yrange`` as demonstrated below.

    ``density_plot(f, (xmin,xmax), (ymin,ymax), ...)``

    INPUT:

    - ``f`` -- a function of two variables

    - ``(xmin,xmax)`` -- 2-tuple, the range of ``x`` values OR 3-tuple
      ``(x,xmin,xmax)``

    - ``(ymin,ymax)`` -- 2-tuple, the range of ``y`` values OR 3-tuple
      ``(y,ymin,ymax)``

    The following inputs must all be passed in as named parameters:

    - ``plot_points`` -- integer (default: 25); number of points to plot
      in each direction of the grid

    - ``cmap`` -- a colormap (default: ``'gray'``), the name of
      a predefined colormap, a list of colors or an instance of a matplotlib
      Colormap. Type: ``import matplotlib.cm; matplotlib.cm.datad.keys()``
      for available colormap names.

    - ``interpolation`` -- string (default: ``'catrom'``), the interpolation
      method to use: ``'bilinear'``, ``'bicubic'``, ``'spline16'``,
      ``'spline36'``, ``'quadric'``, ``'gaussian'``, ``'sinc'``,
      ``'bessel'``, ``'mitchell'``, ``'lanczos'``, ``'catrom'``,
      ``'hermite'``, ``'hanning'``, ``'hamming'``, ``'kaiser'``


    EXAMPLES:

    Here we plot a simple function of two variables.  Note that
    since the input function is an expression, we need to explicitly
    declare the variables in 3-tuples for the range::

        sage: x,y = var('x,y')
        sage: density_plot(sin(x) * sin(y), (x,-2,2), (y,-2,2))
        Graphics object consisting of 1 graphics primitive

    .. PLOT::

        x,y = var('x,y')
        g = density_plot(sin(x) * sin(y), (x,-2,2), (y,-2,2))
        sphinx_plot(g)

    Here we change the ranges and add some options; note that here
    ``f`` is callable (has variables declared), so we can use 2-tuple ranges::

        sage: x,y = var('x,y')
        sage: f(x,y) = x^2 * cos(x*y)
        sage: density_plot(f, (x,-10,5), (y,-5,5), interpolation='sinc', plot_points=100)
        Graphics object consisting of 1 graphics primitive

    .. PLOT::

        x,y = var('x,y')
        def f(x,y): return x**2 * cos(x*y)
        g = density_plot(f, (x,-10,5), (y,-5,5), interpolation='sinc', plot_points=100)
        sphinx_plot(g)

    An even more complicated plot::

        sage: x,y = var('x,y')
        sage: density_plot(sin(x^2+y^2) * cos(x) * sin(y), (x,-4,4), (y,-4,4), cmap='jet', plot_points=100)
        Graphics object consisting of 1 graphics primitive

    .. PLOT::

        x,y = var('x,y')
        g = density_plot(sin(x**2 + y**2)*cos(x)*sin(y), (x,-4,4), (y,-4,4), cmap='jet', plot_points=100)
        sphinx_plot(g)

    This should show a "spotlight" right on the origin::

        sage: x,y = var('x,y')
        sage: density_plot(1/(x^10 + y^10), (x,-10,10), (y,-10,10))
        Graphics object consisting of 1 graphics primitive

    .. PLOT::

        x,y = var('x,y')
        g = density_plot(1/(x**10 + y**10), (x,-10,10), (y,-10,10))
        sphinx_plot(g)

    Some elliptic curves, but with symbolic endpoints.  In the first
    example, the plot is rotated 90 degrees because we switch the
    variables `x`, `y`::

        sage: density_plot(y^2 + 1 - x^3 - x, (y,-pi,pi), (x,-pi,pi))
        Graphics object consisting of 1 graphics primitive

    .. PLOT::

        x,y = var('x,y')
        g = density_plot(y**2 + 1 - x**3 - x, (y,-pi,pi), (x,-pi,pi))
        sphinx_plot(g)

    ::

        sage: density_plot(y^2 + 1 - x^3 - x, (x,-pi,pi), (y,-pi,pi))
        Graphics object consisting of 1 graphics primitive

    .. PLOT::

        x,y = var('x,y')
        g = density_plot(y**2 + 1 - x**3 - x, (x,-pi,pi), (y,-pi,pi))
        sphinx_plot(g)

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

        sage: density_plot(log(x) + log(y), (x,1,10), (y,1,10), dpi=20)
        Graphics object consisting of 1 graphics primitive

    .. PLOT::

        x,y = var('x,y')
        g = density_plot(log(x) + log(y), (x,1,10), (y,1,10), dpi=20)
        sphinx_plot(g)

    ::

        sage: density_plot(log(x) + log(y), (x,1,10), (y,1,10)).show(dpi=20) # These are equivalent

    TESTS:

    Check that :trac:`15315` is fixed, i.e., density_plot respects the
    ``aspect_ratio`` parameter. Without the fix, it looks like a thin line
    of width a few mm. With the fix it should look like a nice fat layered
    image::

        sage: density_plot((x*y)^(1/2), (x,0,3), (y,0,500), aspect_ratio=.01)
        Graphics object consisting of 1 graphics primitive

    Default ``aspect_ratio`` is ``"automatic"``, and that should work too::

        sage: density_plot((x*y)^(1/2), (x,0,3), (y,0,500))
        Graphics object consisting of 1 graphics primitive

    """
    from sage.plot.all import Graphics
    from sage.plot.misc import setup_for_eval_on_grid
    g, ranges = setup_for_eval_on_grid([f], [xrange, yrange],
                                       options['plot_points'])
    g = g[0]
    xrange, yrange = [r[:2] for r in ranges]

    xy_data_array = [[
        g(x, y) for x in xsrange(*ranges[0], include_endpoint=True)
    ] for y in xsrange(*ranges[1], include_endpoint=True)]

    g = Graphics()
    g._set_extra_kwds(
        Graphics._extract_kwds_for_show(options, ignore=['xmin', 'xmax']))
    g.add_primitive(DensityPlot(xy_data_array, xrange, yrange, options))
    return g
Beispiel #53
0
def disk(point, radius, angle, **options):
    r"""
    A disk (that is, a sector or wedge of a circle) with center
    at a point = `(x,y)` (or `(x,y,z)` and parallel to the
    `xy`-plane) with radius = `r` spanning (in radians)
    angle=`(rad1, rad2)`.

    Type ``disk.options`` to see all options.

    EXAMPLES:

    Make some dangerous disks::

        sage: bl = disk((0.0,0.0), 1, (pi, 3*pi/2), color='yellow')
        sage: tr = disk((0.0,0.0), 1, (0, pi/2), color='yellow')
        sage: tl = disk((0.0,0.0), 1, (pi/2, pi), color='black')
        sage: br = disk((0.0,0.0), 1, (3*pi/2, 2*pi), color='black')
        sage: P  = tl+tr+bl+br
        sage: P.show(xmin=-2,xmax=2,ymin=-2,ymax=2)

    The default aspect ratio is 1.0::

        sage: disk((0.0,0.0), 1, (pi, 3*pi/2)).aspect_ratio()
        1.0

    Another example of a disk::

        sage: bl = disk((0.0,0.0), 1, (pi, 3*pi/2), rgbcolor=(1,1,0))
        sage: bl.show(figsize=[5,5])

    Note that since ``thickness`` defaults to zero, it is best to change
    that option when using ``fill=False``::

        sage: disk((2,3), 1, (pi/4,pi/3), hue=.8, alpha=.3, fill=False, thickness=2)

    The previous two examples also illustrate using ``hue`` and ``rgbcolor``
    as ways of specifying the color of the graphic.

    We can also use this command to plot three-dimensional disks parallel
    to the `xy`-plane::

        sage: d = disk((1,1,3), 1, (pi,3*pi/2), rgbcolor=(1,0,0))
        sage: d
        sage: type(d)
        <type 'sage.plot.plot3d.index_face_set.IndexFaceSet'>

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

        sage: disk((0, 0), 5, (0, pi/2), xmin=0, xmax=5, ymin=0, ymax=5, figsize=(2,2), rgbcolor=(1, 0, 1))
        sage: disk((0, 0), 5, (0, pi/2), rgbcolor=(1, 0, 1)).show(xmin=0, xmax=5, ymin=0, ymax=5, figsize=(2,2)) # These are equivalent

    TESTS:

    Testing that legend labels work right::

        sage: disk((2,4), 3, (pi/8, pi/4), hue=1, legend_label='disk', legend_color='blue')

    We cannot currently plot disks in more than three dimensions::

        sage: d = disk((1,1,1,1), 1, (0,pi))
        Traceback (most recent call last):
        ...
        ValueError: The center point of a plotted disk should have two or three coordinates.
    """
    from sage.plot.all import Graphics
    g = 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'

    g._set_extra_kwds(Graphics._extract_kwds_for_show(options))
    g.add_primitive(Disk(point, radius, angle, options))
    if options['legend_label']:
        g.legend(True)
        g._legend_colors = [options['legend_color']]
    if len(point)==2:
        return g
    elif len(point)==3:
        return g[0].plot3d(z=point[2])
    else:
        raise ValueError, 'The center point of a plotted disk should have two or three coordinates.'
Beispiel #54
0
class HyperbolicTriangleDisc(object):  #]GraphicPrimitive):
    r"""
    Hyperbolic triangles in the disc model of the hyperbolic plane.
    Note that we are given coordinates in the upper half-plane and map them to the disc.
    
    """
    @options(center=CC(0, 1))
    def __init__(self, A, B, C, **options):
        """
        Initialize HyperbolicTriangle under the map (z-z0)/(z-\bar(z0)):
        
        Examples::
        
            sage: from sage.plot.hyperbolic_triangle import HyperbolicTriangle
            sage: print(HyperbolicTriangle(0, 1/2, I, {}))
            Hyperbolic triangle (0.000000000000000, 0.500000000000000, 1.00000000000000*I)
        """
        A, B, C = (CC(A), CC(B), CC(C))
        self.path = []
        self._options = {}
        self._graphics = Graphics()
        self._verbose = options.pop('verbose', None)
        Z0 = options['center']  #.get('center',C(0,1))
        options.pop('center', None)
        self._npts = options.pop('npts', 10)
        sides = options.pop('sides', [1, 2, 3])
        #options.pop('fill',None)
        self._options.update(options)
        self._z0 = CC(Z0)
        self._z0bar = CC(Z0).conjugate()
        verbose = self._verbose
        sides.sort()
        if sides == [1]:
            if verbose > 0:
                print("Drawing A - B!")
            self._hyperbolic_arc_d(A, B, True)
        elif sides == [2]:
            if verbose > 0:
                print("Drawing B - C!")
            self._hyperbolic_arc_d(B, C, True)
        elif sides == [3]:
            if verbose > 0:
                print("Drawing C - A!")
            self._hyperbolic_arc_d(C, A, True)
        elif sides == [1, 2]:
            if verbose > 0:
                print("Drawing A - B! & B - C!")
            self._hyperbolic_arc_d(A, B, True)
            self._hyperbolic_arc_d(B, C, False)
        elif sides == [1, 3]:
            if verbose > 0:
                print("Drawing C - A! & A - B")
            self._hyperbolic_arc_d(C, A, True)
            self._hyperbolic_arc_d(A, B, False)
        elif sides == [2, 3]:
            if verbose > 0:
                print("Drawing B - C! & C - A")
            self._hyperbolic_arc_d(B, C, True)
            self._hyperbolic_arc_d(C, A, False)
        else:
            self._hyperbolic_arc_d(A, B, True)
            self._hyperbolic_arc_d(B, C, False)
            self._hyperbolic_arc_d(C, A, False)
        #self._hyperbolic_arc_d(A, B, True);
        #self._hyperbolic_arc_d(B, C);
        #self._hyperbolic_arc_d(C, A);
        #BezierPath.__init__(self, self.path, options)

        #super(HyperbolicTriangleDisc,self).__init__(options)
        self.A, self.B, self.C = (A, B, C)

    def _cayley_transform(self, z):
        #print "z=",z,z==infyinity,type(z),type(infinity)
        if z == infinity or z == CC(infinity):
            return CC(1, 0)
        return (CC(z) - self._z0) / (CC(z) - self._z0bar)

    def _hyperbolic_arc_d(self, z0, z3, first=False):
        """
        Function to construct Bezier path as an approximation to
        the hyperbolic arc between the complex numbers z0 and z3 in the
        hyperbolic plane.
        """

        w0 = self._cayley_transform(z0)
        w3 = self._cayley_transform(z3)
        if self._verbose > 0:
            print("in plane z0,z3={0},{1}".format(z0, z3))
            print("in disc: {0},{1}".format(w0, w3))
        npts = self._npts
        if z0 == infinity or z0 == CC(infinity):
            zm = [z3 + CC(0, j + 0.5) for j in range(npts - 2)]
            wm = [self._cayley_transform(x) for x in zm]
            pts = [w3]
            pts.extend(wm)
            pts.append(w0)
            opt = self._options
            opt['fill'] = False
            self._graphics.add_primitive(
                BezierPath([[(x.real(), x.imag()) for x in pts]], opt))
            return
        if z3 == infinity or z3 == CC(infinity):
            zm = [z0 + CC(0, j + 0.5) for j in range(npts - 2)]
            wm = [self._cayley_transform(x) for x in zm]
            pts = [w0]
            pts.extend(wm)
            pts.append(w3)
            opt = self._options
            opt['fill'] = False
            self._graphics.add_primitive(
                BezierPath([[(x.real(), x.imag()) for x in pts]], opt))
            #self._graphics.add_primitive(Line([w1.real(),w2.real()],[w1.imag(),w2.imag()],self._options))
            #self.path.append([(0,w0.imag()),CC(0,y), (0,w3.imag())])
            return
        x0 = z0.real()
        y0 = z0.imag()
        x3 = z3.real()
        y3 = z3.imag()
        if y0 == 0 and y3 == 0:
            p = (z0.real() + z3.real()) / 2
            r = abs(z0 - p)
            zm = CC(p, r)
            self._hyperbolic_arc_d(z0, zm, first)
            self._hyperbolic_arc_d(zm, z3)
            return
        else:
            if abs(x0 - x3) < 1e-10:  ## on the same vertical line
                xmid = (x0 + x3) * 0.5
                h = y3 - y0
                zm = [CC(xmid, y0 + t * h / (npts - 1)) for t in range(npts)]
            else:
                p = RR((x0 + x3) * (x3 - x0) + (y0 + y3) *
                       (y3 - y0)) / (2 * (x3 - x0))
                r = RR((p - x0)**2 + y0**2).sqrt()  # radius of the circle in H
                zm = ((z0 + z3) / 2 - p) / abs(
                    (z0 + z3) / 2 - p
                ) * r + p  # midpoint (at least approximately) of geodesic between z0 and z3
                t0 = CC(z0 - p).argument()
                t3 = CC(z3 - p).argument()
                if self._verbose > 1:
                    print("x0,x3={0},{1}".format(x0, x3))
                    print("t0,t3={0},{1}".format(t0, t3))
                    print("r={0}".format(r))
                    print("opt={0}".format(self._options))
                if x0 <= x3:
                    zm = [
                        p + r * CC(0, (t0 + t * (t3 - t0) / (npts - 1))).exp()
                        for t in range(npts)
                    ]
                else:
                    zm = [
                        p + r * CC(0, (t0 + t * (t3 - t0) / (npts - 1))).exp()
                        for t in range(npts)
                    ]
                #print "zm=",zm
                #zm.insert(0,z0)
                #zm.append(z3)
            pts = [self._cayley_transform(x) for x in zm]
            opt = self._options
            opt['fill'] = False
            #w0 = self._cayley_transform(z0)
            #w3 = self._cayley_transform(z3)

            if self._verbose > 2:
                print("pts={0}".format(pts))
            self._graphics.add_primitive(
                BezierPath([[(x.real(), x.imag()) for x in pts]], opt))
            return
            #print "z0_test=",(p+r*exp(t0*I))
            #print "z3_test=",(p+r*exp(t3*I))
            #t = (8*zm-4*(z0+z3)).imag()/3/(z3-z0).real()
            # I have no idea what these points should represent....
            #z1 = z0 + t*CC(z0.imag(), (p-z0.real()))
            #z2 = z3 - t*CC(z3.imag(), (p-z3.real()))
            wm = [self._cayley_transform(x) for x in zm]
            pp = self._cayley_transform(CC(p, 0))
            w1 = self._cayley_transform(z0)
            w2 = self._cayley_transform(z3)
            c = self._cayley_transform(CC(
                p, 0))  # center of circle on the unit disk.
            if self._verbose > 2:
                print("p,r={0},{1}".format(p, r))
                print("zm={0}".format(zm))
                #print "t=",t
                #print "tt=",(8*zm-4*(z0+z3)).imag()/3/(z3-z0).real()

                print("C(c)={0}".format(pp))
                print("C(zm)={0}".format(wm))
                print("C(z0)={0}".format(w1))
                print("C(z3)={0}".format(w2))
                #print "z2=",z2

            r = abs(w1 - c)  # radius
            t0 = CC(w0 - pp).argument()
            t3 = CC(w3 - pp).argument()
            t = abs(t0 - t3)
        if self._verbose > 0:
            print("adding a:rc {0}".format(
                (zm.real(), zm.imag(), r, r, t, t0, t3)))
        self._graphics.add_primitive(
            Line([w1.real(), w2.real(), wm.real()],
                 [w1.imag(), w2.imag(), wm.imag()], {
                     'thickness': 2,
                     'alpha': 1,
                     'rgbcolor': 'blue',
                     'legend_label': ""
                 }))
        self._graphics.add_primitive(
            Point(
                [w1.real(), w2.real(), wm.real()],
                [w1.imag(), w2.imag(), wm.imag()], {
                    'size': 10,
                    'alpha': 1,
                    'faceted': True,
                    'rgbcolor': 'red',
                    'legend_label': ""
                }))

        #self._graphics.add_primitive(Arc(pp.real(),pp.imag(),r,r,t,t0,t3,self._options))
        #self._graphics. Arc(zm.real(),zm.imag(),r,r,abs(t),-abs(t),abs(t),self._options)

    def __call__(self):
        return self._graphics
Beispiel #55
0
def density_plot(f, xrange, yrange, **options):
    r"""
    ``density_plot`` takes a function of two variables, `f(x,y)`
    and plots the height of of the function over the specified
    ``xrange`` and ``yrange`` as demonstrated below.

    ``density_plot(f, (xmin, xmax), (ymin, ymax), ...)``

    INPUT:

    - ``f`` -- a function of two variables

    - ``(xmin, xmax)`` -- 2-tuple, the range of ``x`` values OR 3-tuple
      ``(x,xmin,xmax)``

    - ``(ymin, ymax)`` -- 2-tuple, the range of ``y`` values OR 3-tuple
      ``(y,ymin,ymax)``

    The following inputs must all be passed in as named parameters:

    - ``plot_points`` -- integer (default: 25); number of points to plot
      in each direction of the grid

    - ``cmap`` -- a colormap (type ``cmap_help()`` for more information).

    - ``interpolation`` -- string (default: ``'catrom'``), the interpolation
      method to use: ``'bilinear'``, ``'bicubic'``, ``'spline16'``,
      ``'spline36'``, ``'quadric'``, ``'gaussian'``, ``'sinc'``,
      ``'bessel'``, ``'mitchell'``, ``'lanczos'``, ``'catrom'``,
      ``'hermite'``, ``'hanning'``, ``'hamming'``, ``'kaiser'``


    EXAMPLES:

    Here we plot a simple function of two variables.  Note that
    since the input function is an expression, we need to explicitly
    declare the variables in 3-tuples for the range::

        sage: x,y = var('x,y')
        sage: density_plot(sin(x)*sin(y), (x, -2, 2), (y, -2, 2))
        Graphics object consisting of 1 graphics primitive


    Here we change the ranges and add some options; note that here
    ``f`` is callable (has variables declared), so we can use 2-tuple ranges::

        sage: x,y = var('x,y')
        sage: f(x,y) = x^2*cos(x*y)
        sage: density_plot(f, (x,-10,5), (y, -5,5), interpolation='sinc', plot_points=100)
        Graphics object consisting of 1 graphics primitive

    An even more complicated plot::

        sage: x,y = var('x,y')
        sage: density_plot(sin(x^2 + y^2)*cos(x)*sin(y), (x, -4, 4), (y, -4, 4), cmap='jet', plot_points=100)
        Graphics object consisting of 1 graphics primitive

    This should show a "spotlight" right on the origin::

        sage: x,y = var('x,y')
        sage: density_plot(1/(x^10+y^10), (x, -10, 10), (y, -10, 10))
        Graphics object consisting of 1 graphics primitive

    Some elliptic curves, but with symbolic endpoints.  In the first
    example, the plot is rotated 90 degrees because we switch the
    variables `x`, `y`::

        sage: density_plot(y^2 + 1 - x^3 - x, (y,-pi,pi), (x,-pi,pi))
        Graphics object consisting of 1 graphics primitive

    ::

        sage: density_plot(y^2 + 1 - x^3 - x, (x,-pi,pi), (y,-pi,pi))
        Graphics object consisting of 1 graphics primitive

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

        sage: density_plot(log(x) + log(y), (x, 1, 10), (y, 1, 10), dpi=20)
        Graphics object consisting of 1 graphics primitive

    ::

        sage: density_plot(log(x) + log(y), (x, 1, 10), (y, 1, 10)).show(dpi=20) # These are equivalent

    TESTS:

    Check that :trac:`15315` is fixed, i.e., density_plot respects the
    ``aspect_ratio`` parameter. Without the fix, it looks like a thin line
    of width a few mm. With the fix it should look like a nice fat layered
    image::

        sage: density_plot((x*y)^(1/2), (x,0,3), (y,0,500), aspect_ratio=.01)
        Graphics object consisting of 1 graphics primitive

    Default ``aspect_ratio`` is ``"automatic"``, and that should work too::

        sage: density_plot((x*y)^(1/2), (x,0,3), (y,0,500))
        Graphics object consisting of 1 graphics primitive

    """
    from sage.plot.all import Graphics
    from sage.plot.misc import setup_for_eval_on_grid
    g, ranges = setup_for_eval_on_grid([f], [xrange, yrange], options['plot_points'])
    g = g[0]
    xrange,yrange=[r[:2] for r in ranges]

    xy_data_array = [[g(x, y) for x in xsrange(*ranges[0], include_endpoint=True)]
                              for y in xsrange(*ranges[1], include_endpoint=True)]

    g = Graphics()
    g._set_extra_kwds(Graphics._extract_kwds_for_show(options, ignore=['xmin', 'xmax']))
    g.add_primitive(DensityPlot(xy_data_array, xrange, yrange, options))
    return g
Beispiel #56
0
    def __init__(self, A, B, C, **options):
        """
        Initialize HyperbolicTriangle under the map (z-z0)/(z-\bar(z0)):
        
        Examples::
        
            sage: from sage.plot.hyperbolic_triangle import HyperbolicTriangle
            sage: print(HyperbolicTriangle(0, 1/2, I, {}))
            Hyperbolic triangle (0.000000000000000, 0.500000000000000, 1.00000000000000*I)
        """
        A, B, C = (CC(A), CC(B), CC(C))
        self.path = []
        self._options = {}
        self._graphics = Graphics()
        self._verbose = options.pop('verbose', None)
        Z0 = options['center']  #.get('center',C(0,1))
        options.pop('center', None)
        self._npts = options.pop('npts', 10)
        sides = options.pop('sides', [1, 2, 3])
        #options.pop('fill',None)
        self._options.update(options)
        self._z0 = CC(Z0)
        self._z0bar = CC(Z0).conjugate()
        verbose = self._verbose
        sides.sort()
        if sides == [1]:
            if verbose > 0:
                print("Drawing A - B!")
            self._hyperbolic_arc_d(A, B, True)
        elif sides == [2]:
            if verbose > 0:
                print("Drawing B - C!")
            self._hyperbolic_arc_d(B, C, True)
        elif sides == [3]:
            if verbose > 0:
                print("Drawing C - A!")
            self._hyperbolic_arc_d(C, A, True)
        elif sides == [1, 2]:
            if verbose > 0:
                print("Drawing A - B! & B - C!")
            self._hyperbolic_arc_d(A, B, True)
            self._hyperbolic_arc_d(B, C, False)
        elif sides == [1, 3]:
            if verbose > 0:
                print("Drawing C - A! & A - B")
            self._hyperbolic_arc_d(C, A, True)
            self._hyperbolic_arc_d(A, B, False)
        elif sides == [2, 3]:
            if verbose > 0:
                print("Drawing B - C! & C - A")
            self._hyperbolic_arc_d(B, C, True)
            self._hyperbolic_arc_d(C, A, False)
        else:
            self._hyperbolic_arc_d(A, B, True)
            self._hyperbolic_arc_d(B, C, False)
            self._hyperbolic_arc_d(C, A, False)
        #self._hyperbolic_arc_d(A, B, True);
        #self._hyperbolic_arc_d(B, C);
        #self._hyperbolic_arc_d(C, A);
        #BezierPath.__init__(self, self.path, options)

        #super(HyperbolicTriangleDisc,self).__init__(options)
        self.A, self.B, self.C = (A, B, C)
Beispiel #57
0
def circle(center, radius, **options):
    """
    Return a circle at a point center = `(x,y)` (or `(x,y,z)` and 
    parallel to the `xy`-plane) with radius = `r`.  Type 
    ``circle.options`` to see all options.
    
    OPTIONS:

    - ``alpha`` - default: 1

    - ``fill`` - default: False

    - ``thickness`` - default: 1

    - ``linestyle`` - default: 'solid' (2D plotting only)

    - ``edgecolor`` - default: 'blue' (2D plotting only)

    - ``facecolor`` - default: 'blue' (2D plotting only, useful only
      if ``fill=True``)

    - ``rgbcolor`` - 2D or 3D plotting.  This option overrides
      ``edgecolor`` and ``facecolor`` for 2D plotting.

    - ``legend_label`` - the label for this item in the legend

    EXAMPLES:

    The default color is blue, but this is easy to change::

        sage: c = circle((1,1), 1)
        sage: c

    ::

        sage: c = circle((1,1), 1, rgbcolor=(1,0,0))
        sage: c

    We can also use this command to plot three-dimensional circles parallel
    to the `xy`-plane::

        sage: c = circle((1,1,3), 1, rgbcolor=(1,0,0))
        sage: c
        sage: type(c)
        <class 'sage.plot.plot3d.base.TransformGroup'>

    To correct the aspect ratio of certain graphics, it is necessary
    to show with a ``figsize`` of square dimensions::

        sage: c.show(figsize=[5,5],xmin=-1,xmax=3,ymin=-1,ymax=3)

    Here we make a more complicated plot, with many circles of different colors::

        sage: g = Graphics()
        sage: step=6; ocur=1/5; paths=16;
        sage: PI = math.pi    # numerical for speed -- fine for graphics
        sage: for r in range(1,paths+1):
        ...       for x,y in [((r+ocur)*math.cos(n), (r+ocur)*math.sin(n)) for n in srange(0, 2*PI+PI/step, PI/step)]:
        ...           g += circle((x,y), ocur, rgbcolor=hue(r/paths))
        ...       rnext = (r+1)^2
        ...       ocur = (rnext-r)-ocur
        ...
        sage: g.show(xmin=-(paths+1)^2, xmax=(paths+1)^2, ymin=-(paths+1)^2, ymax=(paths+1)^2, figsize=[6,6])

    Note that the ``rgbcolor`` option overrides the other coloring options.
    This produces red fill in a blue circle::

        sage: circle((2,3), 1, fill=True, edgecolor='blue')

    This produces an all-green filled circle::

        sage: circle((2,3), 1, fill=True, edgecolor='blue', rgbcolor='green')

    The option ``hue`` overrides *all* other options, so be careful with its use.
    This produces a purplish filled circle::

        sage: circle((2,3), 1, fill=True, edgecolor='blue', rgbcolor='green', hue=.8)

    And a circle with a legend::

        sage: circle((4,5), 1, rgbcolor='yellow', fill=True, legend_label='the sun').show(xmin=0, ymin=0)

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

        sage: circle((0, 0), 2, figsize=[10,10]) # That circle is huge!

    ::

        sage: circle((0, 0), 2).show(figsize=[10,10]) # These are equivalent

    TESTS:

    We cannot currently plot circles in more than three dimensions::

        sage: circle((1,1,1,1), 1, rgbcolor=(1,0,0))
        Traceback (most recent call last):
        ...
        ValueError: The center of a plotted circle should have two or three coordinates.

    The default aspect ratio for a circle is 1.0::

        sage: P = circle((1,1), 1)
        sage: P.aspect_ratio()
        1.0
    """
    from sage.plot.all import Graphics
    g = Graphics()
    g._set_extra_kwds(Graphics._extract_kwds_for_show(options))
    g.add_primitive(Circle(center[0], center[1], radius, options))
    if options['legend_label']:
        g.legend(True)
    if len(center)==2:
        return g
    elif len(center)==3:
        return g[0].plot3d(z=center[2])
    else:
        raise ValueError, 'The center of a plotted circle should have two or three coordinates.'
Beispiel #58
0
def density_plot(f, xrange, yrange, **options):
    r"""
    ``density_plot`` takes a function of two variables, `f(x,y)`
    and plots the height of of the function over the specified
    ``xrange`` and ``yrange`` as demonstrated below.

    ``density_plot(f, (xmin, xmax), (ymin, ymax), ...)``

    INPUT:

    - ``f`` -- a function of two variables

    - ``(xmin, xmax)`` -- 2-tuple, the range of ``x`` values OR 3-tuple
      ``(x,xmin,xmax)``

    - ``(ymin, ymax)`` -- 2-tuple, the range of ``y`` values OR 3-tuple
      ``(y,ymin,ymax)``

    The following inputs must all be passed in as named parameters:

    - ``plot_points`` -- integer (default: 25); number of points to plot
      in each direction of the grid

    - ``cmap`` -- a colormap (type ``cmap_help()`` for more information).

    - ``interpolation`` -- string (default: ``'catrom'``), the interpolation
      method to use: ``'bilinear'``, ``'bicubic'``, ``'spline16'``,
      ``'spline36'``, ``'quadric'``, ``'gaussian'``, ``'sinc'``,
      ``'bessel'``, ``'mitchell'``, ``'lanczos'``, ``'catrom'``,
      ``'hermite'``, ``'hanning'``, ``'hamming'``, ``'kaiser'``

    EXAMPLES:

    Here we plot a simple function of two variables.  Note that
    since the input function is an expression, we need to explicitly
    declare the variables in 3-tuples for the range::

        sage: x,y = var('x,y')
        sage: density_plot(sin(x)*sin(y), (x, -2, 2), (y, -2, 2))

    Here we change the ranges and add some options; note that here
    ``f`` is callable (has variables declared), so we can use 2-tuple ranges::

        sage: x,y = var('x,y')
        sage: f(x,y) = x^2*cos(x*y)
        sage: density_plot(f, (x,-10,5), (y, -5,5), interpolation='sinc', plot_points=100)

    An even more complicated plot::

        sage: x,y = var('x,y')
        sage: density_plot(sin(x^2 + y^2)*cos(x)*sin(y), (x, -4, 4), (y, -4, 4), cmap='jet', plot_points=100)

    This should show a "spotlight" right on the origin::

        sage: x,y = var('x,y')
        sage: density_plot(1/(x^10+y^10), (x, -10, 10), (y, -10, 10))

    Some elliptic curves, but with symbolic endpoints.  In the first
    example, the plot is rotated 90 degrees because we switch the
    variables `x`, `y`::

        sage: density_plot(y^2 + 1 - x^3 - x, (y,-pi,pi), (x,-pi,pi))

    ::

        sage: density_plot(y^2 + 1 - x^3 - x, (x,-pi,pi), (y,-pi,pi))

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

        sage: density_plot(log(x) + log(y), (x, 1, 10), (y, 1, 10), dpi=20)

    ::

        sage: density_plot(log(x) + log(y), (x, 1, 10), (y, 1, 10)).show(dpi=20) # These are equivalent
    """
    from sage.plot.all import Graphics
    from sage.plot.misc import setup_for_eval_on_grid
    g, ranges = setup_for_eval_on_grid([f], [xrange, yrange],
                                       options['plot_points'])
    g = g[0]
    xrange, yrange = [r[:2] for r in ranges]

    xy_data_array = [[
        g(x, y) for x in xsrange(*ranges[0], include_endpoint=True)
    ] for y in xsrange(*ranges[1], include_endpoint=True)]

    g = Graphics()
    g._set_extra_kwds(
        Graphics._extract_kwds_for_show(options, ignore=['xmin', 'xmax']))
    g.add_primitive(DensityPlot(xy_data_array, xrange, yrange, options))
    return g
Beispiel #59
0
def arrow2d(tailpoint=None, headpoint=None, path=None, **options):
    """
    If tailpoint and headpoint are provided, returns an arrow from (xmin, ymin) 
    to (xmax, ymax).  If tailpoint or headpoint is None and path is not None,
    returns an arrow along the path.  (See further info on paths in bezier_path).

    INPUT:

    - ``tailpoint`` - the starting point of the arrow

    - ``headpoint`` - where the arrow is pointing to

    - ``path`` - the list of points and control points (see bezier_path for detail) that
      the arrow will follow from source to destination

    - ``head`` - 0, 1 or 2, whether to draw the head at the start (0), end (1) or both (2)
      of the path (using 0 will swap headpoint and tailpoint).  This is ignored
      in 3D plotting.

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

    - ``width`` - (default: 2) the width of the arrow shaft, in points

    - ``color`` - (default: (0,0,1)) the color of the arrow (as an RGB tuple or a string)

    - ``hue`` - the color of the arrow (as a number)

    - ``arrowsize`` - the size of the arrowhead

    - ``arrowshorten`` - the length in points to shorten the arrow (ignored if using path
      parameter)

    - ``legend_label`` - the label for this item in the legend

    - ``zorder`` - the layer level to draw the arrow-- note that this is ignored in 3D
      plotting.

    EXAMPLES:

    A straight, blue arrow::

       sage: arrow2d((1, 1), (3, 3))

    Make a red arrow::

       sage: arrow2d((-1, -1), (2, 3), color=(1,0,0))
       sage: arrow2d((-1, -1), (2, 3), color='red')

    You can change the width of an arrow::

        sage: arrow2d((1, 1), (3, 3), width=5, arrowsize=15)

    Use a dashed line instead of a solid one for the arrow::

        sage: arrow2d((1, 1), (3, 3), linestyle='dashed')
        sage: arrow2d((1, 1), (3, 3), linestyle='--')

    A pretty circle of arrows::

        sage: sum([arrow2d((0,0), (cos(x),sin(x)), hue=x/(2*pi)) for x in [0..2*pi,step=0.1]])

    If we want to draw the arrow between objects, for example, the
    boundaries of two lines, we can use the arrowshorten option
    to make the arrow shorter by a certain number of points::

        sage: line([(0,0),(1,0)],thickness=10)+line([(0,1),(1,1)], thickness=10)+arrow2d((0.5,0),(0.5,1), arrowshorten=10,rgbcolor=(1,0,0))

    If BOTH headpoint and tailpoint are None, then an empty plot is returned::

        sage: arrow2d(headpoint=None, tailpoint=None)


    We can also draw an arrow with a legend::

        sage: arrow((0,0), (0,2), legend_label='up')

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

        sage: arrow2d((-2, 2), (7,1), frame=True)
        sage: arrow2d((-2, 2), (7,1)).show(frame=True)
    """
    # Allow the usual linestyles used in the plot() command
    dict_line = {':': 'dotted', '-': 'solid', '--': 'dashed', '-.': 'dashdot'}
    if options['linestyle'] in dict_line:
        options['linestyle'] = dict_line[options['linestyle']]

    from sage.plot.all import Graphics
    g = Graphics()
    g._set_extra_kwds(Graphics._extract_kwds_for_show(options))

    if headpoint is not None and tailpoint is not None:
        xtail, ytail = tailpoint
        xhead, yhead = headpoint
        g.add_primitive(Arrow(xtail, ytail, xhead, yhead, options=options))
    elif path is not None:
        g.add_primitive(CurveArrow(path, options=options))
    elif tailpoint is None and headpoint is None:
        return g
    else:
        raise TypeError('Arrow requires either both headpoint and tailpoint or a path parameter.')
    if options['legend_label']:
        g.legend(True)
    return g
Beispiel #60
0
def arrow2d(tailpoint=None, headpoint=None, path=None, **options):
    """
    If tailpoint and headpoint are provided, returns an arrow from (xmin, ymin)
    to (xmax, ymax).  If tailpoint or headpoint is None and path is not None,
    returns an arrow along the path.  (See further info on paths in bezier_path).

    INPUT:

    - ``tailpoint`` - the starting point of the arrow

    - ``headpoint`` - where the arrow is pointing to

    - ``path`` - the list of points and control points (see bezier_path for detail) that
      the arrow will follow from source to destination

    - ``head`` - 0, 1 or 2, whether to draw the head at the start (0), end (1) or both (2)
      of the path (using 0 will swap headpoint and tailpoint).  This is ignored
      in 3D plotting.

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

    - ``width`` - (default: 2) the width of the arrow shaft, in points

    - ``color`` - (default: (0,0,1)) the color of the arrow (as an RGB tuple or a string)

    - ``hue`` - the color of the arrow (as a number)

    - ``arrowsize`` - the size of the arrowhead

    - ``arrowshorten`` - the length in points to shorten the arrow (ignored if using path
      parameter)

    - ``legend_label`` - the label for this item in the legend

    - ``legend_color`` - the color for the legend label

    - ``zorder`` - the layer level to draw the arrow-- note that this is ignored in 3D
      plotting.

    EXAMPLES:

    A straight, blue arrow::

       sage: arrow2d((1, 1), (3, 3))
       Graphics object consisting of 1 graphics primitive

    Make a red arrow::

       sage: arrow2d((-1, -1), (2, 3), color=(1,0,0))
       Graphics object consisting of 1 graphics primitive
       sage: arrow2d((-1, -1), (2, 3), color='red')
       Graphics object consisting of 1 graphics primitive

    You can change the width of an arrow::

        sage: arrow2d((1, 1), (3, 3), width=5, arrowsize=15)
        Graphics object consisting of 1 graphics primitive

    Use a dashed line instead of a solid one for the arrow::

        sage: arrow2d((1, 1), (3, 3), linestyle='dashed')
        Graphics object consisting of 1 graphics primitive
        sage: arrow2d((1, 1), (3, 3), linestyle='--')
        Graphics object consisting of 1 graphics primitive

    A pretty circle of arrows::

        sage: sum([arrow2d((0,0), (cos(x),sin(x)), hue=x/(2*pi)) for x in [0..2*pi,step=0.1]])
        Graphics object consisting of 63 graphics primitives

    If we want to draw the arrow between objects, for example, the
    boundaries of two lines, we can use the arrowshorten option
    to make the arrow shorter by a certain number of points::

        sage: line([(0,0),(1,0)],thickness=10)+line([(0,1),(1,1)], thickness=10)+arrow2d((0.5,0),(0.5,1), arrowshorten=10,rgbcolor=(1,0,0))
        Graphics object consisting of 3 graphics primitives

    If BOTH headpoint and tailpoint are None, then an empty plot is returned::

        sage: arrow2d(headpoint=None, tailpoint=None)
        Graphics object consisting of 0 graphics primitives

    We can also draw an arrow with a legend::

        sage: arrow((0,0), (0,2), legend_label='up', legend_color='purple')
        Graphics object consisting of 1 graphics primitive

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

        sage: arrow2d((-2, 2), (7,1), frame=True)
        Graphics object consisting of 1 graphics primitive
        sage: arrow2d((-2, 2), (7,1)).show(frame=True)
    """
    from sage.plot.all import Graphics
    g = Graphics()
    g._set_extra_kwds(Graphics._extract_kwds_for_show(options))

    if headpoint is not None and tailpoint is not None:
        xtail, ytail = tailpoint
        xhead, yhead = headpoint
        g.add_primitive(Arrow(xtail, ytail, xhead, yhead, options=options))
    elif path is not None:
        g.add_primitive(CurveArrow(path, options=options))
    elif tailpoint is None and headpoint is None:
        return g
    else:
        raise TypeError('Arrow requires either both headpoint and tailpoint or a path parameter.')
    if options['legend_label']:
        g.legend(True)
        g._legend_colors = [options['legend_color']]
    return g