passagemath-graphs 10.6.1rc1__cp310-cp310-musllinux_1_2_aarch64.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.
- passagemath_graphs-10.6.1rc1.dist-info/METADATA +292 -0
- passagemath_graphs-10.6.1rc1.dist-info/RECORD +260 -0
- passagemath_graphs-10.6.1rc1.dist-info/WHEEL +5 -0
- passagemath_graphs-10.6.1rc1.dist-info/top_level.txt +2 -0
- passagemath_graphs.libs/libgcc_s-69c45f16.so.1 +0 -0
- passagemath_graphs.libs/libgmp-8e78bd9b.so.10.5.0 +0 -0
- passagemath_graphs.libs/libstdc++-1f1a71be.so.6.0.33 +0 -0
- sage/all__sagemath_graphs.py +39 -0
- sage/combinat/abstract_tree.py +2723 -0
- sage/combinat/all__sagemath_graphs.py +34 -0
- sage/combinat/binary_tree.py +5306 -0
- sage/combinat/cluster_algebra_quiver/all.py +22 -0
- sage/combinat/cluster_algebra_quiver/cluster_seed.py +5208 -0
- sage/combinat/cluster_algebra_quiver/interact.py +124 -0
- sage/combinat/cluster_algebra_quiver/mutation_class.py +625 -0
- sage/combinat/cluster_algebra_quiver/mutation_type.py +1555 -0
- sage/combinat/cluster_algebra_quiver/quiver.py +2290 -0
- sage/combinat/cluster_algebra_quiver/quiver_mutation_type.py +2468 -0
- sage/combinat/designs/MOLS_handbook_data.py +570 -0
- sage/combinat/designs/all.py +58 -0
- sage/combinat/designs/bibd.py +1655 -0
- sage/combinat/designs/block_design.py +1071 -0
- sage/combinat/designs/covering_array.py +269 -0
- sage/combinat/designs/covering_design.py +530 -0
- sage/combinat/designs/database.py +5615 -0
- sage/combinat/designs/design_catalog.py +122 -0
- sage/combinat/designs/designs_pyx.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/combinat/designs/designs_pyx.pxd +21 -0
- sage/combinat/designs/designs_pyx.pyx +993 -0
- sage/combinat/designs/difference_family.py +3951 -0
- sage/combinat/designs/difference_matrices.py +279 -0
- sage/combinat/designs/evenly_distributed_sets.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/combinat/designs/evenly_distributed_sets.pyx +661 -0
- sage/combinat/designs/ext_rep.py +1064 -0
- sage/combinat/designs/gen_quadrangles_with_spread.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/combinat/designs/gen_quadrangles_with_spread.pyx +339 -0
- sage/combinat/designs/group_divisible_designs.py +361 -0
- sage/combinat/designs/incidence_structures.py +2357 -0
- sage/combinat/designs/latin_squares.py +581 -0
- sage/combinat/designs/orthogonal_arrays.py +2244 -0
- sage/combinat/designs/orthogonal_arrays_build_recursive.py +1780 -0
- sage/combinat/designs/orthogonal_arrays_find_recursive.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/combinat/designs/orthogonal_arrays_find_recursive.pyx +967 -0
- sage/combinat/designs/resolvable_bibd.py +815 -0
- sage/combinat/designs/steiner_quadruple_systems.py +1306 -0
- sage/combinat/designs/subhypergraph_search.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/combinat/designs/subhypergraph_search.pyx +530 -0
- sage/combinat/designs/twographs.py +306 -0
- sage/combinat/finite_state_machine.py +14874 -0
- sage/combinat/finite_state_machine_generators.py +2006 -0
- sage/combinat/graph_path.py +448 -0
- sage/combinat/interval_posets.py +3908 -0
- sage/combinat/nu_tamari_lattice.py +269 -0
- sage/combinat/ordered_tree.py +1446 -0
- sage/combinat/posets/all.py +46 -0
- sage/combinat/posets/bubble_shuffle.py +247 -0
- sage/combinat/posets/cartesian_product.py +493 -0
- sage/combinat/posets/d_complete.py +182 -0
- sage/combinat/posets/elements.py +273 -0
- sage/combinat/posets/forest.py +30 -0
- sage/combinat/posets/hasse_cython.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/combinat/posets/hasse_cython.pyx +174 -0
- sage/combinat/posets/hasse_diagram.py +3672 -0
- sage/combinat/posets/hochschild_lattice.py +158 -0
- sage/combinat/posets/incidence_algebras.py +794 -0
- sage/combinat/posets/lattices.py +5117 -0
- sage/combinat/posets/linear_extension_iterator.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/combinat/posets/linear_extension_iterator.pyx +292 -0
- sage/combinat/posets/linear_extensions.py +1037 -0
- sage/combinat/posets/mobile.py +275 -0
- sage/combinat/posets/moebius_algebra.py +776 -0
- sage/combinat/posets/poset_examples.py +2178 -0
- sage/combinat/posets/posets.py +9360 -0
- sage/combinat/rooted_tree.py +1070 -0
- sage/combinat/shard_order.py +239 -0
- sage/combinat/tamari_lattices.py +384 -0
- sage/combinat/yang_baxter_graph.py +923 -0
- sage/databases/all__sagemath_graphs.py +1 -0
- sage/databases/knotinfo_db.py +1231 -0
- sage/ext_data/all__sagemath_graphs.py +1 -0
- sage/ext_data/graphs/graph_plot_js.html +330 -0
- sage/ext_data/kenzo/CP2.txt +45 -0
- sage/ext_data/kenzo/CP3.txt +349 -0
- sage/ext_data/kenzo/CP4.txt +4774 -0
- sage/ext_data/kenzo/README.txt +49 -0
- sage/ext_data/kenzo/S4.txt +20 -0
- sage/graphs/all.py +42 -0
- sage/graphs/asteroidal_triples.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/asteroidal_triples.pyx +320 -0
- sage/graphs/base/all.py +1 -0
- sage/graphs/base/boost_graph.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/base/boost_graph.pxd +106 -0
- sage/graphs/base/boost_graph.pyx +3045 -0
- sage/graphs/base/c_graph.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/base/c_graph.pxd +106 -0
- sage/graphs/base/c_graph.pyx +5096 -0
- sage/graphs/base/dense_graph.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/base/dense_graph.pxd +28 -0
- sage/graphs/base/dense_graph.pyx +801 -0
- sage/graphs/base/graph_backends.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/base/graph_backends.pxd +5 -0
- sage/graphs/base/graph_backends.pyx +797 -0
- sage/graphs/base/overview.py +85 -0
- sage/graphs/base/sparse_graph.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/base/sparse_graph.pxd +90 -0
- sage/graphs/base/sparse_graph.pyx +1653 -0
- sage/graphs/base/static_dense_graph.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/base/static_dense_graph.pxd +5 -0
- sage/graphs/base/static_dense_graph.pyx +1032 -0
- sage/graphs/base/static_sparse_backend.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/base/static_sparse_backend.pxd +27 -0
- sage/graphs/base/static_sparse_backend.pyx +1583 -0
- sage/graphs/base/static_sparse_graph.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/base/static_sparse_graph.pxd +37 -0
- sage/graphs/base/static_sparse_graph.pyx +1375 -0
- sage/graphs/bipartite_graph.py +2732 -0
- sage/graphs/centrality.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/centrality.pyx +1038 -0
- sage/graphs/cographs.py +519 -0
- sage/graphs/comparability.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/comparability.pyx +851 -0
- sage/graphs/connectivity.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/connectivity.pxd +157 -0
- sage/graphs/connectivity.pyx +4813 -0
- sage/graphs/convexity_properties.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/convexity_properties.pxd +16 -0
- sage/graphs/convexity_properties.pyx +870 -0
- sage/graphs/digraph.py +4754 -0
- sage/graphs/digraph_generators.py +1993 -0
- sage/graphs/distances_all_pairs.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/distances_all_pairs.pxd +12 -0
- sage/graphs/distances_all_pairs.pyx +2938 -0
- sage/graphs/domination.py +1363 -0
- sage/graphs/dot2tex_utils.py +100 -0
- sage/graphs/edge_connectivity.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/edge_connectivity.pyx +1215 -0
- sage/graphs/generators/all.py +1 -0
- sage/graphs/generators/basic.py +1769 -0
- sage/graphs/generators/chessboard.py +538 -0
- sage/graphs/generators/classical_geometries.py +1611 -0
- sage/graphs/generators/degree_sequence.py +235 -0
- sage/graphs/generators/distance_regular.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/generators/distance_regular.pyx +2846 -0
- sage/graphs/generators/families.py +4759 -0
- sage/graphs/generators/intersection.py +565 -0
- sage/graphs/generators/platonic_solids.py +262 -0
- sage/graphs/generators/random.py +2623 -0
- sage/graphs/generators/smallgraphs.py +5741 -0
- sage/graphs/generators/world_map.py +724 -0
- sage/graphs/generic_graph.py +26867 -0
- sage/graphs/generic_graph_pyx.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/generic_graph_pyx.pxd +34 -0
- sage/graphs/generic_graph_pyx.pyx +1673 -0
- sage/graphs/genus.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/genus.pyx +622 -0
- sage/graphs/graph.py +9645 -0
- sage/graphs/graph_coloring.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_coloring.pyx +2284 -0
- sage/graphs/graph_database.py +1177 -0
- sage/graphs/graph_decompositions/all.py +1 -0
- sage/graphs/graph_decompositions/bandwidth.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_decompositions/bandwidth.pyx +428 -0
- sage/graphs/graph_decompositions/clique_separators.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_decompositions/clique_separators.pyx +616 -0
- sage/graphs/graph_decompositions/cutwidth.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_decompositions/cutwidth.pyx +753 -0
- sage/graphs/graph_decompositions/fast_digraph.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_decompositions/fast_digraph.pxd +13 -0
- sage/graphs/graph_decompositions/fast_digraph.pyx +212 -0
- sage/graphs/graph_decompositions/graph_products.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_decompositions/graph_products.pyx +508 -0
- sage/graphs/graph_decompositions/modular_decomposition.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_decompositions/modular_decomposition.pxd +27 -0
- sage/graphs/graph_decompositions/modular_decomposition.pyx +1536 -0
- sage/graphs/graph_decompositions/slice_decomposition.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_decompositions/slice_decomposition.pxd +18 -0
- sage/graphs/graph_decompositions/slice_decomposition.pyx +1106 -0
- sage/graphs/graph_decompositions/tree_decomposition.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_decompositions/tree_decomposition.pxd +17 -0
- sage/graphs/graph_decompositions/tree_decomposition.pyx +1996 -0
- sage/graphs/graph_decompositions/vertex_separation.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_decompositions/vertex_separation.pxd +5 -0
- sage/graphs/graph_decompositions/vertex_separation.pyx +1963 -0
- sage/graphs/graph_editor.py +82 -0
- sage/graphs/graph_generators.py +3314 -0
- sage/graphs/graph_generators_pyx.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_generators_pyx.pyx +95 -0
- sage/graphs/graph_input.py +812 -0
- sage/graphs/graph_latex.py +2064 -0
- sage/graphs/graph_list.py +410 -0
- sage/graphs/graph_plot.py +1756 -0
- sage/graphs/graph_plot_js.py +338 -0
- sage/graphs/hyperbolicity.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/hyperbolicity.pyx +1704 -0
- sage/graphs/hypergraph_generators.py +364 -0
- sage/graphs/independent_sets.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/independent_sets.pxd +13 -0
- sage/graphs/independent_sets.pyx +402 -0
- sage/graphs/isgci.py +1033 -0
- sage/graphs/isoperimetric_inequalities.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/isoperimetric_inequalities.pyx +489 -0
- sage/graphs/line_graph.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/line_graph.pyx +743 -0
- sage/graphs/lovasz_theta.py +77 -0
- sage/graphs/matching.py +1633 -0
- sage/graphs/matching_covered_graph.py +3590 -0
- sage/graphs/orientations.py +1489 -0
- sage/graphs/partial_cube.py +459 -0
- sage/graphs/path_enumeration.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/path_enumeration.pyx +2040 -0
- sage/graphs/pq_trees.py +1129 -0
- sage/graphs/print_graphs.py +201 -0
- sage/graphs/schnyder.py +865 -0
- sage/graphs/spanning_tree.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/spanning_tree.pyx +1457 -0
- sage/graphs/strongly_regular_db.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/strongly_regular_db.pyx +3340 -0
- sage/graphs/traversals.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/traversals.pxd +9 -0
- sage/graphs/traversals.pyx +1872 -0
- sage/graphs/trees.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/trees.pxd +15 -0
- sage/graphs/trees.pyx +310 -0
- sage/graphs/tutte_polynomial.py +713 -0
- sage/graphs/views.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/views.pyx +794 -0
- sage/graphs/weakly_chordal.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/weakly_chordal.pyx +604 -0
- sage/groups/all__sagemath_graphs.py +1 -0
- sage/groups/perm_gps/all__sagemath_graphs.py +1 -0
- sage/groups/perm_gps/partn_ref/all__sagemath_graphs.py +1 -0
- sage/groups/perm_gps/partn_ref/refinement_graphs.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/groups/perm_gps/partn_ref/refinement_graphs.pxd +38 -0
- sage/groups/perm_gps/partn_ref/refinement_graphs.pyx +1666 -0
- sage/knots/all.py +6 -0
- sage/knots/free_knotinfo_monoid.py +507 -0
- sage/knots/gauss_code.py +291 -0
- sage/knots/knot.py +682 -0
- sage/knots/knot_table.py +284 -0
- sage/knots/knotinfo.py +2900 -0
- sage/knots/link.py +4715 -0
- sage/sandpiles/all.py +13 -0
- sage/sandpiles/examples.py +225 -0
- sage/sandpiles/sandpile.py +6365 -0
- sage/topology/all.py +22 -0
- sage/topology/cell_complex.py +1214 -0
- sage/topology/cubical_complex.py +1976 -0
- sage/topology/delta_complex.py +1806 -0
- sage/topology/filtered_simplicial_complex.py +744 -0
- sage/topology/moment_angle_complex.py +823 -0
- sage/topology/simplicial_complex.py +5160 -0
- sage/topology/simplicial_complex_catalog.py +92 -0
- sage/topology/simplicial_complex_examples.py +1680 -0
- sage/topology/simplicial_complex_homset.py +205 -0
- sage/topology/simplicial_complex_morphism.py +836 -0
- sage/topology/simplicial_set.py +4102 -0
- sage/topology/simplicial_set_catalog.py +55 -0
- sage/topology/simplicial_set_constructions.py +2954 -0
- sage/topology/simplicial_set_examples.py +865 -0
- sage/topology/simplicial_set_morphism.py +1464 -0
@@ -0,0 +1,2064 @@
|
|
1
|
+
# sage_setup: distribution = sagemath-graphs
|
2
|
+
# sage.doctest: needs sage.plot
|
3
|
+
r"""
|
4
|
+
LaTeX options for graphs
|
5
|
+
|
6
|
+
This module provides a class to hold, manipulate and employ various options for
|
7
|
+
rendering a graph in LaTeX, in addition to providing the code that actually
|
8
|
+
generates a LaTeX representation of a (combinatorial) graph.
|
9
|
+
|
10
|
+
AUTHORS:
|
11
|
+
|
12
|
+
- Rob Beezer (2009-05-20): :class:`~sage.graphs.graph_latex.GraphLatex` class
|
13
|
+
- Fidel Barerra Cruz (2009-05-20): ``tkz-graph`` commands to render a graph
|
14
|
+
- Nicolas M. Thiéry (2010-02): dot2tex/graphviz interface
|
15
|
+
- Rob Beezer (2010-05-29): Extended range of ``tkz-graph`` options
|
16
|
+
|
17
|
+
LaTeX Versions of Graphs
|
18
|
+
-------------------------------------
|
19
|
+
|
20
|
+
.. image:: ../../media/heawood-graph-latex.png
|
21
|
+
:align: center
|
22
|
+
|
23
|
+
Many mathematical objects in Sage have LaTeX representations, and graphs are no
|
24
|
+
exception. For a graph ``g``, the command ``view(g)``, issued at the Sage
|
25
|
+
command line or in the notebook, will create a graphic version of ``g``.
|
26
|
+
Similarly, ``latex(g)`` will return a (long) string that is a representation of
|
27
|
+
the graph in LaTeX. Other ways of employing LaTeX in Sage, such as ``%latex``
|
28
|
+
in a notebook cell, or the Typeset checkbox in the notebook, will handle ``g``
|
29
|
+
appropriately.
|
30
|
+
|
31
|
+
Support through the ``tkz-graph`` package is by Alain Matthes, the author of
|
32
|
+
``tkz-graph``, whose work can be found at https://www.ctan.org/pkg/tkz-graph.
|
33
|
+
|
34
|
+
The range of possible options for customizing the appearance of a graph are
|
35
|
+
carefully documented at :meth:`sage.graphs.graph_latex.GraphLatex.set_option`.
|
36
|
+
As a broad overview, the following options are supported:
|
37
|
+
|
38
|
+
- Pre-built Styles: the pre-built styles of the tkz-graph package provide nice
|
39
|
+
drawings quickly
|
40
|
+
- Dimensions: can be specified in natural units, then uniformly scaled after
|
41
|
+
design work
|
42
|
+
- Vertex Colors: the perimeter and fill color for vertices can be specified,
|
43
|
+
including on a per-vertex basis
|
44
|
+
- Vertex Shapes: may be circles, shaded spheres, rectangles or diamonds,
|
45
|
+
including on a per-vertex basis
|
46
|
+
- Vertex Sizes: may be specified as minimums, and will automatically sized to
|
47
|
+
contain vertex labels, including on a per-vertex basis
|
48
|
+
- Vertex Labels: can use latex formatting, and may have their colors specified,
|
49
|
+
including on a per-vertex basis
|
50
|
+
- Vertex Label Placement: can be interior to the vertex, or external at a
|
51
|
+
configurable location
|
52
|
+
- Edge Colors: a solid color with or without a second color down the middle, on
|
53
|
+
a per-edge basis
|
54
|
+
- Edge Thickness: can be set, including on a per-edge basis
|
55
|
+
- Edge Labels: can use latex formatting, and may have their colors specified,
|
56
|
+
including on a per-edge basis
|
57
|
+
- Edge Label Placement: can be to the left, right, above, below, inline, and
|
58
|
+
then sloped or horizontal
|
59
|
+
- Digraph Edges: are slightly curved, with arrowheads
|
60
|
+
- Loops: may be specified by their size, and with a direction equaling one of
|
61
|
+
the four compass points
|
62
|
+
|
63
|
+
To use LaTeX in Sage you of course need a working TeX installation and it will
|
64
|
+
work best if you have the ``dvipng`` and ``magick`` utilities. For graphs you
|
65
|
+
need the ``tkz-graph.sty`` and ``tkz-berge.sty`` style files of the tkz-graph
|
66
|
+
package. TeX, dvipng, and convert should be widely available through package
|
67
|
+
managers or installers. You may need to install the tkz-graph style files in
|
68
|
+
the appropriate locations, a task beyond the scope of this introduction.
|
69
|
+
Primary locations for these programs are:
|
70
|
+
|
71
|
+
- TeX: http://ctan.org/
|
72
|
+
- dvipng: http://sourceforge.net/projects/dvipng/
|
73
|
+
- magick: http://www.imagemagick.org (the ImageMagick suite)
|
74
|
+
- tkz-graph: https://www.ctan.org/pkg/tkz-graph
|
75
|
+
|
76
|
+
Customizing the output is accomplished in several ways. Suppose ``g`` is a
|
77
|
+
graph, then ``g.set_latex_options()`` can be used to efficiently set or modify
|
78
|
+
various options. Setting individual options, or querying options, can be
|
79
|
+
accomplished by first using a command like ``opts = g.latex_options()`` to
|
80
|
+
obtain a :class:`sage.graphs.graph_latex.GraphLatex` object which has several
|
81
|
+
methods to set and retrieve options.
|
82
|
+
|
83
|
+
Here is a minimal session demonstrating how to use these features. The following
|
84
|
+
setup should work in the notebook or at the command-line.::
|
85
|
+
|
86
|
+
sage: H = graphs.HeawoodGraph()
|
87
|
+
sage: H.set_latex_options(
|
88
|
+
....: graphic_size=(5,5),
|
89
|
+
....: vertex_size=0.2,
|
90
|
+
....: edge_thickness=0.04,
|
91
|
+
....: edge_color='green',
|
92
|
+
....: vertex_color='green',
|
93
|
+
....: vertex_label_color='red'
|
94
|
+
....: )
|
95
|
+
|
96
|
+
At this point, ``view(H)`` should call ``pdflatex`` to process the string
|
97
|
+
created by ``latex(H)`` and then display the resulting graphic.
|
98
|
+
|
99
|
+
To use this image in a LaTeX document, you could of course just copy and save
|
100
|
+
the resulting graphic. However, the ``latex()`` command will produce the
|
101
|
+
underlying LaTeX code, which can be incorporated into a standalone LaTeX
|
102
|
+
document.::
|
103
|
+
|
104
|
+
sage: from sage.graphs.graph_latex import check_tkz_graph
|
105
|
+
sage: check_tkz_graph() # random - depends on TeX installation
|
106
|
+
sage: latex(H)
|
107
|
+
\begin{tikzpicture}
|
108
|
+
\definecolor{cv0}{rgb}{0.0,0.502,0.0}
|
109
|
+
\definecolor{cfv0}{rgb}{1.0,1.0,1.0}
|
110
|
+
\definecolor{clv0}{rgb}{1.0,0.0,0.0}
|
111
|
+
\definecolor{cv1}{rgb}{0.0,0.502,0.0}
|
112
|
+
\definecolor{cfv1}{rgb}{1.0,1.0,1.0}
|
113
|
+
\definecolor{clv1}{rgb}{1.0,0.0,0.0}
|
114
|
+
\definecolor{cv2}{rgb}{0.0,0.502,0.0}
|
115
|
+
\definecolor{cfv2}{rgb}{1.0,1.0,1.0}
|
116
|
+
\definecolor{clv2}{rgb}{1.0,0.0,0.0}
|
117
|
+
\definecolor{cv3}{rgb}{0.0,0.502,0.0}
|
118
|
+
\definecolor{cfv3}{rgb}{1.0,1.0,1.0}
|
119
|
+
\definecolor{clv3}{rgb}{1.0,0.0,0.0}
|
120
|
+
\definecolor{cv4}{rgb}{0.0,0.502,0.0}
|
121
|
+
\definecolor{cfv4}{rgb}{1.0,1.0,1.0}
|
122
|
+
\definecolor{clv4}{rgb}{1.0,0.0,0.0}
|
123
|
+
\definecolor{cv5}{rgb}{0.0,0.502,0.0}
|
124
|
+
\definecolor{cfv5}{rgb}{1.0,1.0,1.0}
|
125
|
+
\definecolor{clv5}{rgb}{1.0,0.0,0.0}
|
126
|
+
\definecolor{cv6}{rgb}{0.0,0.502,0.0}
|
127
|
+
\definecolor{cfv6}{rgb}{1.0,1.0,1.0}
|
128
|
+
\definecolor{clv6}{rgb}{1.0,0.0,0.0}
|
129
|
+
\definecolor{cv7}{rgb}{0.0,0.502,0.0}
|
130
|
+
\definecolor{cfv7}{rgb}{1.0,1.0,1.0}
|
131
|
+
\definecolor{clv7}{rgb}{1.0,0.0,0.0}
|
132
|
+
\definecolor{cv8}{rgb}{0.0,0.502,0.0}
|
133
|
+
\definecolor{cfv8}{rgb}{1.0,1.0,1.0}
|
134
|
+
\definecolor{clv8}{rgb}{1.0,0.0,0.0}
|
135
|
+
\definecolor{cv9}{rgb}{0.0,0.502,0.0}
|
136
|
+
\definecolor{cfv9}{rgb}{1.0,1.0,1.0}
|
137
|
+
\definecolor{clv9}{rgb}{1.0,0.0,0.0}
|
138
|
+
\definecolor{cv10}{rgb}{0.0,0.502,0.0}
|
139
|
+
\definecolor{cfv10}{rgb}{1.0,1.0,1.0}
|
140
|
+
\definecolor{clv10}{rgb}{1.0,0.0,0.0}
|
141
|
+
\definecolor{cv11}{rgb}{0.0,0.502,0.0}
|
142
|
+
\definecolor{cfv11}{rgb}{1.0,1.0,1.0}
|
143
|
+
\definecolor{clv11}{rgb}{1.0,0.0,0.0}
|
144
|
+
\definecolor{cv12}{rgb}{0.0,0.502,0.0}
|
145
|
+
\definecolor{cfv12}{rgb}{1.0,1.0,1.0}
|
146
|
+
\definecolor{clv12}{rgb}{1.0,0.0,0.0}
|
147
|
+
\definecolor{cv13}{rgb}{0.0,0.502,0.0}
|
148
|
+
\definecolor{cfv13}{rgb}{1.0,1.0,1.0}
|
149
|
+
\definecolor{clv13}{rgb}{1.0,0.0,0.0}
|
150
|
+
\definecolor{cv0v1}{rgb}{0.0,0.502,0.0}
|
151
|
+
\definecolor{cv0v5}{rgb}{0.0,0.502,0.0}
|
152
|
+
\definecolor{cv0v13}{rgb}{0.0,0.502,0.0}
|
153
|
+
\definecolor{cv1v2}{rgb}{0.0,0.502,0.0}
|
154
|
+
\definecolor{cv1v10}{rgb}{0.0,0.502,0.0}
|
155
|
+
\definecolor{cv2v3}{rgb}{0.0,0.502,0.0}
|
156
|
+
\definecolor{cv2v7}{rgb}{0.0,0.502,0.0}
|
157
|
+
\definecolor{cv3v4}{rgb}{0.0,0.502,0.0}
|
158
|
+
\definecolor{cv3v12}{rgb}{0.0,0.502,0.0}
|
159
|
+
\definecolor{cv4v5}{rgb}{0.0,0.502,0.0}
|
160
|
+
\definecolor{cv4v9}{rgb}{0.0,0.502,0.0}
|
161
|
+
\definecolor{cv5v6}{rgb}{0.0,0.502,0.0}
|
162
|
+
\definecolor{cv6v7}{rgb}{0.0,0.502,0.0}
|
163
|
+
\definecolor{cv6v11}{rgb}{0.0,0.502,0.0}
|
164
|
+
\definecolor{cv7v8}{rgb}{0.0,0.502,0.0}
|
165
|
+
\definecolor{cv8v9}{rgb}{0.0,0.502,0.0}
|
166
|
+
\definecolor{cv8v13}{rgb}{0.0,0.502,0.0}
|
167
|
+
\definecolor{cv9v10}{rgb}{0.0,0.502,0.0}
|
168
|
+
\definecolor{cv10v11}{rgb}{0.0,0.502,0.0}
|
169
|
+
\definecolor{cv11v12}{rgb}{0.0,0.502,0.0}
|
170
|
+
\definecolor{cv12v13}{rgb}{0.0,0.502,0.0}
|
171
|
+
%
|
172
|
+
\Vertex[style={minimum size=0.2cm,draw=cv0,fill=cfv0,text=clv0,shape=circle},LabelOut=false,L=\hbox{$0$},x=2.5cm,y=5.0cm]{v0}
|
173
|
+
\Vertex[style={minimum size=0.2cm,draw=cv1,fill=cfv1,text=clv1,shape=circle},LabelOut=false,L=\hbox{$1$},x=1.3874cm,y=4.7524cm]{v1}
|
174
|
+
\Vertex[style={minimum size=0.2cm,draw=cv2,fill=cfv2,text=clv2,shape=circle},LabelOut=false,L=\hbox{$2$},x=0.4952cm,y=4.0587cm]{v2}
|
175
|
+
\Vertex[style={minimum size=0.2cm,draw=cv3,fill=cfv3,text=clv3,shape=circle},LabelOut=false,L=\hbox{$3$},x=0.0cm,y=3.0563cm]{v3}
|
176
|
+
\Vertex[style={minimum size=0.2cm,draw=cv4,fill=cfv4,text=clv4,shape=circle},LabelOut=false,L=\hbox{$4$},x=0.0cm,y=1.9437cm]{v4}
|
177
|
+
\Vertex[style={minimum size=0.2cm,draw=cv5,fill=cfv5,text=clv5,shape=circle},LabelOut=false,L=\hbox{$5$},x=0.4952cm,y=0.9413cm]{v5}
|
178
|
+
\Vertex[style={minimum size=0.2cm,draw=cv6,fill=cfv6,text=clv6,shape=circle},LabelOut=false,L=\hbox{$6$},x=1.3874cm,y=0.2476cm]{v6}
|
179
|
+
\Vertex[style={minimum size=0.2cm,draw=cv7,fill=cfv7,text=clv7,shape=circle},LabelOut=false,L=\hbox{$7$},x=2.5cm,y=0.0cm]{v7}
|
180
|
+
\Vertex[style={minimum size=0.2cm,draw=cv8,fill=cfv8,text=clv8,shape=circle},LabelOut=false,L=\hbox{$8$},x=3.6126cm,y=0.2476cm]{v8}
|
181
|
+
\Vertex[style={minimum size=0.2cm,draw=cv9,fill=cfv9,text=clv9,shape=circle},LabelOut=false,L=\hbox{$9$},x=4.5048cm,y=0.9413cm]{v9}
|
182
|
+
\Vertex[style={minimum size=0.2cm,draw=cv10,fill=cfv10,text=clv10,shape=circle},LabelOut=false,L=\hbox{$10$},x=5.0cm,y=1.9437cm]{v10}
|
183
|
+
\Vertex[style={minimum size=0.2cm,draw=cv11,fill=cfv11,text=clv11,shape=circle},LabelOut=false,L=\hbox{$11$},x=5.0cm,y=3.0563cm]{v11}
|
184
|
+
\Vertex[style={minimum size=0.2cm,draw=cv12,fill=cfv12,text=clv12,shape=circle},LabelOut=false,L=\hbox{$12$},x=4.5048cm,y=4.0587cm]{v12}
|
185
|
+
\Vertex[style={minimum size=0.2cm,draw=cv13,fill=cfv13,text=clv13,shape=circle},LabelOut=false,L=\hbox{$13$},x=3.6126cm,y=4.7524cm]{v13}
|
186
|
+
%
|
187
|
+
\Edge[lw=0.04cm,style={color=cv0v1,},](v0)(v1)
|
188
|
+
\Edge[lw=0.04cm,style={color=cv0v5,},](v0)(v5)
|
189
|
+
\Edge[lw=0.04cm,style={color=cv0v13,},](v0)(v13)
|
190
|
+
\Edge[lw=0.04cm,style={color=cv1v2,},](v1)(v2)
|
191
|
+
\Edge[lw=0.04cm,style={color=cv1v10,},](v1)(v10)
|
192
|
+
\Edge[lw=0.04cm,style={color=cv2v3,},](v2)(v3)
|
193
|
+
\Edge[lw=0.04cm,style={color=cv2v7,},](v2)(v7)
|
194
|
+
\Edge[lw=0.04cm,style={color=cv3v4,},](v3)(v4)
|
195
|
+
\Edge[lw=0.04cm,style={color=cv3v12,},](v3)(v12)
|
196
|
+
\Edge[lw=0.04cm,style={color=cv4v5,},](v4)(v5)
|
197
|
+
\Edge[lw=0.04cm,style={color=cv4v9,},](v4)(v9)
|
198
|
+
\Edge[lw=0.04cm,style={color=cv5v6,},](v5)(v6)
|
199
|
+
\Edge[lw=0.04cm,style={color=cv6v7,},](v6)(v7)
|
200
|
+
\Edge[lw=0.04cm,style={color=cv6v11,},](v6)(v11)
|
201
|
+
\Edge[lw=0.04cm,style={color=cv7v8,},](v7)(v8)
|
202
|
+
\Edge[lw=0.04cm,style={color=cv8v9,},](v8)(v9)
|
203
|
+
\Edge[lw=0.04cm,style={color=cv8v13,},](v8)(v13)
|
204
|
+
\Edge[lw=0.04cm,style={color=cv9v10,},](v9)(v10)
|
205
|
+
\Edge[lw=0.04cm,style={color=cv10v11,},](v10)(v11)
|
206
|
+
\Edge[lw=0.04cm,style={color=cv11v12,},](v11)(v12)
|
207
|
+
\Edge[lw=0.04cm,style={color=cv12v13,},](v12)(v13)
|
208
|
+
%
|
209
|
+
\end{tikzpicture}
|
210
|
+
|
211
|
+
EXAMPLES:
|
212
|
+
|
213
|
+
This example illustrates switching between the built-in styles when using the
|
214
|
+
tkz_graph format.::
|
215
|
+
|
216
|
+
sage: g = graphs.PetersenGraph()
|
217
|
+
sage: g.set_latex_options(tkz_style='Classic')
|
218
|
+
sage: from sage.graphs.graph_latex import check_tkz_graph
|
219
|
+
sage: check_tkz_graph() # random - depends on TeX installation
|
220
|
+
sage: latex(g)
|
221
|
+
\begin{tikzpicture}
|
222
|
+
\GraphInit[vstyle=Classic]
|
223
|
+
...
|
224
|
+
\end{tikzpicture}
|
225
|
+
sage: opts = g.latex_options()
|
226
|
+
sage: opts
|
227
|
+
LaTeX options for Petersen graph: {'tkz_style': 'Classic'}
|
228
|
+
sage: g.set_latex_options(tkz_style = 'Art')
|
229
|
+
sage: opts.get_option('tkz_style')
|
230
|
+
'Art'
|
231
|
+
sage: opts
|
232
|
+
LaTeX options for Petersen graph: {'tkz_style': 'Art'}
|
233
|
+
sage: latex(g)
|
234
|
+
\begin{tikzpicture}
|
235
|
+
\GraphInit[vstyle=Art]
|
236
|
+
...
|
237
|
+
\end{tikzpicture}
|
238
|
+
|
239
|
+
This example illustrates using the optional dot2tex module::
|
240
|
+
|
241
|
+
sage: g = graphs.PetersenGraph()
|
242
|
+
sage: g.set_latex_options(format='dot2tex', prog='neato')
|
243
|
+
sage: from sage.graphs.graph_latex import check_tkz_graph
|
244
|
+
sage: check_tkz_graph() # random - depends on TeX installation
|
245
|
+
sage: latex(g) # optional - dot2tex graphviz
|
246
|
+
\begin{tikzpicture}[>=latex,line join=bevel,]
|
247
|
+
...
|
248
|
+
\end{tikzpicture}
|
249
|
+
|
250
|
+
Among other things, this supports the flexible ``edge_options`` option
|
251
|
+
(see :meth:`sage.graphs.generic_graph.GenericGraph.graphviz_string`);
|
252
|
+
here we color in red all edges touching the vertex ``0``::
|
253
|
+
|
254
|
+
sage: g = graphs.PetersenGraph()
|
255
|
+
sage: g.set_latex_options(format='dot2tex', edge_options=lambda u_v_label: {"color": "red"} if u_v_label[0] == 0 else {})
|
256
|
+
sage: latex(g) # optional - dot2tex graphviz
|
257
|
+
\begin{tikzpicture}[>=latex,line join=bevel,]
|
258
|
+
...
|
259
|
+
\end{tikzpicture}
|
260
|
+
|
261
|
+
|
262
|
+
TESTS:
|
263
|
+
|
264
|
+
This graph will look horrible, but it illustrates (and tests) a great variety of
|
265
|
+
the possible options available through Sage's interface to the ``tkz-graph``
|
266
|
+
package. So it is worth viewing this in the notebook to see the effects of
|
267
|
+
various defaults and choices.::
|
268
|
+
|
269
|
+
sage: # needs sage.symbolic
|
270
|
+
sage: var('x y u w')
|
271
|
+
(x, y, u, w)
|
272
|
+
sage: G = Graph(loops=True)
|
273
|
+
sage: for i in range(5):
|
274
|
+
....: for j in range(i+1, 5):
|
275
|
+
....: G.add_edge((i, j), label=(x^i*y^j).expand())
|
276
|
+
sage: G.add_edge((0,0), label=sin(u))
|
277
|
+
sage: G.add_edge((4,4), label=w^5)
|
278
|
+
sage: G.set_pos(G.layout_circular())
|
279
|
+
sage: G.set_latex_options(
|
280
|
+
....: units='in',
|
281
|
+
....: graphic_size=(8,8),
|
282
|
+
....: margins=(1,2,2,1),
|
283
|
+
....: scale=0.5,
|
284
|
+
....: vertex_color='0.8',
|
285
|
+
....: vertex_colors={1:'aqua', 3:'y', 4:'#0000FF'},
|
286
|
+
....: vertex_fill_color='blue',
|
287
|
+
....: vertex_fill_colors={1:'green', 3:'b', 4:'#FF00FF'},
|
288
|
+
....: vertex_label_color='brown',
|
289
|
+
....: vertex_label_colors={0:'g',1:'purple',2:'#007F00'},
|
290
|
+
....: vertex_shape='diamond',
|
291
|
+
....: vertex_shapes={1:'rectangle', 2:'sphere', 3:'sphere', 4:'circle'},
|
292
|
+
....: vertex_size=0.3,
|
293
|
+
....: vertex_sizes={0:1.0, 2:0.3, 4:1.0},
|
294
|
+
....: vertex_label_placements = {2:(0.6, 180), 4:(0,45)},
|
295
|
+
....: edge_color='purple',
|
296
|
+
....: edge_colors={(0,2):'g',(3,4):'red'},
|
297
|
+
....: edge_fills=True,
|
298
|
+
....: edge_fill_color='green',
|
299
|
+
....: edge_label_colors={(2,3):'y',(0,4):'blue'},
|
300
|
+
....: edge_thickness=0.05,
|
301
|
+
....: edge_thicknesses={(3,4):0.2, (0,4):0.02},
|
302
|
+
....: edge_labels=True,
|
303
|
+
....: edge_label_sloped=True,
|
304
|
+
....: edge_label_slopes={(0,3):False, (2,4):False},
|
305
|
+
....: edge_label_placement=0.50,
|
306
|
+
....: edge_label_placements={(0,4):'above', (2,3):'left', (0,0):'above', (4,4):'below'},
|
307
|
+
....: loop_placement=(2.0, 'NO'),
|
308
|
+
....: loop_placements={4:(8.0, 'EA')}
|
309
|
+
....: )
|
310
|
+
sage: from sage.graphs.graph_latex import check_tkz_graph
|
311
|
+
sage: check_tkz_graph() # random - depends on TeX installation
|
312
|
+
sage: print(latex(G))
|
313
|
+
\begin{tikzpicture}
|
314
|
+
\definecolor{cv0}{rgb}{0.8,0.8,0.8}
|
315
|
+
\definecolor{cfv0}{rgb}{0.0,0.0,1.0}
|
316
|
+
\definecolor{clv0}{rgb}{0.0,0.5,0.0}
|
317
|
+
\definecolor{cv1}{rgb}{0.0,1.0,1.0}
|
318
|
+
\definecolor{cfv1}{rgb}{0.0,0.502,0.0}
|
319
|
+
\definecolor{clv1}{rgb}{0.502,0.0,0.502}
|
320
|
+
\definecolor{cv2}{rgb}{0.8,0.8,0.8}
|
321
|
+
\definecolor{cfv2}{rgb}{0.0,0.0,1.0}
|
322
|
+
\definecolor{clv2}{rgb}{0.0,0.498,0.0}
|
323
|
+
\definecolor{cv3}{rgb}{0.75,0.75,0.0}
|
324
|
+
\definecolor{cfv3}{rgb}{0.0,0.0,1.0}
|
325
|
+
\definecolor{clv3}{rgb}{0.6471,0.1647,0.1647}
|
326
|
+
\definecolor{cv4}{rgb}{0.0,0.0,1.0}
|
327
|
+
\definecolor{cfv4}{rgb}{1.0,0.0,1.0}
|
328
|
+
\definecolor{clv4}{rgb}{0.6471,0.1647,0.1647}
|
329
|
+
\definecolor{cv0v0}{rgb}{0.502,0.0,0.502}
|
330
|
+
\definecolor{cfv0v0}{rgb}{0.0,0.502,0.0}
|
331
|
+
\definecolor{clv0v0}{rgb}{0.0,0.0,0.0}
|
332
|
+
\definecolor{cv0v1}{rgb}{0.502,0.0,0.502}
|
333
|
+
\definecolor{cfv0v1}{rgb}{0.0,0.502,0.0}
|
334
|
+
\definecolor{clv0v1}{rgb}{0.0,0.0,0.0}
|
335
|
+
\definecolor{cv0v2}{rgb}{0.0,0.5,0.0}
|
336
|
+
\definecolor{cfv0v2}{rgb}{0.0,0.502,0.0}
|
337
|
+
\definecolor{clv0v2}{rgb}{0.0,0.0,0.0}
|
338
|
+
\definecolor{cv0v3}{rgb}{0.502,0.0,0.502}
|
339
|
+
\definecolor{cfv0v3}{rgb}{0.0,0.502,0.0}
|
340
|
+
\definecolor{clv0v3}{rgb}{0.0,0.0,0.0}
|
341
|
+
\definecolor{cv0v4}{rgb}{0.502,0.0,0.502}
|
342
|
+
\definecolor{cfv0v4}{rgb}{0.0,0.502,0.0}
|
343
|
+
\definecolor{clv0v4}{rgb}{0.0,0.0,1.0}
|
344
|
+
\definecolor{cv1v2}{rgb}{0.502,0.0,0.502}
|
345
|
+
\definecolor{cfv1v2}{rgb}{0.0,0.502,0.0}
|
346
|
+
\definecolor{clv1v2}{rgb}{0.0,0.0,0.0}
|
347
|
+
\definecolor{cv1v3}{rgb}{0.502,0.0,0.502}
|
348
|
+
\definecolor{cfv1v3}{rgb}{0.0,0.502,0.0}
|
349
|
+
\definecolor{clv1v3}{rgb}{0.0,0.0,0.0}
|
350
|
+
\definecolor{cv1v4}{rgb}{0.502,0.0,0.502}
|
351
|
+
\definecolor{cfv1v4}{rgb}{0.0,0.502,0.0}
|
352
|
+
\definecolor{clv1v4}{rgb}{0.0,0.0,0.0}
|
353
|
+
\definecolor{cv2v3}{rgb}{0.502,0.0,0.502}
|
354
|
+
\definecolor{cfv2v3}{rgb}{0.0,0.502,0.0}
|
355
|
+
\definecolor{clv2v3}{rgb}{0.75,0.75,0.0}
|
356
|
+
\definecolor{cv2v4}{rgb}{0.502,0.0,0.502}
|
357
|
+
\definecolor{cfv2v4}{rgb}{0.0,0.502,0.0}
|
358
|
+
\definecolor{clv2v4}{rgb}{0.0,0.0,0.0}
|
359
|
+
\definecolor{cv3v4}{rgb}{1.0,0.0,0.0}
|
360
|
+
\definecolor{cfv3v4}{rgb}{0.0,0.502,0.0}
|
361
|
+
\definecolor{clv3v4}{rgb}{0.0,0.0,0.0}
|
362
|
+
\definecolor{cv4v4}{rgb}{0.502,0.0,0.502}
|
363
|
+
\definecolor{cfv4v4}{rgb}{0.0,0.502,0.0}
|
364
|
+
\definecolor{clv4v4}{rgb}{0.0,0.0,0.0}
|
365
|
+
%
|
366
|
+
\Vertex[style={minimum size=0.5in,draw=cv0,fill=cfv0,text=clv0,shape=diamond},LabelOut=false,L=\hbox{$0$},x=1.75in,y=3.0in]{v0}
|
367
|
+
\Vertex[style={minimum size=0.15in,draw=cv1,fill=cfv1,text=clv1,shape=rectangle},LabelOut=false,L=\hbox{$1$},x=0.5in,y=2.0451in]{v1}
|
368
|
+
\Vertex[style={minimum size=0.15in,draw=cv2,fill=cfv2,text=clv2,shape=circle,shading=ball,line width=0pt,ball color=cv2,},LabelOut=true,Ldist=0.3in,Lpos=180.0,L=\hbox{$2$},x=0.9775in,y=0.5in]{v2}
|
369
|
+
\Vertex[style={minimum size=0.15in,draw=cv3,fill=cfv3,text=clv3,shape=circle,shading=ball,line width=0pt,ball color=cv3,},LabelOut=false,L=\hbox{$3$},x=2.5225in,y=0.5in]{v3}
|
370
|
+
\Vertex[style={minimum size=0.5in,draw=cv4,fill=cfv4,text=clv4,shape=circle},LabelOut=true,Ldist=0.0in,Lpos=45.0,L=\hbox{$4$},x=3.0in,y=2.0451in]{v4}
|
371
|
+
%
|
372
|
+
\Loop[dist=1.0in,dir=NO,style={color=cv0v0,double=cfv0v0},labelstyle={sloped,above,text=clv0v0,},label=\hbox{$\sin\left(u\right)$},](v0)
|
373
|
+
\Edge[lw=0.025in,style={color=cv0v1,double=cfv0v1},labelstyle={sloped,pos=0.5,text=clv0v1,},label=\hbox{$y$},](v0)(v1)
|
374
|
+
\Edge[lw=0.025in,style={color=cv0v2,double=cfv0v2},labelstyle={sloped,pos=0.5,text=clv0v2,},label=\hbox{$y^{2}$},](v0)(v2)
|
375
|
+
\Edge[lw=0.025in,style={color=cv0v3,double=cfv0v3},labelstyle={pos=0.5,text=clv0v3,},label=\hbox{$y^{3}$},](v0)(v3)
|
376
|
+
\Edge[lw=0.01in,style={color=cv0v4,double=cfv0v4},labelstyle={sloped,above,text=clv0v4,},label=\hbox{$y^{4}$},](v0)(v4)
|
377
|
+
\Edge[lw=0.025in,style={color=cv1v2,double=cfv1v2},labelstyle={sloped,pos=0.5,text=clv1v2,},label=\hbox{$x y^{2}$},](v1)(v2)
|
378
|
+
\Edge[lw=0.025in,style={color=cv1v3,double=cfv1v3},labelstyle={sloped,pos=0.5,text=clv1v3,},label=\hbox{$x y^{3}$},](v1)(v3)
|
379
|
+
\Edge[lw=0.025in,style={color=cv1v4,double=cfv1v4},labelstyle={sloped,pos=0.5,text=clv1v4,},label=\hbox{$x y^{4}$},](v1)(v4)
|
380
|
+
\Edge[lw=0.025in,style={color=cv2v3,double=cfv2v3},labelstyle={sloped,left,text=clv2v3,},label=\hbox{$x^{2} y^{3}$},](v2)(v3)
|
381
|
+
\Edge[lw=0.025in,style={color=cv2v4,double=cfv2v4},labelstyle={pos=0.5,text=clv2v4,},label=\hbox{$x^{2} y^{4}$},](v2)(v4)
|
382
|
+
\Edge[lw=0.1in,style={color=cv3v4,double=cfv3v4},labelstyle={sloped,pos=0.5,text=clv3v4,},label=\hbox{$x^{3} y^{4}$},](v3)(v4)
|
383
|
+
\Loop[dist=4.0in,dir=EA,style={color=cv4v4,double=cfv4v4},labelstyle={sloped,below,text=clv4v4,},label=\hbox{$w^{5}$},](v4)
|
384
|
+
%
|
385
|
+
\end{tikzpicture}
|
386
|
+
|
387
|
+
GraphLatex class and functions
|
388
|
+
------------------------------
|
389
|
+
"""
|
390
|
+
# ****************************************************************************
|
391
|
+
# Copyright (C) 2009 Robert Beezer <beezer@ups.edu>
|
392
|
+
# Copyright (C) 2009 Fidel Barrera Cruz <fidel.barrera@gmail.com>
|
393
|
+
#
|
394
|
+
# Distributed under the terms of the GNU General Public License (GPL)
|
395
|
+
# as published by the Free Software Foundation; either version 2 of
|
396
|
+
# the License, or (at your option) any later version.
|
397
|
+
# https://www.gnu.org/licenses/
|
398
|
+
# ****************************************************************************
|
399
|
+
|
400
|
+
from sage.structure.sage_object import SageObject
|
401
|
+
from sage.misc.cachefunc import cached_function
|
402
|
+
from sage.misc.latex import latex
|
403
|
+
|
404
|
+
|
405
|
+
def check_tkz_graph():
|
406
|
+
r"""
|
407
|
+
Check if the proper LaTeX packages for the ``tikzpicture`` environment are
|
408
|
+
installed in the user's environment, and issue a warning otherwise.
|
409
|
+
|
410
|
+
The warning is only issued on the first call to this function. So any
|
411
|
+
doctest that illustrates the use of the tkz-graph packages should call this
|
412
|
+
once as having random output to exhaust the warnings before testing output.
|
413
|
+
|
414
|
+
See also :meth:`sage.misc.latex.Latex.check_file`
|
415
|
+
|
416
|
+
TESTS::
|
417
|
+
|
418
|
+
sage: from sage.graphs.graph_latex import check_tkz_graph
|
419
|
+
sage: check_tkz_graph() # random - depends on TeX installation
|
420
|
+
sage: check_tkz_graph() # at least the second time, so no output
|
421
|
+
"""
|
422
|
+
latex.check_file("tikz.sty", """This package is required to render graphs in LaTeX.
|
423
|
+
Visit '...'.
|
424
|
+
""")
|
425
|
+
latex.check_file("tkz-graph.sty", """This package is required to render graphs in LaTeX.
|
426
|
+
Visit 'https://www.ctan.org/pkg/tkz-graph'.
|
427
|
+
""")
|
428
|
+
latex.check_file("tkz-berge.sty", """This package is required to render graphs in LaTeX.
|
429
|
+
Visit 'https://www.ctan.org/pkg/tkz-berge'.
|
430
|
+
""")
|
431
|
+
|
432
|
+
|
433
|
+
def have_tkz_graph() -> bool:
|
434
|
+
r"""
|
435
|
+
Return ``True`` if the proper LaTeX packages for the ``tikzpicture``
|
436
|
+
environment are installed in the user's environment, namely ``tikz``,
|
437
|
+
``tkz-graph`` and ``tkz-berge``.
|
438
|
+
|
439
|
+
The result is cached.
|
440
|
+
|
441
|
+
See also :meth:`sage.misc.latex.Latex.has_file`
|
442
|
+
|
443
|
+
TESTS::
|
444
|
+
|
445
|
+
sage: from sage.graphs.graph_latex import have_tkz_graph
|
446
|
+
sage: have_tkz_graph() # random - depends on TeX installation
|
447
|
+
sage: have_tkz_graph() in [True, False]
|
448
|
+
True
|
449
|
+
"""
|
450
|
+
return latex.has_file("tikz.sty") and latex.has_file("tkz-graph.sty") and latex.has_file("tkz-berge.sty")
|
451
|
+
|
452
|
+
|
453
|
+
@cached_function
|
454
|
+
def setup_latex_preamble():
|
455
|
+
r"""
|
456
|
+
Add appropriate ``\usepackage{...}``, and other instructions to the latex
|
457
|
+
preamble for the packages that are needed for processing graphs(``tikz``,
|
458
|
+
``tkz-graph``, ``tkz-berge``), if available in the ``LaTeX`` installation.
|
459
|
+
|
460
|
+
See also :meth:`sage.misc.latex.Latex.add_package_to_preamble_if_available`.
|
461
|
+
|
462
|
+
EXAMPLES::
|
463
|
+
|
464
|
+
sage: sage.graphs.graph_latex.setup_latex_preamble()
|
465
|
+
|
466
|
+
TESTS::
|
467
|
+
|
468
|
+
sage: ("\\usepackage{tikz}" in latex.extra_preamble()) == latex.has_file("tikz.sty")
|
469
|
+
True
|
470
|
+
"""
|
471
|
+
latex.add_package_to_preamble_if_available("tikz")
|
472
|
+
latex.add_package_to_preamble_if_available("tkz-graph")
|
473
|
+
latex.add_package_to_preamble_if_available("tkz-berge")
|
474
|
+
if have_tkz_graph():
|
475
|
+
latex.add_to_preamble("\\usetikzlibrary{arrows,shapes}")
|
476
|
+
|
477
|
+
|
478
|
+
class GraphLatex(SageObject):
|
479
|
+
r"""
|
480
|
+
A class to hold, manipulate and employ options for converting
|
481
|
+
a graph to LaTeX.
|
482
|
+
|
483
|
+
This class serves two purposes. First it holds the values of various
|
484
|
+
options designed to work with the ``tkz-graph`` LaTeX package for rendering
|
485
|
+
graphs. As such, a graph that uses this class will hold a reference to it.
|
486
|
+
Second, this class contains the code to convert a graph into the
|
487
|
+
corresponding LaTeX constructs, returning a string.
|
488
|
+
|
489
|
+
EXAMPLES::
|
490
|
+
|
491
|
+
sage: from sage.graphs.graph_latex import GraphLatex
|
492
|
+
sage: opts = GraphLatex(graphs.PetersenGraph())
|
493
|
+
sage: opts
|
494
|
+
LaTeX options for Petersen graph: {}
|
495
|
+
sage: g = graphs.PetersenGraph()
|
496
|
+
sage: opts = g.latex_options()
|
497
|
+
sage: g == loads(dumps(g))
|
498
|
+
True
|
499
|
+
"""
|
500
|
+
|
501
|
+
# These are the "allowed" options for a graph, private to the class,
|
502
|
+
# along with their default value and description
|
503
|
+
# This allows intelligent errors when non-existent options are referenced
|
504
|
+
# Additionally, for each new option added here:
|
505
|
+
# 1. Document values in GraphLatex.set_option() docstring
|
506
|
+
# 2. Describe also in docstring for the sage.graphs.graph_latex module
|
507
|
+
#
|
508
|
+
# TODO: use some standard option handling mechanism
|
509
|
+
# This dictionary could also contain type information (list of admissible
|
510
|
+
# values) and a description
|
511
|
+
# See e.g. @option
|
512
|
+
__graphlatex_options = {'tkz_style': 'Custom',
|
513
|
+
'format': 'tkz_graph',
|
514
|
+
'layout': 'acyclic',
|
515
|
+
'prog': 'dot',
|
516
|
+
'units': 'cm',
|
517
|
+
'scale': 1.0,
|
518
|
+
'graphic_size': (5, 5),
|
519
|
+
'margins': (0, 0, 0, 0),
|
520
|
+
'vertex_color': 'black',
|
521
|
+
'vertex_colors': {},
|
522
|
+
'vertex_fill_color': 'white',
|
523
|
+
'vertex_fill_colors': {},
|
524
|
+
'vertex_shape': 'circle',
|
525
|
+
'vertex_shapes': {},
|
526
|
+
'vertex_size': 1.0,
|
527
|
+
'vertex_sizes': {},
|
528
|
+
'vertex_labels': True,
|
529
|
+
'vertex_labels_math': True,
|
530
|
+
'vertex_label_color': 'black',
|
531
|
+
'vertex_label_colors': {},
|
532
|
+
'vertex_label_placement': 'center',
|
533
|
+
'vertex_label_placements': {},
|
534
|
+
'edge_options': (),
|
535
|
+
'edge_color': 'black',
|
536
|
+
'edge_colors': {},
|
537
|
+
'edge_fills': False,
|
538
|
+
'edge_fill_color': 'black',
|
539
|
+
'edge_fill_colors': {},
|
540
|
+
'edge_thickness': 0.1,
|
541
|
+
'edge_thicknesses': {},
|
542
|
+
'edge_labels': False,
|
543
|
+
'edge_labels_math': True,
|
544
|
+
'edge_label_color': 'black',
|
545
|
+
'edge_label_colors': {},
|
546
|
+
'edge_label_sloped': True,
|
547
|
+
'edge_label_slopes': {},
|
548
|
+
'edge_label_placement': 0.50,
|
549
|
+
'edge_label_placements': {},
|
550
|
+
'loop_placement': (3.0, 'NO'),
|
551
|
+
'loop_placements': {},
|
552
|
+
'color_by_label': False,
|
553
|
+
'rankdir': 'down',
|
554
|
+
'subgraph_clusters': []}
|
555
|
+
|
556
|
+
def __init__(self, graph, **options):
|
557
|
+
r"""
|
558
|
+
Return a GraphLatex object, which holds all the parameters needed for
|
559
|
+
creating a LaTeX string that will be rendered as a picture of the graph.
|
560
|
+
|
561
|
+
See :mod:`sage.graphs.graph_latex` for more documentation.
|
562
|
+
|
563
|
+
EXAMPLES::
|
564
|
+
|
565
|
+
sage: from sage.graphs.graph_latex import GraphLatex
|
566
|
+
sage: GraphLatex(graphs.PetersenGraph())
|
567
|
+
LaTeX options for Petersen graph: {}
|
568
|
+
"""
|
569
|
+
self._graph = graph
|
570
|
+
self._options = {}
|
571
|
+
self.set_options(**options)
|
572
|
+
|
573
|
+
def __eq__(self, other):
|
574
|
+
r"""
|
575
|
+
Two :class:`sage.graphs.graph_latex.GraphLatex` objects are equal if
|
576
|
+
their options are equal.
|
577
|
+
|
578
|
+
The graphs they are associated with are ignored in the comparison.
|
579
|
+
|
580
|
+
TESTS::
|
581
|
+
|
582
|
+
sage: from sage.graphs.graph_latex import GraphLatex
|
583
|
+
sage: opts1 = GraphLatex(graphs.PetersenGraph())
|
584
|
+
sage: opts2 = GraphLatex(graphs.CompleteGraph(10))
|
585
|
+
sage: opts1.set_option('tkz_style', 'Art')
|
586
|
+
sage: opts2.set_option('tkz_style', 'Art')
|
587
|
+
sage: opts1 == opts2
|
588
|
+
True
|
589
|
+
sage: opts2.set_option('tkz_style', 'Normal')
|
590
|
+
sage: opts1 == opts2
|
591
|
+
False
|
592
|
+
"""
|
593
|
+
if not isinstance(other, GraphLatex):
|
594
|
+
return False
|
595
|
+
return self._options == other._options
|
596
|
+
|
597
|
+
def _repr_(self):
|
598
|
+
r"""
|
599
|
+
Return a string representation of a
|
600
|
+
:class:`sage.graphs.graph_latex.GraphLatex` object which includes the
|
601
|
+
name of the graph and the dictionary of current options.
|
602
|
+
|
603
|
+
EXAMPLES::
|
604
|
+
|
605
|
+
sage: g = graphs.PetersenGraph()
|
606
|
+
sage: opts = g.latex_options()
|
607
|
+
sage: opts.set_option('tkz_style', 'Classic')
|
608
|
+
sage: opts.set_option('vertex_size', 3.6)
|
609
|
+
sage: print(opts._repr_())
|
610
|
+
LaTeX options for Petersen graph: {'tkz_style': 'Classic', 'vertex_size': 3.60000000000000}
|
611
|
+
"""
|
612
|
+
return "LaTeX options for %s: %s" % (self._graph, self._options)
|
613
|
+
|
614
|
+
def set_option(self, option_name, option_value=None):
|
615
|
+
r"""
|
616
|
+
Set, modify, clear a LaTeX option for controlling the rendering of a
|
617
|
+
graph.
|
618
|
+
|
619
|
+
The possible options are documented here, because ultimately it is this
|
620
|
+
routine that sets the values. However, the
|
621
|
+
:meth:`sage.graphs.generic_graph.GenericGraph.set_latex_options` method
|
622
|
+
is the easiest way to set options, and allows several to be set at once.
|
623
|
+
|
624
|
+
INPUT:
|
625
|
+
|
626
|
+
- ``option_name`` -- string for a latex option contained in the list
|
627
|
+
``sage.graphs.graph_latex.GraphLatex.__graphlatex_options``;
|
628
|
+
a :exc:`ValueError` is raised if the option is not allowed
|
629
|
+
|
630
|
+
- ``option_value`` -- a value for the option; if omitted, or set to
|
631
|
+
``None``, the option will use the default value
|
632
|
+
|
633
|
+
The output can be either handled internally by ``Sage``, or delegated to
|
634
|
+
the external software ``dot2tex`` and ``graphviz``. This is controlled
|
635
|
+
by the option ``format``:
|
636
|
+
|
637
|
+
- ``format`` -- string (default: ``'tkz_graph'``); either ``'dot2tex'``
|
638
|
+
or ``'tkz_graph'``
|
639
|
+
|
640
|
+
If format is ``'dot2tex'``, then all the LaTeX generation will be
|
641
|
+
delegated to ``dot2tex`` (which must be installed).
|
642
|
+
|
643
|
+
For ``tkz_graph``, the possible option names, and associated values are
|
644
|
+
given below. This first group allows you to set a style for a graph and
|
645
|
+
specify some sizes related to the eventual image. (For more information
|
646
|
+
consult the documentation for the ``tkz-graph`` package.)
|
647
|
+
|
648
|
+
- ``tkz_style`` -- string (default: ``'Custom'``); the name of a
|
649
|
+
pre-defined ``tkz-graph`` style such as ``'Shade'``, ``'Art'``,
|
650
|
+
``'Normal'``, ``'Dijkstra'``, ``'Welsh'``, ``'Classic'``, and
|
651
|
+
``'Simple'``, or the string ``'Custom'``. Using one of these styles
|
652
|
+
alone will often give a reasonably good drawing with minimal
|
653
|
+
effort. For a custom appearance set this to ``'Custom'`` and use the
|
654
|
+
options described below to override the default values.
|
655
|
+
|
656
|
+
- ``units`` -- string (default: ``'cm'``); a natural unit of
|
657
|
+
measurement used for all dimensions. Possible values are: ``'in'``,
|
658
|
+
``'mm'``, ``'cm'``, ``'pt'``, ``'em'``, ``'ex'``.
|
659
|
+
|
660
|
+
- ``scale`` -- float (default: `1.0`); a dimensionless number that
|
661
|
+
multiplies every linear dimension. So you can design at sizes you are
|
662
|
+
accustomed to, then shrink or expand to meet other needs. Though fonts
|
663
|
+
do not scale.
|
664
|
+
|
665
|
+
- ``graphic_size`` -- tuple (default: ``(5, 5)``); overall dimensions
|
666
|
+
(width, length) of the bounding box around the entire graphic image
|
667
|
+
|
668
|
+
- ``margins`` -- 4-tuple (default: ``(0, 0, 0, 0)``); portion of graphic
|
669
|
+
given over to a plain border as a tuple of four numbers: (left, right,
|
670
|
+
top, bottom). These are subtracted from the ``graphic_size`` to
|
671
|
+
create the area left for the vertices of the graph itself. Note that
|
672
|
+
the processing done by Sage will trim the graphic down to the minimum
|
673
|
+
possible size, removing any border. So this is only useful if you use
|
674
|
+
the latex string in a latex document.
|
675
|
+
|
676
|
+
If not using a pre-built style the following options are used, so the
|
677
|
+
following defaults will apply. It is not possible to begin with a
|
678
|
+
pre-built style and modify it (other than editing the latex string by
|
679
|
+
hand after the fact).
|
680
|
+
|
681
|
+
- ``vertex_color`` -- (default: ``'black'``) a single color to use as
|
682
|
+
the default for outline of vertices. For the ``sphere`` shape this
|
683
|
+
color is used for the entire vertex, which is drawn with a 3D shading.
|
684
|
+
Colors must be specified as a string recognized by the matplotlib
|
685
|
+
library: a standard color name like ``'red'``, or a hex string like
|
686
|
+
``'#2D87A7'``, or a single character from the choices ``'rgbcmykw'``.
|
687
|
+
Additionally, a number between 0 and 1 will create a grayscale value.
|
688
|
+
These color specifications are consistent throughout the options for
|
689
|
+
a ``tikzpicture``.
|
690
|
+
|
691
|
+
- ``vertex_colors`` -- dictionary whose keys are vertices of the graph
|
692
|
+
and whose values are colors. These will be used to color the outline
|
693
|
+
of vertices. See the explanation above for the ``vertex_color`` option
|
694
|
+
to see possible values. These values need only be specified for a
|
695
|
+
proper subset of the vertices. Specified values will supersede a
|
696
|
+
default value.
|
697
|
+
|
698
|
+
- ``vertex_fill_color`` -- (default: ``'white'``) a single color to use
|
699
|
+
as the default for the fill color of vertices. See the explanation
|
700
|
+
above for the ``vertex_color`` option to see possible values. This
|
701
|
+
color is ignored for the ``sphere`` vertex shape.
|
702
|
+
|
703
|
+
- ``vertex_fill_colors`` -- dictionary whose keys are vertices of the
|
704
|
+
graph and whose values are colors. These will be used to fill the
|
705
|
+
interior of vertices. See the explanation above for the
|
706
|
+
``vertex_color`` option to see possible values. These values need only
|
707
|
+
be specified for a proper subset of the vertices. Specified values
|
708
|
+
will supersede a default value.
|
709
|
+
|
710
|
+
- ``vertex_shape`` -- string (default: ``'circle'``); specifies the
|
711
|
+
shape of the vertices. Allowable values are ``'circle'``,
|
712
|
+
``'sphere'``, ``'rectangle'``, ``'diamond'``. The sphere shape has a
|
713
|
+
3D look to its coloring and is uses only one color, that specified by
|
714
|
+
``vertex_color`` and ``vertex_colors``, which are normally used for
|
715
|
+
the outline of the vertex.
|
716
|
+
|
717
|
+
- ``vertex_shapes`` -- dictionary whose keys are vertices of the graph
|
718
|
+
and whose values are shapes. See ``vertex_shape`` for the allowable
|
719
|
+
possibilities.
|
720
|
+
|
721
|
+
- ``vertex_size`` -- float (default: 1.0); the minimum size of a vertex
|
722
|
+
as a number. Vertices will expand to contain their labels if the
|
723
|
+
labels are placed inside the vertices. If you set this value to zero
|
724
|
+
the vertex will be as small as possible (up to tkz-graph's "inner sep"
|
725
|
+
parameter), while still containing labels. However, if labels are not
|
726
|
+
of a uniform size, then the vertices will not be either.
|
727
|
+
|
728
|
+
- ``vertex_sizes`` -- dictionary of sizes for some of the vertices
|
729
|
+
|
730
|
+
- ``vertex_labels`` -- boolean (default: ``True``); determine whether or
|
731
|
+
not to display the vertex labels. If ``False`` subsequent options
|
732
|
+
about vertex labels are ignored.
|
733
|
+
|
734
|
+
- ``vertex_labels_math`` -- boolean (default: ``True``); when ``True``,
|
735
|
+
if a label is a string that begins and ends with dollar signs, then
|
736
|
+
the string will be rendered as a latex string. Otherwise, the label
|
737
|
+
will be automatically subjected to the ``latex()`` method and rendered
|
738
|
+
accordingly. If ``False`` the label is rendered as its textual
|
739
|
+
representation according to the ``_repr`` method. Support for
|
740
|
+
arbitrarily-complicated mathematics is not especially robust.
|
741
|
+
|
742
|
+
- ``vertex_label_color`` -- (default: ``'black'``) a single color to
|
743
|
+
use as the default for labels of vertices. See the explanation above
|
744
|
+
for the ``vertex_color`` option to see possible values.
|
745
|
+
|
746
|
+
- ``vertex_label_colors`` -- dictionary whose keys are vertices of the
|
747
|
+
graph and whose values are colors. These will be used for the text of
|
748
|
+
the labels of vertices. See the explanation above for the
|
749
|
+
``vertex_color`` option to see possible values. These values need only
|
750
|
+
be specified for a proper subset of the vertices. Specified values
|
751
|
+
will supersede a default value.
|
752
|
+
|
753
|
+
- ``vertex_label_placement`` -- (default: ``'center'``) if ``'center'``
|
754
|
+
the label is centered in the interior of the vertex and the vertex
|
755
|
+
will expand to contain the label. Giving instead a pair of numbers
|
756
|
+
will place the label exterior to the vertex at a certain distance from
|
757
|
+
the edge, and at an angle to the positive x-axis, similar in spirit to
|
758
|
+
polar coordinates.
|
759
|
+
|
760
|
+
- ``vertex_label_placements`` -- dictionary of placements indexed by
|
761
|
+
the vertices. See the explanation for ``vertex_label_placement`` for
|
762
|
+
the possible values.
|
763
|
+
|
764
|
+
- ``edge_color`` -- (default: ``'black'``) a single color to use as the
|
765
|
+
default for an edge. See the explanation above for the
|
766
|
+
``vertex_color`` option to see possible values.
|
767
|
+
|
768
|
+
- ``edge_colors`` -- dictionary whose keys are edges of the graph and
|
769
|
+
whose values are colors. These will be used to color the edges. See
|
770
|
+
the explanation above for the ``vertex_color`` option to see possible
|
771
|
+
values. These values need only be specified for a proper subset of the
|
772
|
+
vertices. Specified values will supersede a default value.
|
773
|
+
|
774
|
+
- ``edge_fills`` -- boolean (default: ``False``); whether an edge has a
|
775
|
+
second color running down the middle. This can be a useful effect for
|
776
|
+
highlighting edge crossings.
|
777
|
+
|
778
|
+
- ``edge_fill_color`` -- (default: ``'black'``) a single color to use
|
779
|
+
as the default for the fill color of an edge. The boolean switch
|
780
|
+
``edge_fills`` must be set to ``True`` for this to have an effect. See
|
781
|
+
the explanation above for the ``vertex_color`` option to see possible
|
782
|
+
values.
|
783
|
+
|
784
|
+
- ``edge_fill_colors`` -- dictionary whose keys are edges of the graph
|
785
|
+
and whose values are colors. See the explanation above for the
|
786
|
+
``vertex_color`` option to see possible values. These values need
|
787
|
+
only be specified for a proper subset of the vertices. Specified
|
788
|
+
values will supersede a default value.
|
789
|
+
|
790
|
+
- ``edge_thickness`` -- float (default: 0.1); specifies the width of the
|
791
|
+
edges. Note that ``tkz-graph`` does not interpret this number for
|
792
|
+
loops.
|
793
|
+
|
794
|
+
- ``edge_thicknesses`` -- dictionary of thicknesses for some of the
|
795
|
+
edges of a graph. These values need only be specified for a proper
|
796
|
+
subset of the vertices. Specified values will supersede a default
|
797
|
+
value.
|
798
|
+
|
799
|
+
- ``edge_labels`` -- boolean (default: ``False``); determine if edge
|
800
|
+
labels are shown. If ``False`` subsequent options about edge labels
|
801
|
+
are ignored.
|
802
|
+
|
803
|
+
- ``edge_labels_math`` -- boolean (default: ``True``); control how edge
|
804
|
+
labels are rendered. Read the explanation for the
|
805
|
+
``vertex_labels_math`` option, which behaves identically. Support for
|
806
|
+
arbitrarily-complicated mathematics is not especially robust.
|
807
|
+
|
808
|
+
- ``edge_label_color`` -- (default: ``'black'``) a single color to use
|
809
|
+
as the default for labels of edges. See the explanation above for the
|
810
|
+
``vertex_color`` option to see possible values.
|
811
|
+
|
812
|
+
- ``edge_label_colors`` -- dictionary whose keys are edges of the
|
813
|
+
graph and whose values are colors. These will be used for the text of
|
814
|
+
the labels of edges. See the explanation above for the
|
815
|
+
``vertex_color`` option to see possible values. These values need only
|
816
|
+
be specified for a proper subset of the vertices. Specified values
|
817
|
+
will supersede a default value. Note that labels must be used for this
|
818
|
+
to have any effect, and no care is taken to ensure that label and fill
|
819
|
+
colors work well together.
|
820
|
+
|
821
|
+
- ``edge_label_sloped`` -- boolean (default: ``True``); specifies how
|
822
|
+
edge labels are place. ``False`` results in a horizontal label, while
|
823
|
+
``True`` means the label is rotated to follow the direction of the
|
824
|
+
edge it labels.
|
825
|
+
|
826
|
+
- ``edge_label_slopes`` -- dictionary of booleans, indexed by some
|
827
|
+
subset of the edges. See the ``edge_label_sloped`` option for a
|
828
|
+
description of sloped edge labels.
|
829
|
+
|
830
|
+
- ``edge_label_placement`` -- (default: 0.50) either a number between
|
831
|
+
0.0 and 1.0, or one of: ``'above'``, ``'below'``, ``'left'``,
|
832
|
+
``'right'``. These adjust the location of an edge label along an
|
833
|
+
edge. A number specifies how far along the edge the label is located.
|
834
|
+
``'left'`` and ``'right'`` are conveniences. ``'above'`` and
|
835
|
+
``'below'`` move the label off the edge itself while leaving it near
|
836
|
+
the midpoint of the edge. The default value of ``0.50`` places the
|
837
|
+
label on the midpoint of the edge.
|
838
|
+
|
839
|
+
- ``edge_label_placements`` -- dictionary of edge placements, indexed
|
840
|
+
by the edges. See the ``edge_label_placement`` option for a
|
841
|
+
description of the allowable values.
|
842
|
+
|
843
|
+
- ``loop_placement`` -- (default: ``(3.0, 'NO')``); determine how loops
|
844
|
+
are rendered. the first element of the pair is a distance, which
|
845
|
+
determines how big the loop is and the second element is a string
|
846
|
+
specifying a compass point (North, South, East, West) as one of
|
847
|
+
``'NO'``, ``'SO'``, ``'EA'``, ``'WE'``.
|
848
|
+
|
849
|
+
- ``loop_placements`` -- dictionary of loop placements. See the
|
850
|
+
``loop_placements`` option for the allowable values. While loops are
|
851
|
+
technically edges, this dictionary is indexed by vertices.
|
852
|
+
|
853
|
+
For the ``'dot2tex'`` format, the possible option names and associated
|
854
|
+
values are given below:
|
855
|
+
|
856
|
+
- ``prog`` -- string; the program used for the layout. It must be a
|
857
|
+
string corresponding to one of the software of the graphviz suite:
|
858
|
+
``'dot'``, ``'neato'``, ``'twopi'``, ``'circo'`` or ``'fdp'``.
|
859
|
+
|
860
|
+
- ``edge_labels`` -- boolean (default: ``False)``; whether to display
|
861
|
+
the labels on edges
|
862
|
+
|
863
|
+
- ``edge_colors`` -- a color; can be used to set a global color to the
|
864
|
+
edge of the graph
|
865
|
+
|
866
|
+
- ``color_by_label`` -- boolean (default: ``False``); colors the edges
|
867
|
+
according to their labels
|
868
|
+
|
869
|
+
- ``subgraph_clusters`` -- (default: ``[]``) a list of lists of
|
870
|
+
vertices, if supported by the layout engine, nodes belonging to the
|
871
|
+
same cluster subgraph are drawn together, with the entire drawing of
|
872
|
+
the cluster contained within a bounding rectangle.
|
873
|
+
|
874
|
+
OUTPUT: none; success happens silently
|
875
|
+
|
876
|
+
EXAMPLES:
|
877
|
+
|
878
|
+
Set, then modify, then clear the ``tkz_style`` option, and finally show
|
879
|
+
an error for an unrecognized option name::
|
880
|
+
|
881
|
+
sage: g = graphs.PetersenGraph()
|
882
|
+
sage: opts = g.latex_options()
|
883
|
+
sage: opts
|
884
|
+
LaTeX options for Petersen graph: {}
|
885
|
+
sage: opts.set_option('tkz_style', 'Art')
|
886
|
+
sage: opts
|
887
|
+
LaTeX options for Petersen graph: {'tkz_style': 'Art'}
|
888
|
+
sage: opts.set_option('tkz_style', 'Simple')
|
889
|
+
sage: opts
|
890
|
+
LaTeX options for Petersen graph: {'tkz_style': 'Simple'}
|
891
|
+
sage: opts.set_option('tkz_style')
|
892
|
+
sage: opts
|
893
|
+
LaTeX options for Petersen graph: {}
|
894
|
+
sage: opts.set_option('bad_name', 'nonsense')
|
895
|
+
Traceback (most recent call last):
|
896
|
+
...
|
897
|
+
ValueError: bad_name is not a LaTeX option for a graph.
|
898
|
+
|
899
|
+
See :meth:`sage.graphs.generic_graph.GenericGraph.layout_graphviz` for
|
900
|
+
installation instructions for ``graphviz`` and ``dot2tex``. Furthermore,
|
901
|
+
pgf >= 2.00 should be available inside LaTeX's tree for LaTeX
|
902
|
+
compilation (e.g. when using ``view``). In case your LaTeX distribution
|
903
|
+
does not provide it, here are short instructions:
|
904
|
+
|
905
|
+
- download pgf from http://sourceforge.net/projects/pgf/
|
906
|
+
- unpack it in ``/usr/share/texmf/tex/generic`` (depends on your system)
|
907
|
+
- clean out remaining pgf files from older version
|
908
|
+
- run texhash
|
909
|
+
|
910
|
+
TESTS:
|
911
|
+
|
912
|
+
These test all of the options and one example of each allowable proper
|
913
|
+
input. They should all execute silently. ::
|
914
|
+
|
915
|
+
sage: G = Graph()
|
916
|
+
sage: G.add_edge((0,1))
|
917
|
+
sage: opts = G.latex_options()
|
918
|
+
sage: opts.set_option('tkz_style', 'Custom')
|
919
|
+
sage: opts.set_option('tkz_style', 'Art')
|
920
|
+
sage: opts.set_option('format', 'tkz_graph')
|
921
|
+
sage: opts.set_option('layout', 'acyclic')
|
922
|
+
sage: opts.set_option('prog', 'dot')
|
923
|
+
sage: opts.set_option('units', 'cm')
|
924
|
+
sage: opts.set_option('scale', 1.0)
|
925
|
+
sage: opts.set_option('graphic_size', (5, 5))
|
926
|
+
sage: opts.set_option('margins', (0,0,0,0))
|
927
|
+
sage: opts.set_option('vertex_color', 'black')
|
928
|
+
sage: opts.set_option('vertex_colors', {0:'#ABCDEF'})
|
929
|
+
sage: opts.set_option('vertex_fill_color', 'white')
|
930
|
+
sage: opts.set_option('vertex_fill_colors', {0:'c'})
|
931
|
+
sage: opts.set_option('vertex_shape', 'circle')
|
932
|
+
sage: opts.set_option('vertex_shapes', {0:'sphere'})
|
933
|
+
sage: opts.set_option('vertex_size', 1.0)
|
934
|
+
sage: opts.set_option('vertex_sizes', {0:3.4})
|
935
|
+
sage: opts.set_option('vertex_labels', True)
|
936
|
+
sage: opts.set_option('vertex_labels_math', True)
|
937
|
+
sage: opts.set_option('vertex_label_color', 'black')
|
938
|
+
sage: opts.set_option('vertex_label_colors', {0:'.23'})
|
939
|
+
sage: opts.set_option('vertex_label_placement', 'center')
|
940
|
+
sage: opts.set_option('vertex_label_placement', (3, 4.2))
|
941
|
+
sage: opts.set_option('vertex_label_placements', {0:'center'})
|
942
|
+
sage: opts.set_option('vertex_label_placements', {0:(4.7,1)})
|
943
|
+
sage: opts.set_option('edge_color', 'black')
|
944
|
+
sage: opts.set_option('edge_colors', {(0,1):'w'})
|
945
|
+
sage: opts.set_option('edge_fills', False)
|
946
|
+
sage: opts.set_option('edge_fill_color', 'black')
|
947
|
+
sage: opts.set_option('edge_fill_colors', {(0,1):"#123456"})
|
948
|
+
sage: opts.set_option('edge_thickness', 0.1)
|
949
|
+
sage: opts.set_option('edge_thicknesses', {(0,1):5.2})
|
950
|
+
sage: opts.set_option('edge_labels', False)
|
951
|
+
sage: opts.set_option('edge_labels_math', True)
|
952
|
+
sage: opts.set_option('edge_label_color', 'black')
|
953
|
+
sage: opts.set_option('edge_label_colors', {(0,1):'red'})
|
954
|
+
sage: opts.set_option('edge_label_sloped', True)
|
955
|
+
sage: opts.set_option('edge_label_slopes', {(0,1): False})
|
956
|
+
sage: opts.set_option('edge_label_placement', 'left')
|
957
|
+
sage: opts.set_option('edge_label_placement', 0.50)
|
958
|
+
sage: opts.set_option('edge_label_placements', {(0,1):'above'})
|
959
|
+
sage: opts.set_option('edge_label_placements', {(0,1):0.75})
|
960
|
+
sage: opts.set_option('loop_placement', (3.0, 'NO'))
|
961
|
+
sage: opts.set_option('loop_placements', {0:(5.7,'WE')})
|
962
|
+
sage: opts.set_option('subgraph_clusters', [[0,1]])
|
963
|
+
|
964
|
+
These test some of the logic of possible failures. Some tests, such as
|
965
|
+
inputs of colors, are handled by somewhat general sections of code and
|
966
|
+
are not tested for each possible option. ::
|
967
|
+
|
968
|
+
sage: G=Graph()
|
969
|
+
sage: G.add_edge((0,1))
|
970
|
+
sage: opts = G.latex_options()
|
971
|
+
sage: opts.set_option('tkz_style', 'Crazed')
|
972
|
+
Traceback (most recent call last):
|
973
|
+
...
|
974
|
+
ValueError: tkz_style is not "Custom", nor an implemented tkz-graph style
|
975
|
+
sage: opts.set_option('format', 'NonExistent')
|
976
|
+
Traceback (most recent call last):
|
977
|
+
...
|
978
|
+
ValueError: format option must be one of: tkz_graph, dot2tex not NonExistent
|
979
|
+
sage: opts.set_option('units', 'furlongs')
|
980
|
+
Traceback (most recent call last):
|
981
|
+
...
|
982
|
+
ValueError: units option must be one of: in, mm, cm, pt, em, ex, not furlongs
|
983
|
+
sage: opts.set_option('graphic_size', (1,2,3))
|
984
|
+
Traceback (most recent call last):
|
985
|
+
...
|
986
|
+
ValueError: graphic_size option must be an ordered pair, not (1, 2, 3)
|
987
|
+
sage: opts.set_option('margins', (1,2,3))
|
988
|
+
Traceback (most recent call last):
|
989
|
+
...
|
990
|
+
ValueError: margins option must be 4-tuple, not (1, 2, 3)
|
991
|
+
sage: opts.set_option('vertex_color', 'chartruse')
|
992
|
+
Traceback (most recent call last):
|
993
|
+
...
|
994
|
+
ValueError: vertex_color option needs to be a matplotlib color (always as a string), not chartruse
|
995
|
+
sage: opts.set_option('vertex_labels_math', 'maybe')
|
996
|
+
Traceback (most recent call last):
|
997
|
+
...
|
998
|
+
ValueError: vertex_labels_math option must be True or False, not maybe
|
999
|
+
sage: opts.set_option('vertex_shape', 'decagon')
|
1000
|
+
Traceback (most recent call last):
|
1001
|
+
...
|
1002
|
+
ValueError: vertex_shape option must be the shape of a vertex, not decagon
|
1003
|
+
sage: opts.set_option('scale', 'big')
|
1004
|
+
Traceback (most recent call last):
|
1005
|
+
...
|
1006
|
+
ValueError: scale option must be a positive number, not big
|
1007
|
+
sage: opts.set_option('scale', -6)
|
1008
|
+
Traceback (most recent call last):
|
1009
|
+
...
|
1010
|
+
ValueError: scale option must be a positive number, not -6
|
1011
|
+
sage: opts.set_option('vertex_label_placement', (2,-4))
|
1012
|
+
Traceback (most recent call last):
|
1013
|
+
...
|
1014
|
+
ValueError: vertex_label_placement option must be None, or a pair of positive numbers, not (2, -4)
|
1015
|
+
sage: opts.set_option('edge_label_placement', 3.6)
|
1016
|
+
Traceback (most recent call last):
|
1017
|
+
...
|
1018
|
+
ValueError: edge_label_placement option must be a number between 0.0 and 1.0 or a place (like "above"), not 3.60000000000000
|
1019
|
+
sage: opts.set_option('loop_placement', (5,'SW'))
|
1020
|
+
Traceback (most recent call last):
|
1021
|
+
...
|
1022
|
+
ValueError: loop_placement option must be a pair that is a positive number followed by a compass point abbreviation, not (5, 'SW')
|
1023
|
+
sage: opts.set_option('vertex_fill_colors', {0:'#GG0000'})
|
1024
|
+
Traceback (most recent call last):
|
1025
|
+
...
|
1026
|
+
ValueError: vertex_fill_colors option for 0 needs to be a matplotlib color (always as a string), not #GG0000
|
1027
|
+
sage: opts.set_option('vertex_sizes', {0:-10})
|
1028
|
+
Traceback (most recent call last):
|
1029
|
+
...
|
1030
|
+
ValueError: vertex_sizes option for 0 needs to be a positive number, not -10
|
1031
|
+
sage: opts.set_option('edge_label_slopes', {(0,1):'possibly'})
|
1032
|
+
Traceback (most recent call last):
|
1033
|
+
...
|
1034
|
+
ValueError: edge_label_slopes option for (0, 1) needs to be True or False, not possibly
|
1035
|
+
sage: opts.set_option('vertex_shapes', {0:'pentagon'})
|
1036
|
+
Traceback (most recent call last):
|
1037
|
+
...
|
1038
|
+
ValueError: vertex_shapes option for 0 needs to be a vertex shape, not pentagon
|
1039
|
+
sage: opts.set_option('vertex_label_placements', {0:(1,2,3)})
|
1040
|
+
Traceback (most recent call last):
|
1041
|
+
...
|
1042
|
+
ValueError: vertex_label_placements option for 0 needs to be None or a pair of positive numbers, not (1, 2, 3)
|
1043
|
+
sage: opts.set_option('edge_label_placements', {(0,1):'partway'})
|
1044
|
+
Traceback (most recent call last):
|
1045
|
+
...
|
1046
|
+
ValueError: edge_label_placements option for (0, 1) needs to be a number between 0.0 and 1.0 or a place (like "above"), not partway
|
1047
|
+
sage: opts.set_option('loop_placements', {0:(-3,'WE')})
|
1048
|
+
Traceback (most recent call last):
|
1049
|
+
...
|
1050
|
+
ValueError: loop_placements option for 0 needs to be a positive number and a compass point (like "EA"), not (-3, 'WE')
|
1051
|
+
sage: opts.set_option('margins', (1,2,3,-5))
|
1052
|
+
Traceback (most recent call last):
|
1053
|
+
...
|
1054
|
+
ValueError: margins option of (1, 2, 3, -5) cannot contain -5
|
1055
|
+
"""
|
1056
|
+
# TODO: Needed improvements, possible extensions, dubious ideas
|
1057
|
+
# - digraph edges should be optionally curved or straight with perhaps a
|
1058
|
+
# variable curvature (exit angle from vertex). Always curved now to
|
1059
|
+
# allow for bidirectional.
|
1060
|
+
# - the "draw" option will make boxes around labels as extensions of the
|
1061
|
+
# edge color and thickness
|
1062
|
+
# - edge labels can have colored backgrounds (which look like fills when
|
1063
|
+
# boxed.
|
1064
|
+
# - edge label fonts can be sized (latex style), which will make scaling
|
1065
|
+
# work totally
|
1066
|
+
# - edges can be dotted or dashed, Beezer suggests calling this "edge
|
1067
|
+
# shape" to mirror vertex shapes
|
1068
|
+
# - "line width" works for vertices, should be configurable
|
1069
|
+
# - allow injection of latex code to style a pre-built style for
|
1070
|
+
# example, \SetUpVertex[style={fill=green}] could override color
|
1071
|
+
# selection in a style like "Art"
|
1072
|
+
# - "inner sep" is distance from vertex label to edge of vertex this
|
1073
|
+
# should be set as small as possible - but bigger than the line width.
|
1074
|
+
# - aspect ratio could be preserved, see hints near creation of affine
|
1075
|
+
# transformation.
|
1076
|
+
# - "outer sep" causes edges to stop some distance before reaching
|
1077
|
+
# vertices. Seems of limited value.
|
1078
|
+
# - Multi-edges are not supported. Need to recognize them, twiddle keys
|
1079
|
+
# in dictionaries, plot with a spectrum of bends.
|
1080
|
+
# Seems like a substantial project.
|
1081
|
+
|
1082
|
+
from matplotlib.colors import ColorConverter
|
1083
|
+
from sage.rings.integer import Integer
|
1084
|
+
from sage.rings.real_mpfr import RealLiteral
|
1085
|
+
|
1086
|
+
cc = ColorConverter() # used as a color tester
|
1087
|
+
|
1088
|
+
if option_name not in GraphLatex.__graphlatex_options:
|
1089
|
+
raise ValueError("%s is not a LaTeX option for a graph." % option_name)
|
1090
|
+
if option_value is None: # clear the option, if set
|
1091
|
+
if option_name in self._options:
|
1092
|
+
del self._options[option_name]
|
1093
|
+
else:
|
1094
|
+
# Test options here when attempt to set
|
1095
|
+
name = option_name
|
1096
|
+
value = option_value
|
1097
|
+
#
|
1098
|
+
# Tuples of constants
|
1099
|
+
#
|
1100
|
+
formats = ('tkz_graph', 'dot2tex')
|
1101
|
+
styles = ('Custom', 'Shade', 'Art', 'Normal', 'Dijkstra', 'Welsh', 'Classic', 'Simple')
|
1102
|
+
unit_names = ('in', 'mm', 'cm', 'pt', 'em', 'ex')
|
1103
|
+
shape_names = ('circle', 'sphere', 'rectangle', 'diamond')
|
1104
|
+
label_places = ('above', 'below', 'right', 'left')
|
1105
|
+
compass_points = ('NO', 'SO', 'EA', 'WE')
|
1106
|
+
number_types = (int, Integer, float, RealLiteral)
|
1107
|
+
#
|
1108
|
+
# Options with structurally similar tests
|
1109
|
+
#
|
1110
|
+
boolean_options = ('vertex_labels', 'vertex_labels_math', 'edge_fills',
|
1111
|
+
'edge_labels', 'edge_labels_math', 'edge_label_sloped')
|
1112
|
+
color_options = ('vertex_color', 'vertex_fill_color', 'vertex_label_color',
|
1113
|
+
'edge_color', 'edge_fill_color', 'edge_label_color')
|
1114
|
+
color_dicts = ('vertex_colors', 'vertex_fill_colors', 'vertex_label_colors',
|
1115
|
+
'edge_colors', 'edge_fill_colors', 'edge_label_colors')
|
1116
|
+
boolean_dicts = ('edge_label_slopes',)
|
1117
|
+
positive_scalars = ('scale', 'vertex_size', 'edge_thickness')
|
1118
|
+
positive_scalar_dicts = ('vertex_sizes', 'edge_thicknesses')
|
1119
|
+
positive_tuples = ('graphic_size', 'margins')
|
1120
|
+
#
|
1121
|
+
# Checks/test on single values (ie graph-wide defaults)
|
1122
|
+
#
|
1123
|
+
if name == 'tkz_style' and value not in styles:
|
1124
|
+
raise ValueError('%s is not "Custom", nor an implemented tkz-graph style' % name)
|
1125
|
+
elif name == 'format' and value not in formats:
|
1126
|
+
raise ValueError('%s option must be one of: tkz_graph, dot2tex not %s' % (name, value))
|
1127
|
+
elif name == 'units' and value not in unit_names:
|
1128
|
+
raise ValueError('%s option must be one of: in, mm, cm, pt, em, ex, not %s' % (name, value))
|
1129
|
+
elif name == 'graphic_size' and not (isinstance(value, tuple) and (len(value) == 2)):
|
1130
|
+
raise ValueError('%s option must be an ordered pair, not %s' % (name, value))
|
1131
|
+
elif name == 'margins' and not ((isinstance(value, tuple)) and (len(value) == 4)):
|
1132
|
+
raise ValueError('%s option must be 4-tuple, not %s' % (name, value))
|
1133
|
+
elif name in color_options:
|
1134
|
+
try:
|
1135
|
+
cc.to_rgb(value)
|
1136
|
+
except Exception:
|
1137
|
+
raise ValueError('%s option needs to be a matplotlib color (always as a string), not %s' % (name, value))
|
1138
|
+
elif name in boolean_options and not isinstance(value, bool):
|
1139
|
+
raise ValueError('%s option must be True or False, not %s' % (name, value))
|
1140
|
+
elif name == 'vertex_shape' and value not in shape_names:
|
1141
|
+
raise ValueError('%s option must be the shape of a vertex, not %s' % (name, value))
|
1142
|
+
elif name in positive_scalars and not (type(value) in number_types and (value >= 0.0)):
|
1143
|
+
raise ValueError('%s option must be a positive number, not %s' % (name, value))
|
1144
|
+
elif (name == 'vertex_label_placement' and value != 'center' and
|
1145
|
+
not (isinstance(value, tuple) and len(value) == 2 and
|
1146
|
+
type(value[0]) in number_types and value[0] >= 0 and
|
1147
|
+
type(value[1]) in number_types and value[1] >= 0)):
|
1148
|
+
raise ValueError('%s option must be None, or a pair of positive numbers, not %s' % (name, value))
|
1149
|
+
elif (name == 'edge_label_placement' and
|
1150
|
+
not ((type(value) in number_types and 0 <= value <= 1)
|
1151
|
+
or value in label_places)):
|
1152
|
+
raise ValueError('%s option must be a number between 0.0 and 1.0 or a place (like "above"), not %s' % (name, value))
|
1153
|
+
elif (name == 'loop_placement' and
|
1154
|
+
not (isinstance(value, tuple) and len(value) == 2 and
|
1155
|
+
value[0] >= 0 and value[1] in compass_points)):
|
1156
|
+
raise ValueError('%s option must be a pair that is a positive number followed by a compass point abbreviation, not %s' % (name, value))
|
1157
|
+
#
|
1158
|
+
# Checks/test on dictionaries of values (ie per-vertex or per-edge defaults)
|
1159
|
+
#
|
1160
|
+
elif name in color_dicts:
|
1161
|
+
if not isinstance(value, dict):
|
1162
|
+
raise TypeError('%s option must be a dictionary, not %s' % (name, value))
|
1163
|
+
else:
|
1164
|
+
for key, c in value.items():
|
1165
|
+
try:
|
1166
|
+
cc.to_rgb(c)
|
1167
|
+
except Exception:
|
1168
|
+
raise ValueError('%s option for %s needs to be a matplotlib color (always as a string), not %s' % (name, key, c))
|
1169
|
+
elif name in positive_scalar_dicts:
|
1170
|
+
if not isinstance(value, dict):
|
1171
|
+
raise TypeError('%s option must be a dictionary, not %s' % (name, value))
|
1172
|
+
else:
|
1173
|
+
for key, x in value.items():
|
1174
|
+
if type(x) not in [int, Integer, float, RealLiteral] or not x >= 0.0:
|
1175
|
+
raise ValueError('%s option for %s needs to be a positive number, not %s' % (name, key, x))
|
1176
|
+
elif name in boolean_dicts:
|
1177
|
+
if not isinstance(value, dict):
|
1178
|
+
raise TypeError('%s option must be a dictionary, not %s' % (name, value))
|
1179
|
+
else:
|
1180
|
+
for key, b in value.items():
|
1181
|
+
if not isinstance(b, bool):
|
1182
|
+
raise ValueError('%s option for %s needs to be True or False, not %s' % (name, key, b))
|
1183
|
+
elif name == 'vertex_shapes':
|
1184
|
+
if not isinstance(value, dict):
|
1185
|
+
raise TypeError('%s option must be a dictionary, not %s' % (name, value))
|
1186
|
+
else:
|
1187
|
+
for key, s in value.items():
|
1188
|
+
if s not in shape_names:
|
1189
|
+
raise ValueError('%s option for %s needs to be a vertex shape, not %s' % (name, key, s))
|
1190
|
+
elif name == 'vertex_label_placements':
|
1191
|
+
if not isinstance(value, dict):
|
1192
|
+
raise TypeError('%s option must be a dictionary, not %s' % (name, value))
|
1193
|
+
else:
|
1194
|
+
for key, p in value.items():
|
1195
|
+
if (p != 'center' and
|
1196
|
+
not (isinstance(p, tuple) and len(p) == 2 and
|
1197
|
+
type(p[0]) in number_types and p[0] >= 0 and
|
1198
|
+
type(p[1]) in number_types and p[1] >= 0)):
|
1199
|
+
raise ValueError('%s option for %s needs to be None or a pair of positive numbers, not %s' % (name, key, p))
|
1200
|
+
elif name == 'edge_label_placements':
|
1201
|
+
if not isinstance(value, dict):
|
1202
|
+
raise TypeError('%s option must be a dictionary, not %s' % (name, value))
|
1203
|
+
else:
|
1204
|
+
for key, p in value.items():
|
1205
|
+
if not (isinstance(p, (float, RealLiteral)) and (0 <= p <= 1)) and (p not in label_places):
|
1206
|
+
raise ValueError('%s option for %s needs to be a number between 0.0 and 1.0 or a place (like "above"), not %s' % (name, key, p))
|
1207
|
+
elif name == 'loop_placements':
|
1208
|
+
if not isinstance(value, dict):
|
1209
|
+
raise TypeError('%s option must be a dictionary, not %s' % (name, value))
|
1210
|
+
else:
|
1211
|
+
for key, p in value.items():
|
1212
|
+
if not ((isinstance(p, tuple)) and (len(p) == 2) and (p[0] >= 0) and (p[1] in compass_points)):
|
1213
|
+
raise ValueError('%s option for %s needs to be a positive number and a compass point (like "EA"), not %s' % (name, key, p))
|
1214
|
+
# These have been verified as tuples before going into this next check
|
1215
|
+
elif name in positive_tuples:
|
1216
|
+
for x in value:
|
1217
|
+
if type(x) not in [int, Integer, float, RealLiteral] or not x >= 0.0:
|
1218
|
+
raise ValueError('%s option of %s cannot contain %s' % (name, value, x))
|
1219
|
+
#
|
1220
|
+
# Verified. Set it.
|
1221
|
+
self._options[option_name] = option_value
|
1222
|
+
|
1223
|
+
def set_options(self, **kwds):
|
1224
|
+
r"""
|
1225
|
+
Set several LaTeX options for a graph all at once.
|
1226
|
+
|
1227
|
+
INPUT:
|
1228
|
+
|
1229
|
+
- ``kwds`` -- any number of option/value pairs to set many graph latex
|
1230
|
+
options at once (a variable number, in any order). Existing values are
|
1231
|
+
overwritten, new values are added. Existing values can be cleared by
|
1232
|
+
setting the value to ``None``. Errors are raised in the
|
1233
|
+
:func:`set_option` method.
|
1234
|
+
|
1235
|
+
EXAMPLES::
|
1236
|
+
|
1237
|
+
sage: g = graphs.PetersenGraph()
|
1238
|
+
sage: opts = g.latex_options()
|
1239
|
+
sage: opts.set_options(tkz_style='Welsh')
|
1240
|
+
sage: opts.get_option('tkz_style')
|
1241
|
+
'Welsh'
|
1242
|
+
"""
|
1243
|
+
if kwds:
|
1244
|
+
for name, value in kwds.items():
|
1245
|
+
self.set_option(name, value)
|
1246
|
+
|
1247
|
+
def get_option(self, option_name):
|
1248
|
+
r"""
|
1249
|
+
Return the current value of the named option.
|
1250
|
+
|
1251
|
+
INPUT:
|
1252
|
+
|
1253
|
+
- ``option_name`` -- the name of an option
|
1254
|
+
|
1255
|
+
OUTPUT:
|
1256
|
+
|
1257
|
+
If the name is not present in ``__graphlatex_options`` it is an error to
|
1258
|
+
ask for it. If an option has not been set then the default value is
|
1259
|
+
returned. Otherwise, the value of the option is returned.
|
1260
|
+
|
1261
|
+
EXAMPLES::
|
1262
|
+
|
1263
|
+
sage: g = graphs.PetersenGraph()
|
1264
|
+
sage: opts = g.latex_options()
|
1265
|
+
sage: opts.set_option('tkz_style', 'Art')
|
1266
|
+
sage: opts.get_option('tkz_style')
|
1267
|
+
'Art'
|
1268
|
+
sage: opts.set_option('tkz_style')
|
1269
|
+
sage: opts.get_option('tkz_style') == "Custom"
|
1270
|
+
True
|
1271
|
+
sage: opts.get_option('bad_name')
|
1272
|
+
Traceback (most recent call last):
|
1273
|
+
...
|
1274
|
+
ValueError: bad_name is not a Latex option for a graph.
|
1275
|
+
"""
|
1276
|
+
if option_name not in GraphLatex.__graphlatex_options:
|
1277
|
+
raise ValueError("%s is not a Latex option for a graph." % option_name)
|
1278
|
+
else:
|
1279
|
+
if option_name in self._options:
|
1280
|
+
return self._options[option_name]
|
1281
|
+
else:
|
1282
|
+
return GraphLatex.__graphlatex_options[option_name]
|
1283
|
+
|
1284
|
+
def latex(self):
|
1285
|
+
r"""
|
1286
|
+
Return a string in LaTeX representing a graph.
|
1287
|
+
|
1288
|
+
This is the command that is invoked by
|
1289
|
+
``sage.graphs.generic_graph.GenericGraph._latex_`` for a graph, so it
|
1290
|
+
returns a string of LaTeX commands that can be incorporated into a LaTeX
|
1291
|
+
document unmodified. The exact contents of this string are influenced by
|
1292
|
+
the options set via the methods
|
1293
|
+
:meth:`sage.graphs.generic_graph.GenericGraph.set_latex_options`,
|
1294
|
+
:meth:`set_option`, and :meth:`set_options`.
|
1295
|
+
|
1296
|
+
By setting the ``format`` option different packages can be used to
|
1297
|
+
create the latex version of a graph. Supported packages are
|
1298
|
+
``tkz-graph`` and ``dot2tex``.
|
1299
|
+
|
1300
|
+
EXAMPLES::
|
1301
|
+
|
1302
|
+
sage: from sage.graphs.graph_latex import check_tkz_graph
|
1303
|
+
sage: check_tkz_graph() # random - depends on TeX installation
|
1304
|
+
sage: g = graphs.CompleteGraph(2)
|
1305
|
+
sage: opts = g.latex_options()
|
1306
|
+
sage: print(opts.latex())
|
1307
|
+
\begin{tikzpicture}
|
1308
|
+
\definecolor{cv0}{rgb}{0.0,0.0,0.0}
|
1309
|
+
\definecolor{cfv0}{rgb}{1.0,1.0,1.0}
|
1310
|
+
\definecolor{clv0}{rgb}{0.0,0.0,0.0}
|
1311
|
+
\definecolor{cv1}{rgb}{0.0,0.0,0.0}
|
1312
|
+
\definecolor{cfv1}{rgb}{1.0,1.0,1.0}
|
1313
|
+
\definecolor{clv1}{rgb}{0.0,0.0,0.0}
|
1314
|
+
\definecolor{cv0v1}{rgb}{0.0,0.0,0.0}
|
1315
|
+
%
|
1316
|
+
\Vertex[style={minimum size=1.0cm,draw=cv0,fill=cfv0,text=clv0,shape=circle},LabelOut=false,L=\hbox{$0$},x=2.5cm,y=5.0cm]{v0}
|
1317
|
+
\Vertex[style={minimum size=1.0cm,draw=cv1,fill=cfv1,text=clv1,shape=circle},LabelOut=false,L=\hbox{$1$},x=2.5cm,y=0.0cm]{v1}
|
1318
|
+
%
|
1319
|
+
\Edge[lw=0.1cm,style={color=cv0v1,},](v0)(v1)
|
1320
|
+
%
|
1321
|
+
\end{tikzpicture}
|
1322
|
+
|
1323
|
+
We check that :issue:`22070` is fixed::
|
1324
|
+
|
1325
|
+
sage: edges = [(i,(i+1)%3,a) for i,a in enumerate('abc')]
|
1326
|
+
sage: G_with_labels = DiGraph(edges)
|
1327
|
+
sage: C = [[0,1], [2]]
|
1328
|
+
sage: kwds = dict(subgraph_clusters=C,color_by_label=True,prog='dot',format='dot2tex')
|
1329
|
+
sage: opts = G_with_labels.latex_options()
|
1330
|
+
sage: opts.set_options(edge_labels=True, **kwds) # optional - dot2tex graphviz
|
1331
|
+
sage: latex(G_with_labels) # optional - dot2tex graphviz
|
1332
|
+
\begin{tikzpicture}[>=latex,line join=bevel,]
|
1333
|
+
%%
|
1334
|
+
\begin{scope}
|
1335
|
+
\pgfsetstrokecolor{black}
|
1336
|
+
\definecolor{strokecol}{rgb}{...};
|
1337
|
+
\pgfsetstrokecolor{strokecol}
|
1338
|
+
\definecolor{fillcol}{rgb}{...};
|
1339
|
+
\pgfsetfillcolor{fillcol}
|
1340
|
+
\filldraw ... cycle;
|
1341
|
+
\end{scope}
|
1342
|
+
\begin{scope}
|
1343
|
+
\pgfsetstrokecolor{black}
|
1344
|
+
\definecolor{strokecol}{rgb}{...};
|
1345
|
+
\pgfsetstrokecolor{strokecol}
|
1346
|
+
\definecolor{fillcol}{rgb}{...};
|
1347
|
+
\pgfsetfillcolor{fillcol}
|
1348
|
+
\filldraw ... cycle;
|
1349
|
+
\end{scope}
|
1350
|
+
...
|
1351
|
+
\end{tikzpicture}
|
1352
|
+
"""
|
1353
|
+
format = self.get_option('format')
|
1354
|
+
if format == "tkz_graph":
|
1355
|
+
return self.tkz_picture()
|
1356
|
+
elif format == "dot2tex":
|
1357
|
+
return self.dot2tex_picture()
|
1358
|
+
|
1359
|
+
def dot2tex_picture(self):
|
1360
|
+
r"""
|
1361
|
+
Call ``dot2tex`` to construct a string of LaTeX commands representing a
|
1362
|
+
graph as a ``tikzpicture``.
|
1363
|
+
|
1364
|
+
EXAMPLES::
|
1365
|
+
|
1366
|
+
sage: g = digraphs.ButterflyGraph(1)
|
1367
|
+
sage: from sage.graphs.graph_latex import check_tkz_graph
|
1368
|
+
sage: check_tkz_graph() # random - depends on TeX installation
|
1369
|
+
sage: print(g.latex_options().dot2tex_picture()) # optional - dot2tex graphviz
|
1370
|
+
\begin{tikzpicture}[>=latex,line join=bevel,]
|
1371
|
+
%%
|
1372
|
+
\node (node_...) at (...bp,...bp) [draw,draw=none] {$\left(...\right)$};
|
1373
|
+
\node (node_...) at (...bp,...bp) [draw,draw=none] {$\left(...\right)$};
|
1374
|
+
\node (node_...) at (...bp,...bp) [draw,draw=none] {$\left(...\right)$};
|
1375
|
+
\node (node_...) at (...bp,...bp) [draw,draw=none] {$\left(...\right)$};
|
1376
|
+
\draw [black,->] (node_...) ..controls (...bp,...bp) and (...bp,...bp) .. (node_...);
|
1377
|
+
\draw [black,->] (node_...) ..controls (...bp,...bp) and (...bp,...bp) .. (node_...);
|
1378
|
+
\draw [black,->] (node_...) ..controls (...bp,...bp) and (...bp,...bp) .. (node_...);
|
1379
|
+
\draw [black,->] (node_...) ..controls (...bp,...bp) and (...bp,...bp) .. (node_...);
|
1380
|
+
%
|
1381
|
+
\end{tikzpicture}
|
1382
|
+
|
1383
|
+
We make sure :issue:`13624` is fixed::
|
1384
|
+
|
1385
|
+
sage: G = DiGraph()
|
1386
|
+
sage: G.add_edge(3333, 88, 'my_label')
|
1387
|
+
sage: G.set_latex_options(edge_labels=True)
|
1388
|
+
sage: print(G.latex_options().dot2tex_picture()) # optional - dot2tex graphviz
|
1389
|
+
\begin{tikzpicture}[>=latex,line join=bevel,]
|
1390
|
+
%%
|
1391
|
+
\node (node_...) at (...bp,...bp) [draw,draw=none] {$...$};
|
1392
|
+
\node (node_...) at (...bp,...bp) [draw,draw=none] {$...$};
|
1393
|
+
\draw [black,->] (node_...) ..controls (...bp,...bp) and (...bp,...bp) .. (node_...);
|
1394
|
+
\definecolor{strokecol}{rgb}{0.0,0.0,0.0};
|
1395
|
+
\pgfsetstrokecolor{strokecol}
|
1396
|
+
\draw (...bp,...bp) node {$\text{\texttt{my{\char`\_}label}}$};
|
1397
|
+
%
|
1398
|
+
\end{tikzpicture}
|
1399
|
+
|
1400
|
+
Check that :issue:`25120` is fixed::
|
1401
|
+
|
1402
|
+
sage: G = Graph([(0,1)])
|
1403
|
+
sage: G.set_latex_options(edge_colors = {(0,1): 'red'})
|
1404
|
+
sage: print(G.latex_options().dot2tex_picture()) # optional - dot2tex graphviz
|
1405
|
+
\begin{tikzpicture}[>=latex,line join=bevel,]
|
1406
|
+
...
|
1407
|
+
\draw [red,] (node_0) ... (node_1);
|
1408
|
+
...
|
1409
|
+
\end{tikzpicture}
|
1410
|
+
|
1411
|
+
.. NOTE::
|
1412
|
+
|
1413
|
+
There is a lot of overlap between what ``tkz_picture`` and
|
1414
|
+
``dot2tex`` do. It would be best to merge them! ``dot2tex`` probably
|
1415
|
+
can work without ``graphviz`` if layout information is provided.
|
1416
|
+
"""
|
1417
|
+
from sage.graphs.dot2tex_utils import assert_have_dot2tex
|
1418
|
+
assert_have_dot2tex()
|
1419
|
+
|
1420
|
+
options = self.__graphlatex_options.copy()
|
1421
|
+
options.update(self._options)
|
1422
|
+
|
1423
|
+
# NOTE: the edge_labels option for graphviz_string is opposite
|
1424
|
+
# see https://github.com/sagemath/sage/issues/25120
|
1425
|
+
if 'edge_colors' in options:
|
1426
|
+
edge_colors = options['edge_colors']
|
1427
|
+
new_edge_colors = {}
|
1428
|
+
for edge, col in edge_colors.items():
|
1429
|
+
if col in new_edge_colors:
|
1430
|
+
new_edge_colors[col].append(edge)
|
1431
|
+
else:
|
1432
|
+
new_edge_colors[col] = [edge]
|
1433
|
+
options['edge_colors'] = new_edge_colors
|
1434
|
+
|
1435
|
+
dotdata = self._graph.graphviz_string(labels='latex', **options)
|
1436
|
+
import dot2tex
|
1437
|
+
return dot2tex.dot2tex(dotdata,
|
1438
|
+
format='tikz',
|
1439
|
+
autosize=True,
|
1440
|
+
crop=True,
|
1441
|
+
figonly='True',
|
1442
|
+
prog=self.get_option('prog')).strip()
|
1443
|
+
# usepdflatex = True, debug = True)
|
1444
|
+
|
1445
|
+
def tkz_picture(self):
|
1446
|
+
r"""
|
1447
|
+
Return a string of LaTeX commands representing a graph as a
|
1448
|
+
``tikzpicture``.
|
1449
|
+
|
1450
|
+
This routine interprets the graph's properties and the options in
|
1451
|
+
``_options`` to render the graph with commands from the ``tkz-graph``
|
1452
|
+
LaTeX package.
|
1453
|
+
|
1454
|
+
This requires that the LaTeX optional packages ``tkz-graph`` and
|
1455
|
+
``tkz-berge`` be installed. You may also need a current version of the
|
1456
|
+
pgf package. If the ``tkz-graph`` and ``tkz-berge`` packages are
|
1457
|
+
present in the system's TeX installation, the appropriate
|
1458
|
+
``\\usepackage{}`` commands will be added to the LaTeX preamble as part
|
1459
|
+
of the initialization of the graph. If these two packages are not
|
1460
|
+
present, then this command will return a warning on its first use, but
|
1461
|
+
will return a string that could be used elsewhere, such as a LaTeX
|
1462
|
+
document.
|
1463
|
+
|
1464
|
+
For more information about tkz-graph you can visit
|
1465
|
+
https://www.ctan.org/pkg/tkz-graph.
|
1466
|
+
|
1467
|
+
EXAMPLES:
|
1468
|
+
|
1469
|
+
With a pre-built ``tkz-graph`` style specified, the latex representation
|
1470
|
+
will be relatively simple. ::
|
1471
|
+
|
1472
|
+
sage: from sage.graphs.graph_latex import check_tkz_graph
|
1473
|
+
sage: check_tkz_graph() # random - depends on TeX installation
|
1474
|
+
sage: g = graphs.CompleteGraph(3)
|
1475
|
+
sage: opts = g.latex_options()
|
1476
|
+
sage: g.set_latex_options(tkz_style='Art')
|
1477
|
+
sage: print(opts.tkz_picture())
|
1478
|
+
\begin{tikzpicture}
|
1479
|
+
\GraphInit[vstyle=Art]
|
1480
|
+
%
|
1481
|
+
\Vertex[L=\hbox{$0$},x=2.5cm,y=5.0cm]{v0}
|
1482
|
+
\Vertex[L=\hbox{$1$},x=0.0cm,y=0.0cm]{v1}
|
1483
|
+
\Vertex[L=\hbox{$2$},x=5.0cm,y=0.0cm]{v2}
|
1484
|
+
%
|
1485
|
+
\Edge[](v0)(v1)
|
1486
|
+
\Edge[](v0)(v2)
|
1487
|
+
\Edge[](v1)(v2)
|
1488
|
+
%
|
1489
|
+
\end{tikzpicture}
|
1490
|
+
|
1491
|
+
Setting the style to "Custom" results in various configurable aspects
|
1492
|
+
set to the defaults, so the string is more involved. ::
|
1493
|
+
|
1494
|
+
sage: from sage.graphs.graph_latex import check_tkz_graph
|
1495
|
+
sage: check_tkz_graph() # random - depends on TeX installation
|
1496
|
+
sage: g = graphs.CompleteGraph(3)
|
1497
|
+
sage: opts = g.latex_options()
|
1498
|
+
sage: g.set_latex_options(tkz_style='Custom')
|
1499
|
+
sage: print(opts.tkz_picture())
|
1500
|
+
\begin{tikzpicture}
|
1501
|
+
\definecolor{cv0}{rgb}{0.0,0.0,0.0}
|
1502
|
+
\definecolor{cfv0}{rgb}{1.0,1.0,1.0}
|
1503
|
+
\definecolor{clv0}{rgb}{0.0,0.0,0.0}
|
1504
|
+
\definecolor{cv1}{rgb}{0.0,0.0,0.0}
|
1505
|
+
\definecolor{cfv1}{rgb}{1.0,1.0,1.0}
|
1506
|
+
\definecolor{clv1}{rgb}{0.0,0.0,0.0}
|
1507
|
+
\definecolor{cv2}{rgb}{0.0,0.0,0.0}
|
1508
|
+
\definecolor{cfv2}{rgb}{1.0,1.0,1.0}
|
1509
|
+
\definecolor{clv2}{rgb}{0.0,0.0,0.0}
|
1510
|
+
\definecolor{cv0v1}{rgb}{0.0,0.0,0.0}
|
1511
|
+
\definecolor{cv0v2}{rgb}{0.0,0.0,0.0}
|
1512
|
+
\definecolor{cv1v2}{rgb}{0.0,0.0,0.0}
|
1513
|
+
%
|
1514
|
+
\Vertex[style={minimum size=1.0cm,draw=cv0,fill=cfv0,text=clv0,shape=circle},LabelOut=false,L=\hbox{$0$},x=2.5cm,y=5.0cm]{v0}
|
1515
|
+
\Vertex[style={minimum size=1.0cm,draw=cv1,fill=cfv1,text=clv1,shape=circle},LabelOut=false,L=\hbox{$1$},x=0.0cm,y=0.0cm]{v1}
|
1516
|
+
\Vertex[style={minimum size=1.0cm,draw=cv2,fill=cfv2,text=clv2,shape=circle},LabelOut=false,L=\hbox{$2$},x=5.0cm,y=0.0cm]{v2}
|
1517
|
+
%
|
1518
|
+
\Edge[lw=0.1cm,style={color=cv0v1,},](v0)(v1)
|
1519
|
+
\Edge[lw=0.1cm,style={color=cv0v2,},](v0)(v2)
|
1520
|
+
\Edge[lw=0.1cm,style={color=cv1v2,},](v1)(v2)
|
1521
|
+
%
|
1522
|
+
\end{tikzpicture}
|
1523
|
+
|
1524
|
+
See the introduction to the :mod:`~sage.graphs.graph_latex` module for
|
1525
|
+
more information on the use of this routine.
|
1526
|
+
|
1527
|
+
TESTS:
|
1528
|
+
|
1529
|
+
Graphs with preset layouts that are vertical or horizontal can cause
|
1530
|
+
problems. First test is a horizontal layout on a path with three
|
1531
|
+
vertices. ::
|
1532
|
+
|
1533
|
+
sage: from sage.graphs.graph_latex import check_tkz_graph
|
1534
|
+
sage: check_tkz_graph() # random - depends on TeX installation
|
1535
|
+
sage: g = graphs.PathGraph(3)
|
1536
|
+
sage: opts = g.latex_options()
|
1537
|
+
sage: print(opts.tkz_picture())
|
1538
|
+
\begin{tikzpicture}
|
1539
|
+
...
|
1540
|
+
\end{tikzpicture}
|
1541
|
+
|
1542
|
+
Scaling to a bounding box is problematic for graphs with just one
|
1543
|
+
vertex, or none. ::
|
1544
|
+
|
1545
|
+
sage: from sage.graphs.graph_latex import check_tkz_graph
|
1546
|
+
sage: check_tkz_graph() # random - depends on TeX installation
|
1547
|
+
sage: g = graphs.CompleteGraph(1)
|
1548
|
+
sage: opts = g.latex_options()
|
1549
|
+
sage: print(opts.tkz_picture())
|
1550
|
+
\begin{tikzpicture}
|
1551
|
+
...
|
1552
|
+
\end{tikzpicture}
|
1553
|
+
|
1554
|
+
With the empty graph, an empty tikzfigure is output. ::
|
1555
|
+
|
1556
|
+
sage: from sage.graphs.graph_latex import check_tkz_graph
|
1557
|
+
sage: check_tkz_graph() # random - depends on TeX installation
|
1558
|
+
sage: g = Graph()
|
1559
|
+
sage: opts = g.latex_options()
|
1560
|
+
sage: print(opts.tkz_picture())
|
1561
|
+
\begin{tikzpicture}
|
1562
|
+
%
|
1563
|
+
%
|
1564
|
+
%
|
1565
|
+
\end{tikzpicture}
|
1566
|
+
|
1567
|
+
For a complicated vertex, a TeX box is used. ::
|
1568
|
+
|
1569
|
+
sage: B = crystals.Tableaux(['B', 2], shape=[1])
|
1570
|
+
sage: latex(B) # optional - !dot2tex
|
1571
|
+
\begin{tikzpicture}
|
1572
|
+
...
|
1573
|
+
\newsavebox{\vertex}
|
1574
|
+
\sbox{\vertex}{${\def\lr#1{\multicolumn{1}{|@{\hspace{.6ex}}c@{\hspace{.6ex}}|}{\raisebox{-.3ex}{$#1$}}}
|
1575
|
+
\raisebox{-.6ex}{$\begin{array}[b]{*{1}c}\cline{1-1}
|
1576
|
+
\lr{1}\\\cline{1-1}
|
1577
|
+
\end{array}$}
|
1578
|
+
}$}\Vertex[style={minimum size=1.0cm,draw=cv0,fill=cfv0,text=clv0,shape=circle},LabelOut=false,L=\usebox{\vertex},x=...,y=...]{v0}
|
1579
|
+
...
|
1580
|
+
\end{tikzpicture}
|
1581
|
+
"""
|
1582
|
+
# This routine does not handle multiple edges
|
1583
|
+
# It will properly handle digraphs where a pair of vertices has an edge
|
1584
|
+
# in each direction, since edges of a digraph are curved.
|
1585
|
+
if self._graph.has_multiple_edges():
|
1586
|
+
raise NotImplementedError('it is not possible create a tkz-graph version of a graph with multiple edges')
|
1587
|
+
|
1588
|
+
from matplotlib.colors import ColorConverter
|
1589
|
+
from sage.misc.latex import latex
|
1590
|
+
|
1591
|
+
# On first use of this method, the next call may print warnings as a
|
1592
|
+
# side effect, but will be silent on any subsequent use.
|
1593
|
+
check_tkz_graph()
|
1594
|
+
|
1595
|
+
# Overhead
|
1596
|
+
cc = ColorConverter() # .to_rgb method to convert "colors" to triples
|
1597
|
+
prefix = 'v' # leading string on internal (to tkz-graph) vertex names
|
1598
|
+
|
1599
|
+
####################
|
1600
|
+
# Pre-built styles
|
1601
|
+
####################
|
1602
|
+
|
1603
|
+
# We preserve the pre-built style OR get defaults for each option, but
|
1604
|
+
# we do not mix the two
|
1605
|
+
style = self.get_option('tkz_style')
|
1606
|
+
customized = (style == 'Custom')
|
1607
|
+
# We don't do much for a pre-built style
|
1608
|
+
# Layout information from the graph
|
1609
|
+
# And vertex labels (if used) are the latex representation of Sage objects
|
1610
|
+
if not customized:
|
1611
|
+
vertex_labels_math = True
|
1612
|
+
|
1613
|
+
###################################
|
1614
|
+
# Layout, image sizing placement
|
1615
|
+
###################################
|
1616
|
+
|
1617
|
+
units = self.get_option('units')
|
1618
|
+
scale = self.get_option('scale')
|
1619
|
+
graphic_size = self.get_option('graphic_size')
|
1620
|
+
margins = self.get_option('margins')
|
1621
|
+
|
1622
|
+
# The positions of the vertices will get scaled to fill the specified
|
1623
|
+
# size of the image, as given by graphic_size. But first a border is
|
1624
|
+
# subtracted away and the graph is scaled to fit there.
|
1625
|
+
|
1626
|
+
# Lower left, upper right corners of box inside borders
|
1627
|
+
llx = margins[0]
|
1628
|
+
lly = margins[3]
|
1629
|
+
urx = graphic_size[0] - margins[1]
|
1630
|
+
ury = graphic_size[1] - margins[2]
|
1631
|
+
# width and height of space
|
1632
|
+
w = urx - llx
|
1633
|
+
h = ury - lly
|
1634
|
+
|
1635
|
+
# TODO: Could use self._graph._layout_bounding_box(pos)
|
1636
|
+
# trans = lambda x,y: [x[0]-y[0],x[1]-y[1]]
|
1637
|
+
# Determine the spread in the x and y directions (i.e. xmax, ymax)
|
1638
|
+
# Needs care for perfectly horizontal and vertical layouts
|
1639
|
+
|
1640
|
+
# We grab the graph's layout (or it is computed as a consequence of the
|
1641
|
+
# request)
|
1642
|
+
pos = self._graph.layout()
|
1643
|
+
if pos.values():
|
1644
|
+
xmin = min(i[0] for i in pos.values())
|
1645
|
+
ymin = min(i[1] for i in pos.values())
|
1646
|
+
xmax = max(i[0] for i in pos.values())
|
1647
|
+
ymax = max(i[1] for i in pos.values())
|
1648
|
+
else:
|
1649
|
+
xmin, xmax, ymin, ymax = 0, 0, 0, 0
|
1650
|
+
|
1651
|
+
# Linear scaling factors that will be used to scale the image to fit
|
1652
|
+
# into the bordered region. Purely horizontal, or purely vertical,
|
1653
|
+
# layouts get put in the middle of the bounding box by setting the
|
1654
|
+
# scaling to a constant value on a midline
|
1655
|
+
xspread = xmax - xmin
|
1656
|
+
if xspread == 0:
|
1657
|
+
x_scale = 0.0
|
1658
|
+
llx = llx + 0.5 * w
|
1659
|
+
else:
|
1660
|
+
x_scale = float(w) / xspread
|
1661
|
+
yspread = ymax - ymin
|
1662
|
+
if yspread == 0:
|
1663
|
+
y_scale = 0.0
|
1664
|
+
lly = lly + 0.5 * h
|
1665
|
+
else:
|
1666
|
+
y_scale = float(h) / yspread
|
1667
|
+
# Could preserve aspect ratio here by setting both scale factors to the
|
1668
|
+
# minimum and doing a shift of the larger to center
|
1669
|
+
# A linear function will map layout positions into the bordered graphic
|
1670
|
+
# space
|
1671
|
+
|
1672
|
+
def translate(p):
|
1673
|
+
return ((p[0] - xmin) * x_scale + llx,
|
1674
|
+
(p[1] - ymin) * y_scale + lly)
|
1675
|
+
|
1676
|
+
#############
|
1677
|
+
# Vertices
|
1678
|
+
#############
|
1679
|
+
|
1680
|
+
# We record the index of each vertex in the graph's list of vertices
|
1681
|
+
# Which is just a convenience for forming vertex names internal to
|
1682
|
+
# tkz-graph
|
1683
|
+
index_of_vertex = {}
|
1684
|
+
vertex_list = self._graph.vertices(sort=False)
|
1685
|
+
for u in self._graph:
|
1686
|
+
index_of_vertex[u] = vertex_list.index(u)
|
1687
|
+
|
1688
|
+
# Vertex labels can be switched on/off, and we don't record or use this
|
1689
|
+
# type of extra information if they are switched off
|
1690
|
+
vertex_labels = self.get_option('vertex_labels')
|
1691
|
+
|
1692
|
+
# We collect options for vertices, default values and for-some-vertices
|
1693
|
+
# information. These are combined into dictionaries on a per-vertex
|
1694
|
+
# basis, for all vertices. This only applies for a custom style
|
1695
|
+
#
|
1696
|
+
# Defaults
|
1697
|
+
#
|
1698
|
+
if customized:
|
1699
|
+
dvc = cc.to_rgb(self.get_option('vertex_color'))
|
1700
|
+
dvfc = cc.to_rgb(self.get_option('vertex_fill_color'))
|
1701
|
+
dsh = self.get_option('vertex_shape')
|
1702
|
+
dvs = self.get_option('vertex_size')
|
1703
|
+
#
|
1704
|
+
# Default label information, if using vertex labels
|
1705
|
+
#
|
1706
|
+
if vertex_labels:
|
1707
|
+
vertex_labels_math = self.get_option('vertex_labels_math')
|
1708
|
+
dvlc = cc.to_rgb(self.get_option('vertex_label_color'))
|
1709
|
+
dvlp = self.get_option('vertex_label_placement')
|
1710
|
+
# needs test for a pair of numbers, angle and distance (or None)
|
1711
|
+
|
1712
|
+
# Retrieve dictionaries for selected vertices
|
1713
|
+
vertex_colors = self.get_option('vertex_colors')
|
1714
|
+
vertex_fill_colors = self.get_option('vertex_fill_colors')
|
1715
|
+
vertex_shapes = self.get_option('vertex_shapes')
|
1716
|
+
vertex_sizes = self.get_option('vertex_sizes')
|
1717
|
+
if vertex_labels:
|
1718
|
+
vertex_label_colors = self.get_option('vertex_label_colors')
|
1719
|
+
vertex_label_placements = self.get_option('vertex_label_placements')
|
1720
|
+
|
1721
|
+
# Form dictionaries, each indexed for all vertices
|
1722
|
+
v_color = {}
|
1723
|
+
vf_color = {}
|
1724
|
+
v_shape = {}
|
1725
|
+
v_size = {}
|
1726
|
+
if vertex_labels:
|
1727
|
+
vl_color = {}
|
1728
|
+
vl_placement = {}
|
1729
|
+
for u in vertex_list:
|
1730
|
+
|
1731
|
+
c = dvc
|
1732
|
+
if u in vertex_colors:
|
1733
|
+
c = cc.to_rgb(vertex_colors[u])
|
1734
|
+
v_color[u] = c
|
1735
|
+
|
1736
|
+
c = dvfc
|
1737
|
+
if u in vertex_fill_colors:
|
1738
|
+
c = cc.to_rgb(vertex_fill_colors[u])
|
1739
|
+
vf_color[u] = c
|
1740
|
+
|
1741
|
+
sh = dsh
|
1742
|
+
if u in vertex_shapes:
|
1743
|
+
sh = vertex_shapes[u]
|
1744
|
+
v_shape[u] = sh
|
1745
|
+
|
1746
|
+
vs = dvs
|
1747
|
+
if u in vertex_sizes:
|
1748
|
+
vs = vertex_sizes[u]
|
1749
|
+
v_size[u] = vs
|
1750
|
+
|
1751
|
+
if vertex_labels:
|
1752
|
+
|
1753
|
+
c = dvlc
|
1754
|
+
if u in vertex_label_colors:
|
1755
|
+
c = cc.to_rgb(vertex_label_colors[u])
|
1756
|
+
vl_color[u] = c
|
1757
|
+
|
1758
|
+
vlp = dvlp
|
1759
|
+
if u in vertex_label_placements:
|
1760
|
+
vlp = vertex_label_placements[u]
|
1761
|
+
# test vlp here
|
1762
|
+
vl_placement[u] = vlp
|
1763
|
+
|
1764
|
+
is_directed = self._graph.is_directed()
|
1765
|
+
|
1766
|
+
##########
|
1767
|
+
# Edges
|
1768
|
+
##########
|
1769
|
+
|
1770
|
+
if customized:
|
1771
|
+
# An "edge fill" is a bit unusual, so we allow it to be turned off
|
1772
|
+
# as the default.
|
1773
|
+
edge_fills = self.get_option('edge_fills')
|
1774
|
+
|
1775
|
+
# Edge labels can be switched on/off, and we don't record or use
|
1776
|
+
# this type of extra information if they are switched off
|
1777
|
+
edge_labels = self.get_option('edge_labels')
|
1778
|
+
|
1779
|
+
# We collect options for edges, default values and for-some-edges
|
1780
|
+
# information. These are combined into dictionaries on a per-edge
|
1781
|
+
# basis, for all edges
|
1782
|
+
|
1783
|
+
# Defaults
|
1784
|
+
|
1785
|
+
dec = cc.to_rgb(self.get_option('edge_color'))
|
1786
|
+
if edge_fills:
|
1787
|
+
defc = cc.to_rgb(self.get_option('edge_fill_color'))
|
1788
|
+
det = self.get_option('edge_thickness')
|
1789
|
+
|
1790
|
+
if edge_labels:
|
1791
|
+
edge_labels_math = self.get_option('edge_labels_math')
|
1792
|
+
delc = cc.to_rgb(self.get_option('edge_label_color'))
|
1793
|
+
dels = self.get_option('edge_label_sloped')
|
1794
|
+
delp = self.get_option('edge_label_placement')
|
1795
|
+
|
1796
|
+
# Retrieve dictionaries for selected edges
|
1797
|
+
edge_colors = self.get_option('edge_colors')
|
1798
|
+
if edge_fills:
|
1799
|
+
edge_fill_colors = self.get_option('edge_fill_colors')
|
1800
|
+
edge_thicknesses = self.get_option('edge_thicknesses')
|
1801
|
+
if edge_labels:
|
1802
|
+
edge_label_colors = self.get_option('edge_label_colors')
|
1803
|
+
edge_label_slopes = self.get_option('edge_label_slopes')
|
1804
|
+
edge_label_placements = self.get_option('edge_label_placements')
|
1805
|
+
|
1806
|
+
# Form dictionaries, each indexed for all edges
|
1807
|
+
#
|
1808
|
+
# A key of a dictionary indexed by edges may be set for an edge of
|
1809
|
+
# an undirected graph in the "wrong" order, so we use a "reverse" to
|
1810
|
+
# test for this case. Everything formed here conforms to the order
|
1811
|
+
# used in the graph.
|
1812
|
+
|
1813
|
+
e_color = {}
|
1814
|
+
if edge_fills:
|
1815
|
+
ef_color = {}
|
1816
|
+
e_thick = {}
|
1817
|
+
if edge_labels:
|
1818
|
+
el_color = {}
|
1819
|
+
el_slope = {}
|
1820
|
+
el_placement = {}
|
1821
|
+
|
1822
|
+
for e in self._graph.edges(sort=False):
|
1823
|
+
edge = (e[0], e[1])
|
1824
|
+
reverse = (e[1], e[0])
|
1825
|
+
|
1826
|
+
c = dec
|
1827
|
+
if edge in edge_colors or (not is_directed and reverse in edge_colors):
|
1828
|
+
if edge in edge_colors:
|
1829
|
+
c = cc.to_rgb(edge_colors[edge])
|
1830
|
+
else:
|
1831
|
+
c = cc.to_rgb(edge_colors[reverse])
|
1832
|
+
e_color[edge] = c
|
1833
|
+
|
1834
|
+
if edge_fills:
|
1835
|
+
c = defc
|
1836
|
+
if edge in edge_fill_colors or (not is_directed and reverse in edge_fill_colors):
|
1837
|
+
if edge in edge_colors:
|
1838
|
+
c = cc.to_rgb(edge_fill_colors[edge])
|
1839
|
+
else:
|
1840
|
+
c = cc.to_rgb(edge_fill_colors[reverse])
|
1841
|
+
ef_color[edge] = c
|
1842
|
+
|
1843
|
+
et = det
|
1844
|
+
if edge in edge_thicknesses or (not is_directed and reverse in edge_thicknesses):
|
1845
|
+
if edge in edge_thicknesses:
|
1846
|
+
et = edge_thicknesses[edge]
|
1847
|
+
else:
|
1848
|
+
et = edge_thicknesses[reverse]
|
1849
|
+
e_thick[edge] = et
|
1850
|
+
|
1851
|
+
if edge_labels:
|
1852
|
+
c = delc
|
1853
|
+
if edge in edge_label_colors or (not is_directed and reverse in edge_label_colors):
|
1854
|
+
if edge in edge_label_colors:
|
1855
|
+
c = cc.to_rgb(edge_label_colors[edge])
|
1856
|
+
else:
|
1857
|
+
c = cc.to_rgb(edge_label_colors[reverse])
|
1858
|
+
el_color[edge] = c
|
1859
|
+
|
1860
|
+
els = dels
|
1861
|
+
if edge in edge_label_slopes or (not is_directed and reverse in edge_label_slopes):
|
1862
|
+
if edge in edge_label_slopes:
|
1863
|
+
els = edge_label_slopes[edge]
|
1864
|
+
else:
|
1865
|
+
els = edge_label_slopes[reverse]
|
1866
|
+
el_slope[edge] = els
|
1867
|
+
|
1868
|
+
elp = delp
|
1869
|
+
if edge in edge_label_placements or (not is_directed and reverse in edge_label_placements):
|
1870
|
+
if edge in edge_label_placements:
|
1871
|
+
elp = edge_label_placements[edge]
|
1872
|
+
else:
|
1873
|
+
elp = edge_label_placements[reverse]
|
1874
|
+
el_placement[edge] = elp
|
1875
|
+
|
1876
|
+
##########
|
1877
|
+
# Loops
|
1878
|
+
##########
|
1879
|
+
|
1880
|
+
# Loops can be styled much like any other edge by indexing on a pair of
|
1881
|
+
# two equal vertices though edge thickness is not implemented in
|
1882
|
+
# tkz-graph! Size and direction are unique, and are indexed by the
|
1883
|
+
# vertex rather than on edges.
|
1884
|
+
|
1885
|
+
# Loop placements are pairs of length, compass-point
|
1886
|
+
if customized:
|
1887
|
+
if self._graph.has_loops():
|
1888
|
+
dlp = self.get_option('loop_placement')
|
1889
|
+
loop_placements = self.get_option('loop_placements')
|
1890
|
+
lp_placement = {}
|
1891
|
+
for u in vertex_list:
|
1892
|
+
lp = dlp
|
1893
|
+
if u in loop_placements:
|
1894
|
+
lp = loop_placements[u]
|
1895
|
+
lp_placement[u] = lp
|
1896
|
+
|
1897
|
+
############################
|
1898
|
+
# Build the output string
|
1899
|
+
############################
|
1900
|
+
|
1901
|
+
# s is the eventual tkz string
|
1902
|
+
# Everything should now be in place
|
1903
|
+
# We build a list and then concatenate it as the return value
|
1904
|
+
s = ['\\begin{tikzpicture}\n']
|
1905
|
+
|
1906
|
+
if not customized:
|
1907
|
+
s += ['\\GraphInit[vstyle=', style, ']\n%\n']
|
1908
|
+
|
1909
|
+
# Internal strings representing colors are defined here in custom style
|
1910
|
+
if customized:
|
1911
|
+
# Define all the colors for the vertices: perimeter, fill, label
|
1912
|
+
vertex_color_names = {}
|
1913
|
+
vertex_fill_color_names = {}
|
1914
|
+
vertex_label_color_names = {}
|
1915
|
+
for u in vertex_list:
|
1916
|
+
vertex_color_names[u] = 'c' + prefix + str(index_of_vertex[u])
|
1917
|
+
s += [r'\definecolor{', vertex_color_names[u], '}{rgb}', '{']
|
1918
|
+
s += [str(round(v_color[u][0], 4)), ',']
|
1919
|
+
s += [str(round(v_color[u][1], 4)), ',']
|
1920
|
+
s += [str(round(v_color[u][2], 4)), '}\n']
|
1921
|
+
vertex_fill_color_names[u] = 'cf' + prefix + str(index_of_vertex[u])
|
1922
|
+
s += [r'\definecolor{', vertex_fill_color_names[u], '}{rgb}', '{']
|
1923
|
+
s += [str(round(vf_color[u][0], 4)), ',']
|
1924
|
+
s += [str(round(vf_color[u][1], 4)), ',']
|
1925
|
+
s += [str(round(vf_color[u][2], 4)), '}\n']
|
1926
|
+
if vertex_labels:
|
1927
|
+
vertex_label_color_names[u] = 'cl' + prefix + str(index_of_vertex[u])
|
1928
|
+
s += [r'\definecolor{', vertex_label_color_names[u], '}{rgb}{']
|
1929
|
+
s += [str(round(vl_color[u][0], 4)), ',']
|
1930
|
+
s += [str(round(vl_color[u][1], 4)), ',']
|
1931
|
+
s += [str(round(vl_color[u][2], 4)), '}\n']
|
1932
|
+
# Define all the colors for the edges: perimeter, fill, label
|
1933
|
+
edge_color_names = {}
|
1934
|
+
edge_fill_color_names = {}
|
1935
|
+
edge_label_color_names = {}
|
1936
|
+
for e in self._graph.edge_iterator():
|
1937
|
+
edge = (e[0], e[1])
|
1938
|
+
edge_color_names[edge] = 'c' + prefix + str(index_of_vertex[edge[0]]) + prefix + str(index_of_vertex[edge[1]])
|
1939
|
+
s += [r'\definecolor{', edge_color_names[edge], '}{rgb}{']
|
1940
|
+
s += [str(round(e_color[edge][0], 4)), ',']
|
1941
|
+
s += [str(round(e_color[edge][1], 4)), ',']
|
1942
|
+
s += [str(round(e_color[edge][2], 4)), '}\n']
|
1943
|
+
if edge_fills:
|
1944
|
+
edge_fill_color_names[edge] = 'cf' + prefix + str(index_of_vertex[edge[0]]) + prefix + str(index_of_vertex[edge[1]])
|
1945
|
+
s += [r'\definecolor{', edge_fill_color_names[edge], '}{rgb}{']
|
1946
|
+
s += [str(round(ef_color[edge][0], 4)), ',']
|
1947
|
+
s += [str(round(ef_color[edge][1], 4)), ',']
|
1948
|
+
s += [str(round(ef_color[edge][2], 4)), '}\n']
|
1949
|
+
if edge_labels:
|
1950
|
+
edge_label_color_names[edge] = 'cl' + prefix + str(index_of_vertex[edge[0]]) + prefix + str(index_of_vertex[edge[1]])
|
1951
|
+
s += [r'\definecolor{', edge_label_color_names[edge], '}{rgb}{']
|
1952
|
+
s += [str(round(el_color[edge][0], 4)), ',']
|
1953
|
+
s += [str(round(el_color[edge][1], 4)), ',']
|
1954
|
+
s += [str(round(el_color[edge][2], 4)), '}\n']
|
1955
|
+
s += ['%\n']
|
1956
|
+
|
1957
|
+
# Create vertices
|
1958
|
+
v = []
|
1959
|
+
box = ''
|
1960
|
+
used = False
|
1961
|
+
for u in vertex_list:
|
1962
|
+
t = [r'\Vertex[']
|
1963
|
+
# colors, shapes, sizes, labels/placement for 'Custom' style
|
1964
|
+
if customized:
|
1965
|
+
t += ['style={'] # begin style list
|
1966
|
+
t += ['minimum size=', str(round(float(scale * v_size[u]), 4)),
|
1967
|
+
units, ',']
|
1968
|
+
t += ['draw=', vertex_color_names[u], ',']
|
1969
|
+
t += ['fill=', vertex_fill_color_names[u], ',']
|
1970
|
+
if vertex_labels:
|
1971
|
+
t += ['text=', vertex_label_color_names[u], ',']
|
1972
|
+
if v_shape[u] == 'sphere':
|
1973
|
+
t += ['shape=circle,shading=ball,line width=0pt,ball color=', vertex_color_names[u], ',']
|
1974
|
+
else:
|
1975
|
+
t += ['shape=', v_shape[u]]
|
1976
|
+
t += ['},'] # end style list
|
1977
|
+
if vertex_labels:
|
1978
|
+
if vl_placement[u] == 'center':
|
1979
|
+
t += ['LabelOut=false,']
|
1980
|
+
else:
|
1981
|
+
t += ['LabelOut=true,']
|
1982
|
+
t += ['Ldist=', str(round(float(scale * vl_placement[u][0]), 4)), units, ',']
|
1983
|
+
t += ['Lpos=', str(round(float(vl_placement[u][1]), 4)), ','] # degrees, no units
|
1984
|
+
else:
|
1985
|
+
t += ['NoLabel,']
|
1986
|
+
# vertex label information is available to all pre-built styles
|
1987
|
+
# but may be ignored by the style, so not apparent
|
1988
|
+
if vertex_labels or not customized:
|
1989
|
+
if vertex_labels_math and not (isinstance(u, str) and u[0] == '$' and u[-1] == '$'):
|
1990
|
+
ltx = str(latex(u))
|
1991
|
+
if '\\' in ltx: # complicated case; use \sbox
|
1992
|
+
box = r'\sbox{\vertex}{$' + ltx + '$}'
|
1993
|
+
lab = r'\usebox{\vertex}'
|
1994
|
+
else:
|
1995
|
+
lab = r'\hbox{$%s$}' % ltx
|
1996
|
+
else:
|
1997
|
+
lab = r'\hbox{%s}' % u
|
1998
|
+
t += ['L=', lab, ',']
|
1999
|
+
scaled_pos = translate(pos[u])
|
2000
|
+
t += ['x=', str(round(float(scale * scaled_pos[0]), 4)), units, ',']
|
2001
|
+
t += ['y=', str(round(float(scale * scaled_pos[1]), 4)), units]
|
2002
|
+
t += [']']
|
2003
|
+
t += ['{', prefix, str(index_of_vertex[u]), '}\n']
|
2004
|
+
if box:
|
2005
|
+
v += [box] + t
|
2006
|
+
box = ''
|
2007
|
+
used = True
|
2008
|
+
else:
|
2009
|
+
v += t
|
2010
|
+
if used:
|
2011
|
+
s += [r'\newsavebox{\vertex}' + '\n'] + v
|
2012
|
+
else:
|
2013
|
+
s += v
|
2014
|
+
s += ['%\n']
|
2015
|
+
|
2016
|
+
# Create edges and loops
|
2017
|
+
for e in self._graph.edges(sort=False):
|
2018
|
+
edge = (e[0], e[1])
|
2019
|
+
loop = e[0] == e[1]
|
2020
|
+
if loop:
|
2021
|
+
u = e[0]
|
2022
|
+
s += ['\\Loop[']
|
2023
|
+
if customized:
|
2024
|
+
s += ['dist=', str(round(float(scale * lp_placement[u][0]), 4)), units, ',']
|
2025
|
+
s += ['dir=', lp_placement[u][1], ',']
|
2026
|
+
else:
|
2027
|
+
s += ['\\Edge[']
|
2028
|
+
# colors, shapes, sizes, labels/placement for 'Custom' style
|
2029
|
+
if customized:
|
2030
|
+
if not loop: # lw not available for loops!
|
2031
|
+
s += ['lw=', str(round(float(scale * e_thick[edge]), 4)), units, ',']
|
2032
|
+
s += ['style={'] # begin style list
|
2033
|
+
if is_directed and not loop:
|
2034
|
+
s += ['post, bend right', ',']
|
2035
|
+
s += ['color=', edge_color_names[edge], ',']
|
2036
|
+
if edge_fills:
|
2037
|
+
s += ['double=', edge_fill_color_names[edge]]
|
2038
|
+
s += ['},'] # end style list
|
2039
|
+
if edge_labels:
|
2040
|
+
s += ['labelstyle={']
|
2041
|
+
if el_slope[edge]:
|
2042
|
+
s += ['sloped,']
|
2043
|
+
if isinstance(el_placement[edge], str):
|
2044
|
+
s += [el_placement[edge], ',']
|
2045
|
+
else:
|
2046
|
+
s += ['pos=', str(round(float(el_placement[edge]), 4)), ','] # no units needed
|
2047
|
+
s += ['text=', edge_label_color_names[edge], ',']
|
2048
|
+
s += ['},']
|
2049
|
+
el = self._graph.edge_label(edge[0], edge[1])
|
2050
|
+
if edge_labels_math and not (isinstance(el, str) and el[0] == '$' and el[-1] == '$'):
|
2051
|
+
lab = r'\hbox{$%s$}' % latex(el)
|
2052
|
+
else:
|
2053
|
+
lab = r'\hbox{%s}' % el
|
2054
|
+
s += ['label=', lab, ',']
|
2055
|
+
s += [']']
|
2056
|
+
if not loop:
|
2057
|
+
s += ['(', prefix, str(index_of_vertex[e[0]]), ')']
|
2058
|
+
s += ['(', prefix, str(index_of_vertex[e[1]]), ')\n']
|
2059
|
+
|
2060
|
+
# Wrap it up
|
2061
|
+
s += ['%\n']
|
2062
|
+
s += ['\\end{tikzpicture}']
|
2063
|
+
|
2064
|
+
return ''.join(s)
|