# Base class for polyhedra: Methods for plotting and affine hull projection#

class sage.geometry.polyhedron.base6.Polyhedron_base6(parent, Vrep, Hrep, Vrep_minimal=None, Hrep_minimal=None, pref_rep=None, mutable=False, **kwds)#

Methods related to plotting including affine hull projection.

affine_hull(*args, **kwds)#

Return the affine hull of self as a polyhedron.

EXAMPLES:

sage: half_plane_in_space = Polyhedron(ieqs=[(0,1,0,0)], eqns=[(0,0,0,1)])
sage: half_plane_in_space.affine_hull().Hrepresentation()
(An equation (0, 0, 1) x + 0 == 0,)

sage: polytopes.cube().affine_hull().is_universe()
True

affine_hull_manifold(name=None, latex_name=None, start_index=0, ambient_space=None, ambient_chart=None, names=None, **kwds)#

Return the affine hull of self as a manifold.

If self is full-dimensional, it is just the ambient Euclidean space. Otherwise, it is a Riemannian submanifold of the ambient Euclidean space.

INPUT:

• ambient_space – a EuclideanSpace of the ambient dimension (default: the manifold of ambient_chart, if provided; otherwise, a new instance of EuclideanSpace).

• ambient_chart – a chart on ambient_space.

• names – names for the coordinates on the affine hull.

• optional arguments accepted by affine_hull_projection().

The default chart is determined by the optional arguments of affine_hull_projection().

EXAMPLES:

sage: triangle = Polyhedron([(1,0,0), (0,1,0), (0,0,1)]);  triangle
A 2-dimensional polyhedron in ZZ^3 defined as the convex hull of 3 vertices
sage: A = triangle.affine_hull_manifold(name='A'); A
2-dimensional Riemannian submanifold A embedded in the Euclidean space E^3
sage: A.embedding().display()
A → E^3
(x0, x1) ↦ (x, y, z) = (t0 + x0, t0 + x1, t0 - x0 - x1 + 1)
sage: A.embedding().inverse().display()
E^3 → A
(x, y, z) ↦ (x0, x1) = (x, y)
[Chart (E^3, (x0_E3, x1_E3, t0_E3))]
sage: A.normal().display()
n = 1/3*sqrt(3) e_x + 1/3*sqrt(3) e_y + 1/3*sqrt(3) e_z
sage: A.induced_metric()       # Need to call this before volume_form
Riemannian metric gamma on the 2-dimensional Riemannian submanifold A embedded in the Euclidean space E^3
sage: A.volume_form()
2-form eps_gamma on the 2-dimensional Riemannian submanifold A embedded in the Euclidean space E^3


Orthogonal version:

sage: A = triangle.affine_hull_manifold(name='A', orthogonal=True); A
2-dimensional Riemannian submanifold A embedded in the Euclidean space E^3
sage: A.embedding().display()
A → E^3
(x0, x1) ↦ (x, y, z) = (t0 - 1/2*x0 - 1/3*x1 + 1, t0 + 1/2*x0 - 1/3*x1, t0 + 2/3*x1)
sage: A.embedding().inverse().display()
E^3 → A
(x, y, z) ↦ (x0, x1) = (-x + y + 1, -1/2*x - 1/2*y + z + 1/2)


Arrangement of affine hull of facets:

sage: D = polytopes.dodecahedron()                                  # optional - sage.rings.number_field
sage: E3 = EuclideanSpace(3)                                        # optional - sage.rings.number_field
sage: submanifolds = [                                              # optional - sage.rings.number_field
....:     F.as_polyhedron().affine_hull_manifold(name=f'F{i}', orthogonal=True, ambient_space=E3)
....:     for i, F in enumerate(D.facets())]
sage: sum(FM.plot({}, srange(-2, 2, 0.1), srange(-2, 2, 0.1), opacity=0.2)  # not tested  # optional - sage.plot  # optional - sage.rings.number_field
....:     for FM in submanifolds) + D.plot()
Graphics3d Object


Full-dimensional case:

sage: cube = polytopes.cube(); cube
A 3-dimensional polyhedron in ZZ^3 defined as the convex hull of 8 vertices
sage: cube.affine_hull_manifold()
Euclidean space E^3

affine_hull_projection(as_polyhedron, as_affine_map=None, orthogonal=False, orthonormal=False, extend=False, minimal=False, return_all_data=False, as_convex_set=False)#

Return the polyhedron projected into its affine hull.

Each polyhedron is contained in some smallest affine subspace (possibly the entire ambient space) – its affine hull. We provide an affine linear map that projects the ambient space of the polyhedron to the standard Euclidean space of dimension of the polyhedron, which restricts to a bijection from the affine hull.

The projection map is not unique; some parameters control the choice of the map. Other parameters control the output of the function.

INPUT:

• as_polyhedron (or as_convex_set) – (boolean or the default None) and

• as_affine_map – (boolean, default False) control the output

The default as_polyhedron=None translates to as_polyhedron=not as_affine_map, therefore to as_polyhedron=True if nothing is specified.

If exactly one of either as_polyhedron or as_affine_map is set, then either a polyhedron or the affine transformation is returned. The affine transformation sends the embedded polytope to a fulldimensional one. It is given as a pair (A, b), where A is a linear transformation and $$b$$ is a vector, and the affine transformation sends v to A(v)+b.

If both as_polyhedron and as_affine_map are set, then both are returned, encapsulated in an instance of AffineHullProjectionData.

• return_all_data – (boolean, default False)

If set, then as_polyhedron and as_affine_map will set (possibly overridden) and additional (internal) data concerning the transformation is returned. Everything is encapsulated in an instance of AffineHullProjectionData in this case.

• orthogonal – boolean (default: False); if True, provide an orthogonal transformation.

• orthonormal – boolean (default: False); if True, provide an orthonormal transformation. If the base ring does not provide the necessary square roots, the extend parameter needs to be set to True.

• extend – boolean (default: False); if True, allow base ring to be extended if necessary. This becomes relevant when requiring an orthonormal transformation.

• minimal – boolean (default: False); if True, when doing an extension, it computes the minimal base ring of the extension, otherwise the base ring is AA.

OUTPUT:

A full-dimensional polyhedron or an affine transformation, depending on the parameters as_polyhedron and as_affine_map, or an instance of AffineHullProjectionData containing all data (parameter return_all_data).

If the output is an instance of AffineHullProjectionData, the following fields may be set:

• image – the projection of the original polyhedron

• projection_map – the affine map as a pair whose first component is a linear transformation and its second component a shift; see above.

• section_map – an affine map as a pair whose first component is a linear transformation and its second component a shift. It maps the codomain of affine_map to the affine hull of self. It is a right inverse of projection_map.

Note that all of these data are compatible.

Todo

• make the parameters orthogonal and orthonormal work with unbounded polyhedra.

EXAMPLES:

sage: triangle = Polyhedron([(1,0,0), (0,1,0), (0,0,1)]);  triangle
A 2-dimensional polyhedron in ZZ^3 defined as the convex hull of 3 vertices
sage: triangle.affine_hull_projection()
A 2-dimensional polyhedron in ZZ^2 defined as the convex hull of 3 vertices

sage: half3d = Polyhedron(vertices=[(3,2,1)], rays=[(1,0,0)])
sage: half3d.affine_hull_projection().Vrepresentation()
(A ray in the direction (1), A vertex at (3))


The resulting affine hulls depend on the parameter orthogonal and orthonormal:

sage: L = Polyhedron([[1,0],[0,1]]); L
A 1-dimensional polyhedron in ZZ^2 defined as the convex hull of 2 vertices
sage: A = L.affine_hull_projection(); A
A 1-dimensional polyhedron in ZZ^1 defined as the convex hull of 2 vertices
sage: A.vertices()
(A vertex at (0), A vertex at (1))
sage: A = L.affine_hull_projection(orthogonal=True); A
A 1-dimensional polyhedron in QQ^1 defined as the convex hull of 2 vertices
sage: A.vertices()
(A vertex at (0), A vertex at (2))
sage: A = L.affine_hull_projection(orthonormal=True)                                  # optional - sage.rings.number_field
Traceback (most recent call last):
...
ValueError: the base ring needs to be extended; try with "extend=True"
sage: A = L.affine_hull_projection(orthonormal=True, extend=True); A                  # optional - sage.rings.number_field
A 1-dimensional polyhedron in AA^1 defined as the convex hull of 2 vertices
sage: A.vertices()                                                                    # optional - sage.rings.number_field
(A vertex at (1.414213562373095?), A vertex at (0.?e-18))


More generally:

sage: S = polytopes.simplex(); S
A 3-dimensional polyhedron in ZZ^4 defined as the convex hull of 4 vertices
sage: S.vertices()
(A vertex at (0, 0, 0, 1),
A vertex at (0, 0, 1, 0),
A vertex at (0, 1, 0, 0),
A vertex at (1, 0, 0, 0))
sage: A = S.affine_hull_projection(); A
A 3-dimensional polyhedron in ZZ^3 defined as the convex hull of 4 vertices
sage: A.vertices()
(A vertex at (0, 0, 0),
A vertex at (0, 0, 1),
A vertex at (0, 1, 0),
A vertex at (1, 0, 0))
sage: A = S.affine_hull_projection(orthogonal=True); A
A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 4 vertices
sage: A.vertices()
(A vertex at (0, 0, 0),
A vertex at (2, 0, 0),
A vertex at (1, 3/2, 0),
A vertex at (1, 1/2, 4/3))
sage: A = S.affine_hull_projection(orthonormal=True, extend=True); A
A 3-dimensional polyhedron in AA^3 defined as the convex hull of 4 vertices
sage: A.vertices()
(A vertex at (0.7071067811865475?, 0.4082482904638630?, 1.154700538379252?),
A vertex at (0.7071067811865475?, 1.224744871391589?, 0.?e-18),
A vertex at (1.414213562373095?, 0.?e-18, 0.?e-18),
A vertex at (0.?e-18, 0.?e-18, 0.?e-18))


With the parameter minimal one can get a minimal base ring:

sage: s = polytopes.simplex(3)
sage: s_AA = s.affine_hull_projection(orthonormal=True, extend=True)
sage: s_AA.base_ring()
Algebraic Real Field
sage: s_full = s.affine_hull_projection(orthonormal=True, extend=True, minimal=True)
sage: s_full.base_ring()
Number Field in a with defining polynomial y^4 - 4*y^2 + 1 with a = 0.5176380902050415?


More examples with the orthonormal parameter:

sage: P = polytopes.permutahedron(3); P                   # optional - sage.combinat  # optional - sage.rings.number_field
A 2-dimensional polyhedron in ZZ^3 defined as the convex hull of 6 vertices
sage: set([F.as_polyhedron().affine_hull_projection(orthonormal=True, extend=True).volume() for F in P.affine_hull_projection().faces(1)]) == {1, sqrt(AA(2))}  # optional - sage.combinat  # optional - sage.rings.number_field
True
sage: set([F.as_polyhedron().affine_hull_projection(orthonormal=True, extend=True).volume() for F in P.affine_hull_projection(orthonormal=True, extend=True).faces(1)]) == {sqrt(AA(2))}  # optional - sage.combinat  # optional - sage.rings.number_field
True

sage: D = polytopes.dodecahedron()                                                    # optional - sage.rings.number_field
sage: F = D.faces(2)[0].as_polyhedron()                                               # optional - sage.rings.number_field
sage: F.affine_hull_projection(orthogonal=True)                                       # optional - sage.rings.number_field
A 2-dimensional polyhedron in (Number Field in sqrt5 with defining polynomial x^2 - 5 with sqrt5 = 2.236067977499790?)^2 defined as the convex hull of 5 vertices
sage: F.affine_hull_projection(orthonormal=True, extend=True)                         # optional - sage.rings.number_field
A 2-dimensional polyhedron in AA^2 defined as the convex hull of 5 vertices

sage: K.<sqrt2> = QuadraticField(2)                                                   # optional - sage.rings.number_field
sage: P = Polyhedron([2*[K.zero()],2*[sqrt2]]); P                                     # optional - sage.rings.number_field
A 1-dimensional polyhedron in (Number Field in sqrt2 with defining polynomial x^2 - 2 with sqrt2 = 1.414213562373095?)^2 defined as the convex hull of 2 vertices
sage: P.vertices()                                                                    # optional - sage.rings.number_field
(A vertex at (0, 0), A vertex at (sqrt2, sqrt2))
sage: A = P.affine_hull_projection(orthonormal=True); A                               # optional - sage.rings.number_field
A 1-dimensional polyhedron in (Number Field in sqrt2 with defining polynomial x^2 - 2 with sqrt2 = 1.414213562373095?)^1 defined as the convex hull of 2 vertices
sage: A.vertices()                                                                    # optional - sage.rings.number_field
(A vertex at (0), A vertex at (2))

sage: K.<sqrt3> = QuadraticField(3)                                                   # optional - sage.rings.number_field
sage: P = Polyhedron([2*[K.zero()],2*[sqrt3]]); P                                     # optional - sage.rings.number_field
A 1-dimensional polyhedron in (Number Field in sqrt3 with defining polynomial x^2 - 3 with sqrt3 = 1.732050807568878?)^2 defined as the convex hull of 2 vertices
sage: P.vertices()                                                                    # optional - sage.rings.number_field
(A vertex at (0, 0), A vertex at (sqrt3, sqrt3))
sage: A = P.affine_hull_projection(orthonormal=True)                                  # optional - sage.rings.number_field
Traceback (most recent call last):
...
ValueError: the base ring needs to be extended; try with "extend=True"
sage: A = P.affine_hull_projection(orthonormal=True, extend=True); A                  # optional - sage.rings.number_field
A 1-dimensional polyhedron in AA^1 defined as the convex hull of 2 vertices
sage: A.vertices()                                                                    # optional - sage.rings.number_field
(A vertex at (0), A vertex at (2.449489742783178?))
sage: sqrt(6).n()                                                                     # optional - sage.rings.number_field
2.44948974278318


The affine hull is combinatorially equivalent to the input:

sage: P.is_combinatorially_isomorphic(P.affine_hull_projection())                     # optional - sage.rings.number_field
True
sage: P.is_combinatorially_isomorphic(P.affine_hull_projection(orthogonal=True))      # optional - sage.rings.number_field
True
sage: P.is_combinatorially_isomorphic(P.affine_hull_projection(orthonormal=True, extend=True))   # optional - sage.rings.number_field
True


The orthonormal=True parameter preserves volumes; it provides an isometric copy of the polyhedron:

sage: Pentagon = polytopes.dodecahedron().faces(2)[0].as_polyhedron()                 # optional - sage.rings.number_field
sage: P = Pentagon.affine_hull_projection(orthonormal=True, extend=True)              # optional - sage.rings.number_field
sage: _, c= P.is_inscribed(certificate=True)                                          # optional - sage.rings.number_field
sage: c                                                                               # optional - sage.rings.number_field
(0.4721359549995794?, 0.6498393924658126?)
sage: circumradius = (c-vector(P.vertices()[0])).norm()                               # optional - sage.rings.number_field
sage: p = polytopes.regular_polygon(5)                                                # optional - sage.rings.number_field
sage: p.volume()                                                                      # optional - sage.rings.number_field
2.377641290737884?
sage: P.volume()                                                                      # optional - sage.rings.number_field
1.53406271079097?
sage: p.volume()*circumradius^2                                                       # optional - sage.rings.number_field
1.534062710790965?
sage: P.volume() == p.volume()*circumradius^2                                         # optional - sage.rings.number_field
True


One can also use orthogonal parameter to calculate volumes; in this case we don’t need to switch base rings. One has to divide by the square root of the determinant of the linear part of the affine transformation times its transpose:

sage: Pentagon = polytopes.dodecahedron().faces(2)[0].as_polyhedron()                 # optional - sage.rings.number_field
sage: Pnormal = Pentagon.affine_hull_projection(orthonormal=True, extend=True)        # optional - sage.rings.number_field
sage: Pgonal = Pentagon.affine_hull_projection(orthogonal=True)                       # optional - sage.rings.number_field
sage: A, b = Pentagon.affine_hull_projection(orthogonal=True, as_affine_map=True)     # optional - sage.rings.number_field
sage: Adet = (A.matrix().transpose()*A.matrix()).det()                                # optional - sage.rings.number_field
sage: Pnormal.volume()                                                                # optional - sage.rings.number_field
1.53406271079097?
sage: Pgonal.volume()/Adet.sqrt(extend=True)                                          # optional - sage.rings.number_field
-80*(55*sqrt(5) - 123)/sqrt(-6368*sqrt(5) + 14240)
sage: Pgonal.volume()/AA(Adet).sqrt().n(digits=20)                                    # optional - sage.rings.number_field
1.5340627107909646813
sage: AA(Pgonal.volume()^2) == (Pnormal.volume()^2)*AA(Adet)                          # optional - sage.rings.number_field
True


Another example with as_affine_map=True:

sage: P = polytopes.permutahedron(4)                                                      # optional - sage.combinat  # optional - sage.rings.number_field
sage: A, b = P.affine_hull_projection(orthonormal=True, as_affine_map=True, extend=True)  # optional - sage.combinat  # optional - sage.rings.number_field
sage: Q = P.affine_hull_projection(orthonormal=True, extend=True)                         # optional - sage.combinat  # optional - sage.rings.number_field
sage: Q.center()                                                                          # optional - sage.combinat  # optional - sage.rings.number_field
(0.7071067811865475?, 1.224744871391589?, 1.732050807568878?)
sage: A(P.center()) + b == Q.center()                                                     # optional - sage.combinat  # optional - sage.rings.number_field
True


For unbounded, non full-dimensional polyhedra, the orthogonal=True and orthonormal=True is not implemented:

sage: P = Polyhedron(ieqs=[[0, 1, 0], [0, 0, 1], [0, 0, -1]]); P
A 1-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 1 ray
sage: P.is_compact()
False
sage: P.is_full_dimensional()
False
sage: P.affine_hull_projection(orthogonal=True)
Traceback (most recent call last):
...
NotImplementedError: "orthogonal=True" and "orthonormal=True" work only for compact polyhedra
sage: P.affine_hull_projection(orthonormal=True)
Traceback (most recent call last):
...
NotImplementedError: "orthogonal=True" and "orthonormal=True" work only for compact polyhedra


Setting as_affine_map to True without orthogonal or orthonormal set to True:

sage: S = polytopes.simplex()
sage: S.affine_hull_projection(as_affine_map=True)
(Vector space morphism represented by the matrix:
[1 0 0]
[0 1 0]
[0 0 1]
[0 0 0]
Domain: Vector space of dimension 4 over Rational Field
Codomain: Vector space of dimension 3 over Rational Field,
(0, 0, 0))


If the polyhedron is full-dimensional, it is returned:

sage: polytopes.cube().affine_hull_projection()
A 3-dimensional polyhedron in ZZ^3 defined as the convex hull of 8 vertices
sage: polytopes.cube().affine_hull_projection(as_affine_map=True)
(Vector space morphism represented by the matrix:
[1 0 0]
[0 1 0]
[0 0 1]
Domain: Vector space of dimension 3 over Rational Field
Codomain: Vector space of dimension 3 over Rational Field,
(0, 0, 0))


Return polyhedron and affine map:

sage: S = polytopes.simplex(2)
sage: data = S.affine_hull_projection(orthogonal=True,
....:                                 as_polyhedron=True,
....:                                 as_affine_map=True); data
AffineHullProjectionData(image=A 2-dimensional polyhedron in QQ^2
defined as the convex hull of 3 vertices,
projection_linear_map=Vector space morphism represented by the matrix:
[  -1 -1/2]
[   1 -1/2]
[   0    1]
Domain: Vector space of dimension 3 over Rational Field
Codomain: Vector space of dimension 2 over Rational Field,
projection_translation=(1, 1/2),
section_linear_map=None,
section_translation=None)


Return all data:

sage: data = S.affine_hull_projection(orthogonal=True, return_all_data=True); data
AffineHullProjectionData(image=A 2-dimensional polyhedron in QQ^2
defined as the convex hull of 3 vertices,
projection_linear_map=Vector space morphism represented by the matrix:
[  -1 -1/2]
[   1 -1/2]
[   0    1]
Domain: Vector space of dimension 3 over Rational Field
Codomain: Vector space of dimension 2 over Rational Field,
projection_translation=(1, 1/2),
section_linear_map=Vector space morphism represented by the matrix:
[-1/2  1/2    0]
[-1/3 -1/3  2/3]
Domain: Vector space of dimension 2 over Rational Field
Codomain: Vector space of dimension 3 over Rational Field, section_translation=(1, 0, 0))


The section map is a right inverse of the projection map:

sage: data.image.linear_transformation(data.section_linear_map.matrix().transpose()) + data.section_translation == S
True


Same without orthogonal=True:

sage: data = S.affine_hull_projection(return_all_data=True); data
AffineHullProjectionData(image=A 2-dimensional polyhedron in ZZ^2
defined as the convex hull of 3 vertices,
projection_linear_map=Vector space morphism represented by the matrix:
[1 0]
[0 1]
[0 0]
Domain: Vector space of dimension 3 over Rational Field
Codomain: Vector space of dimension 2 over Rational Field, projection_translation=(0, 0),
section_linear_map=Vector space morphism represented by the matrix:
[ 1  0 -1]
[ 0  1 -1]
Domain: Vector space of dimension 2 over Rational Field
Codomain: Vector space of dimension 3 over Rational Field, section_translation=(0, 0, 1))
sage: data.image.linear_transformation(data.section_linear_map.matrix().transpose()) + data.section_translation == S
True

sage: P0 = Polyhedron(
....:     ieqs=[(0, -1, 0, 1, 1, 1), (0, 1, 1, 0, -1, -1), (0, -1, 1, 1, 0, 0),
....:           (0, 1, 0, 0, 0, 0), (0, 0, 1, 1, -1, -1), (0, 0, 0, 0, 0, 1),
....:           (0, 0, 0, 0, 1, 0), (0, 0, 0, 1, 0, -1), (0, 0, 1, 0, 0, 0)])
sage: P = P0.intersection(Polyhedron(eqns=[(-1, 1, 1, 1, 1, 1)]))
sage: P.dim()
4
sage: P.affine_hull_projection(orthogonal=True, as_affine_map=True)[0]
Vector space morphism represented by the matrix:
[    0     0     0   1/3]
[ -2/3  -1/6     0 -1/12]
[  1/3  -1/6   1/2 -1/12]
[    0   1/2     0 -1/12]
[  1/3  -1/6  -1/2 -1/12]
Domain: Vector space of dimension 5 over Rational Field
Codomain: Vector space of dimension 4 over Rational Field

gale_transform()#

Return the Gale transform of a polytope as described in the reference below.

OUTPUT:

A list of vectors, the Gale transform. The dimension is the dimension of the affine dependencies of the vertices of the polytope.

EXAMPLES:

This is from the reference, for a triangular prism:

sage: p = Polyhedron(vertices = [[0,0],[0,1],[1,0]])
sage: p2 = p.prism()
sage: p2.gale_transform()
((-1, 0), (0, -1), (1, 1), (-1, -1), (1, 0), (0, 1))


REFERENCES:

Lectures in Geometric Combinatorics, R.R.Thomas, 2006, AMS Press.

gale_transform_to_polyhedron().

plot(point=None, line=None, polygon=None, wireframe='blue', fill='green', position=None, orthonormal=True, **kwds)#

Return a graphical representation.

INPUT:

• point, line, polygon – Parameters to pass to point (0d), line (1d), and polygon (2d) plot commands. Allowed values are:

• A Python dictionary to be passed as keywords to the plot commands.

• A string or triple of numbers: The color. This is equivalent to passing the dictionary {'color':...}.

• False: Switches off the drawing of the corresponding graphics object

• wireframe, fill – Similar to point, line, and polygon, but fill is used for the graphics objects in the dimension of the polytope (or of dimension 2 for higher dimensional polytopes) and wireframe is used for all lower-dimensional graphics objects (default: ‘green’ for fill and ‘blue’ for wireframe)

• position – positive number; the position to take the projection point in Schlegel diagrams.

• orthonormal – Boolean (default: True); whether to use orthonormal projections.

• **kwds – optional keyword parameters that are passed to all graphics objects.

OUTPUT:

A (multipart) graphics object.

EXAMPLES:

sage: square = polytopes.hypercube(2)
sage: point = Polyhedron([[1,1]])
sage: line = Polyhedron([[1,1],[2,1]])
sage: cube = polytopes.hypercube(3)
sage: hypercube = polytopes.hypercube(4)


By default, the wireframe is rendered in blue and the fill in green:

sage: square.plot()  # optional - sage.plot
Graphics object consisting of 6 graphics primitives
sage: point.plot()  # optional - sage.plot
Graphics object consisting of 1 graphics primitive
sage: line.plot()  # optional - sage.plot
Graphics object consisting of 2 graphics primitives
sage: cube.plot()  # optional - sage.plot
Graphics3d Object
sage: hypercube.plot()  # optional - sage.plot
Graphics3d Object


Draw the lines in red and nothing else:

sage: square.plot(point=False, line='red', polygon=False)  # optional - sage.plot
Graphics object consisting of 4 graphics primitives
sage: point.plot(point=False, line='red', polygon=False)  # optional - sage.plot
Graphics object consisting of 0 graphics primitives
sage: line.plot(point=False, line='red', polygon=False)  # optional - sage.plot
Graphics object consisting of 1 graphics primitive
sage: cube.plot(point=False, line='red', polygon=False)  # optional - sage.plot
Graphics3d Object
sage: hypercube.plot(point=False, line='red', polygon=False)  # optional - sage.plot
Graphics3d Object


Draw points in red, no lines, and a blue polygon:

sage: square.plot(point={'color':'red'}, line=False, polygon=(0,0,1))  # optional - sage.plot
Graphics object consisting of 2 graphics primitives
sage: point.plot(point={'color':'red'}, line=False, polygon=(0,0,1))  # optional - sage.plot
Graphics object consisting of 1 graphics primitive
sage: line.plot(point={'color':'red'}, line=False, polygon=(0,0,1))  # optional - sage.plot
Graphics object consisting of 1 graphics primitive
sage: cube.plot(point={'color':'red'}, line=False, polygon=(0,0,1))  # optional - sage.plot
Graphics3d Object
sage: hypercube.plot(point={'color':'red'}, line=False, polygon=(0,0,1))  # optional - sage.plot
Graphics3d Object


If we instead use the fill and wireframe options, the coloring depends on the dimension of the object:

sage: square.plot(fill='green', wireframe='red')  # optional - sage.plot
Graphics object consisting of 6 graphics primitives
sage: point.plot(fill='green', wireframe='red')  # optional - sage.plot
Graphics object consisting of 1 graphics primitive
sage: line.plot(fill='green', wireframe='red')  # optional - sage.plot
Graphics object consisting of 2 graphics primitives
sage: cube.plot(fill='green', wireframe='red')  # optional - sage.plot
Graphics3d Object
sage: hypercube.plot(fill='green', wireframe='red')  # optional - sage.plot
Graphics3d Object


It is possible to draw polyhedra up to dimension 4, no matter what the ambient dimension is:

sage: hcube = polytopes.hypercube(5)
sage: facet = hcube.facets()[0].as_polyhedron();facet
A 4-dimensional polyhedron in ZZ^5 defined as the convex hull of 16 vertices
sage: facet.plot()  # optional - sage.plot
Graphics3d Object


For a 3d plot, we may draw the polygons with rainbow colors, using any of the following ways:

sage: cube.plot(polygon='rainbow')  # optional - sage.plot
Graphics3d Object
sage: cube.plot(polygon={'color':'rainbow'})  # optional - sage.plot
Graphics3d Object
sage: cube.plot(fill='rainbow')  # optional - sage.plot
Graphics3d Object


For a 3d plot, the size of a point, the thickness of a line and the width of an arrow are controlled by the respective parameters:

sage: prism = Polyhedron(vertices=[[0,0,0],[1,0,0],[0,1,0]], rays=[[0,0,1]])
sage: prism.plot(size=20, thickness=30, width=1)  # optional - sage.plot
Graphics3d Object
sage: prism.plot(point={'size':20, 'color':'black'}, line={'thickness':30, 'width':1, 'color':'black'}, polygon='rainbow')  # optional - sage.plot
Graphics3d Object

projection(projection=None)#

Return a projection object.

INPUT:

• proj – a projection function

OUTPUT:

The identity projection. This is useful for plotting polyhedra.

schlegel_projection() for a more interesting projection.

EXAMPLES:

sage: p = polytopes.hypercube(3)
sage: proj = p.projection()
sage: proj
The projection of a polyhedron into 3 dimensions

render_solid(**kwds)#

Return a solid rendering of a 2- or 3-d polytope.

EXAMPLES:

sage: p = polytopes.hypercube(3)
sage: p_solid = p.render_solid(opacity = .7)
sage: type(p_solid)
<class 'sage.plot.plot3d.index_face_set.IndexFaceSet'>

render_wireframe(**kwds)#

For polytopes in 2 or 3 dimensions, return the edges as a list of lines.

EXAMPLES:

sage: p = Polyhedron([[1,2,],[1,1],[0,0]])
sage: p_wireframe = p.render_wireframe()
sage: p_wireframe._objects
[Line defined by 2 points, Line defined by 2 points, Line defined by 2 points]

schlegel_projection(facet=None, position=None)#

Return the Schlegel projection.

• The facet is orthonormally transformed into its affine hull.

• The position specifies a point coming out of the barycenter of the facet from which the other vertices will be projected into the facet.

INPUT:

• facet – a PolyhedronFace. The facet into which the Schlegel diagram is created. The default is the first facet.

• position – a positive number. Determines a relative distance from the barycenter of facet. A value close to 0 will place the projection point close to the facet and a large value further away. Default is $$1$$. If the given value is too large, an error is returned.

OUTPUT:

A Projection object.

EXAMPLES:

sage: p = polytopes.hypercube(3)
sage: sch_proj = p.schlegel_projection()
sage: schlegel_edge_indices = sch_proj.lines
sage: schlegel_edges = [sch_proj.coordinates_of(x) for x in schlegel_edge_indices]
sage: len([x for x in schlegel_edges if x[0][0] > 0])
8


The Schlegel projection preserves the convexity of facets, see trac ticket #30015:

sage: fcube = polytopes.hypercube(4)
sage: tfcube = fcube.face_truncation(fcube.faces(0)[0])
sage: tfcube.facets()[-1]
A 3-dimensional face of a Polyhedron in QQ^4 defined as the convex hull of 8 vertices
sage: sp = tfcube.schlegel_projection(tfcube.facets()[-1])
sage: sp.plot()  # optional - sage.plot
Graphics3d Object


The same truncated cube but see inside the tetrahedral facet:

sage: tfcube.facets()[4]
A 3-dimensional face of a Polyhedron in QQ^4 defined as the convex hull of 4 vertices
sage: sp = tfcube.schlegel_projection(tfcube.facets()[4])
sage: sp.plot()  # optional - sage.plot
Graphics3d Object


A different values of position changes the projection:

sage: sp = tfcube.schlegel_projection(tfcube.facets()[4],1/2)
sage: sp.plot()  # optional - sage.plot
Graphics3d Object
sage: sp = tfcube.schlegel_projection(tfcube.facets()[4],4)
sage: sp.plot()  # optional - sage.plot
Graphics3d Object


A value which is too large give a projection point that sees more than one facet resulting in a error:

sage: sp = tfcube.schlegel_projection(tfcube.facets()[4],5)
Traceback (most recent call last):
...
ValueError: the chosen position is too large

show(**kwds)#

Display graphics immediately

This method attempts to display the graphics immediately, without waiting for the currently running code (if any) to return to the command line. Be careful, calling it from within a loop will potentially launch a large number of external viewer programs.

INPUT:

• kwds – optional keyword arguments. See plot() for the description of available options.

OUTPUT:

This method does not return anything. Use plot() if you want to generate a graphics object that can be saved or further transformed.

EXAMPLES:

sage: square = polytopes.hypercube(2)
sage: square.show(point='red')         # optional - sage.plot

tikz(view=[0, 0, 1], angle=0, scale=1, edge_color='blue!95!black', facet_color='blue!95!black', opacity=0.8, vertex_color='green', axis=False)#

Return a string tikz_pic consisting of a tikz picture of self according to a projection view and an angle angle obtained via the threejs viewer. self must be bounded.

INPUT:

• view - list (default: [0,0,1]) representing the rotation axis (see note below).

• angle - integer (default: 0) angle of rotation in degree from 0 to 360 (see note below).

• scale - integer (default: 1) specifying the scaling of the tikz picture.

• edge_color - string (default: ‘blue!95!black’) representing colors which tikz recognize.

• facet_color - string (default: ‘blue!95!black’) representing colors which tikz recognize.

• vertex_color - string (default: ‘green’) representing colors which tikz recognize.

• opacity - real number (default: 0.8) between 0 and 1 giving the opacity of the front facets.

• axis - Boolean (default: False) draw the axes at the origin or not.

OUTPUT:

• LatexExpr – containing the TikZ picture.

Note

This is a wrapper of a method of the projection object self.projection(). See tikz() for more detail.

The inputs view and angle can be obtained by visualizing it using .show(aspect_ratio=1). This will open an interactive view in your default browser, where you can rotate the polytope. Once the desired view angle is found, click on the information icon in the lower right-hand corner and select Get Viewpoint. This will copy a string of the form ‘[x,y,z],angle’ to your local clipboard. Go back to Sage and type Img = P.tikz([x,y,z],angle).

The inputs view and angle can also be obtained from the viewer Jmol:

1) Right click on the image
2) Select Console
3) Select the tab State
4) Scroll to the line moveto


moveto 0.0 {x y z angle} Scale


The view is then [x,y,z] and angle is angle. The following number is the scale.

Jmol performs a rotation of angle degrees along the vector [x,y,z] and show the result from the z-axis.

EXAMPLES:

sage: co = polytopes.cuboctahedron()
sage: Img = co.tikz([0,0,1], 0)
sage: print('\n'.join(Img.splitlines()[:9]))
\begin{tikzpicture}%
[x={(1.000000cm, 0.000000cm)},
y={(0.000000cm, 1.000000cm)},
z={(0.000000cm, 0.000000cm)},
scale=1.000000,
back/.style={loosely dotted, thin},
edge/.style={color=blue!95!black, thick},
facet/.style={fill=blue!95!black,fill opacity=0.800000},
vertex/.style={inner sep=1pt,circle,draw=green!25!black,fill=green!75!black,thick}]
sage: print('\n'.join(Img.splitlines()[12:21]))
%% with the command: ._tikz_3d_in_3d and parameters:
%% view = [0, 0, 1]
%% angle = 0
%% scale = 1
%% edge_color = blue!95!black
%% facet_color = blue!95!black
%% opacity = 0.8
%% vertex_color = green
%% axis = False
sage: print('\n'.join(Img.splitlines()[22:26]))
%% Coordinate of the vertices:
%%
\coordinate (-1.00000, -1.00000, 0.00000) at (-1.00000, -1.00000, 0.00000);
\coordinate (-1.00000, 0.00000, -1.00000) at (-1.00000, 0.00000, -1.00000);