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.
Files changed (260) hide show
  1. passagemath_graphs-10.6.1rc1.dist-info/METADATA +292 -0
  2. passagemath_graphs-10.6.1rc1.dist-info/RECORD +260 -0
  3. passagemath_graphs-10.6.1rc1.dist-info/WHEEL +5 -0
  4. passagemath_graphs-10.6.1rc1.dist-info/top_level.txt +2 -0
  5. passagemath_graphs.libs/libgcc_s-69c45f16.so.1 +0 -0
  6. passagemath_graphs.libs/libgmp-8e78bd9b.so.10.5.0 +0 -0
  7. passagemath_graphs.libs/libstdc++-1f1a71be.so.6.0.33 +0 -0
  8. sage/all__sagemath_graphs.py +39 -0
  9. sage/combinat/abstract_tree.py +2723 -0
  10. sage/combinat/all__sagemath_graphs.py +34 -0
  11. sage/combinat/binary_tree.py +5306 -0
  12. sage/combinat/cluster_algebra_quiver/all.py +22 -0
  13. sage/combinat/cluster_algebra_quiver/cluster_seed.py +5208 -0
  14. sage/combinat/cluster_algebra_quiver/interact.py +124 -0
  15. sage/combinat/cluster_algebra_quiver/mutation_class.py +625 -0
  16. sage/combinat/cluster_algebra_quiver/mutation_type.py +1555 -0
  17. sage/combinat/cluster_algebra_quiver/quiver.py +2290 -0
  18. sage/combinat/cluster_algebra_quiver/quiver_mutation_type.py +2468 -0
  19. sage/combinat/designs/MOLS_handbook_data.py +570 -0
  20. sage/combinat/designs/all.py +58 -0
  21. sage/combinat/designs/bibd.py +1655 -0
  22. sage/combinat/designs/block_design.py +1071 -0
  23. sage/combinat/designs/covering_array.py +269 -0
  24. sage/combinat/designs/covering_design.py +530 -0
  25. sage/combinat/designs/database.py +5615 -0
  26. sage/combinat/designs/design_catalog.py +122 -0
  27. sage/combinat/designs/designs_pyx.cpython-310-aarch64-linux-gnu.so +0 -0
  28. sage/combinat/designs/designs_pyx.pxd +21 -0
  29. sage/combinat/designs/designs_pyx.pyx +993 -0
  30. sage/combinat/designs/difference_family.py +3951 -0
  31. sage/combinat/designs/difference_matrices.py +279 -0
  32. sage/combinat/designs/evenly_distributed_sets.cpython-310-aarch64-linux-gnu.so +0 -0
  33. sage/combinat/designs/evenly_distributed_sets.pyx +661 -0
  34. sage/combinat/designs/ext_rep.py +1064 -0
  35. sage/combinat/designs/gen_quadrangles_with_spread.cpython-310-aarch64-linux-gnu.so +0 -0
  36. sage/combinat/designs/gen_quadrangles_with_spread.pyx +339 -0
  37. sage/combinat/designs/group_divisible_designs.py +361 -0
  38. sage/combinat/designs/incidence_structures.py +2357 -0
  39. sage/combinat/designs/latin_squares.py +581 -0
  40. sage/combinat/designs/orthogonal_arrays.py +2244 -0
  41. sage/combinat/designs/orthogonal_arrays_build_recursive.py +1780 -0
  42. sage/combinat/designs/orthogonal_arrays_find_recursive.cpython-310-aarch64-linux-gnu.so +0 -0
  43. sage/combinat/designs/orthogonal_arrays_find_recursive.pyx +967 -0
  44. sage/combinat/designs/resolvable_bibd.py +815 -0
  45. sage/combinat/designs/steiner_quadruple_systems.py +1306 -0
  46. sage/combinat/designs/subhypergraph_search.cpython-310-aarch64-linux-gnu.so +0 -0
  47. sage/combinat/designs/subhypergraph_search.pyx +530 -0
  48. sage/combinat/designs/twographs.py +306 -0
  49. sage/combinat/finite_state_machine.py +14874 -0
  50. sage/combinat/finite_state_machine_generators.py +2006 -0
  51. sage/combinat/graph_path.py +448 -0
  52. sage/combinat/interval_posets.py +3908 -0
  53. sage/combinat/nu_tamari_lattice.py +269 -0
  54. sage/combinat/ordered_tree.py +1446 -0
  55. sage/combinat/posets/all.py +46 -0
  56. sage/combinat/posets/bubble_shuffle.py +247 -0
  57. sage/combinat/posets/cartesian_product.py +493 -0
  58. sage/combinat/posets/d_complete.py +182 -0
  59. sage/combinat/posets/elements.py +273 -0
  60. sage/combinat/posets/forest.py +30 -0
  61. sage/combinat/posets/hasse_cython.cpython-310-aarch64-linux-gnu.so +0 -0
  62. sage/combinat/posets/hasse_cython.pyx +174 -0
  63. sage/combinat/posets/hasse_diagram.py +3672 -0
  64. sage/combinat/posets/hochschild_lattice.py +158 -0
  65. sage/combinat/posets/incidence_algebras.py +794 -0
  66. sage/combinat/posets/lattices.py +5117 -0
  67. sage/combinat/posets/linear_extension_iterator.cpython-310-aarch64-linux-gnu.so +0 -0
  68. sage/combinat/posets/linear_extension_iterator.pyx +292 -0
  69. sage/combinat/posets/linear_extensions.py +1037 -0
  70. sage/combinat/posets/mobile.py +275 -0
  71. sage/combinat/posets/moebius_algebra.py +776 -0
  72. sage/combinat/posets/poset_examples.py +2178 -0
  73. sage/combinat/posets/posets.py +9360 -0
  74. sage/combinat/rooted_tree.py +1070 -0
  75. sage/combinat/shard_order.py +239 -0
  76. sage/combinat/tamari_lattices.py +384 -0
  77. sage/combinat/yang_baxter_graph.py +923 -0
  78. sage/databases/all__sagemath_graphs.py +1 -0
  79. sage/databases/knotinfo_db.py +1231 -0
  80. sage/ext_data/all__sagemath_graphs.py +1 -0
  81. sage/ext_data/graphs/graph_plot_js.html +330 -0
  82. sage/ext_data/kenzo/CP2.txt +45 -0
  83. sage/ext_data/kenzo/CP3.txt +349 -0
  84. sage/ext_data/kenzo/CP4.txt +4774 -0
  85. sage/ext_data/kenzo/README.txt +49 -0
  86. sage/ext_data/kenzo/S4.txt +20 -0
  87. sage/graphs/all.py +42 -0
  88. sage/graphs/asteroidal_triples.cpython-310-aarch64-linux-gnu.so +0 -0
  89. sage/graphs/asteroidal_triples.pyx +320 -0
  90. sage/graphs/base/all.py +1 -0
  91. sage/graphs/base/boost_graph.cpython-310-aarch64-linux-gnu.so +0 -0
  92. sage/graphs/base/boost_graph.pxd +106 -0
  93. sage/graphs/base/boost_graph.pyx +3045 -0
  94. sage/graphs/base/c_graph.cpython-310-aarch64-linux-gnu.so +0 -0
  95. sage/graphs/base/c_graph.pxd +106 -0
  96. sage/graphs/base/c_graph.pyx +5096 -0
  97. sage/graphs/base/dense_graph.cpython-310-aarch64-linux-gnu.so +0 -0
  98. sage/graphs/base/dense_graph.pxd +28 -0
  99. sage/graphs/base/dense_graph.pyx +801 -0
  100. sage/graphs/base/graph_backends.cpython-310-aarch64-linux-gnu.so +0 -0
  101. sage/graphs/base/graph_backends.pxd +5 -0
  102. sage/graphs/base/graph_backends.pyx +797 -0
  103. sage/graphs/base/overview.py +85 -0
  104. sage/graphs/base/sparse_graph.cpython-310-aarch64-linux-gnu.so +0 -0
  105. sage/graphs/base/sparse_graph.pxd +90 -0
  106. sage/graphs/base/sparse_graph.pyx +1653 -0
  107. sage/graphs/base/static_dense_graph.cpython-310-aarch64-linux-gnu.so +0 -0
  108. sage/graphs/base/static_dense_graph.pxd +5 -0
  109. sage/graphs/base/static_dense_graph.pyx +1032 -0
  110. sage/graphs/base/static_sparse_backend.cpython-310-aarch64-linux-gnu.so +0 -0
  111. sage/graphs/base/static_sparse_backend.pxd +27 -0
  112. sage/graphs/base/static_sparse_backend.pyx +1583 -0
  113. sage/graphs/base/static_sparse_graph.cpython-310-aarch64-linux-gnu.so +0 -0
  114. sage/graphs/base/static_sparse_graph.pxd +37 -0
  115. sage/graphs/base/static_sparse_graph.pyx +1375 -0
  116. sage/graphs/bipartite_graph.py +2732 -0
  117. sage/graphs/centrality.cpython-310-aarch64-linux-gnu.so +0 -0
  118. sage/graphs/centrality.pyx +1038 -0
  119. sage/graphs/cographs.py +519 -0
  120. sage/graphs/comparability.cpython-310-aarch64-linux-gnu.so +0 -0
  121. sage/graphs/comparability.pyx +851 -0
  122. sage/graphs/connectivity.cpython-310-aarch64-linux-gnu.so +0 -0
  123. sage/graphs/connectivity.pxd +157 -0
  124. sage/graphs/connectivity.pyx +4813 -0
  125. sage/graphs/convexity_properties.cpython-310-aarch64-linux-gnu.so +0 -0
  126. sage/graphs/convexity_properties.pxd +16 -0
  127. sage/graphs/convexity_properties.pyx +870 -0
  128. sage/graphs/digraph.py +4754 -0
  129. sage/graphs/digraph_generators.py +1993 -0
  130. sage/graphs/distances_all_pairs.cpython-310-aarch64-linux-gnu.so +0 -0
  131. sage/graphs/distances_all_pairs.pxd +12 -0
  132. sage/graphs/distances_all_pairs.pyx +2938 -0
  133. sage/graphs/domination.py +1363 -0
  134. sage/graphs/dot2tex_utils.py +100 -0
  135. sage/graphs/edge_connectivity.cpython-310-aarch64-linux-gnu.so +0 -0
  136. sage/graphs/edge_connectivity.pyx +1215 -0
  137. sage/graphs/generators/all.py +1 -0
  138. sage/graphs/generators/basic.py +1769 -0
  139. sage/graphs/generators/chessboard.py +538 -0
  140. sage/graphs/generators/classical_geometries.py +1611 -0
  141. sage/graphs/generators/degree_sequence.py +235 -0
  142. sage/graphs/generators/distance_regular.cpython-310-aarch64-linux-gnu.so +0 -0
  143. sage/graphs/generators/distance_regular.pyx +2846 -0
  144. sage/graphs/generators/families.py +4759 -0
  145. sage/graphs/generators/intersection.py +565 -0
  146. sage/graphs/generators/platonic_solids.py +262 -0
  147. sage/graphs/generators/random.py +2623 -0
  148. sage/graphs/generators/smallgraphs.py +5741 -0
  149. sage/graphs/generators/world_map.py +724 -0
  150. sage/graphs/generic_graph.py +26867 -0
  151. sage/graphs/generic_graph_pyx.cpython-310-aarch64-linux-gnu.so +0 -0
  152. sage/graphs/generic_graph_pyx.pxd +34 -0
  153. sage/graphs/generic_graph_pyx.pyx +1673 -0
  154. sage/graphs/genus.cpython-310-aarch64-linux-gnu.so +0 -0
  155. sage/graphs/genus.pyx +622 -0
  156. sage/graphs/graph.py +9645 -0
  157. sage/graphs/graph_coloring.cpython-310-aarch64-linux-gnu.so +0 -0
  158. sage/graphs/graph_coloring.pyx +2284 -0
  159. sage/graphs/graph_database.py +1177 -0
  160. sage/graphs/graph_decompositions/all.py +1 -0
  161. sage/graphs/graph_decompositions/bandwidth.cpython-310-aarch64-linux-gnu.so +0 -0
  162. sage/graphs/graph_decompositions/bandwidth.pyx +428 -0
  163. sage/graphs/graph_decompositions/clique_separators.cpython-310-aarch64-linux-gnu.so +0 -0
  164. sage/graphs/graph_decompositions/clique_separators.pyx +616 -0
  165. sage/graphs/graph_decompositions/cutwidth.cpython-310-aarch64-linux-gnu.so +0 -0
  166. sage/graphs/graph_decompositions/cutwidth.pyx +753 -0
  167. sage/graphs/graph_decompositions/fast_digraph.cpython-310-aarch64-linux-gnu.so +0 -0
  168. sage/graphs/graph_decompositions/fast_digraph.pxd +13 -0
  169. sage/graphs/graph_decompositions/fast_digraph.pyx +212 -0
  170. sage/graphs/graph_decompositions/graph_products.cpython-310-aarch64-linux-gnu.so +0 -0
  171. sage/graphs/graph_decompositions/graph_products.pyx +508 -0
  172. sage/graphs/graph_decompositions/modular_decomposition.cpython-310-aarch64-linux-gnu.so +0 -0
  173. sage/graphs/graph_decompositions/modular_decomposition.pxd +27 -0
  174. sage/graphs/graph_decompositions/modular_decomposition.pyx +1536 -0
  175. sage/graphs/graph_decompositions/slice_decomposition.cpython-310-aarch64-linux-gnu.so +0 -0
  176. sage/graphs/graph_decompositions/slice_decomposition.pxd +18 -0
  177. sage/graphs/graph_decompositions/slice_decomposition.pyx +1106 -0
  178. sage/graphs/graph_decompositions/tree_decomposition.cpython-310-aarch64-linux-gnu.so +0 -0
  179. sage/graphs/graph_decompositions/tree_decomposition.pxd +17 -0
  180. sage/graphs/graph_decompositions/tree_decomposition.pyx +1996 -0
  181. sage/graphs/graph_decompositions/vertex_separation.cpython-310-aarch64-linux-gnu.so +0 -0
  182. sage/graphs/graph_decompositions/vertex_separation.pxd +5 -0
  183. sage/graphs/graph_decompositions/vertex_separation.pyx +1963 -0
  184. sage/graphs/graph_editor.py +82 -0
  185. sage/graphs/graph_generators.py +3314 -0
  186. sage/graphs/graph_generators_pyx.cpython-310-aarch64-linux-gnu.so +0 -0
  187. sage/graphs/graph_generators_pyx.pyx +95 -0
  188. sage/graphs/graph_input.py +812 -0
  189. sage/graphs/graph_latex.py +2064 -0
  190. sage/graphs/graph_list.py +410 -0
  191. sage/graphs/graph_plot.py +1756 -0
  192. sage/graphs/graph_plot_js.py +338 -0
  193. sage/graphs/hyperbolicity.cpython-310-aarch64-linux-gnu.so +0 -0
  194. sage/graphs/hyperbolicity.pyx +1704 -0
  195. sage/graphs/hypergraph_generators.py +364 -0
  196. sage/graphs/independent_sets.cpython-310-aarch64-linux-gnu.so +0 -0
  197. sage/graphs/independent_sets.pxd +13 -0
  198. sage/graphs/independent_sets.pyx +402 -0
  199. sage/graphs/isgci.py +1033 -0
  200. sage/graphs/isoperimetric_inequalities.cpython-310-aarch64-linux-gnu.so +0 -0
  201. sage/graphs/isoperimetric_inequalities.pyx +489 -0
  202. sage/graphs/line_graph.cpython-310-aarch64-linux-gnu.so +0 -0
  203. sage/graphs/line_graph.pyx +743 -0
  204. sage/graphs/lovasz_theta.py +77 -0
  205. sage/graphs/matching.py +1633 -0
  206. sage/graphs/matching_covered_graph.py +3590 -0
  207. sage/graphs/orientations.py +1489 -0
  208. sage/graphs/partial_cube.py +459 -0
  209. sage/graphs/path_enumeration.cpython-310-aarch64-linux-gnu.so +0 -0
  210. sage/graphs/path_enumeration.pyx +2040 -0
  211. sage/graphs/pq_trees.py +1129 -0
  212. sage/graphs/print_graphs.py +201 -0
  213. sage/graphs/schnyder.py +865 -0
  214. sage/graphs/spanning_tree.cpython-310-aarch64-linux-gnu.so +0 -0
  215. sage/graphs/spanning_tree.pyx +1457 -0
  216. sage/graphs/strongly_regular_db.cpython-310-aarch64-linux-gnu.so +0 -0
  217. sage/graphs/strongly_regular_db.pyx +3340 -0
  218. sage/graphs/traversals.cpython-310-aarch64-linux-gnu.so +0 -0
  219. sage/graphs/traversals.pxd +9 -0
  220. sage/graphs/traversals.pyx +1872 -0
  221. sage/graphs/trees.cpython-310-aarch64-linux-gnu.so +0 -0
  222. sage/graphs/trees.pxd +15 -0
  223. sage/graphs/trees.pyx +310 -0
  224. sage/graphs/tutte_polynomial.py +713 -0
  225. sage/graphs/views.cpython-310-aarch64-linux-gnu.so +0 -0
  226. sage/graphs/views.pyx +794 -0
  227. sage/graphs/weakly_chordal.cpython-310-aarch64-linux-gnu.so +0 -0
  228. sage/graphs/weakly_chordal.pyx +604 -0
  229. sage/groups/all__sagemath_graphs.py +1 -0
  230. sage/groups/perm_gps/all__sagemath_graphs.py +1 -0
  231. sage/groups/perm_gps/partn_ref/all__sagemath_graphs.py +1 -0
  232. sage/groups/perm_gps/partn_ref/refinement_graphs.cpython-310-aarch64-linux-gnu.so +0 -0
  233. sage/groups/perm_gps/partn_ref/refinement_graphs.pxd +38 -0
  234. sage/groups/perm_gps/partn_ref/refinement_graphs.pyx +1666 -0
  235. sage/knots/all.py +6 -0
  236. sage/knots/free_knotinfo_monoid.py +507 -0
  237. sage/knots/gauss_code.py +291 -0
  238. sage/knots/knot.py +682 -0
  239. sage/knots/knot_table.py +284 -0
  240. sage/knots/knotinfo.py +2900 -0
  241. sage/knots/link.py +4715 -0
  242. sage/sandpiles/all.py +13 -0
  243. sage/sandpiles/examples.py +225 -0
  244. sage/sandpiles/sandpile.py +6365 -0
  245. sage/topology/all.py +22 -0
  246. sage/topology/cell_complex.py +1214 -0
  247. sage/topology/cubical_complex.py +1976 -0
  248. sage/topology/delta_complex.py +1806 -0
  249. sage/topology/filtered_simplicial_complex.py +744 -0
  250. sage/topology/moment_angle_complex.py +823 -0
  251. sage/topology/simplicial_complex.py +5160 -0
  252. sage/topology/simplicial_complex_catalog.py +92 -0
  253. sage/topology/simplicial_complex_examples.py +1680 -0
  254. sage/topology/simplicial_complex_homset.py +205 -0
  255. sage/topology/simplicial_complex_morphism.py +836 -0
  256. sage/topology/simplicial_set.py +4102 -0
  257. sage/topology/simplicial_set_catalog.py +55 -0
  258. sage/topology/simplicial_set_constructions.py +2954 -0
  259. sage/topology/simplicial_set_examples.py +865 -0
  260. 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)