passagemath-polyhedra 10.6.31rc3__cp314-cp314-musllinux_1_2_x86_64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of passagemath-polyhedra might be problematic. Click here for more details.
- passagemath_polyhedra-10.6.31rc3.dist-info/METADATA +367 -0
- passagemath_polyhedra-10.6.31rc3.dist-info/METADATA.bak +369 -0
- passagemath_polyhedra-10.6.31rc3.dist-info/RECORD +208 -0
- passagemath_polyhedra-10.6.31rc3.dist-info/WHEEL +5 -0
- passagemath_polyhedra-10.6.31rc3.dist-info/top_level.txt +2 -0
- passagemath_polyhedra.libs/libgcc_s-0cd532bd.so.1 +0 -0
- passagemath_polyhedra.libs/libgmp-0e7fc84e.so.10.5.0 +0 -0
- passagemath_polyhedra.libs/libgomp-8949ffbe.so.1.0.0 +0 -0
- passagemath_polyhedra.libs/libstdc++-5d72f927.so.6.0.33 +0 -0
- sage/all__sagemath_polyhedra.py +50 -0
- sage/game_theory/all.py +8 -0
- sage/game_theory/catalog.py +6 -0
- sage/game_theory/catalog_normal_form_games.py +923 -0
- sage/game_theory/cooperative_game.py +844 -0
- sage/game_theory/matching_game.py +1181 -0
- sage/game_theory/normal_form_game.py +2697 -0
- sage/game_theory/parser.py +275 -0
- sage/geometry/all__sagemath_polyhedra.py +22 -0
- sage/geometry/cone.py +6940 -0
- sage/geometry/cone_catalog.py +847 -0
- sage/geometry/cone_critical_angles.py +1027 -0
- sage/geometry/convex_set.py +1119 -0
- sage/geometry/fan.py +3743 -0
- sage/geometry/fan_isomorphism.py +389 -0
- sage/geometry/fan_morphism.py +1884 -0
- sage/geometry/hasse_diagram.py +202 -0
- sage/geometry/hyperplane_arrangement/affine_subspace.py +390 -0
- sage/geometry/hyperplane_arrangement/all.py +1 -0
- sage/geometry/hyperplane_arrangement/arrangement.py +3895 -0
- sage/geometry/hyperplane_arrangement/check_freeness.py +145 -0
- sage/geometry/hyperplane_arrangement/hyperplane.py +773 -0
- sage/geometry/hyperplane_arrangement/library.py +825 -0
- sage/geometry/hyperplane_arrangement/ordered_arrangement.py +642 -0
- sage/geometry/hyperplane_arrangement/plot.py +520 -0
- sage/geometry/integral_points.py +35 -0
- sage/geometry/integral_points_generic_dense.cpython-314-x86_64-linux-musl.so +0 -0
- sage/geometry/integral_points_generic_dense.pyx +7 -0
- sage/geometry/lattice_polytope.py +5894 -0
- sage/geometry/linear_expression.py +773 -0
- sage/geometry/newton_polygon.py +767 -0
- sage/geometry/point_collection.cpython-314-x86_64-linux-musl.so +0 -0
- sage/geometry/point_collection.pyx +1008 -0
- sage/geometry/polyhedral_complex.py +2616 -0
- sage/geometry/polyhedron/all.py +8 -0
- sage/geometry/polyhedron/backend_cdd.py +460 -0
- sage/geometry/polyhedron/backend_cdd_rdf.py +231 -0
- sage/geometry/polyhedron/backend_field.py +347 -0
- sage/geometry/polyhedron/backend_normaliz.py +2503 -0
- sage/geometry/polyhedron/backend_number_field.py +168 -0
- sage/geometry/polyhedron/backend_polymake.py +765 -0
- sage/geometry/polyhedron/backend_ppl.py +582 -0
- sage/geometry/polyhedron/base.py +1206 -0
- sage/geometry/polyhedron/base0.py +1444 -0
- sage/geometry/polyhedron/base1.py +886 -0
- sage/geometry/polyhedron/base2.py +812 -0
- sage/geometry/polyhedron/base3.py +1845 -0
- sage/geometry/polyhedron/base4.py +1262 -0
- sage/geometry/polyhedron/base5.py +2700 -0
- sage/geometry/polyhedron/base6.py +1741 -0
- sage/geometry/polyhedron/base7.py +997 -0
- sage/geometry/polyhedron/base_QQ.py +1258 -0
- sage/geometry/polyhedron/base_RDF.py +98 -0
- sage/geometry/polyhedron/base_ZZ.py +934 -0
- sage/geometry/polyhedron/base_mutable.py +215 -0
- sage/geometry/polyhedron/base_number_field.py +122 -0
- sage/geometry/polyhedron/cdd_file_format.py +155 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/all.py +1 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/base.cpython-314-x86_64-linux-musl.so +0 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/base.pxd +76 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx +3859 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.cpython-314-x86_64-linux-musl.so +0 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.pxd +39 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.pyx +1038 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/conversions.cpython-314-x86_64-linux-musl.so +0 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/conversions.pxd +9 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/conversions.pyx +501 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/face_data_structure.pxd +207 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.cpython-314-x86_64-linux-musl.so +0 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pxd +102 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pyx +2274 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/face_list_data_structure.cpython-314-x86_64-linux-musl.so +0 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/face_list_data_structure.pxd +370 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/face_list_data_structure.pyx +84 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/list_of_faces.cpython-314-x86_64-linux-musl.so +0 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/list_of_faces.pxd +31 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/list_of_faces.pyx +587 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/polyhedron_face_lattice.cpython-314-x86_64-linux-musl.so +0 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/polyhedron_face_lattice.pxd +52 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/polyhedron_face_lattice.pyx +560 -0
- sage/geometry/polyhedron/constructor.py +773 -0
- sage/geometry/polyhedron/double_description.py +753 -0
- sage/geometry/polyhedron/double_description_inhomogeneous.py +564 -0
- sage/geometry/polyhedron/face.py +1060 -0
- sage/geometry/polyhedron/generating_function.py +1810 -0
- sage/geometry/polyhedron/lattice_euclidean_group_element.py +178 -0
- sage/geometry/polyhedron/library.py +3502 -0
- sage/geometry/polyhedron/misc.py +121 -0
- sage/geometry/polyhedron/modules/all.py +1 -0
- sage/geometry/polyhedron/modules/formal_polyhedra_module.py +155 -0
- sage/geometry/polyhedron/palp_database.py +447 -0
- sage/geometry/polyhedron/parent.py +1279 -0
- sage/geometry/polyhedron/plot.py +1986 -0
- sage/geometry/polyhedron/ppl_lattice_polygon.py +556 -0
- sage/geometry/polyhedron/ppl_lattice_polytope.py +1257 -0
- sage/geometry/polyhedron/representation.py +1723 -0
- sage/geometry/pseudolines.py +515 -0
- sage/geometry/relative_interior.py +445 -0
- sage/geometry/toric_plotter.py +1103 -0
- sage/geometry/triangulation/all.py +2 -0
- sage/geometry/triangulation/base.cpython-314-x86_64-linux-musl.so +0 -0
- sage/geometry/triangulation/base.pyx +963 -0
- sage/geometry/triangulation/data.h +147 -0
- sage/geometry/triangulation/data.pxd +4 -0
- sage/geometry/triangulation/element.py +914 -0
- sage/geometry/triangulation/functions.h +10 -0
- sage/geometry/triangulation/functions.pxd +4 -0
- sage/geometry/triangulation/point_configuration.py +2256 -0
- sage/geometry/triangulation/triangulations.h +49 -0
- sage/geometry/triangulation/triangulations.pxd +7 -0
- sage/geometry/voronoi_diagram.py +319 -0
- sage/interfaces/all__sagemath_polyhedra.py +1 -0
- sage/interfaces/polymake.py +2028 -0
- sage/numerical/all.py +13 -0
- sage/numerical/all__sagemath_polyhedra.py +11 -0
- sage/numerical/backends/all.py +1 -0
- sage/numerical/backends/all__sagemath_polyhedra.py +1 -0
- sage/numerical/backends/cvxopt_backend.cpython-314-x86_64-linux-musl.so +0 -0
- sage/numerical/backends/cvxopt_backend.pyx +1006 -0
- sage/numerical/backends/cvxopt_backend_test.py +19 -0
- sage/numerical/backends/cvxopt_sdp_backend.cpython-314-x86_64-linux-musl.so +0 -0
- sage/numerical/backends/cvxopt_sdp_backend.pyx +382 -0
- sage/numerical/backends/cvxpy_backend.cpython-314-x86_64-linux-musl.so +0 -0
- sage/numerical/backends/cvxpy_backend.pxd +41 -0
- sage/numerical/backends/cvxpy_backend.pyx +934 -0
- sage/numerical/backends/cvxpy_backend_test.py +13 -0
- sage/numerical/backends/generic_backend_test.py +24 -0
- sage/numerical/backends/interactivelp_backend.cpython-314-x86_64-linux-musl.so +0 -0
- sage/numerical/backends/interactivelp_backend.pxd +36 -0
- sage/numerical/backends/interactivelp_backend.pyx +1231 -0
- sage/numerical/backends/interactivelp_backend_test.py +12 -0
- sage/numerical/backends/logging_backend.py +391 -0
- sage/numerical/backends/matrix_sdp_backend.cpython-314-x86_64-linux-musl.so +0 -0
- sage/numerical/backends/matrix_sdp_backend.pxd +15 -0
- sage/numerical/backends/matrix_sdp_backend.pyx +478 -0
- sage/numerical/backends/ppl_backend.cpython-314-x86_64-linux-musl.so +0 -0
- sage/numerical/backends/ppl_backend.pyx +1126 -0
- sage/numerical/backends/ppl_backend_test.py +13 -0
- sage/numerical/backends/scip_backend.cpython-314-x86_64-linux-musl.so +0 -0
- sage/numerical/backends/scip_backend.pxd +22 -0
- sage/numerical/backends/scip_backend.pyx +1289 -0
- sage/numerical/backends/scip_backend_test.py +13 -0
- sage/numerical/interactive_simplex_method.py +5338 -0
- sage/numerical/knapsack.py +665 -0
- sage/numerical/linear_functions.cpython-314-x86_64-linux-musl.so +0 -0
- sage/numerical/linear_functions.pxd +31 -0
- sage/numerical/linear_functions.pyx +1648 -0
- sage/numerical/linear_tensor.py +470 -0
- sage/numerical/linear_tensor_constraints.py +448 -0
- sage/numerical/linear_tensor_element.cpython-314-x86_64-linux-musl.so +0 -0
- sage/numerical/linear_tensor_element.pxd +6 -0
- sage/numerical/linear_tensor_element.pyx +459 -0
- sage/numerical/mip.cpython-314-x86_64-linux-musl.so +0 -0
- sage/numerical/mip.pxd +40 -0
- sage/numerical/mip.pyx +3667 -0
- sage/numerical/sdp.cpython-314-x86_64-linux-musl.so +0 -0
- sage/numerical/sdp.pxd +39 -0
- sage/numerical/sdp.pyx +1433 -0
- sage/rings/all__sagemath_polyhedra.py +3 -0
- sage/rings/polynomial/all__sagemath_polyhedra.py +10 -0
- sage/rings/polynomial/omega.py +982 -0
- sage/schemes/all__sagemath_polyhedra.py +2 -0
- sage/schemes/toric/all.py +10 -0
- sage/schemes/toric/chow_group.py +1248 -0
- sage/schemes/toric/divisor.py +2082 -0
- sage/schemes/toric/divisor_class.cpython-314-x86_64-linux-musl.so +0 -0
- sage/schemes/toric/divisor_class.pyx +322 -0
- sage/schemes/toric/fano_variety.py +1606 -0
- sage/schemes/toric/homset.py +650 -0
- sage/schemes/toric/ideal.py +451 -0
- sage/schemes/toric/library.py +1322 -0
- sage/schemes/toric/morphism.py +1958 -0
- sage/schemes/toric/points.py +1032 -0
- sage/schemes/toric/sheaf/all.py +1 -0
- sage/schemes/toric/sheaf/constructor.py +302 -0
- sage/schemes/toric/sheaf/klyachko.py +921 -0
- sage/schemes/toric/toric_subscheme.py +905 -0
- sage/schemes/toric/variety.py +3460 -0
- sage/schemes/toric/weierstrass.py +1078 -0
- sage/schemes/toric/weierstrass_covering.py +457 -0
- sage/schemes/toric/weierstrass_higher.py +288 -0
- sage_wheels/share/reflexive_polytopes/Full2d/zzdb.info +10 -0
- sage_wheels/share/reflexive_polytopes/Full2d/zzdb.v03 +0 -0
- sage_wheels/share/reflexive_polytopes/Full2d/zzdb.v04 +0 -0
- sage_wheels/share/reflexive_polytopes/Full2d/zzdb.v05 +1 -0
- sage_wheels/share/reflexive_polytopes/Full2d/zzdb.v06 +1 -0
- sage_wheels/share/reflexive_polytopes/Full3d/zzdb.info +22 -0
- sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v04 +0 -0
- sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v05 +0 -0
- sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v06 +0 -0
- sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v07 +0 -0
- sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v08 +0 -0
- sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v09 +0 -0
- sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v10 +0 -0
- sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v11 +1 -0
- sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v12 +1 -0
- sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v13 +1 -0
- sage_wheels/share/reflexive_polytopes/reflexive_polytopes_2d +80 -0
- sage_wheels/share/reflexive_polytopes/reflexive_polytopes_3d +37977 -0
|
@@ -0,0 +1,1103 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-polyhedra
|
|
2
|
+
r"""
|
|
3
|
+
Toric plotter
|
|
4
|
+
|
|
5
|
+
This module provides a helper class :class:`ToricPlotter` for producing plots
|
|
6
|
+
of objects related to toric geometry. Default plotting objects can be adjusted
|
|
7
|
+
using :func:`options` and reset using :func:`reset_options`.
|
|
8
|
+
|
|
9
|
+
AUTHORS:
|
|
10
|
+
|
|
11
|
+
- Andrey Novoseltsev (2010-10-03): initial version, using some code bits by
|
|
12
|
+
Volker Braun.
|
|
13
|
+
|
|
14
|
+
EXAMPLES:
|
|
15
|
+
|
|
16
|
+
In most cases, this module is used indirectly, e.g. ::
|
|
17
|
+
|
|
18
|
+
sage: fan = toric_varieties.dP6().fan() # needs palp sage.graphs
|
|
19
|
+
sage: fan.plot() # needs palp sage.graphs sage.plot sage.symbolic
|
|
20
|
+
Graphics object consisting of 31 graphics primitives
|
|
21
|
+
|
|
22
|
+
You may change default plotting options as follows::
|
|
23
|
+
|
|
24
|
+
sage: toric_plotter.options("show_rays")
|
|
25
|
+
True
|
|
26
|
+
sage: toric_plotter.options(show_rays=False)
|
|
27
|
+
sage: toric_plotter.options("show_rays")
|
|
28
|
+
False
|
|
29
|
+
sage: fan.plot() # needs palp sage.graphs sage.plot sage.symbolic
|
|
30
|
+
Graphics object consisting of 19 graphics primitives
|
|
31
|
+
sage: toric_plotter.reset_options()
|
|
32
|
+
sage: toric_plotter.options("show_rays")
|
|
33
|
+
True
|
|
34
|
+
sage: fan.plot() # needs palp sage.graphs sage.plot sage.symbolic
|
|
35
|
+
Graphics object consisting of 31 graphics primitives
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
# ****************************************************************************
|
|
40
|
+
# Copyright (C) 2010 Volker Braun <vbraun.name@gmail.com>
|
|
41
|
+
# Copyright (C) 2010 Andrey Novoseltsev <novoselt@gmail.com>
|
|
42
|
+
# Copyright (C) 2010 William Stein <wstein@gmail.com>
|
|
43
|
+
#
|
|
44
|
+
#
|
|
45
|
+
# Distributed under the terms of the GNU General Public License (GPL)
|
|
46
|
+
#
|
|
47
|
+
# https://www.gnu.org/licenses/
|
|
48
|
+
# ****************************************************************************
|
|
49
|
+
|
|
50
|
+
from copy import copy
|
|
51
|
+
from math import pi
|
|
52
|
+
|
|
53
|
+
from sage.arith.misc import integer_ceil as ceil, integer_floor as floor
|
|
54
|
+
from sage.geometry.polyhedron.constructor import Polyhedron
|
|
55
|
+
from sage.misc.lazy_import import lazy_import
|
|
56
|
+
from sage.modules.free_module_element import vector
|
|
57
|
+
lazy_import("sage.plot.all", ["Color", "Graphics",
|
|
58
|
+
"arrow", "disk", "line", "point",
|
|
59
|
+
"polygon", "rainbow", "text"])
|
|
60
|
+
lazy_import("sage.plot.plot3d.all", "text3d")
|
|
61
|
+
from sage.rings.real_double import RDF
|
|
62
|
+
from sage.structure.sage_object import SageObject
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
# These options are used to initialize/reset plotting options.
|
|
66
|
+
# Most of them are set to "None" and "real default values" are computed
|
|
67
|
+
# automatically based on the plotted object and parameters actually provided by
|
|
68
|
+
# the user.
|
|
69
|
+
_default_options = dict()
|
|
70
|
+
_default_options["mode"] = "round" # Can be also "box" and "generators"
|
|
71
|
+
_default_options["show_lattice"] = None # Default is "True for small plots"
|
|
72
|
+
_default_options["show_rays"] = True
|
|
73
|
+
_default_options["show_generators"] = True
|
|
74
|
+
_default_options["show_walls"] = True
|
|
75
|
+
|
|
76
|
+
_default_options["generator_color"] = "blue"
|
|
77
|
+
_default_options["label_color"] = "black"
|
|
78
|
+
_default_options["point_color"] = "black"
|
|
79
|
+
_default_options["ray_color"] = "purple"
|
|
80
|
+
_default_options["wall_color"] = "rainbow"
|
|
81
|
+
_default_options["wall_alpha"] = 0.4
|
|
82
|
+
|
|
83
|
+
_default_options["point_size"] = None
|
|
84
|
+
_default_options["ray_thickness"] = 3
|
|
85
|
+
_default_options["generator_thickness"] = None
|
|
86
|
+
_default_options["font_size"] = 14
|
|
87
|
+
|
|
88
|
+
_default_options["ray_label"] = "u"
|
|
89
|
+
_default_options["wall_label"] = r"\sigma"
|
|
90
|
+
|
|
91
|
+
# If none of these are given, the default will be 2.5
|
|
92
|
+
_default_options["radius"] = None
|
|
93
|
+
_default_options["xmin"] = None
|
|
94
|
+
_default_options["xmax"] = None
|
|
95
|
+
_default_options["ymin"] = None
|
|
96
|
+
_default_options["ymax"] = None
|
|
97
|
+
_default_options["zmin"] = None
|
|
98
|
+
_default_options["zmax"] = None
|
|
99
|
+
|
|
100
|
+
_default_options["lattice_filter"] = None
|
|
101
|
+
|
|
102
|
+
_default_options["wall_zorder"] = -5
|
|
103
|
+
_default_options["ray_zorder"] = -4
|
|
104
|
+
_default_options["generator_zorder"] = -3
|
|
105
|
+
_default_options["point_zorder"] = -2
|
|
106
|
+
_default_options["label_zorder"] = -1
|
|
107
|
+
|
|
108
|
+
# These options are actually used as "current defaults" in plotting functions.
|
|
109
|
+
_options = copy(_default_options)
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
class ToricPlotter(SageObject):
|
|
113
|
+
r"""
|
|
114
|
+
Create a toric plotter.
|
|
115
|
+
|
|
116
|
+
INPUT:
|
|
117
|
+
|
|
118
|
+
- ``all_options`` -- a :class:`dictionary <dict>`, containing any of the
|
|
119
|
+
options related to toric objects (see :func:`options`) and any other
|
|
120
|
+
options that will be passed to lower level plotting functions
|
|
121
|
+
|
|
122
|
+
- ``dimension`` -- integer (1, 2, or 3); dimension of toric objects to
|
|
123
|
+
be plotted
|
|
124
|
+
|
|
125
|
+
- ``generators`` -- (optional) a list of ray generators; see examples for
|
|
126
|
+
a detailed explanation of this argument
|
|
127
|
+
|
|
128
|
+
OUTPUT: a toric plotter
|
|
129
|
+
|
|
130
|
+
EXAMPLES:
|
|
131
|
+
|
|
132
|
+
In most cases there is no need to create and use :class:`ToricPlotter`
|
|
133
|
+
directly. Instead, use plotting method of the object which you want to
|
|
134
|
+
plot, e.g. ::
|
|
135
|
+
|
|
136
|
+
sage: fan = toric_varieties.dP6().fan() # needs palp sage.graphs
|
|
137
|
+
sage: fan.plot() # needs palp sage.graphs sage.plot sage.symbolic
|
|
138
|
+
Graphics object consisting of 31 graphics primitives
|
|
139
|
+
sage: print(fan.plot()) # needs palp sage.graphs sage.plot sage.symbolic
|
|
140
|
+
Graphics object consisting of 31 graphics primitives
|
|
141
|
+
|
|
142
|
+
If you do want to create your own plotting function for some toric
|
|
143
|
+
structure, the anticipated usage of toric plotters is the following:
|
|
144
|
+
|
|
145
|
+
- collect all necessary options in a dictionary;
|
|
146
|
+
|
|
147
|
+
- pass these options and ``dimension`` to :class:`ToricPlotter`;
|
|
148
|
+
|
|
149
|
+
- call :meth:`include_points` on ray generators and any other points that
|
|
150
|
+
you want to be present on the plot (it will try to set appropriate
|
|
151
|
+
cut-off bounds);
|
|
152
|
+
|
|
153
|
+
- call :meth:`adjust_options` to choose "nice" default values for all
|
|
154
|
+
options that were not set yet and ensure consistency of rectangular and
|
|
155
|
+
spherical cut-off bounds;
|
|
156
|
+
|
|
157
|
+
- call :meth:`set_rays` on ray generators to scale them to the cut-off
|
|
158
|
+
bounds of the plot;
|
|
159
|
+
|
|
160
|
+
- call appropriate ``plot_*`` functions to actually construct the plot.
|
|
161
|
+
|
|
162
|
+
For example, the plot from the previous example can be obtained as
|
|
163
|
+
follows::
|
|
164
|
+
|
|
165
|
+
sage: # needs palp sage.graphs sage.plot sage.symbolic
|
|
166
|
+
sage: from sage.geometry.toric_plotter import ToricPlotter
|
|
167
|
+
sage: options = dict() # use default for everything
|
|
168
|
+
sage: tp = ToricPlotter(options, fan.lattice().degree())
|
|
169
|
+
sage: tp.include_points(fan.rays())
|
|
170
|
+
sage: tp.adjust_options()
|
|
171
|
+
sage: tp.set_rays(fan.rays())
|
|
172
|
+
sage: result = tp.plot_lattice()
|
|
173
|
+
sage: result += tp.plot_rays()
|
|
174
|
+
sage: result += tp.plot_generators()
|
|
175
|
+
sage: result += tp.plot_walls(fan(2))
|
|
176
|
+
sage: result
|
|
177
|
+
Graphics object consisting of 31 graphics primitives
|
|
178
|
+
|
|
179
|
+
In most situations it is only necessary to include generators of rays, in
|
|
180
|
+
this case they can be passed to the constructor as an optional argument.
|
|
181
|
+
In the example above, the toric plotter can be completely set up using ::
|
|
182
|
+
|
|
183
|
+
sage: tp = ToricPlotter(options, fan.lattice().degree(), fan.rays()) # needs palp sage.graphs sage.plot sage.symbolic
|
|
184
|
+
|
|
185
|
+
All options are exposed as attributes of toric plotters and can be modified
|
|
186
|
+
after constructions, however you will have to manually call
|
|
187
|
+
:meth:`adjust_options` and :meth:`set_rays` again if you decide to change
|
|
188
|
+
the plotting mode and/or cut-off bounds. Otherwise plots maybe invalid.
|
|
189
|
+
"""
|
|
190
|
+
|
|
191
|
+
def __init__(self, all_options, dimension, generators=None):
|
|
192
|
+
r"""
|
|
193
|
+
See :class:`ToricPlotter` for documentation.
|
|
194
|
+
|
|
195
|
+
TESTS::
|
|
196
|
+
|
|
197
|
+
sage: from sage.geometry.toric_plotter import ToricPlotter
|
|
198
|
+
sage: tp = ToricPlotter(dict(), 2)
|
|
199
|
+
sage: TestSuite(tp).run()
|
|
200
|
+
"""
|
|
201
|
+
super().__init__()
|
|
202
|
+
sd = self.__dict__
|
|
203
|
+
extra_options = dict()
|
|
204
|
+
self.extra_options = extra_options
|
|
205
|
+
toric_options = options()
|
|
206
|
+
for option, value in all_options.items():
|
|
207
|
+
if option in toric_options:
|
|
208
|
+
sd[option] = value
|
|
209
|
+
else:
|
|
210
|
+
extra_options[option] = value
|
|
211
|
+
for option, value in toric_options.items():
|
|
212
|
+
if option not in sd:
|
|
213
|
+
sd[option] = value
|
|
214
|
+
if dimension not in [1, 2, 3]:
|
|
215
|
+
raise ValueError("toric objects can be plotted only for "
|
|
216
|
+
"dimensions 1, 2, and 3, not %s!" % dimension)
|
|
217
|
+
self.dimension = dimension
|
|
218
|
+
self.origin = vector(RDF, max(dimension, 2)) # 1-d is plotted in 2-d
|
|
219
|
+
if self.mode not in ["box", "generators", "round"]:
|
|
220
|
+
raise ValueError("unrecognized plotting mode: %s!" % self.mode)
|
|
221
|
+
# If radius was explicitly set by the user, it sets other bounds too.
|
|
222
|
+
# If we don't take it into account here, they will be replaced by
|
|
223
|
+
# automatically computed values.
|
|
224
|
+
if sd["radius"] is not None:
|
|
225
|
+
for key in ["xmin", "ymin", "zmin"]:
|
|
226
|
+
if sd[key] is None:
|
|
227
|
+
sd[key] = - sd["radius"]
|
|
228
|
+
for key in ["xmax", "ymax", "zmax"]:
|
|
229
|
+
if sd[key] is None:
|
|
230
|
+
sd[key] = sd["radius"]
|
|
231
|
+
# We also set some of the "extra_options" if they were not given.
|
|
232
|
+
if "axes" not in extra_options:
|
|
233
|
+
extra_options["axes"] = False
|
|
234
|
+
if "frame" not in extra_options:
|
|
235
|
+
extra_options["frame"] = False
|
|
236
|
+
if "aspect_ratio" not in extra_options:
|
|
237
|
+
extra_options["aspect_ratio"] = 1
|
|
238
|
+
if generators is not None:
|
|
239
|
+
# Completely prepare the plotter
|
|
240
|
+
self.include_points(generators)
|
|
241
|
+
self.adjust_options()
|
|
242
|
+
self.set_rays(generators)
|
|
243
|
+
|
|
244
|
+
def __eq__(self, other):
|
|
245
|
+
r"""
|
|
246
|
+
Check if ``self`` is equal to ``other``.
|
|
247
|
+
|
|
248
|
+
INPUT:
|
|
249
|
+
|
|
250
|
+
- ``other`` -- anything
|
|
251
|
+
|
|
252
|
+
OUTPUT: ``True`` if ``self`` is equal to ``other``, ``False`` otherwise
|
|
253
|
+
|
|
254
|
+
TESTS::
|
|
255
|
+
|
|
256
|
+
sage: from sage.geometry.toric_plotter import ToricPlotter
|
|
257
|
+
sage: ToricPlotter(dict(), 2) == ToricPlotter(dict(), 2)
|
|
258
|
+
True
|
|
259
|
+
sage: ToricPlotter(dict(), 2) == 0
|
|
260
|
+
False
|
|
261
|
+
"""
|
|
262
|
+
# Just to make TestSuite happy...
|
|
263
|
+
return type(self) is type(other) and self.__dict__ == other.__dict__
|
|
264
|
+
|
|
265
|
+
def adjust_options(self):
|
|
266
|
+
r"""
|
|
267
|
+
Adjust plotting options.
|
|
268
|
+
|
|
269
|
+
This function determines appropriate default values for those options,
|
|
270
|
+
that were not specified by the user, based on the other options. See
|
|
271
|
+
:class:`ToricPlotter` for a detailed example.
|
|
272
|
+
|
|
273
|
+
OUTPUT: none
|
|
274
|
+
|
|
275
|
+
TESTS::
|
|
276
|
+
|
|
277
|
+
sage: from sage.geometry.toric_plotter import ToricPlotter
|
|
278
|
+
sage: tp = ToricPlotter(dict(), 2)
|
|
279
|
+
sage: print(tp.show_lattice)
|
|
280
|
+
None
|
|
281
|
+
sage: tp.adjust_options()
|
|
282
|
+
sage: print(tp.show_lattice)
|
|
283
|
+
True
|
|
284
|
+
"""
|
|
285
|
+
# Unfortunately, some of the defaults are dimension specific for no
|
|
286
|
+
# good reason but to remedy 2-d/3-d plotting inconsistencies in Sage.
|
|
287
|
+
d = self.dimension
|
|
288
|
+
if d <= 2:
|
|
289
|
+
if self.point_size is None:
|
|
290
|
+
self.point_size = 50
|
|
291
|
+
elif d == 3:
|
|
292
|
+
if self.point_size is None:
|
|
293
|
+
self.point_size = 10
|
|
294
|
+
if self.generator_thickness is None:
|
|
295
|
+
self.generator_thickness = self.ray_thickness
|
|
296
|
+
sd = self.__dict__
|
|
297
|
+
bounds = ["radius", "xmin", "xmax", "ymin", "ymax", "zmin", "zmax"]
|
|
298
|
+
bounds = [abs(sd[bound]) for bound in bounds if sd[bound] is not None]
|
|
299
|
+
r = RDF(max(bounds + [0.5]) if bounds else 2.5)
|
|
300
|
+
self.radius = r
|
|
301
|
+
round = self.mode == "round"
|
|
302
|
+
for key in ["xmin", "ymin", "zmin"]:
|
|
303
|
+
if round or sd[key] is None:
|
|
304
|
+
sd[key] = - r
|
|
305
|
+
sd[key] = min(sd[key], - 0.5)
|
|
306
|
+
sd[key] = RDF(sd[key])
|
|
307
|
+
for key in ["xmax", "ymax", "zmax"]:
|
|
308
|
+
if round or sd[key] is None:
|
|
309
|
+
sd[key] = r
|
|
310
|
+
sd[key] = max(sd[key], 0.5)
|
|
311
|
+
sd[key] = RDF(sd[key])
|
|
312
|
+
if self.show_lattice is None:
|
|
313
|
+
self.show_lattice = (r <= 5) if d <= 2 else r <= 3
|
|
314
|
+
|
|
315
|
+
def include_points(self, points, force=False):
|
|
316
|
+
r"""
|
|
317
|
+
Try to include ``points`` into the bounding box of ``self``.
|
|
318
|
+
|
|
319
|
+
INPUT:
|
|
320
|
+
|
|
321
|
+
- ``points`` -- list of points
|
|
322
|
+
|
|
323
|
+
- ``force`` -- boolean (default: ``False``); by default, only bounds
|
|
324
|
+
that were not set before will be chosen to include ``points``. Use
|
|
325
|
+
``force=True`` if you don't mind increasing existing bounding box.
|
|
326
|
+
|
|
327
|
+
OUTPUT: none
|
|
328
|
+
|
|
329
|
+
EXAMPLES::
|
|
330
|
+
|
|
331
|
+
sage: from sage.geometry.toric_plotter import ToricPlotter
|
|
332
|
+
sage: tp = ToricPlotter(dict(), 2)
|
|
333
|
+
sage: print(tp.radius)
|
|
334
|
+
None
|
|
335
|
+
sage: tp.include_points([(3, 4)])
|
|
336
|
+
sage: print(tp.radius)
|
|
337
|
+
5.5...
|
|
338
|
+
sage: tp.include_points([(5, 12)])
|
|
339
|
+
sage: print(tp.radius)
|
|
340
|
+
5.5...
|
|
341
|
+
sage: tp.include_points([(5, 12)], force=True)
|
|
342
|
+
sage: print(tp.radius)
|
|
343
|
+
13.5...
|
|
344
|
+
"""
|
|
345
|
+
if not points:
|
|
346
|
+
return
|
|
347
|
+
points = [vector(RDF, pt) for pt in points]
|
|
348
|
+
sd = self.__dict__
|
|
349
|
+
|
|
350
|
+
def update(bound, new_value, points):
|
|
351
|
+
if force or sd[bound] is None:
|
|
352
|
+
new_value = eval(new_value)
|
|
353
|
+
if sd[bound] is None:
|
|
354
|
+
sd[bound] = new_value
|
|
355
|
+
elif abs(sd[bound]) < abs(new_value):
|
|
356
|
+
sd[bound] = new_value
|
|
357
|
+
|
|
358
|
+
update("radius", "max(pt.norm() for pt in points) + 0.5", points)
|
|
359
|
+
try:
|
|
360
|
+
update("xmin", "min(pt[0] for pt in points) - 0.5", points)
|
|
361
|
+
update("xmax", "max(pt[0] for pt in points) + 0.5", points)
|
|
362
|
+
update("ymin", "min(pt[1] for pt in points) - 0.5", points)
|
|
363
|
+
update("ymax", "max(pt[1] for pt in points) + 0.5", points)
|
|
364
|
+
update("zmin", "min(pt[2] for pt in points) - 0.5", points)
|
|
365
|
+
update("zmax", "max(pt[2] for pt in points) + 0.5", points)
|
|
366
|
+
except IndexError: # 1 or 2 dimensional case
|
|
367
|
+
pass
|
|
368
|
+
|
|
369
|
+
def plot_generators(self):
|
|
370
|
+
r"""
|
|
371
|
+
Plot ray generators.
|
|
372
|
+
|
|
373
|
+
Ray generators must be specified during construction or using
|
|
374
|
+
:meth:`set_rays` before calling this method.
|
|
375
|
+
|
|
376
|
+
OUTPUT: a plot
|
|
377
|
+
|
|
378
|
+
EXAMPLES::
|
|
379
|
+
|
|
380
|
+
sage: from sage.geometry.toric_plotter import ToricPlotter
|
|
381
|
+
sage: tp = ToricPlotter(dict(), 2, [(3,4)])
|
|
382
|
+
sage: tp.plot_generators() # needs sage.plot
|
|
383
|
+
Graphics object consisting of 1 graphics primitive
|
|
384
|
+
"""
|
|
385
|
+
generators = self.generators
|
|
386
|
+
result = Graphics()
|
|
387
|
+
if not generators or not self.show_generators:
|
|
388
|
+
return result
|
|
389
|
+
colors = color_list(self.generator_color, len(generators))
|
|
390
|
+
d = self.dimension
|
|
391
|
+
extra_options = self.extra_options
|
|
392
|
+
origin = self.origin
|
|
393
|
+
thickness = self.generator_thickness
|
|
394
|
+
zorder = self.generator_zorder
|
|
395
|
+
for generator, ray, color in zip(generators, self.rays, colors):
|
|
396
|
+
if ray.dot_product(ray) < generator.dot_product(generator):
|
|
397
|
+
result += line([origin, ray],
|
|
398
|
+
color=color, thickness=thickness,
|
|
399
|
+
zorder=zorder, **extra_options)
|
|
400
|
+
else:
|
|
401
|
+
# This should not be the case, but as of 4.6 plotting
|
|
402
|
+
# functions are inconsistent and arrows behave very
|
|
403
|
+
# different compared to lines.
|
|
404
|
+
if d <= 2:
|
|
405
|
+
result += arrow(origin, generator,
|
|
406
|
+
color=color, width=thickness,
|
|
407
|
+
arrowsize=thickness + 1,
|
|
408
|
+
zorder=zorder, **extra_options)
|
|
409
|
+
else:
|
|
410
|
+
result += line([origin, generator], arrow_head=True,
|
|
411
|
+
color=color, thickness=thickness,
|
|
412
|
+
zorder=zorder, **extra_options)
|
|
413
|
+
return result
|
|
414
|
+
|
|
415
|
+
def plot_labels(self, labels, positions):
|
|
416
|
+
r"""
|
|
417
|
+
Plot ``labels`` at specified ``positions``.
|
|
418
|
+
|
|
419
|
+
INPUT:
|
|
420
|
+
|
|
421
|
+
- ``labels`` -- string or list of strings
|
|
422
|
+
|
|
423
|
+
- ``positions`` -- list of points
|
|
424
|
+
|
|
425
|
+
OUTPUT: a plot
|
|
426
|
+
|
|
427
|
+
EXAMPLES::
|
|
428
|
+
|
|
429
|
+
sage: from sage.geometry.toric_plotter import ToricPlotter
|
|
430
|
+
sage: tp = ToricPlotter(dict(), 2)
|
|
431
|
+
sage: tp.plot_labels("u", [(1.5,0)]) # needs sage.plot
|
|
432
|
+
Graphics object consisting of 1 graphics primitive
|
|
433
|
+
"""
|
|
434
|
+
result = Graphics()
|
|
435
|
+
color = self.label_color
|
|
436
|
+
extra_options = self.extra_options
|
|
437
|
+
zorder = self.label_zorder
|
|
438
|
+
font_size = self.font_size
|
|
439
|
+
twod = self.dimension <= 2
|
|
440
|
+
labels = label_list(labels, len(positions), twod)
|
|
441
|
+
for label, position in zip(labels, positions):
|
|
442
|
+
if label is None:
|
|
443
|
+
continue
|
|
444
|
+
if twod:
|
|
445
|
+
result += text(label, position,
|
|
446
|
+
color=color, fontsize=font_size,
|
|
447
|
+
zorder=zorder, **extra_options)
|
|
448
|
+
else:
|
|
449
|
+
result += text3d(label, position, color=color, **extra_options)
|
|
450
|
+
return result
|
|
451
|
+
|
|
452
|
+
def plot_lattice(self):
|
|
453
|
+
r"""
|
|
454
|
+
Plot the lattice (i.e. its points in the cut-off bounds of ``self``).
|
|
455
|
+
|
|
456
|
+
OUTPUT: a plot
|
|
457
|
+
|
|
458
|
+
EXAMPLES::
|
|
459
|
+
|
|
460
|
+
sage: from sage.geometry.toric_plotter import ToricPlotter
|
|
461
|
+
sage: tp = ToricPlotter(dict(), 2)
|
|
462
|
+
sage: tp.adjust_options()
|
|
463
|
+
sage: tp.plot_lattice() # needs sage.plot
|
|
464
|
+
Graphics object consisting of 1 graphics primitive
|
|
465
|
+
"""
|
|
466
|
+
if not self.show_lattice:
|
|
467
|
+
# Plot the origin anyway, otherwise rays/generators may look ugly.
|
|
468
|
+
return self.plot_points([self.origin])
|
|
469
|
+
d = self.dimension
|
|
470
|
+
if d == 1:
|
|
471
|
+
points = ((x, 0)
|
|
472
|
+
for x in range(ceil(self.xmin), floor(self.xmax) + 1))
|
|
473
|
+
elif d == 2:
|
|
474
|
+
points = ((x, y)
|
|
475
|
+
for x in range(ceil(self.xmin), floor(self.xmax) + 1)
|
|
476
|
+
for y in range(ceil(self.ymin), floor(self.ymax) + 1))
|
|
477
|
+
elif d == 3:
|
|
478
|
+
points = ((x, y, z)
|
|
479
|
+
for x in range(ceil(self.xmin), floor(self.xmax) + 1)
|
|
480
|
+
for y in range(ceil(self.ymin), floor(self.ymax) + 1)
|
|
481
|
+
for z in range(ceil(self.zmin), floor(self.zmax) + 1))
|
|
482
|
+
if self.mode == "round":
|
|
483
|
+
r = 1.01 * self.radius # To make sure integer values work OK.
|
|
484
|
+
points = (pt for pt in points if vector(pt).dot_product(vector(pt)) <= r)
|
|
485
|
+
f = self.lattice_filter
|
|
486
|
+
if f is not None:
|
|
487
|
+
points = (pt for pt in points if f(pt))
|
|
488
|
+
return self.plot_points(tuple(points))
|
|
489
|
+
|
|
490
|
+
def plot_points(self, points):
|
|
491
|
+
r"""
|
|
492
|
+
Plot given ``points``.
|
|
493
|
+
|
|
494
|
+
INPUT:
|
|
495
|
+
|
|
496
|
+
- ``points`` -- list of points
|
|
497
|
+
|
|
498
|
+
OUTPUT: a plot
|
|
499
|
+
|
|
500
|
+
EXAMPLES::
|
|
501
|
+
|
|
502
|
+
sage: from sage.geometry.toric_plotter import ToricPlotter
|
|
503
|
+
sage: tp = ToricPlotter(dict(), 2)
|
|
504
|
+
sage: tp.adjust_options()
|
|
505
|
+
sage: tp.plot_points([(1,0), (0,1)]) # needs sage.plot
|
|
506
|
+
Graphics object consisting of 1 graphics primitive
|
|
507
|
+
"""
|
|
508
|
+
return point(points, color=self.point_color, size=self.point_size,
|
|
509
|
+
zorder=self.point_zorder, **self.extra_options)
|
|
510
|
+
|
|
511
|
+
def plot_ray_labels(self):
|
|
512
|
+
r"""
|
|
513
|
+
Plot ray labels.
|
|
514
|
+
|
|
515
|
+
Usually ray labels are plotted together with rays, but in some cases it
|
|
516
|
+
is desirable to output them separately.
|
|
517
|
+
|
|
518
|
+
Ray generators must be specified during construction or using
|
|
519
|
+
:meth:`set_rays` before calling this method.
|
|
520
|
+
|
|
521
|
+
OUTPUT: a plot
|
|
522
|
+
|
|
523
|
+
EXAMPLES::
|
|
524
|
+
|
|
525
|
+
sage: from sage.geometry.toric_plotter import ToricPlotter
|
|
526
|
+
sage: tp = ToricPlotter(dict(), 2, [(3,4)])
|
|
527
|
+
sage: tp.plot_ray_labels() # needs sage.plot
|
|
528
|
+
Graphics object consisting of 1 graphics primitive
|
|
529
|
+
"""
|
|
530
|
+
return self.plot_labels(self.ray_label,
|
|
531
|
+
[1.1 * ray for ray in self.rays])
|
|
532
|
+
|
|
533
|
+
def plot_rays(self):
|
|
534
|
+
r"""
|
|
535
|
+
Plot rays and their labels.
|
|
536
|
+
|
|
537
|
+
Ray generators must be specified during construction or using
|
|
538
|
+
:meth:`set_rays` before calling this method.
|
|
539
|
+
|
|
540
|
+
OUTPUT: a plot
|
|
541
|
+
|
|
542
|
+
EXAMPLES::
|
|
543
|
+
|
|
544
|
+
sage: from sage.geometry.toric_plotter import ToricPlotter
|
|
545
|
+
sage: tp = ToricPlotter(dict(), 2, [(3,4)])
|
|
546
|
+
sage: tp.plot_rays() # needs sage.plot
|
|
547
|
+
Graphics object consisting of 2 graphics primitives
|
|
548
|
+
"""
|
|
549
|
+
result = Graphics()
|
|
550
|
+
rays = self.rays
|
|
551
|
+
if not rays or not self.show_rays:
|
|
552
|
+
return result
|
|
553
|
+
extra_options = self.extra_options
|
|
554
|
+
origin = self.origin
|
|
555
|
+
colors = color_list(self.ray_color, len(rays))
|
|
556
|
+
thickness = self.ray_thickness
|
|
557
|
+
zorder = self.ray_zorder
|
|
558
|
+
for end, color in zip(rays, colors):
|
|
559
|
+
result += line([origin, end],
|
|
560
|
+
color=color, thickness=thickness,
|
|
561
|
+
zorder=zorder, **extra_options)
|
|
562
|
+
result += self.plot_ray_labels()
|
|
563
|
+
return result
|
|
564
|
+
|
|
565
|
+
def plot_walls(self, walls):
|
|
566
|
+
r"""
|
|
567
|
+
Plot ``walls``, i.e. 2-d cones, and their labels.
|
|
568
|
+
|
|
569
|
+
Ray generators must be specified during construction or using
|
|
570
|
+
:meth:`set_rays` before calling this method and these specified
|
|
571
|
+
ray generators will be used in conjunction with
|
|
572
|
+
:meth:`~sage.geometry.cone.ConvexRationalPolyhedralCone.ambient_ray_indices`
|
|
573
|
+
of ``walls``.
|
|
574
|
+
|
|
575
|
+
INPUT:
|
|
576
|
+
|
|
577
|
+
- ``walls`` -- list of 2-d cones
|
|
578
|
+
|
|
579
|
+
OUTPUT: a plot
|
|
580
|
+
|
|
581
|
+
EXAMPLES::
|
|
582
|
+
|
|
583
|
+
sage: quadrant = Cone([(1,0), (0,1)])
|
|
584
|
+
sage: from sage.geometry.toric_plotter import ToricPlotter
|
|
585
|
+
sage: tp = ToricPlotter(dict(), 2, quadrant.rays())
|
|
586
|
+
sage: tp.plot_walls([quadrant]) # needs sage.plot sage.symbolic
|
|
587
|
+
Graphics object consisting of 2 graphics primitives
|
|
588
|
+
|
|
589
|
+
Let's also check that the truncating polyhedron is functioning
|
|
590
|
+
correctly::
|
|
591
|
+
|
|
592
|
+
sage: tp = ToricPlotter({"mode": "box"}, 2, quadrant.rays())
|
|
593
|
+
sage: tp.plot_walls([quadrant]) # needs sage.plot sage.symbolic
|
|
594
|
+
Graphics object consisting of 2 graphics primitives
|
|
595
|
+
"""
|
|
596
|
+
result = Graphics()
|
|
597
|
+
if not walls or not self.show_walls:
|
|
598
|
+
return result
|
|
599
|
+
rays = self.rays
|
|
600
|
+
extra_options = self.extra_options
|
|
601
|
+
mode = self.mode
|
|
602
|
+
alpha = self.wall_alpha
|
|
603
|
+
colors = color_list(self.wall_color, len(walls))
|
|
604
|
+
zorder = self.wall_zorder
|
|
605
|
+
if mode == "box":
|
|
606
|
+
if self.dimension <= 2:
|
|
607
|
+
ieqs = [(self.xmax, -1, 0), (- self.xmin, 1, 0),
|
|
608
|
+
(self.ymax, 0, -1), (- self.ymin, 0, 1)]
|
|
609
|
+
else:
|
|
610
|
+
ieqs = [(self.xmax, -1, 0, 0), (- self.xmin, 1, 0, 0),
|
|
611
|
+
(self.ymax, 0, -1, 0), (- self.ymin, 0, 1, 0),
|
|
612
|
+
(self.zmax, 0, 0, -1), (- self.zmin, 0, 0, 1)]
|
|
613
|
+
box = Polyhedron(ieqs=ieqs, base_ring=RDF)
|
|
614
|
+
for wall, color in zip(walls, colors):
|
|
615
|
+
result += box.intersection(wall.polyhedron()).render_solid(
|
|
616
|
+
alpha=alpha, color=color, zorder=zorder, **extra_options)
|
|
617
|
+
elif mode == "generators":
|
|
618
|
+
origin = self.origin
|
|
619
|
+
for wall, color in zip(walls, colors):
|
|
620
|
+
vertices = [rays[i] for i in wall.ambient_ray_indices()]
|
|
621
|
+
vertices.append(origin)
|
|
622
|
+
result += Polyhedron(vertices=vertices, base_ring=RDF).render_solid(
|
|
623
|
+
alpha=alpha, color=color, zorder=zorder, **extra_options)
|
|
624
|
+
label_sectors = []
|
|
625
|
+
round = mode == "round"
|
|
626
|
+
for wall, color in zip(walls, colors):
|
|
627
|
+
S = wall.linear_subspace()
|
|
628
|
+
lsd = S.dimension()
|
|
629
|
+
if lsd == 0: # Strictly convex wall
|
|
630
|
+
r1, r2 = (rays[i] for i in wall.ambient_ray_indices())
|
|
631
|
+
elif lsd == 1: # wall is a half-plane
|
|
632
|
+
for i, ray in zip(wall.ambient_ray_indices(), wall.rays()):
|
|
633
|
+
if ray in S:
|
|
634
|
+
r1 = rays[i]
|
|
635
|
+
else:
|
|
636
|
+
r2 = rays[i]
|
|
637
|
+
if round:
|
|
638
|
+
# Plot one "extra" sector
|
|
639
|
+
result += sector(- r1, r2,
|
|
640
|
+
alpha=alpha, color=color, zorder=zorder, **extra_options)
|
|
641
|
+
else: # wall is a plane
|
|
642
|
+
r1, r2 = S.basis()
|
|
643
|
+
r1 = vector(RDF, r1)
|
|
644
|
+
r1 = r1 / r1.norm() * self.radius
|
|
645
|
+
r2 = vector(RDF, r2)
|
|
646
|
+
r2 = r2 / r2.norm() * self.radius
|
|
647
|
+
if round:
|
|
648
|
+
# Plot three "extra" sectors
|
|
649
|
+
result += sector(r1, - r2,
|
|
650
|
+
alpha=alpha, color=color, zorder=zorder, **extra_options)
|
|
651
|
+
result += sector(- r1, r2,
|
|
652
|
+
alpha=alpha, color=color, zorder=zorder, **extra_options)
|
|
653
|
+
result += sector(- r1, - r2,
|
|
654
|
+
alpha=alpha, color=color, zorder=zorder, **extra_options)
|
|
655
|
+
label_sectors.append([r1, r2])
|
|
656
|
+
if round:
|
|
657
|
+
result += sector(r1, r2,
|
|
658
|
+
alpha=alpha, color=color, zorder=zorder, **extra_options)
|
|
659
|
+
result += self.plot_labels(self.wall_label,
|
|
660
|
+
[sum(label_sector) / 3 for label_sector in label_sectors])
|
|
661
|
+
return result
|
|
662
|
+
|
|
663
|
+
def set_rays(self, generators):
|
|
664
|
+
r"""
|
|
665
|
+
Set up rays and their ``generators`` to be used by plotting functions.
|
|
666
|
+
|
|
667
|
+
As an alternative to using this method, you can pass ``generators`` to
|
|
668
|
+
:class:`ToricPlotter` constructor.
|
|
669
|
+
|
|
670
|
+
INPUT:
|
|
671
|
+
|
|
672
|
+
- ``generators`` -- list of primitive nonzero ray generators
|
|
673
|
+
|
|
674
|
+
OUTPUT: none
|
|
675
|
+
|
|
676
|
+
EXAMPLES::
|
|
677
|
+
|
|
678
|
+
sage: from sage.geometry.toric_plotter import ToricPlotter
|
|
679
|
+
sage: tp = ToricPlotter(dict(), 2)
|
|
680
|
+
sage: tp.adjust_options()
|
|
681
|
+
sage: tp.plot_rays() # needs sage.plot
|
|
682
|
+
Traceback (most recent call last):
|
|
683
|
+
...
|
|
684
|
+
AttributeError: 'ToricPlotter' object has no attribute 'rays'...
|
|
685
|
+
sage: tp.set_rays([(0,1)])
|
|
686
|
+
sage: tp.plot_rays() # needs sage.plot
|
|
687
|
+
Graphics object consisting of 2 graphics primitives
|
|
688
|
+
"""
|
|
689
|
+
d = self.dimension
|
|
690
|
+
if d == 1:
|
|
691
|
+
generators = [vector(RDF, 2, (gen[0], 0)) for gen in generators]
|
|
692
|
+
else:
|
|
693
|
+
generators = [vector(RDF, d, gen) for gen in generators]
|
|
694
|
+
self.generators = generators
|
|
695
|
+
if self.mode == "box":
|
|
696
|
+
rays = []
|
|
697
|
+
bounds = [self.__dict__[bound]
|
|
698
|
+
for bound in ["xmin", "xmax", "ymin", "ymax", "zmin", "zmax"]]
|
|
699
|
+
bounds = bounds[:2 * d]
|
|
700
|
+
for gen in generators:
|
|
701
|
+
factors = []
|
|
702
|
+
for i, gen_i in enumerate(gen):
|
|
703
|
+
factors.append(gen_i / bounds[2 * i])
|
|
704
|
+
factors.append(gen_i / bounds[2 * i + 1])
|
|
705
|
+
rays.append(gen / max(factors))
|
|
706
|
+
elif self.mode == "generators":
|
|
707
|
+
rays = generators
|
|
708
|
+
elif self.mode == "round":
|
|
709
|
+
r = self.radius
|
|
710
|
+
rays = [r * gen / gen.norm() for gen in generators]
|
|
711
|
+
self.rays = rays
|
|
712
|
+
|
|
713
|
+
|
|
714
|
+
def _unrecognized_option(option):
|
|
715
|
+
r"""
|
|
716
|
+
Raise an exception about wrong ``option``.
|
|
717
|
+
|
|
718
|
+
INPUT:
|
|
719
|
+
|
|
720
|
+
- ``option`` -- string
|
|
721
|
+
|
|
722
|
+
OUTPUT: none, a :exc:`KeyError` exception is raised
|
|
723
|
+
|
|
724
|
+
TESTS::
|
|
725
|
+
|
|
726
|
+
sage: from sage.geometry.toric_plotter import _unrecognized_option
|
|
727
|
+
sage: _unrecognized_option("nontoric")
|
|
728
|
+
Traceback (most recent call last):
|
|
729
|
+
...
|
|
730
|
+
KeyError: "unrecognized toric plot option: 'nontoric'!
|
|
731
|
+
Type 'toric_plotter.options?' to see available options."
|
|
732
|
+
"""
|
|
733
|
+
raise KeyError("unrecognized toric plot option: '%s'! " % option
|
|
734
|
+
+ "Type 'toric_plotter.options?' to see available options.")
|
|
735
|
+
|
|
736
|
+
|
|
737
|
+
def color_list(color, n):
|
|
738
|
+
r"""
|
|
739
|
+
Normalize a list of ``n`` colors.
|
|
740
|
+
|
|
741
|
+
INPUT:
|
|
742
|
+
|
|
743
|
+
- ``color`` -- anything specifying a :class:`Color`, a list of such
|
|
744
|
+
specifications, or the string "rainbow";
|
|
745
|
+
|
|
746
|
+
- ``n`` -- integer
|
|
747
|
+
|
|
748
|
+
OUTPUT: list of ``n`` colors
|
|
749
|
+
|
|
750
|
+
If ``color`` specified a single color, it is repeated ``n`` times. If it
|
|
751
|
+
was a list of ``n`` colors, it is returned without changes. If it was
|
|
752
|
+
"rainbow", the rainbow of ``n`` colors is returned.
|
|
753
|
+
|
|
754
|
+
EXAMPLES::
|
|
755
|
+
|
|
756
|
+
sage: # needs sage.plot
|
|
757
|
+
sage: from sage.geometry.toric_plotter import color_list
|
|
758
|
+
sage: color_list("grey", 1)
|
|
759
|
+
[RGB color (0.5019607843137255, 0.5019607843137255, 0.5019607843137255)]
|
|
760
|
+
sage: len(color_list("grey", 3))
|
|
761
|
+
3
|
|
762
|
+
sage: L = color_list("rainbow", 3)
|
|
763
|
+
sage: L
|
|
764
|
+
[RGB color (1.0, 0.0, 0.0),
|
|
765
|
+
RGB color (0.0, 1.0, 0.0),
|
|
766
|
+
RGB color (0.0, 0.0, 1.0)]
|
|
767
|
+
sage: color_list(L, 3)
|
|
768
|
+
[RGB color (1.0, 0.0, 0.0),
|
|
769
|
+
RGB color (0.0, 1.0, 0.0),
|
|
770
|
+
RGB color (0.0, 0.0, 1.0)]
|
|
771
|
+
sage: color_list(L, 4)
|
|
772
|
+
Traceback (most recent call last):
|
|
773
|
+
...
|
|
774
|
+
ValueError: expected 4 colors, got 3!
|
|
775
|
+
"""
|
|
776
|
+
try:
|
|
777
|
+
color = Color(color)
|
|
778
|
+
return [color] * n
|
|
779
|
+
except (ValueError, TypeError):
|
|
780
|
+
if isinstance(color, (list, tuple)):
|
|
781
|
+
if len(color) != n:
|
|
782
|
+
raise ValueError("expected %d colors, got %d!"
|
|
783
|
+
% (n, len(color)))
|
|
784
|
+
return color
|
|
785
|
+
if color == "rainbow":
|
|
786
|
+
return [Color(c) for c in rainbow(n, "rgbtuple")]
|
|
787
|
+
raise TypeError("cannot interpret %s as a color!" % color)
|
|
788
|
+
|
|
789
|
+
|
|
790
|
+
def label_list(label, n, math_mode, index_set=None):
|
|
791
|
+
r"""
|
|
792
|
+
Normalize a list of ``n`` labels.
|
|
793
|
+
|
|
794
|
+
INPUT:
|
|
795
|
+
|
|
796
|
+
- ``label`` -- ``None``, a string, or a list of string
|
|
797
|
+
|
|
798
|
+
- ``n`` -- integer
|
|
799
|
+
|
|
800
|
+
- ``math_mode`` -- boolean; if ``True``, will produce LaTeX expressions
|
|
801
|
+
for labels
|
|
802
|
+
|
|
803
|
+
- ``index_set`` -- list of integers (default: ``range(n)``) that will be
|
|
804
|
+
used as subscripts for labels
|
|
805
|
+
|
|
806
|
+
OUTPUT: list of ``n`` labels
|
|
807
|
+
|
|
808
|
+
If ``label`` was a list of ``n`` entries, it is returned without changes.
|
|
809
|
+
If ``label`` is ``None``, a list of ``n`` ``None``'s is returned. If
|
|
810
|
+
``label`` is a string, a list of strings of the form ``$label_{i}$`` is
|
|
811
|
+
returned, where `i` ranges over ``index_set``. (If ``math_mode=False``, the
|
|
812
|
+
form "label_i" is used instead.) If ``n=1``, there is no subscript added,
|
|
813
|
+
unless ``index_set`` was specified explicitly.
|
|
814
|
+
|
|
815
|
+
EXAMPLES::
|
|
816
|
+
|
|
817
|
+
sage: from sage.geometry.toric_plotter import label_list
|
|
818
|
+
sage: label_list("u", 3, False)
|
|
819
|
+
['u_0', 'u_1', 'u_2']
|
|
820
|
+
sage: label_list("u", 3, True)
|
|
821
|
+
['$u_{0}$', '$u_{1}$', '$u_{2}$']
|
|
822
|
+
sage: label_list("u", 1, True)
|
|
823
|
+
['$u$']
|
|
824
|
+
"""
|
|
825
|
+
if label is None:
|
|
826
|
+
return [None] * n
|
|
827
|
+
if isinstance(label, (list, tuple)):
|
|
828
|
+
if len(label) != n:
|
|
829
|
+
raise ValueError("expected %d labels, got %d!" % (n, len(label)))
|
|
830
|
+
return label
|
|
831
|
+
if index_set is None:
|
|
832
|
+
if n == 1:
|
|
833
|
+
return ["$%s$" % label.strip("$")] if math_mode else [label]
|
|
834
|
+
index_set = range(n)
|
|
835
|
+
if math_mode:
|
|
836
|
+
label = label.strip("$")
|
|
837
|
+
return list("$%s_{%d}$" % (label, i) for i in index_set)
|
|
838
|
+
else:
|
|
839
|
+
return list("%s_%d" % (label, i) for i in index_set)
|
|
840
|
+
|
|
841
|
+
|
|
842
|
+
def options(option=None, **kwds):
|
|
843
|
+
r"""
|
|
844
|
+
Get or set options for plots of toric geometry objects.
|
|
845
|
+
|
|
846
|
+
.. NOTE::
|
|
847
|
+
|
|
848
|
+
This function provides access to global default options. Any of these
|
|
849
|
+
options can be overridden by passing them directly to plotting
|
|
850
|
+
functions. See also :func:`reset_options`.
|
|
851
|
+
|
|
852
|
+
INPUT:
|
|
853
|
+
|
|
854
|
+
- None;
|
|
855
|
+
|
|
856
|
+
OR:
|
|
857
|
+
|
|
858
|
+
- ``option`` -- string, name of the option whose value you wish to get;
|
|
859
|
+
|
|
860
|
+
OR:
|
|
861
|
+
|
|
862
|
+
- keyword arguments specifying new values for one or more options.
|
|
863
|
+
|
|
864
|
+
OUTPUT:
|
|
865
|
+
|
|
866
|
+
- if there was no input, the dictionary of current options for toric plots;
|
|
867
|
+
|
|
868
|
+
- if ``option`` argument was given, the current value of ``option``;
|
|
869
|
+
|
|
870
|
+
- if other keyword arguments were given, none.
|
|
871
|
+
|
|
872
|
+
**Name Conventions**
|
|
873
|
+
|
|
874
|
+
To clearly distinguish parts of toric plots, in options and methods we use
|
|
875
|
+
the following name conventions:
|
|
876
|
+
|
|
877
|
+
Generator
|
|
878
|
+
A primitive integral vector generating a 1-dimensional cone, plotted as
|
|
879
|
+
an arrow from the origin (or a line, if the head of the arrow is beyond
|
|
880
|
+
cut-off bounds for the plot).
|
|
881
|
+
|
|
882
|
+
Ray
|
|
883
|
+
A 1-dimensional cone, plotted as a line from the origin to the cut-off
|
|
884
|
+
bounds for the plot.
|
|
885
|
+
|
|
886
|
+
Wall
|
|
887
|
+
A 2-dimensional cone, plotted as a region between rays (in the above
|
|
888
|
+
sense). Its exact shape depends on the plotting mode (see below).
|
|
889
|
+
|
|
890
|
+
Chamber
|
|
891
|
+
A 3-dimensional cone, plotting is not implemented yet.
|
|
892
|
+
|
|
893
|
+
**Plotting Modes**
|
|
894
|
+
|
|
895
|
+
A plotting mode mostly determines the shape of the cut-off region (which is
|
|
896
|
+
always relevant for toric plots except for trivial objects consisting of
|
|
897
|
+
the origin only). The following options are available:
|
|
898
|
+
|
|
899
|
+
Box
|
|
900
|
+
The cut-off region is a box with edges parallel to coordinate axes.
|
|
901
|
+
|
|
902
|
+
Generators
|
|
903
|
+
The cut-off region is determined by primitive integral generators of
|
|
904
|
+
rays. Note that this notion is well-defined only for rays and walls,
|
|
905
|
+
in particular you should plot the lattice on your own
|
|
906
|
+
(:meth:`~ToricPlotter.plot_lattice` will use box mode which is likely
|
|
907
|
+
to be unsuitable). While this method may not be suitable for general
|
|
908
|
+
fans, it is quite natural for fans of :class:`CPR-Fano toric varieties.
|
|
909
|
+
<sage.schemes.toric.fano_variety.CPRFanoToricVariety_field`
|
|
910
|
+
|
|
911
|
+
Round
|
|
912
|
+
The cut-off regions is a sphere centered at the origin.
|
|
913
|
+
|
|
914
|
+
**Available Options**
|
|
915
|
+
|
|
916
|
+
Default values for the following options can be set using this function:
|
|
917
|
+
|
|
918
|
+
|
|
919
|
+
- ``mode`` -- "box", "generators", or "round", see above for descriptions;
|
|
920
|
+
|
|
921
|
+
- ``show_lattice`` -- boolean, whether to show lattice points in the
|
|
922
|
+
cut-off region or not;
|
|
923
|
+
|
|
924
|
+
- ``show_rays`` -- boolean, whether to show rays or not;
|
|
925
|
+
|
|
926
|
+
- ``show_generators`` -- boolean, whether to show rays or not;
|
|
927
|
+
|
|
928
|
+
- ``show_walls`` -- boolean, whether to show rays or not;
|
|
929
|
+
|
|
930
|
+
- ``generator_color`` -- a color for generators;
|
|
931
|
+
|
|
932
|
+
- ``label_color`` -- a color for labels;
|
|
933
|
+
|
|
934
|
+
- ``point_color`` -- a color for lattice points;
|
|
935
|
+
|
|
936
|
+
- ``ray_color`` -- a color for rays, a list of colors (one for each ray),
|
|
937
|
+
or the string "rainbow";
|
|
938
|
+
|
|
939
|
+
- ``wall_color`` -- a color for walls, a list of colors (one for each
|
|
940
|
+
wall), or the string "rainbow";
|
|
941
|
+
|
|
942
|
+
- ``wall_alpha`` -- a number between 0 and 1, the alpha-value for walls
|
|
943
|
+
(determining their transparency);
|
|
944
|
+
|
|
945
|
+
- ``point_size`` -- integer; the size of lattice points
|
|
946
|
+
|
|
947
|
+
- ``ray_thickness`` -- integer; the thickness of rays
|
|
948
|
+
|
|
949
|
+
- ``generator_thickness`` -- integer; the thickness of generators
|
|
950
|
+
|
|
951
|
+
- ``font_size`` -- integer; the size of font used for labels
|
|
952
|
+
|
|
953
|
+
- ``ray_label`` -- string or list of strings used for ray labels; use
|
|
954
|
+
``None`` to hide labels
|
|
955
|
+
|
|
956
|
+
- ``wall_label`` -- string or list of strings used for wall labels; use
|
|
957
|
+
``None`` to hide labels
|
|
958
|
+
|
|
959
|
+
- ``radius`` -- a positive number, the radius of the cut-off region for
|
|
960
|
+
"round" mode
|
|
961
|
+
|
|
962
|
+
- ``xmin``, ``xmax``, ``ymin``, ``ymax``, ``zmin``, ``zmax`` -- numbers
|
|
963
|
+
determining the cut-off region for "box" mode. Note that you cannot
|
|
964
|
+
exclude the origin - if you try to do so, bounds will be automatically
|
|
965
|
+
expanded to include it.
|
|
966
|
+
|
|
967
|
+
- ``lattice_filter`` -- a callable, taking as an argument a lattice point
|
|
968
|
+
and returning ``True`` if this point should be included on the plot
|
|
969
|
+
(useful, e.g. for plotting sublattices)
|
|
970
|
+
|
|
971
|
+
- ``wall_zorder``, ``ray_zorder``, ``generator_zorder``, ``point_zorder``,
|
|
972
|
+
``label_zorder`` -- integers, z-orders for different classes of objects.
|
|
973
|
+
By default all values are negative, so that you can add other graphic
|
|
974
|
+
objects on top of a toric plot. You may need to adjust these parameters
|
|
975
|
+
if you want to put a toric plot on top of something else or if you want
|
|
976
|
+
to overlap several toric plots.
|
|
977
|
+
|
|
978
|
+
You can see the current default value of any options by typing, e.g. ::
|
|
979
|
+
|
|
980
|
+
sage: toric_plotter.options("show_rays")
|
|
981
|
+
True
|
|
982
|
+
|
|
983
|
+
If the default value is ``None``, it means that the actual default is
|
|
984
|
+
determined later based on the known options. Note, that not all options can
|
|
985
|
+
be determined in such a way, so you should not set options to ``None``
|
|
986
|
+
unless it was its original state. (You can always revert to this "original
|
|
987
|
+
state" using :meth:`reset_options`.)
|
|
988
|
+
|
|
989
|
+
EXAMPLES:
|
|
990
|
+
|
|
991
|
+
The following line will make all subsequent toric plotting commands to draw
|
|
992
|
+
"rainbows" from walls::
|
|
993
|
+
|
|
994
|
+
sage: toric_plotter.options(wall_color='rainbow')
|
|
995
|
+
|
|
996
|
+
If you prefer a less colorful output (e.g. if you need black-and-white
|
|
997
|
+
illustrations for a paper), you can use something like this::
|
|
998
|
+
|
|
999
|
+
sage: toric_plotter.options(wall_color='grey')
|
|
1000
|
+
"""
|
|
1001
|
+
global _options
|
|
1002
|
+
if option is None and not kwds:
|
|
1003
|
+
return copy(_options)
|
|
1004
|
+
elif option is not None and not kwds:
|
|
1005
|
+
try:
|
|
1006
|
+
return _options[option]
|
|
1007
|
+
except KeyError:
|
|
1008
|
+
_unrecognized_option(option)
|
|
1009
|
+
elif option is None and kwds:
|
|
1010
|
+
for option in kwds:
|
|
1011
|
+
try:
|
|
1012
|
+
_options[option] = kwds[option]
|
|
1013
|
+
except KeyError:
|
|
1014
|
+
_unrecognized_option(option)
|
|
1015
|
+
else:
|
|
1016
|
+
raise ValueError("you cannot specify 'option' and other arguments at "
|
|
1017
|
+
"the same time!")
|
|
1018
|
+
|
|
1019
|
+
|
|
1020
|
+
def reset_options():
|
|
1021
|
+
r"""
|
|
1022
|
+
Reset options for plots of toric geometry objects.
|
|
1023
|
+
|
|
1024
|
+
OUTPUT: none
|
|
1025
|
+
|
|
1026
|
+
EXAMPLES::
|
|
1027
|
+
|
|
1028
|
+
sage: toric_plotter.options("show_rays")
|
|
1029
|
+
True
|
|
1030
|
+
sage: toric_plotter.options(show_rays=False)
|
|
1031
|
+
sage: toric_plotter.options("show_rays")
|
|
1032
|
+
False
|
|
1033
|
+
|
|
1034
|
+
Now all toric plots will not show rays, unless explicitly requested. If you
|
|
1035
|
+
want to go back to "default defaults", use this method::
|
|
1036
|
+
|
|
1037
|
+
sage: toric_plotter.reset_options()
|
|
1038
|
+
sage: toric_plotter.options("show_rays")
|
|
1039
|
+
True
|
|
1040
|
+
"""
|
|
1041
|
+
global _options
|
|
1042
|
+
_options = copy(_default_options)
|
|
1043
|
+
|
|
1044
|
+
|
|
1045
|
+
def sector(ray1, ray2, **extra_options):
|
|
1046
|
+
r"""
|
|
1047
|
+
Plot a sector between ``ray1`` and ``ray2`` centered at the origin.
|
|
1048
|
+
|
|
1049
|
+
.. NOTE::
|
|
1050
|
+
|
|
1051
|
+
This function was intended for plotting strictly convex cones, so it
|
|
1052
|
+
plots the smaller sector between ``ray1`` and ``ray2`` and, therefore,
|
|
1053
|
+
they cannot be opposite. If you do want to use this function for bigger
|
|
1054
|
+
regions, split them into several parts.
|
|
1055
|
+
|
|
1056
|
+
.. NOTE::
|
|
1057
|
+
|
|
1058
|
+
As of version 4.6 Sage does not have a graphic primitive for sectors in
|
|
1059
|
+
3-dimensional space, so this function will actually approximate them
|
|
1060
|
+
using polygons (the number of vertices used depends on the angle
|
|
1061
|
+
between rays).
|
|
1062
|
+
|
|
1063
|
+
INPUT:
|
|
1064
|
+
|
|
1065
|
+
- ``ray1``, ``ray2`` -- rays in 2- or 3-dimensional space of the same
|
|
1066
|
+
length
|
|
1067
|
+
|
|
1068
|
+
- ``extra_options`` -- dictionary of options that should be passed to
|
|
1069
|
+
lower level plotting functions
|
|
1070
|
+
|
|
1071
|
+
OUTPUT: a plot
|
|
1072
|
+
|
|
1073
|
+
EXAMPLES::
|
|
1074
|
+
|
|
1075
|
+
sage: from sage.geometry.toric_plotter import sector
|
|
1076
|
+
sage: sector((1,0), (0,1)) # needs sage.symbolic
|
|
1077
|
+
Graphics object consisting of 1 graphics primitive
|
|
1078
|
+
sage: sector((3,2,1), (1,2,3)) # needs sage.plot
|
|
1079
|
+
Graphics3d Object
|
|
1080
|
+
"""
|
|
1081
|
+
from sage.functions.all import arccos, arctan2
|
|
1082
|
+
|
|
1083
|
+
ray1 = vector(RDF, ray1)
|
|
1084
|
+
ray2 = vector(RDF, ray2)
|
|
1085
|
+
r = ray1.norm()
|
|
1086
|
+
if len(ray1) == 2:
|
|
1087
|
+
# Plot an honest sector
|
|
1088
|
+
phi1 = arctan2(ray1[1], ray1[0])
|
|
1089
|
+
phi2 = arctan2(ray2[1], ray2[0])
|
|
1090
|
+
if phi1 > phi2:
|
|
1091
|
+
phi1, phi2 = phi2, phi1
|
|
1092
|
+
if phi2 - phi1 > pi:
|
|
1093
|
+
phi1, phi2 = phi2, phi1 + 2 * pi
|
|
1094
|
+
return disk((0,0), r, (phi1, phi2), **extra_options)
|
|
1095
|
+
else:
|
|
1096
|
+
# Plot a polygon, 30 vertices per radian.
|
|
1097
|
+
vertices_per_radian = 30
|
|
1098
|
+
n = ceil(arccos(ray1 * ray2 / r**2) * vertices_per_radian)
|
|
1099
|
+
dr = (ray2 - ray1) / n
|
|
1100
|
+
points = (ray1 + i * dr for i in range(n + 1))
|
|
1101
|
+
points = [r / pt.norm() * pt for pt in points]
|
|
1102
|
+
points.append(vector(RDF, 3))
|
|
1103
|
+
return polygon(points, **extra_options)
|