Exemple #1
0
def triangulation_render_2d(triangulation, **kwds):
    r"""
    Return a graphical representation of a 2-d triangulation.

    INPUT:

    - ``triangulation`` -- a :class:`Triangulation`.

    - ``**kwds`` -- keywords that are passed on to the graphics primitives.

    OUTPUT:

    A 2-d graphics object.

    EXAMPLES::

        sage: points = PointConfiguration([[0,0],[0,1],[1,0],[1,1],[-1,-1]])
        sage: triang = points.triangulate()
        sage: triang.plot(axes=False, aspect_ratio=1)   # indirect doctest
        Graphics object consisting of 12 graphics primitives
    """
    from sage.plot.all import point2d, line2d, arrow, polygon2d
    points = [ point.reduced_affine() for point in triangulation.point_configuration() ]
    coord = [ [p[0], p[1]] for p in points ]
    plot_points = sum([ point2d(p,
                                zorder=2, pointsize=10, **kwds)
                        for p in coord ])

    tmp_lines = []
    for t in triangulation:
        if len(t)>=2:
            tmp_lines.append([t[0], t[1]])
        if len(t)>=3:
            tmp_lines.append([t[0], t[2]])
            tmp_lines.append([t[1], t[2]])
    all_lines = []
    interior_lines = []
    for l in tmp_lines:
        if l not in all_lines:
            all_lines.append(l)
        else:
            interior_lines.append(l)
    exterior_lines = [ l for l in all_lines if not l in interior_lines ]

    plot_interior_lines = sum([ line2d([ coord[l[0]], coord[l[1]] ],
                                       zorder=1, rgbcolor=(0,1,0), **kwds)
                                for l in interior_lines ])
    plot_exterior_lines = sum([ line2d([ coord[l[0]], coord[l[1]] ],
                                       zorder=1, rgbcolor=(0,0,1), **kwds)
                                for l in exterior_lines ])

    plot_triangs = sum([ polygon2d([coord[t[0]], coord[t[1]], coord[t[2]]],
                                   zorder=0, rgbcolor=(0.8, 1, 0.8), **kwds)
                         for t in triangulation if len(t)>=3 ])

    return \
        plot_points + \
        plot_interior_lines + plot_exterior_lines + \
        plot_triangs
Exemple #2
0
def triangulation_render_2d(triangulation, **kwds):
    r"""
    Return a graphical representation of a 2-d triangulation.

    INPUT:

    - ``triangulation`` -- a :class:`Triangulation`.

    - ``**kwds`` -- keywords that are passed on to the graphics primitives.

    OUTPUT:

    A 2-d graphics object.

    EXAMPLES::

        sage: points = PointConfiguration([[0,0],[0,1],[1,0],[1,1],[-1,-1]])
        sage: triang = points.triangulate()
        sage: triang.plot(axes=False, aspect_ratio=1)   # indirect doctest
        Graphics object consisting of 12 graphics primitives
    """
    from sage.plot.all import point2d, line2d, arrow, polygon2d

    points = [point.reduced_affine() for point in triangulation.point_configuration()]
    coord = [[p[0], p[1]] for p in points]
    plot_points = sum([point2d(p, zorder=2, pointsize=10, **kwds) for p in coord])

    tmp_lines = []
    for t in triangulation:
        if len(t) >= 2:
            tmp_lines.append([t[0], t[1]])
        if len(t) >= 3:
            tmp_lines.append([t[0], t[2]])
            tmp_lines.append([t[1], t[2]])
    all_lines = []
    interior_lines = []
    for l in tmp_lines:
        if l not in all_lines:
            all_lines.append(l)
        else:
            interior_lines.append(l)
    exterior_lines = [l for l in all_lines if not l in interior_lines]

    plot_interior_lines = sum(
        [line2d([coord[l[0]], coord[l[1]]], zorder=1, rgbcolor=(0, 1, 0), **kwds) for l in interior_lines]
    )
    plot_exterior_lines = sum(
        [line2d([coord[l[0]], coord[l[1]]], zorder=1, rgbcolor=(0, 0, 1), **kwds) for l in exterior_lines]
    )

    plot_triangs = sum(
        [
            polygon2d([coord[t[0]], coord[t[1]], coord[t[2]]], zorder=0, rgbcolor=(0.8, 1, 0.8), **kwds)
            for t in triangulation
            if len(t) >= 3
        ]
    )

    return plot_points + plot_interior_lines + plot_exterior_lines + plot_triangs
Exemple #3
0
    def render_fill_2d(self, **kwds):
        """
        Return the filled interior (a polygon) of a polyhedron in 2d.

        EXAMPLES::

            sage: cps = [i^3 for i in srange(-2,2,1/5)]
            sage: p = Polyhedron(vertices = [[(t^2-1)/(t^2+1),2*t/(t^2+1)] for t in cps])
            sage: proj = p.projection()
            sage: filled_poly = proj.render_fill_2d()
            sage: filled_poly.axes_width()
            0.8
        """
        poly = [polygon2d(self.coordinates_of(p), **kwds)
                 for p in self.polygons]
        return sum(poly)
Exemple #4
0
    def render_fill_2d(self, **kwds):
        """
        Return the filled interior (a polygon) of a polyhedron in 2d.

        EXAMPLES::

            sage: cps = [i^3 for i in srange(-2,2,1/5)]
            sage: p = Polyhedron(vertices = [[(t^2-1)/(t^2+1),2*t/(t^2+1)] for t in cps])
            sage: proj = p.projection()
            sage: filled_poly = proj.render_fill_2d()
            sage: filled_poly.axes_width()
            0.8
        """
        poly = [polygon2d(self.coordinates_of(p), **kwds)
                 for p in self.polygons]
        return sum(poly)
    def plot_completely_periodic(self):
        from sage.plot.all import polygon2d, Graphics, point2d, text
        O = self.orbit
        G = []
        u = self.u  # direction (that we put horizontal)
        m = matrix(2, [u[1], -u[0], u[1], u[0]])
        indices = {}
        xmin = xmax = ymin = ymax = 0
        for comp in self.decomposition.components():
            H = Graphics()
            x = O.V2._isomorphic_vector_space.zero()

            pts = [x]
            below = True
            for p in comp.perimeter():
                sc = p.saddleConnection()
                y = x + m * O.V2._isomorphic_vector_space(
                    O.V2(p.saddleConnection().vector()))

                if p.vertical():
                    if sc in indices:
                        i = indices[sc]
                    else:
                        i = len(indices) // 2
                        indices[sc] = i
                        indices[-sc] = i
                    if below:
                        H += text(str(i), (x + y) / 2, color='black')
                x = y
                xmin = min(xmin, x[0])
                xmax = max(xmax, x[0])
                ymin = min(ymin, x[1])
                ymax = max(ymax, x[1])
                pts.append(x)
            H += polygon2d(pts, color='blue', alpha=0.3)
            H += point2d(pts, color='red', pointsize=20)
            G.append(H)
        aspect_ratio = float(xmax - xmin) / float(ymax - ymin)
        for H in G:
            H.set_axes_range(xmin, xmax, ymin, ymax)
            H.axes(False)
            H.set_aspect_ratio(aspect_ratio)
        return G
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
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 len(L) > 0:
        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 len(P) > 0:
        # 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 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
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 len(L) > 0:
        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 len(P) > 0:
        # 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