def plot_arc(radius, p, q, **opts): # TODO: THIS SHOULD USE THE EXISTING PLOT OF ARCS! # plot the arc from p to q differently depending on the type of self p = ZZ(p) q = ZZ(q) t = var('t') if p - q in [1, -1]: def f(t): return (radius * cos(t), radius * sin(t)) (p, q) = sorted([p, q]) angle_p = vertex_to_angle(p) angle_q = vertex_to_angle(q) return parametric_plot(f(t), (t, angle_q, angle_p), **opts) if self.type() == 'A': angle_p = vertex_to_angle(p) angle_q = vertex_to_angle(q) if angle_p < angle_q: angle_p += 2 * pi internal_angle = angle_p - angle_q if internal_angle > pi: (angle_p, angle_q) = (angle_q + 2 * pi, angle_p) internal_angle = angle_p - angle_q angle_center = (angle_p + angle_q) / 2 hypotenuse = radius / cos(internal_angle / 2) radius_arc = hypotenuse * sin(internal_angle / 2) center = (hypotenuse * cos(angle_center), hypotenuse * sin(angle_center)) center_angle_p = angle_p + pi / 2 center_angle_q = angle_q + 3 * pi / 2 def f(t): return (radius_arc * cos(t) + center[0], radius_arc * sin(t) + center[1]) return parametric_plot(f(t), (t, center_angle_p, center_angle_q), **opts) elif self.type() == 'D': if p >= q: q += self.r() px = -2 * pi * p / self.r() + pi / 2 qx = -2 * pi * q / self.r() + pi / 2 arc_radius = (px - qx) / 2 arc_center = qx + arc_radius def f(t): return exp(I * ((cos(t) + I * sin(t)) * arc_radius + arc_center)) * radius return parametric_plot((real_part(f(t)), imag_part(f(t))), (t, 0, pi), **opts)
def show(self, boundary=True, **options): r""" Plot ``self``. EXAMPLES:: sage: HyperbolicPlane().PD().get_geodesic(0, 1).show() Graphics object consisting of 2 graphics primitives """ opts = dict([('axes', False), ('aspect_ratio', 1)]) opts.update(self.graphics_options()) opts.update(options) end_1, end_2 = [CC(k.coordinates()) for k in self.endpoints()] bd_1, bd_2 = [CC(k.coordinates()) for k in self.ideal_endpoints()] # Check to see if it's a line if bool(real(bd_1)*imag(bd_2) - real(bd_2)*imag(bd_1))**2 < EPSILON: from sage.plot.line import line pic = line([(real(bd_1),imag(bd_1)),(real(bd_2),imag(bd_2))], **opts) else: # If we are here, we know it's not a line # So we compute the center and radius of the circle center = (1/(real(bd_1)*imag(bd_2) - real(bd_2)*imag(bd_1)) * ((imag(bd_2)-imag(bd_1)) + (real(bd_1)-real(bd_2))*I)) radius = RR(abs(bd_1 - center)) # abs is Euclidean distance # Now we calculate the angles for the parametric plot theta1 = CC(end_1 - center).arg() theta2 = CC(end_2 - center).arg() if theta2 < theta1: theta1, theta2 = theta2, theta1 from sage.calculus.var import var from sage.plot.plot import parametric_plot x = var('x') mid = (theta1 + theta2)/2.0 if (radius*cos(mid) + real(center))**2 + \ (radius*sin(mid) + imag(center))**2 > 1.0: # Swap theta1 and theta2 tmp = theta1 + 2*pi theta1 = theta2 theta2 = tmp pic = parametric_plot((radius*cos(x) + real(center), radius*sin(x) + imag(center)), (x, theta1, theta2), **opts) else: pic = parametric_plot((radius*cos(x) + real(center), radius*sin(x) + imag(center)), (x, theta1, theta2), **opts) if boundary: bd_pic = self._model.get_background_graphic() pic = bd_pic + pic return pic
def plot_arc(radius, p, q, **opts): # TODO: THIS SHOULD USE THE EXISTING PLOT OF ARCS! # plot the arc from p to q differently depending on the type of self p = ZZ(p) q = ZZ(q) t = var('t') if p - q in [1, -1]: def f(t): return (radius * cos(t), radius * sin(t)) (p, q) = sorted([p, q]) angle_p = vertex_to_angle(p) angle_q = vertex_to_angle(q) return parametric_plot(f(t), (t, angle_q, angle_p), **opts) if self.type() == 'A': angle_p = vertex_to_angle(p) angle_q = vertex_to_angle(q) if angle_p < angle_q: angle_p += 2 * pi internal_angle = angle_p - angle_q if internal_angle > pi: (angle_p, angle_q) = (angle_q + 2 * pi, angle_p) internal_angle = angle_p - angle_q angle_center = (angle_p+angle_q) / 2 hypotenuse = radius / cos(internal_angle / 2) radius_arc = hypotenuse * sin(internal_angle / 2) center = (hypotenuse * cos(angle_center), hypotenuse * sin(angle_center)) center_angle_p = angle_p + pi / 2 center_angle_q = angle_q + 3 * pi / 2 def f(t): return (radius_arc * cos(t) + center[0], radius_arc * sin(t) + center[1]) return parametric_plot(f(t), (t, center_angle_p, center_angle_q), **opts) elif self.type() == 'D': if p >= q: q += self.r() px = -2 * pi * p / self.r() + pi / 2 qx = -2 * pi * q / self.r() + pi / 2 arc_radius = (px - qx) / 2 arc_center = qx + arc_radius def f(t): return exp(I * ((cos(t) + I * sin(t)) * arc_radius + arc_center)) * radius return parametric_plot((real_part(f(t)), imag_part(f(t))), (t, 0, pi), **opts)
def _circ_arc(t0, t1, c, r, num_pts=500): r""" Circular arc INPUTS: - ''t0'' -- starting parameter - ''t1'' -- ending parameter - ''c'' -- center point of the circle - ''r'' -- radius of circle - ''num_pts'' -- (default 100) number of points on polygon OUTPUT: - ''ca'' -- a polygonal approximation of a circular arc centered at c and radius r, starting at t0 and ending at t1 EXAMPLES:: sage: ca=_circ_arc(0.1,0.2,0.0,1.0,100) """ from sage.plot.plot import parametric_plot from sage.functions.trig import cos, sin from sage.all import var t00 = t0 t11 = t1 ## To make sure the line is correct we reduce all arguments to the same branch, ## e.g. [0,2pi] pi = RR.pi() while t00 < 0.0: t00 = t00 + RR(2.0 * pi) while t11 < 0: t11 = t11 + RR(2.0 * pi) while t00 > 2 * pi: t00 = t00 - RR(2.0 * pi) while t11 > 2 * pi: t11 = t11 - RR(2.0 * pi) xc = CC(c).real() yc = CC(c).imag() # L0 = # [[RR(r*cos(t00+i*(t11-t00)/num_pts))+xc,RR(r*sin(t00+i*(t11-t00)/num_pts))+yc] # for i in range(0 ,num_pts)] t = var("t") if t11 > t00: ca = parametric_plot((r * cos(t) + xc, r * sin(t) + yc), (t, t00, t11)) else: ca = parametric_plot((r * cos(t) + xc, r * sin(t) + yc), (t, t11, t00)) return ca
def show(self, boundary=True, **options): r""" Plot ``self``. EXAMPLES:: sage: HyperbolicPlane().UHP().get_geodesic(0, 1).show() Graphics object consisting of 2 graphics primitives """ opts = {'axes': False, 'aspect_ratio': 1} opts.update(self.graphics_options()) opts.update(options) end_1, end_2 = [CC(k.coordinates()) for k in self.endpoints()] bd_1, bd_2 = [CC(k.coordinates()) for k in self.ideal_endpoints()] if (abs(real(end_1) - real(end_2)) < EPSILON) \ or CC(infinity) in [end_1, end_2]: #on same vertical line # If one of the endpoints is infinity, we replace it with a # large finite point if end_1 == CC(infinity): end_1 = (real(end_2), (imag(end_2) + 10)) end_2 = (real(end_2), imag(end_2)) elif end_2 == CC(infinity): end_2 = (real(end_1), (imag(end_1) + 10)) end_1 = (real(end_1), imag(end_1)) from sage.plot.line import line pic = line((end_1, end_2), **opts) if boundary: cent = min(bd_1, bd_2) bd_dict = {'bd_min': cent - 3, 'bd_max': cent + 3} bd_pic = self._model.get_background_graphic(**bd_dict) pic = bd_pic + pic return pic else: center = (bd_1 + bd_2)/2 # Circle center radius = abs(bd_1 - bd_2)/2 theta1 = CC(end_1 - center).arg() theta2 = CC(end_2 - center).arg() if abs(theta1 - theta2) < EPSILON: theta2 += pi [theta1, theta2] = sorted([theta1, theta2]) from sage.calculus.var import var from sage.plot.plot import parametric_plot x = var('x') pic = parametric_plot((radius*cos(x) + real(center), radius*sin(x) + imag(center)), (x, theta1, theta2), **opts) if boundary: # We want to draw a segment of the real line. The # computations below compute the projection of the # geodesic to the real line, and then draw a little # to the left and right of the projection. shadow_1, shadow_2 = [real(k) for k in [end_1, end_2]] midpoint = (shadow_1 + shadow_2)/2 length = abs(shadow_1 - shadow_2) bd_dict = {'bd_min': midpoint - length, 'bd_max': midpoint + length} bd_pic = self._model.get_background_graphic(**bd_dict) pic = bd_pic + pic return pic
def _circ_arc(t0, t1, c, r, num_pts=5000): r""" Circular arc INPUTS: - ''t0'' -- starting parameter - ''t1'' -- ending parameter - ''c'' -- center point of the circle - ''r'' -- radius of circle - ''num_pts'' -- (default 100) number of points on polygon OUTPUT: - ''ca'' -- a polygonal approximation of a circular arc centered at c and radius r, starting at t0 and ending at t1 EXAMPLES:: sage: ca=_circ_arc(0.1,0.2,0.0,1.0,100) """ from sage.plot.plot import line, parametric_plot from sage.functions.trig import (cos, sin) from sage.all import var t00 = t0 t11 = t1 ## To make sure the line is correct we reduce all arguments to the same branch, ## e.g. [0,2pi] pi = RR.pi() while (t00 < 0.0): t00 = t00 + RR(2.0 * pi) while (t11 < 0): t11 = t11 + RR(2.0 * pi) while (t00 > 2 * pi): t00 = t00 - RR(2.0 * pi) while (t11 > 2 * pi): t11 = t11 - RR(2.0 * pi) xc = CC(c).real() yc = CC(c).imag() num_pts = 3 t = var('t') if t11 > t00: ca = parametric_plot((r * cos(t) + xc, r * sin(t) + yc), (t, t00, t11)) else: ca = parametric_plot((r * cos(t) + xc, r * sin(t) + yc), (t, t11, t00)) #L0 = [[RR(r*cos(t00+i*(t11-t00)/num_pts))+xc,RR(r*sin(t00+i*(t11-t00)/num_pts))+yc] for i in range(0 ,num_pts)] #ca=line(L0) return ca
def plot(self, coord_ranges, local_chart=None, ambient_chart=None, **kwds): r""" Plot of a submanifold embedded in `\RR^2` or `\RR^3` INPUT: - ``coord_ranges`` -- list of pairs (u_min, u_max) for each coordinate u on the submanifold - ``local_chart`` -- (default: None) chart on the submanifold in which the above coordinates are defined; if none is provided, the submanifold default chart is assumed. - ``ambient_chart`` -- (default: None) chart on the ambient manifold in terms of which the embedding is defined; if none is provided, the ambient manifold default chart is assumed. - ``**kwds`` -- (default: None) keywords passed to Sage graphic routines OUTPUT: - Graphics3d object (ambient manifold = `\RR^3`) or Graphics object (ambient manifold = `\RR^2`) EXAMPLES: Plot of a torus embedded in `\RR^3`:: sage: M = Manifold(3, 'R^3', r'\RR^3') sage: c_cart.<x,y,z> = M.chart('x y z') # Cartesian coordinates on R^3 sage: T = Submanifold(M, 2, 'T') sage: W = T.open_domain('W') # Domain of the torus covered by the cyclic coordinates (u,v) sage: c_uv.<u,v> = W.chart(r'u:(0,2*pi) v:(0,2*pi)') # cyclic coordinates on T sage: T.def_embedding(DiffMapping(T, M, [(2+cos(u))*cos(v),(2+cos(u))*sin(v),sin(u)])) sage: T.plot([(0,2*pi), (0,2*pi)], aspect_ratio=1) Plot of a helix embedded in `\RR^3`:: sage: H = Submanifold(M, 1, 'H') sage: c_param.<t> = H.chart('t') sage: H.def_embedding(DiffMapping(H, M, [cos(t), sin(t), t])) sage: H.plot([0,20]) Plot of an Archimedean spiral embedded in `\RR^2`:: sage: M = Manifold(2, 'R^2', r'\RR^2') sage: c_cart.<x,y> = M.chart('x y') sage: S = Submanifold(M, 1, 'S') sage: c_param.<t> = S.chart('t') sage: S.def_embedding(DiffMapping(S, M, [t*cos(t), t*sin(t)])) sage: S.plot([0,40]) """ from sage.plot.plot import parametric_plot if local_chart is None: local_chart = self.def_chart if ambient_chart is None: ambient_chart = self.ambient_manifold.def_chart if self.dim > 2: raise ValueError("The dimension must be at most 2 " + "for plotting.") coord_functions = \ self.embedding.coord_expression[(local_chart, ambient_chart)].functions coord_express = [ coord_functions[i].express for i in range(self.ambient_manifold.dim) ] if self.dim == 1: urange = (local_chart.xx[0], coord_ranges[0], coord_ranges[1]) graph = parametric_plot(coord_express, urange, **kwds) else: # self.dim = 2 urange = (local_chart.xx[0], coord_ranges[0][0], coord_ranges[0][1]) vrange = (local_chart.xx[1], coord_ranges[1][0], coord_ranges[1][1]) graph = parametric_plot(coord_express, urange, vrange, **kwds) return graph
def plot(self, coord_ranges, chartname = None, **kwds): r""" Plot of a submanifold embedded in `\RR^2` or `\RR^3` INPUT: - ``coord_ranges`` -- list of pairs (u_min, u_max) for each coordinate u on the submanifold - ``chartname`` -- (default: None) name of the chart in which the above coordinates are defined; if none is provided, the submanifold default chart is assumed. - ``**kwds`` -- (default: None) keywords passed to Sage graphic routines OUTPUT: - Graphics3d object (ambient manifold = `\RR^3`) or Graphics object (ambient manifold = `\RR^2`) EXAMPLES: Plot of a torus embedded in `\RR^3`:: sage: forget() # required for the doctest (to forget previous assumptions) sage: m = Manifold(3, 'R3') sage: c_cart = Chart(m, 'x y z', 'cart') sage: (u,v) = var('u v') sage: t = Submanifold(m, 2, 'u:[0,2*pi) v:[0,2*pi)', "canonical", [(2+cos(u))*cos(v),(2+cos(u))*sin(v),sin(u)], "torus") sage: t.plot([[0,2*pi], [0,2*pi]], aspect_ratio=1) Plot of a helix embedded in `\RR^3`:: sage: h = Submanifold(m, 1, 'u', 'u', [cos(u), sin(u), u], "helix") sage: h.plot([0,20]) Plot of an Archimedean spiral embedded in `\RR^2`:: sage: R2 = Manifold(2, 'R2') sage: c_cart = Chart(R2, 'x y', 'cart') sage: t = var('t') sage: s = Submanifold(R2, 1, 't', 't', [t*cos(t), t*sin(t)], "spiral") sage: s.plot([0,40]) """ from sage.plot.plot import parametric_plot if chartname is None: chartname = self.def_chart.name amb = self.ambient_manifold.name if amb == 'R3' or amb == 'R2': if 'cart' not in self.ambient_manifold.atlas: raise ValueError("For drawing, " + amb + " Cartesian coordinates must be defined.") coord_functions = \ self.embedding.coord_expression[(chartname, 'cart')].functions chart = self.atlas[chartname] if self.dim == 1: urange = (chart.xx[0], coord_ranges[0], coord_ranges[1]) graph = parametric_plot(coord_functions, urange, **kwds) elif self.dim == 2: urange = (chart.xx[0], coord_ranges[0][0], coord_ranges[0][1]) vrange = (chart.xx[1], coord_ranges[1][0], coord_ranges[1][1]) graph = parametric_plot(coord_functions, urange, vrange, **kwds) else: raise ValueError("The dimension must be at most 2 " + "for plotting.") else: raise NotImplementedError("Plotting is implemented only for " + "submanifolds of R^2 or R^3.") return graph
def plot(self, coord_ranges, local_chart=None, ambient_chart=None, **kwds): r""" Plot of a submanifold embedded in `\RR^2` or `\RR^3` INPUT: - ``coord_ranges`` -- list of pairs (u_min, u_max) for each coordinate u on the submanifold - ``local_chart`` -- (default: None) chart on the submanifold in which the above coordinates are defined; if none is provided, the submanifold default chart is assumed. - ``ambient_chart`` -- (default: None) chart on the ambient manifold in terms of which the embedding is defined; if none is provided, the ambient manifold default chart is assumed. - ``**kwds`` -- (default: None) keywords passed to Sage graphic routines OUTPUT: - Graphics3d object (ambient manifold = `\RR^3`) or Graphics object (ambient manifold = `\RR^2`) EXAMPLES: Plot of a torus embedded in `\RR^3`:: sage: M = Manifold(3, 'R^3', r'\RR^3') sage: c_cart.<x,y,z> = M.chart('x y z') # Cartesian coordinates on R^3 sage: T = Submanifold(M, 2, 'T') sage: W = T.open_domain('W') # Domain of the torus covered by the cyclic coordinates (u,v) sage: c_uv.<u,v> = W.chart(r'u:(0,2*pi) v:(0,2*pi)') # cyclic coordinates on T sage: T.def_embedding(DiffMapping(T, M, [(2+cos(u))*cos(v),(2+cos(u))*sin(v),sin(u)])) sage: T.plot([(0,2*pi), (0,2*pi)], aspect_ratio=1) Plot of a helix embedded in `\RR^3`:: sage: H = Submanifold(M, 1, 'H') sage: c_param.<t> = H.chart('t') sage: H.def_embedding(DiffMapping(H, M, [cos(t), sin(t), t])) sage: H.plot([0,20]) Plot of an Archimedean spiral embedded in `\RR^2`:: sage: M = Manifold(2, 'R^2', r'\RR^2') sage: c_cart.<x,y> = M.chart('x y') sage: S = Submanifold(M, 1, 'S') sage: c_param.<t> = S.chart('t') sage: S.def_embedding(DiffMapping(S, M, [t*cos(t), t*sin(t)])) sage: S.plot([0,40]) """ from sage.plot.plot import parametric_plot if local_chart is None: local_chart = self.def_chart if ambient_chart is None: ambient_chart = self.ambient_manifold.def_chart if self.dim > 2: raise ValueError("The dimension must be at most 2 " + "for plotting.") coord_functions = \ self.embedding.coord_expression[(local_chart, ambient_chart)].functions coord_express = [coord_functions[i].express for i in range(self.ambient_manifold.dim)] if self.dim == 1: urange = (local_chart.xx[0], coord_ranges[0], coord_ranges[1]) graph = parametric_plot(coord_express, urange, **kwds) else: # self.dim = 2 urange = (local_chart.xx[0], coord_ranges[0][0], coord_ranges[0][1]) vrange = (local_chart.xx[1], coord_ranges[1][0], coord_ranges[1][1]) graph = parametric_plot(coord_express, urange, vrange, **kwds) return graph
def plot(self, coord_ranges, chartname=None, **kwds): r""" Plot of a submanifold embedded in `\RR^2` or `\RR^3` INPUT: - ``coord_ranges`` -- list of pairs (u_min, u_max) for each coordinate u on the submanifold - ``chartname`` -- (default: None) name of the chart in which the above coordinates are defined; if none is provided, the submanifold default chart is assumed. - ``**kwds`` -- (default: None) keywords passed to Sage graphic routines OUTPUT: - Graphics3d object (ambient manifold = `\RR^3`) or Graphics object (ambient manifold = `\RR^2`) EXAMPLES: Plot of a torus embedded in `\RR^3`:: sage: forget() # required for the doctest (to forget previous assumptions) sage: m = Manifold(3, 'R3') sage: c_cart = Chart(m, 'x y z', 'cart') sage: (u,v) = var('u v') sage: t = Submanifold(m, 2, 'u:[0,2*pi) v:[0,2*pi)', "canonical", [(2+cos(u))*cos(v),(2+cos(u))*sin(v),sin(u)], "torus") sage: t.plot([[0,2*pi], [0,2*pi]], aspect_ratio=1) Plot of a helix embedded in `\RR^3`:: sage: h = Submanifold(m, 1, 'u', 'u', [cos(u), sin(u), u], "helix") sage: h.plot([0,20]) Plot of an Archimedean spiral embedded in `\RR^2`:: sage: R2 = Manifold(2, 'R2') sage: c_cart = Chart(R2, 'x y', 'cart') sage: t = var('t') sage: s = Submanifold(R2, 1, 't', 't', [t*cos(t), t*sin(t)], "spiral") sage: s.plot([0,40]) """ from sage.plot.plot import parametric_plot if chartname is None: chartname = self.def_chart.name amb = self.ambient_manifold.name if amb == 'R3' or amb == 'R2': if 'cart' not in self.ambient_manifold.atlas: raise ValueError("For drawing, " + amb + " Cartesian coordinates must be defined.") coord_functions = \ self.embedding.coord_expression[(chartname, 'cart')].functions chart = self.atlas[chartname] if self.dim == 1: urange = (chart.xx[0], coord_ranges[0], coord_ranges[1]) graph = parametric_plot(coord_functions, urange, **kwds) elif self.dim == 2: urange = (chart.xx[0], coord_ranges[0][0], coord_ranges[0][1]) vrange = (chart.xx[1], coord_ranges[1][0], coord_ranges[1][1]) graph = parametric_plot(coord_functions, urange, vrange, **kwds) else: raise ValueError("The dimension must be at most 2 " + "for plotting.") else: raise NotImplementedError("Plotting is implemented only for " + "submanifolds of R^2 or R^3.") return graph
def plot_hyperplane(hyperplane, **kwds): r""" Return the plot of a single hyperplane. INPUT: - ``**kwds`` -- plot options: see below OUTPUT: A graphics object of the plot. .. RUBRIC:: Plot Options Beside the usual plot options (enter ``plot?``), the plot command for hyperplanes includes the following: - ``hyperplane_label`` -- Boolean value or string (default: ``True``). If ``True``, the hyperplane is labeled with its equation, if a string, it is labeled by that string, otherwise it is not labeled. - ``label_color`` -- (Default: ``'black'``) Color for hyperplane_label. - ``label_fontsize`` -- Size for ``hyperplane_label`` font (default: 14) (does not work in 3d, yet). - ``label_offset`` -- (Default: 0-dim: 0.1, 1-dim: (0,1), 2-dim: (0,0,0.2)) Amount by which label is offset from ``hyperplane.point()``. - ``point_size`` -- (Default: 50) Size of points in a zero-dimensional arrangement or of an arrangement over a finite field. - ``ranges`` -- Range for the parameters for the parametric plot of the hyperplane. If a single positive number ``r`` is given for the value of ``ranges``, then the ranges for all parameters are set to `[-r, r]`. Otherwise, for a line in the plane, ``ranges`` has the form ``[a, b]`` (default: [-3,3]), and for a plane in 3-space, the ``ranges`` has the form ``[[a, b], [c, d]]`` (default: [[-3,3],[-3,3]]). (The ranges are centered around ``hyperplane.point()``.) EXAMPLES:: sage: H1.<x> = HyperplaneArrangements(QQ) sage: a = 3*x + 4 sage: a.plot() # indirect doctest Graphics object consisting of 3 graphics primitives sage: a.plot(point_size=100,hyperplane_label='hello') Graphics object consisting of 3 graphics primitives sage: H2.<x,y> = HyperplaneArrangements(QQ) sage: b = 3*x + 4*y + 5 sage: b.plot() Graphics object consisting of 2 graphics primitives sage: b.plot(ranges=(1,5),label_offset=(2,-1)) Graphics object consisting of 2 graphics primitives sage: opts = {'hyperplane_label':True, 'label_color':'green', ....: 'label_fontsize':24, 'label_offset':(0,1.5)} sage: b.plot(**opts) Graphics object consisting of 2 graphics primitives sage: H3.<x,y,z> = HyperplaneArrangements(QQ) sage: c = 2*x + 3*y + 4*z + 5 sage: c.plot() Graphics3d Object sage: c.plot(label_offset=(1,0,1), color='green', label_color='red', frame=False) Graphics3d Object sage: d = -3*x + 2*y + 2*z + 3 sage: d.plot(opacity=0.8) Graphics3d Object sage: e = 4*x + 2*z + 3 sage: e.plot(ranges=[[-1,1],[0,8]], label_offset=(2,2,1), aspect_ratio=1) Graphics3d Object """ if hyperplane.base_ring().characteristic(): raise NotImplementedError('base field must have characteristic zero') elif hyperplane.dimension() not in [ 0, 1, 2 ]: # dimension of hyperplane, not ambient space raise ValueError('can only plot hyperplanes in dimensions 1, 2, 3') # handle extra keywords if 'hyperplane_label' in kwds: hyp_label = kwds.pop('hyperplane_label') if not hyp_label: has_hyp_label = False else: has_hyp_label = True else: # default hyp_label = True has_hyp_label = True if has_hyp_label: if hyp_label: # then label hyperplane with its equation if hyperplane.dimension() == 2: # jmol does not like latex label = hyperplane._repr_linear(include_zero=False) else: label = hyperplane._latex_() else: label = hyp_label # a string if 'label_color' in kwds: label_color = kwds.pop('label_color') else: label_color = 'black' if 'label_fontsize' in kwds: label_fontsize = kwds.pop('label_fontsize') else: label_fontsize = 14 if 'label_offset' in kwds: has_offset = True label_offset = kwds.pop('label_offset') else: has_offset = False # give default values below if 'point_size' in kwds: pt_size = kwds.pop('point_size') else: pt_size = 50 if 'ranges' in kwds: ranges_set = True ranges = kwds.pop('ranges') else: ranges_set = False # give default values below # the extra keywords have now been handled # now create the plot if hyperplane.dimension() == 0: # a point on a line x, = hyperplane.A() d = hyperplane.b() p = point((d / x, 0), size=pt_size, **kwds) if has_hyp_label: if not has_offset: label_offset = 0.1 p += text(label, (d / x, label_offset), color=label_color, fontsize=label_fontsize) p += text('', (d / x, label_offset + 0.4)) # add space at top if 'ymax' not in kwds: kwds['ymax'] = 0.5 elif hyperplane.dimension() == 1: # a line in the plane pnt = hyperplane.point() w = hyperplane.linear_part().matrix() t = SR.var('t') if ranges_set: if isinstance(ranges, (list, tuple)): t0, t1 = ranges else: # ranges should be a single positive number t0, t1 = -ranges, ranges else: # default t0, t1 = -3, 3 p = parametric_plot(pnt + t * w[0], (t, t0, t1), **kwds) if has_hyp_label: if has_offset: b0, b1 = label_offset else: b0, b1 = 0, 0.2 label = text(label, (pnt[0] + b0, pnt[1] + b1), color=label_color, fontsize=label_fontsize) p += label elif hyperplane.dimension() == 2: # a plane in 3-space pnt = hyperplane.point() w = hyperplane.linear_part().matrix() s, t = SR.var('s t') if ranges_set: if isinstance(ranges, (list, tuple)): s0, s1 = ranges[0] t0, t1 = ranges[1] else: # ranges should be a single positive integers s0, s1 = -ranges, ranges t0, t1 = -ranges, ranges else: # default s0, s1 = -3, 3 t0, t1 = -3, 3 p = parametric_plot3d(pnt + s * w[0] + t * w[1], (s, s0, s1), (t, t0, t1), **kwds) if has_hyp_label: if has_offset: b0, b1, b2 = label_offset else: b0, b1, b2 = 0, 0, 0 label = text3d(label, (pnt[0] + b0, pnt[1] + b1, pnt[2] + b2), color=label_color, fontsize=label_fontsize) p += label return p
def plot_hyperplane(hyperplane, **kwds): r""" Return the plot of a single hyperplane. INPUT: - ``**kwds`` -- plot options: see below OUTPUT: A graphics object of the plot. .. RUBRIC:: Plot Options Beside the usual plot options (enter ``plot?``), the plot command for hyperplanes includes the following: - ``hyperplane_label`` -- Boolean value or string (default: ``True``). If ``True``, the hyperplane is labeled with its equation, if a string, it is labeled by that string, otherwise it is not labeled. - ``label_color`` -- (Default: ``'black'``) Color for hyperplane_label. - ``label_fontsize`` -- Size for ``hyperplane_label`` font (default: 14) (does not work in 3d, yet). - ``label_offset`` -- (Default: 0-dim: 0.1, 1-dim: (0,1), 2-dim: (0,0,0.2)) Amount by which label is offset from ``hyperplane.point()``. - ``point_size`` -- (Default: 50) Size of points in a zero-dimensional arrangement or of an arrangement over a finite field. - ``ranges`` -- Range for the parameters for the parametric plot of the hyperplane. If a single positive number ``r`` is given for the value of ``ranges``, then the ranges for all parameters are set to `[-r, r]`. Otherwise, for a line in the plane, ``ranges`` has the form ``[a, b]`` (default: [-3,3]), and for a plane in 3-space, the ``ranges`` has the form ``[[a, b], [c, d]]`` (default: [[-3,3],[-3,3]]). (The ranges are centered around ``hyperplane.point()``.) EXAMPLES:: sage: H1.<x> = HyperplaneArrangements(QQ) sage: a = 3*x + 4 sage: a.plot() # indirect doctest Graphics object consisting of 3 graphics primitives sage: a.plot(point_size=100,hyperplane_label='hello') Graphics object consisting of 3 graphics primitives sage: H2.<x,y> = HyperplaneArrangements(QQ) sage: b = 3*x + 4*y + 5 sage: b.plot() Graphics object consisting of 2 graphics primitives sage: b.plot(ranges=(1,5),label_offset=(2,-1)) Graphics object consisting of 2 graphics primitives sage: opts = {'hyperplane_label':True, 'label_color':'green', ....: 'label_fontsize':24, 'label_offset':(0,1.5)} sage: b.plot(**opts) Graphics object consisting of 2 graphics primitives sage: H3.<x,y,z> = HyperplaneArrangements(QQ) sage: c = 2*x + 3*y + 4*z + 5 sage: c.plot() Graphics3d Object sage: c.plot(label_offset=(1,0,1), color='green', label_color='red', frame=False) Graphics3d Object sage: d = -3*x + 2*y + 2*z + 3 sage: d.plot(opacity=0.8) Graphics3d Object sage: e = 4*x + 2*z + 3 sage: e.plot(ranges=[[-1,1],[0,8]], label_offset=(2,2,1), aspect_ratio=1) Graphics3d Object """ if hyperplane.base_ring().characteristic() != 0: raise NotImplementedError('base field must have characteristic zero') elif hyperplane.dimension() not in [0, 1, 2]: # dimension of hyperplane, not ambient space raise ValueError('can only plot hyperplanes in dimensions 1, 2, 3') # handle extra keywords if 'hyperplane_label' in kwds: hyp_label = kwds.pop('hyperplane_label') if not hyp_label: has_hyp_label = False else: has_hyp_label = True else: # default hyp_label = True has_hyp_label = True if has_hyp_label: if hyp_label: # then label hyperplane with its equation if hyperplane.dimension() == 2: # jmol does not like latex label = hyperplane._repr_linear(include_zero=False) else: label = hyperplane._latex_() else: label = hyp_label # a string if 'label_color' in kwds: label_color = kwds.pop('label_color') else: label_color = 'black' if 'label_fontsize' in kwds: label_fontsize = kwds.pop('label_fontsize') else: label_fontsize = 14 if 'label_offset' in kwds: has_offset = True label_offset = kwds.pop('label_offset') else: has_offset = False # give default values below if 'point_size' in kwds: pt_size = kwds.pop('point_size') else: pt_size = 50 if 'ranges' in kwds: ranges_set = True ranges = kwds.pop('ranges') else: ranges_set = False # give default values below # the extra keywords have now been handled # now create the plot if hyperplane.dimension() == 0: # a point on a line x, = hyperplane.A() d = hyperplane.b() p = point((d/x,0), size = pt_size, **kwds) if has_hyp_label: if not has_offset: label_offset = 0.1 p += text(label, (d/x,label_offset), color=label_color,fontsize=label_fontsize) p += text('',(d/x,label_offset+0.4)) # add space at top if 'ymax' not in kwds: kwds['ymax'] = 0.5 elif hyperplane.dimension() == 1: # a line in the plane pnt = hyperplane.point() w = hyperplane.linear_part().matrix() x, y = hyperplane.A() d = hyperplane.b() t = SR.var('t') if ranges_set: if type(ranges) in [list,tuple]: t0, t1 = ranges else: # ranges should be a single positive number t0, t1 = -ranges, ranges else: # default t0, t1 = -3, 3 p = parametric_plot(pnt+t*w[0], (t,t0,t1), **kwds) if has_hyp_label: if has_offset: b0, b1 = label_offset else: b0, b1 = 0, 0.2 label = text(label,(pnt[0]+b0,pnt[1]+b1), color=label_color,fontsize=label_fontsize) p += label elif hyperplane.dimension() == 2: # a plane in 3-space pnt = hyperplane.point() w = hyperplane.linear_part().matrix() a, b, c = hyperplane.A() d = hyperplane.b() s,t = SR.var('s t') if ranges_set: if type(ranges) in [list,tuple]: s0, s1 = ranges[0] t0, t1 = ranges[1] else: # ranges should be a single positive integers s0, s1 = -ranges, ranges t0, t1 = -ranges, ranges else: # default s0, s1 = -3, 3 t0, t1 = -3, 3 p = parametric_plot3d(pnt+s*w[0]+t*w[1],(s,s0,s1),(t,t0,t1),**kwds) if has_hyp_label: if has_offset: b0, b1, b2 = label_offset else: b0, b1, b2 = 0, 0, 0 label = text3d(label,(pnt[0]+b0,pnt[1]+b1,pnt[2]+b2), color=label_color,fontsize=label_fontsize) p += label return p