def plot_histogram(self, clr=(0, 0, 1), eps=0.4): """ Plots the histogram plot of the sequence, which is assumed to be real or from a finite field, with a real indexing set I coercible into RR. Options are clr, which is an RGB value, and eps, which is the spacing between the bars. EXAMPLES: sage: J = range(3) sage: A = [ZZ(i^2)+1 for i in J] sage: s = IndexedSequence(A,J) sage: P = s.plot_histogram() Now type show(P) to view this in a browser. """ #from sage.plot.misc import text F = self.base_ring() ## elements must be coercible into RR I = self.index_object() N = len(I) S = self.list() P = [ polygon([[RR(I[i]) - eps, 0], [ RR(I[i]) - eps, RR(S[i]) ], [RR(I[i]) + eps, RR(S[i])], [RR(I[i]) + eps, 0], [RR(I[i]), 0]], rgbcolor=clr) for i in range(N) ] T = [ text(str(I[i]), (RR(I[i]), -0.8), fontsize=15, rgbcolor=(1, 0, 0)) for i in range(N) ] return sum(P) + sum(T)
def plot_known(self): r""" TESTS:: sage: from ore_algebra import * sage: from ore_algebra.analytic.function import DFiniteFunction sage: DiffOps, x, Dx = DifferentialOperators() sage: f = DFiniteFunction((x^2 + 1)*Dx^2 + 2*x*Dx, [0, 1]) sage: f(-10, 100) # long time [-1.4711276743037345918528755717...] sage: f.approx(5, post_transform=Dx) # long time [0.038461538461538...] sage: f.plot_known() # long time Graphics object consisting of ... graphics primitives """ g = plot.Graphics() for center, polys in self._polys.iteritems(): center, rad = self._disk(Point(center, self.dop)) xrange = (center - rad).mid(), (center + rad).mid() for i, a in enumerate(polys): # color palette copied from sage.plot.plot.plot color = plot.Color((0.66666 + i * 0.61803) % 1, 1, 0.4, space='hsl') Balls = a.pol.base_ring() g += plot.plot(lambda x: a.pol(Balls(x)).mid(), xrange, color=color) g += plot.text(str(a.prec), (center, a.pol(center).mid()), color=color) for point, ini in self._inivecs.iteritems(): g += plot.point2d((point, 0), size=50) return g
def plot_histogram(self, clr=(0,0,1), eps = 0.4): r""" Plot the histogram plot of the sequence. The sequence is assumed to be real or from a finite field, with a real indexing set ``I`` coercible into `\RR`. Options are ``clr``, which is an RGB value, and ``eps``, which is the spacing between the bars. EXAMPLES:: sage: J = range(3) sage: A = [ZZ(i^2)+1 for i in J] sage: s = IndexedSequence(A,J) sage: P = s.plot_histogram() sage: show(P) # Not tested """ # elements must be coercible into RR I = self.index_object() N = len(I) S = self.list() P = [polygon([[RR(I[i])-eps,0],[RR(I[i])-eps,RR(S[i])],[RR(I[i])+eps,RR(S[i])],[RR(I[i])+eps,0],[RR(I[i]),0]], rgbcolor=clr) for i in range(N)] T = [text(str(I[i]),(RR(I[i]),-0.8),fontsize=15,rgbcolor=(1,0,0)) for i in range(N)] return sum(P) + sum(T)
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 plot_labels(self, labels, positions): r""" Plot ``labels`` at specified ``positions``. INPUT: - ``labels`` -- a string or a list of strings; - ``positions`` -- a list of points. OUTPUT: - a plot. EXAMPLES:: sage: from sage.geometry.toric_plotter import ToricPlotter sage: tp = ToricPlotter(dict(), 2) sage: print tp.plot_labels("u", [(1.5,0)]) Graphics object consisting of 1 graphics primitive """ result = Graphics() color = self.label_color extra_options = self.extra_options zorder = self.label_zorder font_size = self.font_size twod = self.dimension <= 2 labels = label_list(labels, len(positions), twod) for label, position in zip(labels, positions): if label is None: continue if twod: result += text(label, position, color=color, fontsize=font_size, zorder=zorder, **extra_options) else: result += text3d(label, position, color=color, **extra_options) return result
def plot_labels(self, labels, positions): r""" Plot ``labels`` at specified ``positions``. INPUT: - ``labels`` -- a string or a list of strings; - ``positions`` -- a list of points. OUTPUT: - a plot. EXAMPLES:: sage: from sage.geometry.toric_plotter import ToricPlotter sage: tp = ToricPlotter(dict(), 2) sage: tp.plot_labels("u", [(1.5,0)]) Graphics object consisting of 1 graphics primitive """ result = Graphics() color = self.label_color extra_options = self.extra_options zorder = self.label_zorder font_size = self.font_size twod = self.dimension <= 2 labels = label_list(labels, len(positions), twod) for label, position in zip(labels, positions): if label is None: continue if twod: result += text(label, position, color=color, fontsize=font_size, zorder=zorder, **extra_options) else: result += text3d(label, position, color=color, **extra_options) return result
def plot_histogram(self, clr=(0,0,1),eps = 0.4): """ Plots the histogram plot of the sequence, which is assumed to be real or from a finite field, with a real indexing set I coercible into RR. Options are clr, which is an RGB value, and eps, which is the spacing between the bars. EXAMPLES: sage: J = range(3) sage: A = [ZZ(i^2)+1 for i in J] sage: s = IndexedSequence(A,J) sage: P = s.plot_histogram() Now type show(P) to view this in a browser. """ #from sage.plot.misc import text F = self.base_ring() ## elements must be coercible into RR I = self.index_object() N = len(I) S = self.list() P = [polygon([[RR(I[i])-eps,0],[RR(I[i])-eps,RR(S[i])],[RR(I[i])+eps,RR(S[i])],[RR(I[i])+eps,0],[RR(I[i]),0]], rgbcolor=clr) for i in range(N)] T = [text(str(I[i]),(RR(I[i]),-0.8),fontsize=15,rgbcolor=(1,0,0)) for i in range(N)] return sum(P)+sum(T)
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 plot_heap(self): r""" Display the Hasse diagram of the heap of ``self``. The Hasse diagram is rendered in the lattice `S \times \NN`, with every element `i` in the poset drawn as a point labelled by its label `s_i`. Every point is placed in the column for its label at a certain level. The levels start at 0 and the level k of an element `i` is the maximal number `k` such that the heap contains a chain `i_0\prec i_1\prec ... \prec i_k` where `i_k=i`. See [Ste1996]_ and [GX2020]_. OUTPUT: GraphicsObject EXAMPLES:: sage: FC = CoxeterGroup(['B', 5]).fully_commutative_elements() sage: FC([3,2,4,3,1]).plot_heap() Graphics object consisting of 15 graphics primitives .. PLOT:: :width: 400px FC = CoxeterGroup(['B', 5]).fully_commutative_elements() g = FC([3,2,4,3,1]).plot_heap() sphinx_plot(g) """ import sage.plot.all as plot m = self.parent().coxeter_group().coxeter_matrix() letters = self.parent().coxeter_group().index_set() graphics = [] h = self.heap() levels = h.level_sets() letters_at_level = [set(self[i] for i in level) for level in levels] for (level_zero_index, members) in enumerate(levels): level = level_zero_index + 1 for i in members: x = self[i] # Draw the node graphics.append( plot.circle((x, level), 0.1, fill=True, facecolor='white', edgecolor='blue', zorder=1)) graphics.append( plot.text(str(x), (x, level), color='blue', zorder=2)) neighbors = {z for z in letters if m[x, z] >= 3} for other in neighbors: highest_level = max((j + 1 for j in range(level_zero_index) if other in letters_at_level[j]), default=None) if highest_level: graphics.append( plot.line([(other, highest_level), (x, level)], color='black', zorder=0)) g = sum(graphics) g.axes(False) return g
def set_vertices(self, **vertex_options): """ Sets the vertex plotting parameters for this GraphPlot. This function is called by the constructor but can also be called to make updates to the vertex options of an existing GraphPlot object. Note that the changes are cumulative. EXAMPLES:: 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: GP = g.graphplot(vertex_size=100, edge_labels=True, color_by_label=True, edge_style='dashed') sage: GP.set_vertices(talk=True) sage: GP.plot() sage: GP.set_vertices(vertex_colors='pink', vertex_shape='^') sage: GP.plot() """ # Handle base vertex options voptions = {} for arg in vertex_options: self._options[arg] = vertex_options[arg] # First set defaults for styles vertex_colors = None if self._options['talk']: voptions['markersize'] = 500 if self._options['partition'] is None: vertex_colors = '#ffffff' else: voptions['markersize'] = self._options['vertex_size'] if 'vertex_colors' not in self._options: if self._options['partition'] is not None: from sage.plot.colors import rainbow, rgbcolor partition = self._options['partition'] l = len(partition) R = rainbow(l) vertex_colors = {} for i in range(l): vertex_colors[R[i]] = partition[i] elif len(self._graph._boundary) != 0: vertex_colors = {} bdy_verts = [] int_verts = [] for v in self._graph.vertex_iterator(): if v in self._graph._boundary: bdy_verts.append(v) else: int_verts.append(v) vertex_colors['#fec7b8'] = int_verts vertex_colors['#b3e8ff'] = bdy_verts elif not vertex_colors: vertex_colors = '#fec7b8' else: vertex_colors = self._options['vertex_colors'] if 'vertex_shape' in self._options: voptions['marker'] = self._options['vertex_shape'] if self._graph.is_directed(): self._vertex_radius = sqrt(voptions['markersize'] / pi) self._arrowshorten = 2 * self._vertex_radius if self._arcdigraph: self._vertex_radius = sqrt(voptions['markersize'] / (20500 * pi)) voptions['zorder'] = 7 if not isinstance(vertex_colors, dict): voptions['facecolor'] = vertex_colors if self._arcdigraph: self._plot_components['vertices'] = [ circle(center, self._vertex_radius, fill=True, facecolor=vertex_colors, clip=False) for center in self._pos.values() ] else: self._plot_components['vertices'] = scatter_plot( self._pos.values(), clip=False, **voptions) else: # Color list must be ordered: pos = [] colors = [] for i in vertex_colors: pos += [self._pos[j] for j in vertex_colors[i]] colors += [i] * len(vertex_colors[i]) # If all the vertices have not been assigned a color if len(self._pos) != len(pos): from sage.plot.colors import rainbow, rgbcolor vertex_colors_rgb = [rgbcolor(c) for c in vertex_colors] for c in rainbow(len(vertex_colors) + 1): if rgbcolor(c) not in vertex_colors_rgb: break leftovers = [j for j in self._pos.values() if j not in pos] pos += leftovers colors += [c] * len(leftovers) if self._arcdigraph: self._plot_components['vertices'] = [ circle(pos[i], self._vertex_radius, fill=True, facecolor=colors[i], clip=False) for i in range(len(pos)) ] else: self._plot_components['vertices'] = scatter_plot( pos, facecolor=colors, clip=False, **voptions) if self._options['vertex_labels']: self._plot_components['vertex_labels'] = [] # TODO: allow text options for v in self._nodelist: self._plot_components['vertex_labels'].append( text(str(v), self._pos[v], rgbcolor=(0, 0, 0), zorder=8))
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 set_edges(self, **edge_options): """ Sets the edge (or arrow) plotting parameters for the GraphPlot object. This function is called by the constructor but can also be called to make updates to the vertex options of an existing GraphPlot object. Note that the changes are cumulative. EXAMPLES:: 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: GP = g.graphplot(vertex_size=100, edge_labels=True, color_by_label=True, edge_style='dashed') sage: GP.set_edges(edge_style='solid') sage: GP.plot() sage: GP.set_edges(edge_color='black') sage: GP.plot() sage: d = DiGraph({}, loops=True, multiedges=True, sparse=True) sage: d.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: GP = d.graphplot(vertex_size=100, edge_labels=True, color_by_label=True, edge_style='dashed') sage: GP.set_edges(edge_style='solid') sage: GP.plot() sage: GP.set_edges(edge_color='black') sage: GP.plot() TESTS:: sage: G = Graph("Fooba") sage: G.show(edge_colors={'red':[(3,6),(2,5)]}) Verify that default edge labels are pretty close to being between the vertices in some cases where they weren't due to truncating division (trac #10124):: sage: test_graphs = graphs.FruchtGraph(), graphs.BullGraph() sage: tol = 0.001 sage: for G in test_graphs: ... E=G.edges() ... for e0, e1, elab in E: ... G.set_edge_label(e0, e1, '%d %d' % (e0, e1)) ... gp = G.graphplot(save_pos=True,edge_labels=True) ... vx = gp._plot_components['vertices'][0].xdata ... vy = gp._plot_components['vertices'][0].ydata ... for elab in gp._plot_components['edge_labels']: ... textobj = elab[0] ... x, y, s = textobj.x, textobj.y, textobj.string ... v0, v1 = map(int, s.split()) ... vn = vector(((x-(vx[v0]+vx[v1])/2.),y-(vy[v0]+vy[v1])/2.)).norm() ... assert vn < tol """ for arg in edge_options: self._options[arg] = edge_options[arg] if 'edge_colors' in edge_options: self._options['color_by_label'] = False # Handle base edge options: thickness, linestyle eoptions={} if 'edge_style' in self._options: eoptions['linestyle'] = self._options['edge_style'] if 'thickness' in self._options: eoptions['thickness'] = self._options['thickness'] # Set labels param to add labels on the fly labels = False if self._options['edge_labels']: labels = True self._plot_components['edge_labels'] = [] # Make dict collection of all edges (keep label and edge color) edges_to_draw = {} if self._options['color_by_label'] or isinstance(self._options['edge_colors'], dict): if self._options['color_by_label']: edge_colors = self._graph._color_by_label() else: edge_colors = self._options['edge_colors'] for color in edge_colors: for edge in edge_colors[color]: key = tuple(sorted([edge[0],edge[1]])) if key == (edge[0],edge[1]): head = 1 else: head = 0 if len(edge) < 3: label = self._graph.edge_label(edge[0],edge[1]) if isinstance(label, list): if key in edges_to_draw: edges_to_draw[key].append((label[-1], color, head)) else: edges_to_draw[key] = [(label[-1], color, head)] for i in range(len(label)-1): edges_to_draw[key].append((label[-1], color, head)) else: label = edge[2] if key in edges_to_draw: edges_to_draw[key].append((label, color, head)) else: edges_to_draw[key] = [(label, color, head)] # add unspecified edges in (default color black) for edge in self._graph.edge_iterator(): key = tuple(sorted([edge[0],edge[1]])) label = edge[2] specified = False if key in edges_to_draw: for old_label, old_color, old_head in edges_to_draw[key]: if label == old_label: specified = True break if not specified: if key == (edge[0],edge[1]): head = 1 else: head = 0 edges_to_draw[key] = [(label, 'black', head)] else: for edge in self._graph.edges(sort=True): key = tuple(sorted([edge[0],edge[1]])) if key == (edge[0],edge[1]): head = 1 else: head = 0 if key in edges_to_draw: edges_to_draw[key].append((edge[2], self._options['edge_color'], head)) else: edges_to_draw[key] = [(edge[2], self._options['edge_color'], head)] if edges_to_draw: self._plot_components['edges'] = [] else: return # Check for multi-edges or loops if self._arcs or self._loops: tmp = edges_to_draw.copy() dist = self._options['dist']*2. loop_size = self._options['loop_size'] max_dist = self._options['max_dist'] from sage.functions.all import sqrt for (a,b) in tmp: if a == b: # Loops distance = dist local_labels = edges_to_draw.pop((a,b)) if len(local_labels)*dist > max_dist: distance = float(max_dist)/len(local_labels) curr_loop_size = loop_size for i in range(len(local_labels)): self._plot_components['edges'].append(circle((self._pos[a][0],self._pos[a][1]-curr_loop_size), curr_loop_size, rgbcolor=local_labels[i][1], **eoptions)) if labels: self._plot_components['edge_labels'].append(text(local_labels[i][0], (self._pos[a][0], self._pos[a][1]-2*curr_loop_size))) curr_loop_size += distance/4 elif len(edges_to_draw[(a,b)]) > 1: # Multi-edge local_labels = edges_to_draw.pop((a,b)) # Compute perpendicular bisector p1 = self._pos[a] p2 = self._pos[b] M = ((p1[0]+p2[0])/2., (p1[1]+p2[1])/2.) # midpoint if not p1[1] == p2[1]: S = float(p1[0]-p2[0])/(p2[1]-p1[1]) # perp slope y = lambda x : S*x-S*M[0]+M[1] # perp bisector line # f,g are functions of distance d to determine x values # on line y at d from point M f = lambda d : sqrt(d**2/(1.+S**2)) + M[0] g = lambda d : -sqrt(d**2/(1.+S**2)) + M[0] odd_x = f even_x = g if p1[0] == p2[0]: odd_y = lambda d : M[1] even_y = odd_y else: odd_y = lambda x : y(f(x)) even_y = lambda x : y(g(x)) else: odd_x = lambda d : M[0] even_x = odd_x odd_y = lambda d : M[1] + d even_y = lambda d : M[1] - d # We now have the control points for each bezier curve # in terms of distance parameter d. # Also note that the label for each edge should be drawn at d/2. # (This is because we're using the perp bisectors). distance = dist if len(local_labels)*dist > max_dist: distance = float(max_dist)/len(local_labels) for i in range(len(local_labels)/2): k = (i+1.0)*distance if self._arcdigraph: odd_start = self._polar_hack_for_multidigraph(p1, [odd_x(k),odd_y(k)], self._vertex_radius)[0] odd_end = self._polar_hack_for_multidigraph([odd_x(k),odd_y(k)], p2, self._vertex_radius)[1] even_start = self._polar_hack_for_multidigraph(p1, [even_x(k),even_y(k)], self._vertex_radius)[0] even_end = self._polar_hack_for_multidigraph([even_x(k),even_y(k)], p2, self._vertex_radius)[1] self._plot_components['edges'].append(arrow(path=[[odd_start,[odd_x(k),odd_y(k)],odd_end]], head=local_labels[2*i][2], zorder=1, rgbcolor=local_labels[2*i][1], **eoptions)) self._plot_components['edges'].append(arrow(path=[[even_start,[even_x(k),even_y(k)],even_end]], head=local_labels[2*i+1][2], zorder=1, rgbcolor=local_labels[2*i+1][1], **eoptions)) else: self._plot_components['edges'].append(bezier_path([[p1,[odd_x(k),odd_y(k)],p2]],zorder=1, rgbcolor=local_labels[2*i][1], **eoptions)) self._plot_components['edges'].append(bezier_path([[p1,[even_x(k),even_y(k)],p2]],zorder=1, rgbcolor=local_labels[2*i+1][1], **eoptions)) if labels: j = k/2.0 self._plot_components['edge_labels'].append(text(local_labels[2*i][0],[odd_x(j),odd_y(j)])) self._plot_components['edge_labels'].append(text(local_labels[2*i+1][0],[even_x(j),even_y(j)])) if len(local_labels)%2 == 1: edges_to_draw[(a,b)] = [local_labels[-1]] # draw line for last odd dir = self._graph.is_directed() for (a,b) in edges_to_draw: if self._arcdigraph: C,D = self._polar_hack_for_multidigraph(self._pos[a], self._pos[b], self._vertex_radius) self._plot_components['edges'].append(arrow(C,D, rgbcolor=edges_to_draw[(a,b)][0][1], head=edges_to_draw[(a,b)][0][2], **eoptions)) if labels: self._plot_components['edge_labels'].append(text(str(edges_to_draw[(a,b)][0][0]),[(C[0]+D[0])/2., (C[1]+D[1])/2.])) elif dir: self._plot_components['edges'].append(arrow(self._pos[a],self._pos[b], rgbcolor=edges_to_draw[(a,b)][0][1], arrowshorten=self._arrowshorten, head=edges_to_draw[(a,b)][0][2], **eoptions)) else: self._plot_components['edges'].append(line([self._pos[a],self._pos[b]], rgbcolor=edges_to_draw[(a,b)][0][1], **eoptions)) if labels and not self._arcdigraph: self._plot_components['edge_labels'].append(text(str(edges_to_draw[(a,b)][0][0]),[(self._pos[a][0]+self._pos[b][0])/2., (self._pos[a][1]+self._pos[b][1])/2.]))
def set_vertices(self, **vertex_options): """ Sets the vertex plotting parameters for this GraphPlot. This function is called by the constructor but can also be called to make updates to the vertex options of an existing GraphPlot object. Note that the changes are cumulative. EXAMPLES:: 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: GP = g.graphplot(vertex_size=100, edge_labels=True, color_by_label=True, edge_style='dashed') sage: GP.set_vertices(talk=True) sage: GP.plot() sage: GP.set_vertices(vertex_colors='pink', vertex_shape='^') sage: GP.plot() """ # Handle base vertex options voptions = {} for arg in vertex_options: self._options[arg] = vertex_options[arg] # First set defaults for styles vertex_colors = None if self._options['talk']: voptions['markersize'] = 500 if self._options['partition'] is None: vertex_colors = '#ffffff' else: voptions['markersize'] = self._options['vertex_size'] if 'vertex_colors' not in self._options or self._options['vertex_colors'] is None: if self._options['partition'] is not None: from sage.plot.colors import rainbow,rgbcolor partition = self._options['partition'] l = len(partition) R = rainbow(l) vertex_colors = {} for i in range(l): vertex_colors[R[i]] = partition[i] elif len(self._graph._boundary) != 0: vertex_colors = {} bdy_verts = [] int_verts = [] for v in self._graph.vertex_iterator(): if v in self._graph._boundary: bdy_verts.append(v) else: int_verts.append(v) vertex_colors['#fec7b8'] = int_verts vertex_colors['#b3e8ff'] = bdy_verts elif not vertex_colors: vertex_colors='#fec7b8' else: vertex_colors = self._options['vertex_colors'] if 'vertex_shape' in self._options: voptions['marker'] = self._options['vertex_shape'] if self._graph.is_directed(): self._vertex_radius = sqrt(voptions['markersize']/pi) self._arrowshorten = 2*self._vertex_radius if self._arcdigraph: self._vertex_radius = sqrt(voptions['markersize']/(20500*pi)) voptions['zorder'] = 7 if not isinstance(vertex_colors, dict): voptions['facecolor'] = vertex_colors if self._arcdigraph: self._plot_components['vertices'] = [circle(center, self._vertex_radius, fill=True, facecolor=vertex_colors, clip=False) for center in self._pos.values()] else: self._plot_components['vertices'] = scatter_plot( self._pos.values(), clip=False, **voptions) else: # Color list must be ordered: pos = [] colors = [] for i in vertex_colors: pos += [self._pos[j] for j in vertex_colors[i]] colors += [i]*len(vertex_colors[i]) # If all the vertices have not been assigned a color if len(self._pos)!=len(pos): from sage.plot.colors import rainbow,rgbcolor vertex_colors_rgb=[rgbcolor(c) for c in vertex_colors] for c in rainbow(len(vertex_colors)+1): if rgbcolor(c) not in vertex_colors_rgb: break leftovers=[j for j in self._pos.values() if j not in pos] pos+=leftovers colors+=[c]*len(leftovers) if self._arcdigraph: self._plot_components['vertices'] = [circle(pos[i], self._vertex_radius, fill=True, facecolor=colors[i], clip=False) for i in range(len(pos))] else: self._plot_components['vertices'] = scatter_plot(pos, facecolor=colors, clip=False, **voptions) if self._options['vertex_labels']: self._plot_components['vertex_labels'] = [] # TODO: allow text options for v in self._nodelist: self._plot_components['vertex_labels'].append(text(str(v), self._pos[v], rgbcolor=(0,0,0), zorder=8))
def plot_bounds(dop, ini=None, pt=None, eps=None, **kwds): r""" EXAMPLES:: sage: from ore_algebra import * sage: from ore_algebra.analytic.naive_sum import * sage: Dops, x, Dx = DifferentialOperators() sage: plot_bounds(Dx - 1, [CBF(1)], CBF(i)/2, RBF(1e-20)) Graphics object consisting of 5 graphics primitives sage: plot_bounds(x*Dx^3 + 2*Dx^2 + x*Dx, eps=1e-8) Graphics object consisting of 5 graphics primitives sage: dop = x*Dx^2 + Dx + x sage: plot_bounds(dop, eps=1e-8, ....: ini=LogSeriesInitialValues(0, {0: (1, 0)}, dop)) Graphics object consisting of 5 graphics primitives sage: dop = ((x^2 + 10*x + 50)*Dx^10 + (5/9*x^2 + 50/9*x + 155/9)*Dx^9 ....: + (-10/3*x^2 - 100/3*x - 190/3)*Dx^8 + (30*x^2 + 300*x + 815)*Dx^7 ....: + (145*x^2 + 1445*x + 3605)*Dx^6 + (5/2*x^2 + 25*x + 115/2)*Dx^5 ....: + (20*x^2 + 395/2*x + 1975/4)*Dx^4 + (-5*x^2 - 50*x - 130)*Dx^3 ....: + (5/4*x^2 + 25/2*x + 105/4)*Dx^2 + (-20*x^2 - 195*x - 480)*Dx ....: + 5*x - 10) sage: plot_bounds(dop, pol_part_len=4, bound_inverse="solve", eps=1e-10) # long time Graphics object consisting of 5 graphics primitives """ import sage.plot.all as plot from sage.all import VectorSpace, QQ, RIF from ore_algebra.analytic.bounds import abs_min_nonzero_root if ini is None: ini = _random_ini(dop) if pt is None: rad = abs_min_nonzero_root(dop.leading_coefficient()) pt = QQ(2) if rad == infinity else RIF(rad/2).simplest_rational() if eps is None: eps = RBF(1e-50) logger.info("point: %s", pt) logger.info("initial values: %s", ini) recd = [] maj = bounds.DiffOpBound(dop, max_effort=0, **kwds) series_sum(dop, ini, pt, eps, stride=1, record_bounds_in=recd, maj=maj) ref_sum = recd[-1][1][0].add_error(recd[-1][2]) recd[-1:] = [] # Note: this won't work well when the errors get close to the double # precision underflow threshold. err = [(psum[0]-ref_sum).abs() for n, psum, _ in recd] large = float(1e200) # plot() is not robust to large values error_plot_upper = plot.line( [(n, v.upper()) for (n, v) in enumerate(err) if abs(float(v.upper())) < large], color="lightgray", scale="semilogy") error_plot = plot.line( [(n, v.lower()) for (n, v) in enumerate(err) if abs(float(v.lower())) < large], color="black", scale="semilogy") bound_plot_lower = plot.line( [(n, bound.lower()) for n, _, bound in recd if abs(float(bound.lower())) < large], color="lightblue", scale="semilogy") bound_plot = plot.line( [(n, bound.upper()) for n, _, bound in recd if abs(float(bound.upper())) < large], color="blue", scale="semilogy") title = repr(dop) + " @ x=" + repr(pt) title = title if len(title) < 80 else title[:77]+"..." myplot = error_plot_upper + error_plot + bound_plot_lower + bound_plot ymax = myplot.ymax() if ymax < float('inf'): txt = plot.text(title, (myplot.xmax(), ymax), horizontal_alignment='right', vertical_alignment='top') myplot += txt return myplot
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 set_edges(self, **edge_options): """ Sets the edge (or arrow) plotting parameters for the GraphPlot object. This function is called by the constructor but can also be called to make updates to the vertex options of an existing GraphPlot object. Note that the changes are cumulative. EXAMPLES:: 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: GP = g.graphplot(vertex_size=100, edge_labels=True, color_by_label=True, edge_style='dashed') sage: GP.set_edges(edge_style='solid') sage: GP.plot() sage: GP.set_edges(edge_color='black') sage: GP.plot() sage: d = DiGraph({}, loops=True, multiedges=True, sparse=True) sage: d.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: GP = d.graphplot(vertex_size=100, edge_labels=True, color_by_label=True, edge_style='dashed') sage: GP.set_edges(edge_style='solid') sage: GP.plot() sage: GP.set_edges(edge_color='black') sage: GP.plot() TESTS:: sage: G = Graph("Fooba") sage: G.show(edge_colors={'red':[(3,6),(2,5)]}) Verify that default edge labels are pretty close to being between the vertices in some cases where they weren't due to truncating division (trac #10124):: sage: test_graphs = graphs.FruchtGraph(), graphs.BullGraph() sage: tol = 0.001 sage: for G in test_graphs: ... E=G.edges() ... for e0, e1, elab in E: ... G.set_edge_label(e0, e1, '%d %d' % (e0, e1)) ... gp = G.graphplot(save_pos=True,edge_labels=True) ... vx = gp._plot_components['vertices'][0].xdata ... vy = gp._plot_components['vertices'][0].ydata ... for elab in gp._plot_components['edge_labels']: ... textobj = elab[0] ... x, y, s = textobj.x, textobj.y, textobj.string ... v0, v1 = map(int, s.split()) ... vn = vector(((x-(vx[v0]+vx[v1])/2.),y-(vy[v0]+vy[v1])/2.)).norm() ... assert vn < tol """ for arg in edge_options: self._options[arg] = edge_options[arg] if 'edge_colors' in edge_options: self._options['color_by_label'] = False # Handle base edge options: thickness, linestyle eoptions = {} if 'edge_style' in self._options: eoptions['linestyle'] = self._options['edge_style'] if 'thickness' in self._options: eoptions['thickness'] = self._options['thickness'] # Set labels param to add labels on the fly labels = False if self._options['edge_labels']: labels = True self._plot_components['edge_labels'] = [] # Make dict collection of all edges (keep label and edge color) edges_to_draw = {} if self._options['color_by_label'] or isinstance( self._options['edge_colors'], dict): if self._options['color_by_label']: edge_colors = self._graph._color_by_label() else: edge_colors = self._options['edge_colors'] for color in edge_colors: for edge in edge_colors[color]: key = tuple(sorted([edge[0], edge[1]])) if key == (edge[0], edge[1]): head = 1 else: head = 0 if len(edge) < 3: label = self._graph.edge_label(edge[0], edge[1]) if isinstance(label, list): if key in edges_to_draw: edges_to_draw[key].append( (label[-1], color, head)) else: edges_to_draw[key] = [(label[-1], color, head)] for i in range(len(label) - 1): edges_to_draw[key].append( (label[-1], color, head)) else: label = edge[2] if key in edges_to_draw: edges_to_draw[key].append((label, color, head)) else: edges_to_draw[key] = [(label, color, head)] # add unspecified edges in (default color black) for edge in self._graph.edge_iterator(): key = tuple(sorted([edge[0], edge[1]])) label = edge[2] specified = False if key in edges_to_draw: for old_label, old_color, old_head in edges_to_draw[key]: if label == old_label: specified = True break if not specified: if key == (edge[0], edge[1]): head = 1 else: head = 0 edges_to_draw[key] = [(label, 'black', head)] else: for edge in self._graph.edges(sort=True): key = tuple(sorted([edge[0], edge[1]])) if key == (edge[0], edge[1]): head = 1 else: head = 0 if key in edges_to_draw: edges_to_draw[key].append( (edge[2], self._options['edge_color'], head)) else: edges_to_draw[key] = [(edge[2], self._options['edge_color'], head)] if edges_to_draw: self._plot_components['edges'] = [] else: return # Check for multi-edges or loops if self._arcs or self._loops: tmp = edges_to_draw.copy() dist = self._options['dist'] * 2. loop_size = self._options['loop_size'] max_dist = self._options['max_dist'] from sage.functions.all import sqrt for (a, b) in tmp: if a == b: # Loops distance = dist local_labels = edges_to_draw.pop((a, b)) if len(local_labels) * dist > max_dist: distance = float(max_dist) / len(local_labels) curr_loop_size = loop_size for i in range(len(local_labels)): self._plot_components['edges'].append( circle((self._pos[a][0], self._pos[a][1] - curr_loop_size), curr_loop_size, rgbcolor=local_labels[i][1], **eoptions)) if labels: self._plot_components['edge_labels'].append( text(local_labels[i][0], (self._pos[a][0], self._pos[a][1] - 2 * curr_loop_size))) curr_loop_size += distance / 4 elif len(edges_to_draw[(a, b)]) > 1: # Multi-edge local_labels = edges_to_draw.pop((a, b)) # Compute perpendicular bisector p1 = self._pos[a] p2 = self._pos[b] M = ( (p1[0] + p2[0]) / 2., (p1[1] + p2[1]) / 2.) # midpoint if not p1[1] == p2[1]: S = float(p1[0] - p2[0]) / (p2[1] - p1[1] ) # perp slope y = lambda x: S * x - S * M[0] + M[ 1] # perp bisector line # f,g are functions of distance d to determine x values # on line y at d from point M f = lambda d: sqrt(d**2 / (1. + S**2)) + M[0] g = lambda d: -sqrt(d**2 / (1. + S**2)) + M[0] odd_x = f even_x = g if p1[0] == p2[0]: odd_y = lambda d: M[1] even_y = odd_y else: odd_y = lambda x: y(f(x)) even_y = lambda x: y(g(x)) else: odd_x = lambda d: M[0] even_x = odd_x odd_y = lambda d: M[1] + d even_y = lambda d: M[1] - d # We now have the control points for each bezier curve # in terms of distance parameter d. # Also note that the label for each edge should be drawn at d/2. # (This is because we're using the perp bisectors). distance = dist if len(local_labels) * dist > max_dist: distance = float(max_dist) / len(local_labels) for i in range(len(local_labels) / 2): k = (i + 1.0) * distance if self._arcdigraph: odd_start = self._polar_hack_for_multidigraph( p1, [odd_x(k), odd_y(k)], self._vertex_radius)[0] odd_end = self._polar_hack_for_multidigraph( [odd_x(k), odd_y(k)], p2, self._vertex_radius)[1] even_start = self._polar_hack_for_multidigraph( p1, [even_x(k), even_y(k)], self._vertex_radius)[0] even_end = self._polar_hack_for_multidigraph( [even_x(k), even_y(k)], p2, self._vertex_radius)[1] self._plot_components['edges'].append( arrow(path=[[ odd_start, [odd_x(k), odd_y(k)], odd_end ]], head=local_labels[2 * i][2], zorder=1, rgbcolor=local_labels[2 * i][1], **eoptions)) self._plot_components['edges'].append( arrow(path=[[ even_start, [even_x(k), even_y(k)], even_end ]], head=local_labels[2 * i + 1][2], zorder=1, rgbcolor=local_labels[2 * i + 1][1], **eoptions)) else: self._plot_components['edges'].append( bezier_path( [[p1, [odd_x(k), odd_y(k)], p2]], zorder=1, rgbcolor=local_labels[2 * i][1], **eoptions)) self._plot_components['edges'].append( bezier_path( [[p1, [even_x(k), even_y(k)], p2]], zorder=1, rgbcolor=local_labels[2 * i + 1][1], **eoptions)) if labels: j = k / 2.0 self._plot_components['edge_labels'].append( text(local_labels[2 * i][0], [odd_x(j), odd_y(j)])) self._plot_components['edge_labels'].append( text(local_labels[2 * i + 1][0], [even_x(j), even_y(j)])) if len(local_labels) % 2 == 1: edges_to_draw[(a, b)] = [local_labels[-1] ] # draw line for last odd dir = self._graph.is_directed() for (a, b) in edges_to_draw: if self._arcdigraph: C, D = self._polar_hack_for_multidigraph( self._pos[a], self._pos[b], self._vertex_radius) self._plot_components['edges'].append( arrow(C, D, rgbcolor=edges_to_draw[(a, b)][0][1], head=edges_to_draw[(a, b)][0][2], **eoptions)) if labels: self._plot_components['edge_labels'].append( text(str(edges_to_draw[(a, b)][0][0]), [(C[0] + D[0]) / 2., (C[1] + D[1]) / 2.])) elif dir: self._plot_components['edges'].append( arrow(self._pos[a], self._pos[b], rgbcolor=edges_to_draw[(a, b)][0][1], arrowshorten=self._arrowshorten, head=edges_to_draw[(a, b)][0][2], **eoptions)) else: self._plot_components['edges'].append( line([self._pos[a], self._pos[b]], rgbcolor=edges_to_draw[(a, b)][0][1], **eoptions)) if labels and not self._arcdigraph: self._plot_components['edge_labels'].append( text(str(edges_to_draw[(a, b)][0][0]), [(self._pos[a][0] + self._pos[b][0]) / 2., (self._pos[a][1] + self._pos[b][1]) / 2.]))