passagemath-categories 10.6.32__cp314-cp314t-musllinux_1_2_aarch64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- passagemath_categories-10.6.32.dist-info/METADATA +156 -0
- passagemath_categories-10.6.32.dist-info/RECORD +719 -0
- passagemath_categories-10.6.32.dist-info/WHEEL +5 -0
- passagemath_categories-10.6.32.dist-info/top_level.txt +2 -0
- passagemath_categories.libs/libgcc_s-2d945d6c.so.1 +0 -0
- passagemath_categories.libs/libgmp-28992bcb.so.10.5.0 +0 -0
- passagemath_categories.libs/libstdc++-85f2cd6d.so.6.0.33 +0 -0
- sage/all__sagemath_categories.py +28 -0
- sage/arith/all.py +38 -0
- sage/arith/constants.pxd +27 -0
- sage/arith/functions.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/arith/functions.pxd +4 -0
- sage/arith/functions.pyx +221 -0
- sage/arith/misc.py +6552 -0
- sage/arith/multi_modular.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/arith/multi_modular.pxd +39 -0
- sage/arith/multi_modular.pyx +994 -0
- sage/arith/rational_reconstruction.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/arith/rational_reconstruction.pxd +4 -0
- sage/arith/rational_reconstruction.pyx +115 -0
- sage/arith/srange.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/arith/srange.pyx +571 -0
- sage/calculus/all__sagemath_categories.py +2 -0
- sage/calculus/functional.py +481 -0
- sage/calculus/functions.py +151 -0
- sage/categories/additive_groups.py +73 -0
- sage/categories/additive_magmas.py +1044 -0
- sage/categories/additive_monoids.py +114 -0
- sage/categories/additive_semigroups.py +184 -0
- sage/categories/affine_weyl_groups.py +238 -0
- sage/categories/algebra_ideals.py +95 -0
- sage/categories/algebra_modules.py +96 -0
- sage/categories/algebras.py +349 -0
- sage/categories/algebras_with_basis.py +377 -0
- sage/categories/all.py +160 -0
- sage/categories/aperiodic_semigroups.py +29 -0
- sage/categories/associative_algebras.py +47 -0
- sage/categories/bialgebras.py +101 -0
- sage/categories/bialgebras_with_basis.py +414 -0
- sage/categories/bimodules.py +206 -0
- sage/categories/chain_complexes.py +268 -0
- sage/categories/classical_crystals.py +480 -0
- sage/categories/coalgebras.py +405 -0
- sage/categories/coalgebras_with_basis.py +232 -0
- sage/categories/coercion_methods.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/categories/coercion_methods.pyx +52 -0
- sage/categories/commutative_additive_groups.py +104 -0
- sage/categories/commutative_additive_monoids.py +45 -0
- sage/categories/commutative_additive_semigroups.py +48 -0
- sage/categories/commutative_algebra_ideals.py +87 -0
- sage/categories/commutative_algebras.py +94 -0
- sage/categories/commutative_ring_ideals.py +58 -0
- sage/categories/commutative_rings.py +736 -0
- sage/categories/complete_discrete_valuation.py +293 -0
- sage/categories/complex_reflection_groups.py +145 -0
- sage/categories/complex_reflection_or_generalized_coxeter_groups.py +1249 -0
- sage/categories/coxeter_group_algebras.py +186 -0
- sage/categories/coxeter_groups.py +3402 -0
- sage/categories/crystals.py +2628 -0
- sage/categories/cw_complexes.py +216 -0
- sage/categories/dedekind_domains.py +137 -0
- sage/categories/discrete_valuation.py +325 -0
- sage/categories/distributive_magmas_and_additive_magmas.py +100 -0
- sage/categories/division_rings.py +114 -0
- sage/categories/domains.py +95 -0
- sage/categories/drinfeld_modules.py +789 -0
- sage/categories/dual.py +42 -0
- sage/categories/enumerated_sets.py +1146 -0
- sage/categories/euclidean_domains.py +271 -0
- sage/categories/examples/algebras_with_basis.py +102 -0
- sage/categories/examples/all.py +1 -0
- sage/categories/examples/commutative_additive_monoids.py +130 -0
- sage/categories/examples/commutative_additive_semigroups.py +199 -0
- sage/categories/examples/coxeter_groups.py +8 -0
- sage/categories/examples/crystals.py +236 -0
- sage/categories/examples/cw_complexes.py +163 -0
- sage/categories/examples/facade_sets.py +187 -0
- sage/categories/examples/filtered_algebras_with_basis.py +204 -0
- sage/categories/examples/filtered_modules_with_basis.py +154 -0
- sage/categories/examples/finite_coxeter_groups.py +252 -0
- sage/categories/examples/finite_dimensional_algebras_with_basis.py +148 -0
- sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py +495 -0
- sage/categories/examples/finite_enumerated_sets.py +208 -0
- sage/categories/examples/finite_monoids.py +150 -0
- sage/categories/examples/finite_semigroups.py +190 -0
- sage/categories/examples/finite_weyl_groups.py +191 -0
- sage/categories/examples/graded_connected_hopf_algebras_with_basis.py +152 -0
- sage/categories/examples/graded_modules_with_basis.py +168 -0
- sage/categories/examples/graphs.py +122 -0
- sage/categories/examples/hopf_algebras_with_basis.py +145 -0
- sage/categories/examples/infinite_enumerated_sets.py +190 -0
- sage/categories/examples/lie_algebras.py +352 -0
- sage/categories/examples/lie_algebras_with_basis.py +196 -0
- sage/categories/examples/magmas.py +162 -0
- sage/categories/examples/manifolds.py +94 -0
- sage/categories/examples/monoids.py +144 -0
- sage/categories/examples/posets.py +178 -0
- sage/categories/examples/semigroups.py +580 -0
- sage/categories/examples/semigroups_cython.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/categories/examples/semigroups_cython.pyx +221 -0
- sage/categories/examples/semirings.py +249 -0
- sage/categories/examples/sets_cat.py +706 -0
- sage/categories/examples/sets_with_grading.py +101 -0
- sage/categories/examples/with_realizations.py +542 -0
- sage/categories/fields.py +991 -0
- sage/categories/filtered_algebras.py +63 -0
- sage/categories/filtered_algebras_with_basis.py +548 -0
- sage/categories/filtered_hopf_algebras_with_basis.py +138 -0
- sage/categories/filtered_modules.py +210 -0
- sage/categories/filtered_modules_with_basis.py +1209 -0
- sage/categories/finite_complex_reflection_groups.py +1506 -0
- sage/categories/finite_coxeter_groups.py +1138 -0
- sage/categories/finite_crystals.py +103 -0
- sage/categories/finite_dimensional_algebras_with_basis.py +1860 -0
- sage/categories/finite_dimensional_bialgebras_with_basis.py +33 -0
- sage/categories/finite_dimensional_coalgebras_with_basis.py +33 -0
- sage/categories/finite_dimensional_graded_lie_algebras_with_basis.py +231 -0
- sage/categories/finite_dimensional_hopf_algebras_with_basis.py +38 -0
- sage/categories/finite_dimensional_lie_algebras_with_basis.py +2774 -0
- sage/categories/finite_dimensional_modules_with_basis.py +1407 -0
- sage/categories/finite_dimensional_nilpotent_lie_algebras_with_basis.py +167 -0
- sage/categories/finite_dimensional_semisimple_algebras_with_basis.py +270 -0
- sage/categories/finite_enumerated_sets.py +769 -0
- sage/categories/finite_fields.py +252 -0
- sage/categories/finite_groups.py +256 -0
- sage/categories/finite_lattice_posets.py +242 -0
- sage/categories/finite_monoids.py +316 -0
- sage/categories/finite_permutation_groups.py +339 -0
- sage/categories/finite_posets.py +1994 -0
- sage/categories/finite_semigroups.py +136 -0
- sage/categories/finite_sets.py +93 -0
- sage/categories/finite_weyl_groups.py +39 -0
- sage/categories/finitely_generated_lambda_bracket_algebras.py +112 -0
- sage/categories/finitely_generated_lie_conformal_algebras.py +114 -0
- sage/categories/finitely_generated_magmas.py +57 -0
- sage/categories/finitely_generated_semigroups.py +214 -0
- sage/categories/function_fields.py +76 -0
- sage/categories/g_sets.py +77 -0
- sage/categories/gcd_domains.py +65 -0
- sage/categories/generalized_coxeter_groups.py +94 -0
- sage/categories/graded_algebras.py +85 -0
- sage/categories/graded_algebras_with_basis.py +258 -0
- sage/categories/graded_bialgebras.py +32 -0
- sage/categories/graded_bialgebras_with_basis.py +32 -0
- sage/categories/graded_coalgebras.py +65 -0
- sage/categories/graded_coalgebras_with_basis.py +51 -0
- sage/categories/graded_hopf_algebras.py +41 -0
- sage/categories/graded_hopf_algebras_with_basis.py +169 -0
- sage/categories/graded_lie_algebras.py +91 -0
- sage/categories/graded_lie_algebras_with_basis.py +44 -0
- sage/categories/graded_lie_conformal_algebras.py +74 -0
- sage/categories/graded_modules.py +133 -0
- sage/categories/graded_modules_with_basis.py +329 -0
- sage/categories/graphs.py +138 -0
- sage/categories/group_algebras.py +430 -0
- sage/categories/groupoid.py +94 -0
- sage/categories/groups.py +667 -0
- sage/categories/h_trivial_semigroups.py +64 -0
- sage/categories/hecke_modules.py +185 -0
- sage/categories/highest_weight_crystals.py +980 -0
- sage/categories/hopf_algebras.py +219 -0
- sage/categories/hopf_algebras_with_basis.py +309 -0
- sage/categories/infinite_enumerated_sets.py +115 -0
- sage/categories/integral_domains.py +203 -0
- sage/categories/j_trivial_semigroups.py +29 -0
- sage/categories/kac_moody_algebras.py +82 -0
- sage/categories/kahler_algebras.py +203 -0
- sage/categories/l_trivial_semigroups.py +63 -0
- sage/categories/lambda_bracket_algebras.py +280 -0
- sage/categories/lambda_bracket_algebras_with_basis.py +107 -0
- sage/categories/lattice_posets.py +89 -0
- sage/categories/left_modules.py +49 -0
- sage/categories/lie_algebras.py +1070 -0
- sage/categories/lie_algebras_with_basis.py +261 -0
- sage/categories/lie_conformal_algebras.py +350 -0
- sage/categories/lie_conformal_algebras_with_basis.py +147 -0
- sage/categories/lie_groups.py +73 -0
- sage/categories/loop_crystals.py +1290 -0
- sage/categories/magmas.py +1189 -0
- sage/categories/magmas_and_additive_magmas.py +149 -0
- sage/categories/magmatic_algebras.py +365 -0
- sage/categories/manifolds.py +352 -0
- sage/categories/matrix_algebras.py +40 -0
- sage/categories/metric_spaces.py +387 -0
- sage/categories/modular_abelian_varieties.py +78 -0
- sage/categories/modules.py +989 -0
- sage/categories/modules_with_basis.py +2794 -0
- sage/categories/monoid_algebras.py +38 -0
- sage/categories/monoids.py +739 -0
- sage/categories/noetherian_rings.py +87 -0
- sage/categories/number_fields.py +242 -0
- sage/categories/ore_modules.py +189 -0
- sage/categories/partially_ordered_monoids.py +49 -0
- sage/categories/permutation_groups.py +63 -0
- sage/categories/pointed_sets.py +42 -0
- sage/categories/polyhedra.py +74 -0
- sage/categories/poor_man_map.py +270 -0
- sage/categories/posets.py +722 -0
- sage/categories/principal_ideal_domains.py +270 -0
- sage/categories/quantum_group_representations.py +543 -0
- sage/categories/quotient_fields.py +728 -0
- sage/categories/r_trivial_semigroups.py +45 -0
- sage/categories/regular_crystals.py +898 -0
- sage/categories/regular_supercrystals.py +170 -0
- sage/categories/right_modules.py +49 -0
- sage/categories/ring_ideals.py +74 -0
- sage/categories/rings.py +1904 -0
- sage/categories/rngs.py +175 -0
- sage/categories/schemes.py +393 -0
- sage/categories/semigroups.py +1060 -0
- sage/categories/semirings.py +71 -0
- sage/categories/semisimple_algebras.py +114 -0
- sage/categories/sets_with_grading.py +235 -0
- sage/categories/shephard_groups.py +43 -0
- sage/categories/signed_tensor.py +120 -0
- sage/categories/simplicial_complexes.py +134 -0
- sage/categories/simplicial_sets.py +1206 -0
- sage/categories/super_algebras.py +149 -0
- sage/categories/super_algebras_with_basis.py +144 -0
- sage/categories/super_hopf_algebras_with_basis.py +126 -0
- sage/categories/super_lie_conformal_algebras.py +193 -0
- sage/categories/super_modules.py +229 -0
- sage/categories/super_modules_with_basis.py +193 -0
- sage/categories/supercommutative_algebras.py +99 -0
- sage/categories/supercrystals.py +406 -0
- sage/categories/tensor.py +110 -0
- sage/categories/topological_spaces.py +170 -0
- sage/categories/triangular_kac_moody_algebras.py +439 -0
- sage/categories/tutorial.py +58 -0
- sage/categories/unique_factorization_domains.py +318 -0
- sage/categories/unital_algebras.py +426 -0
- sage/categories/vector_bundles.py +159 -0
- sage/categories/vector_spaces.py +357 -0
- sage/categories/weyl_groups.py +853 -0
- sage/combinat/all__sagemath_categories.py +34 -0
- sage/combinat/backtrack.py +180 -0
- sage/combinat/combinat.py +2269 -0
- sage/combinat/combinat_cython.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/combinat/combinat_cython.pxd +6 -0
- sage/combinat/combinat_cython.pyx +390 -0
- sage/combinat/combination.py +796 -0
- sage/combinat/combinatorial_map.py +416 -0
- sage/combinat/composition.py +2192 -0
- sage/combinat/dlx.py +510 -0
- sage/combinat/integer_lists/__init__.py +7 -0
- sage/combinat/integer_lists/base.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/combinat/integer_lists/base.pxd +16 -0
- sage/combinat/integer_lists/base.pyx +713 -0
- sage/combinat/integer_lists/invlex.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/combinat/integer_lists/invlex.pxd +4 -0
- sage/combinat/integer_lists/invlex.pyx +1650 -0
- sage/combinat/integer_lists/lists.py +328 -0
- sage/combinat/integer_lists/nn.py +48 -0
- sage/combinat/integer_vector.py +1818 -0
- sage/combinat/integer_vector_weighted.py +413 -0
- sage/combinat/matrices/all__sagemath_categories.py +5 -0
- sage/combinat/matrices/dancing_links.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/combinat/matrices/dancing_links.pyx +1159 -0
- sage/combinat/matrices/dancing_links_c.h +380 -0
- sage/combinat/matrices/dlxcpp.py +136 -0
- sage/combinat/partition.py +10070 -0
- sage/combinat/partitions.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/combinat/partitions.pyx +743 -0
- sage/combinat/permutation.py +10168 -0
- sage/combinat/permutation_cython.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/combinat/permutation_cython.pxd +11 -0
- sage/combinat/permutation_cython.pyx +407 -0
- sage/combinat/q_analogues.py +1090 -0
- sage/combinat/ranker.py +268 -0
- sage/combinat/subset.py +1561 -0
- sage/combinat/subsets_hereditary.py +202 -0
- sage/combinat/subsets_pairwise.py +184 -0
- sage/combinat/tools.py +63 -0
- sage/combinat/tuple.py +348 -0
- sage/data_structures/all.py +2 -0
- sage/data_structures/all__sagemath_categories.py +2 -0
- sage/data_structures/binary_matrix.pxd +138 -0
- sage/data_structures/binary_search.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/data_structures/binary_search.pxd +3 -0
- sage/data_structures/binary_search.pyx +66 -0
- sage/data_structures/bitset.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/data_structures/bitset.pxd +40 -0
- sage/data_structures/bitset.pyx +2385 -0
- sage/data_structures/bitset_base.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/data_structures/bitset_base.pxd +926 -0
- sage/data_structures/bitset_base.pyx +117 -0
- sage/data_structures/bitset_intrinsics.h +487 -0
- sage/data_structures/blas_dict.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/data_structures/blas_dict.pxd +12 -0
- sage/data_structures/blas_dict.pyx +469 -0
- sage/data_structures/list_of_pairs.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/data_structures/list_of_pairs.pxd +16 -0
- sage/data_structures/list_of_pairs.pyx +122 -0
- sage/data_structures/mutable_poset.py +3312 -0
- sage/data_structures/pairing_heap.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/data_structures/pairing_heap.h +346 -0
- sage/data_structures/pairing_heap.pxd +88 -0
- sage/data_structures/pairing_heap.pyx +1464 -0
- sage/data_structures/sparse_bitset.pxd +62 -0
- sage/data_structures/stream.py +5070 -0
- sage/databases/all__sagemath_categories.py +7 -0
- sage/databases/sql_db.py +2236 -0
- sage/ext/all__sagemath_categories.py +3 -0
- sage/ext/fast_callable.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/ext/fast_callable.pxd +4 -0
- sage/ext/fast_callable.pyx +2746 -0
- sage/ext/fast_eval.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/ext/fast_eval.pxd +1 -0
- sage/ext/fast_eval.pyx +102 -0
- sage/ext/interpreters/__init__.py +1 -0
- sage/ext/interpreters/all__sagemath_categories.py +2 -0
- sage/ext/interpreters/wrapper_el.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/ext/interpreters/wrapper_el.pxd +18 -0
- sage/ext/interpreters/wrapper_el.pyx +148 -0
- sage/ext/interpreters/wrapper_py.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/ext/interpreters/wrapper_py.pxd +17 -0
- sage/ext/interpreters/wrapper_py.pyx +133 -0
- sage/functions/airy.py +937 -0
- sage/functions/all.py +97 -0
- sage/functions/bessel.py +2102 -0
- sage/functions/error.py +784 -0
- sage/functions/exp_integral.py +1529 -0
- sage/functions/gamma.py +1087 -0
- sage/functions/generalized.py +672 -0
- sage/functions/hyperbolic.py +747 -0
- sage/functions/hypergeometric.py +1156 -0
- sage/functions/jacobi.py +1705 -0
- sage/functions/log.py +1402 -0
- sage/functions/min_max.py +338 -0
- sage/functions/orthogonal_polys.py +3106 -0
- sage/functions/other.py +2303 -0
- sage/functions/piecewise.py +1505 -0
- sage/functions/prime_pi.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/functions/prime_pi.pyx +262 -0
- sage/functions/special.py +1212 -0
- sage/functions/spike_function.py +278 -0
- sage/functions/transcendental.py +690 -0
- sage/functions/trig.py +1062 -0
- sage/functions/wigner.py +726 -0
- sage/geometry/abc.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/geometry/abc.pyx +82 -0
- sage/geometry/all__sagemath_categories.py +1 -0
- sage/groups/all__sagemath_categories.py +11 -0
- sage/groups/generic.py +1733 -0
- sage/groups/groups_catalog.py +113 -0
- sage/groups/perm_gps/all__sagemath_categories.py +1 -0
- sage/groups/perm_gps/partn_ref/all.py +1 -0
- sage/groups/perm_gps/partn_ref/all__sagemath_categories.py +1 -0
- sage/groups/perm_gps/partn_ref/automorphism_group_canonical_label.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/groups/perm_gps/partn_ref/automorphism_group_canonical_label.pxd +52 -0
- sage/groups/perm_gps/partn_ref/automorphism_group_canonical_label.pyx +906 -0
- sage/groups/perm_gps/partn_ref/canonical_augmentation.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/groups/perm_gps/partn_ref/canonical_augmentation.pxd +85 -0
- sage/groups/perm_gps/partn_ref/canonical_augmentation.pyx +534 -0
- sage/groups/perm_gps/partn_ref/data_structures.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/groups/perm_gps/partn_ref/data_structures.pxd +576 -0
- sage/groups/perm_gps/partn_ref/data_structures.pyx +1792 -0
- sage/groups/perm_gps/partn_ref/double_coset.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/groups/perm_gps/partn_ref/double_coset.pxd +45 -0
- sage/groups/perm_gps/partn_ref/double_coset.pyx +739 -0
- sage/groups/perm_gps/partn_ref/refinement_lists.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/groups/perm_gps/partn_ref/refinement_lists.pxd +18 -0
- sage/groups/perm_gps/partn_ref/refinement_lists.pyx +82 -0
- sage/groups/perm_gps/partn_ref/refinement_python.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/groups/perm_gps/partn_ref/refinement_python.pxd +16 -0
- sage/groups/perm_gps/partn_ref/refinement_python.pyx +564 -0
- sage/groups/perm_gps/partn_ref/refinement_sets.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/groups/perm_gps/partn_ref/refinement_sets.pxd +60 -0
- sage/groups/perm_gps/partn_ref/refinement_sets.pyx +858 -0
- sage/interfaces/abc.py +140 -0
- sage/interfaces/all.py +58 -0
- sage/interfaces/all__sagemath_categories.py +1 -0
- sage/interfaces/expect.py +1643 -0
- sage/interfaces/interface.py +1682 -0
- sage/interfaces/process.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/interfaces/process.pxd +5 -0
- sage/interfaces/process.pyx +288 -0
- sage/interfaces/quit.py +167 -0
- sage/interfaces/sage0.py +604 -0
- sage/interfaces/sagespawn.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/interfaces/sagespawn.pyx +308 -0
- sage/interfaces/tab_completion.py +101 -0
- sage/misc/all__sagemath_categories.py +78 -0
- sage/misc/allocator.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/misc/allocator.pxd +6 -0
- sage/misc/allocator.pyx +47 -0
- sage/misc/binary_tree.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/misc/binary_tree.pxd +29 -0
- sage/misc/binary_tree.pyx +537 -0
- sage/misc/callable_dict.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/misc/callable_dict.pyx +89 -0
- sage/misc/citation.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/misc/citation.pyx +159 -0
- sage/misc/converting_dict.py +293 -0
- sage/misc/defaults.py +129 -0
- sage/misc/derivative.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/misc/derivative.pyx +223 -0
- sage/misc/functional.py +2005 -0
- sage/misc/html.py +589 -0
- sage/misc/latex.py +2673 -0
- sage/misc/latex_macros.py +236 -0
- sage/misc/latex_standalone.py +1833 -0
- sage/misc/map_threaded.py +38 -0
- sage/misc/mathml.py +76 -0
- sage/misc/method_decorator.py +88 -0
- sage/misc/mrange.py +755 -0
- sage/misc/multireplace.py +41 -0
- sage/misc/object_multiplexer.py +92 -0
- sage/misc/parser.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/misc/parser.pyx +1107 -0
- sage/misc/random_testing.py +264 -0
- sage/misc/rest_index_of_methods.py +377 -0
- sage/misc/search.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/misc/search.pxd +2 -0
- sage/misc/search.pyx +68 -0
- sage/misc/stopgap.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/misc/stopgap.pyx +95 -0
- sage/misc/table.py +853 -0
- sage/monoids/all__sagemath_categories.py +1 -0
- sage/monoids/indexed_free_monoid.py +1071 -0
- sage/monoids/monoid.py +82 -0
- sage/numerical/all__sagemath_categories.py +1 -0
- sage/numerical/backends/all__sagemath_categories.py +1 -0
- sage/numerical/backends/generic_backend.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/numerical/backends/generic_backend.pxd +61 -0
- sage/numerical/backends/generic_backend.pyx +1893 -0
- sage/numerical/backends/generic_sdp_backend.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/numerical/backends/generic_sdp_backend.pxd +38 -0
- sage/numerical/backends/generic_sdp_backend.pyx +755 -0
- sage/parallel/all.py +6 -0
- sage/parallel/decorate.py +575 -0
- sage/parallel/map_reduce.py +1997 -0
- sage/parallel/multiprocessing_sage.py +76 -0
- sage/parallel/ncpus.py +35 -0
- sage/parallel/parallelism.py +364 -0
- sage/parallel/reference.py +47 -0
- sage/parallel/use_fork.py +333 -0
- sage/rings/abc.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/abc.pxd +31 -0
- sage/rings/abc.pyx +526 -0
- sage/rings/algebraic_closure_finite_field.py +1154 -0
- sage/rings/all__sagemath_categories.py +91 -0
- sage/rings/big_oh.py +227 -0
- sage/rings/continued_fraction.py +2754 -0
- sage/rings/continued_fraction_gosper.py +220 -0
- sage/rings/factorint.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/factorint.pyx +295 -0
- sage/rings/fast_arith.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/fast_arith.pxd +21 -0
- sage/rings/fast_arith.pyx +535 -0
- sage/rings/finite_rings/all__sagemath_categories.py +9 -0
- sage/rings/finite_rings/conway_polynomials.py +542 -0
- sage/rings/finite_rings/element_base.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/finite_rings/element_base.pxd +12 -0
- sage/rings/finite_rings/element_base.pyx +1176 -0
- sage/rings/finite_rings/finite_field_base.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/finite_rings/finite_field_base.pxd +7 -0
- sage/rings/finite_rings/finite_field_base.pyx +2171 -0
- sage/rings/finite_rings/finite_field_constructor.py +827 -0
- sage/rings/finite_rings/finite_field_prime_modn.py +372 -0
- sage/rings/finite_rings/galois_group.py +154 -0
- sage/rings/finite_rings/hom_finite_field.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/finite_rings/hom_finite_field.pxd +23 -0
- sage/rings/finite_rings/hom_finite_field.pyx +856 -0
- sage/rings/finite_rings/hom_prime_finite_field.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/finite_rings/hom_prime_finite_field.pxd +15 -0
- sage/rings/finite_rings/hom_prime_finite_field.pyx +164 -0
- sage/rings/finite_rings/homset.py +357 -0
- sage/rings/finite_rings/integer_mod.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/finite_rings/integer_mod.pxd +56 -0
- sage/rings/finite_rings/integer_mod.pyx +4586 -0
- sage/rings/finite_rings/integer_mod_limits.h +11 -0
- sage/rings/finite_rings/integer_mod_ring.py +2044 -0
- sage/rings/finite_rings/residue_field.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/finite_rings/residue_field.pxd +30 -0
- sage/rings/finite_rings/residue_field.pyx +1811 -0
- sage/rings/finite_rings/stdint.pxd +19 -0
- sage/rings/fraction_field.py +1452 -0
- sage/rings/fraction_field_element.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/fraction_field_element.pyx +1357 -0
- sage/rings/function_field/all.py +7 -0
- sage/rings/function_field/all__sagemath_categories.py +2 -0
- sage/rings/function_field/constructor.py +218 -0
- sage/rings/function_field/element.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/function_field/element.pxd +11 -0
- sage/rings/function_field/element.pyx +1008 -0
- sage/rings/function_field/element_rational.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/function_field/element_rational.pyx +513 -0
- sage/rings/function_field/extensions.py +230 -0
- sage/rings/function_field/function_field.py +1468 -0
- sage/rings/function_field/function_field_rational.py +1005 -0
- sage/rings/function_field/ideal.py +1155 -0
- sage/rings/function_field/ideal_rational.py +629 -0
- sage/rings/function_field/jacobian_base.py +826 -0
- sage/rings/function_field/jacobian_hess.py +1053 -0
- sage/rings/function_field/jacobian_khuri_makdisi.py +1027 -0
- sage/rings/function_field/maps.py +1039 -0
- sage/rings/function_field/order.py +281 -0
- sage/rings/function_field/order_basis.py +586 -0
- sage/rings/function_field/order_rational.py +576 -0
- sage/rings/function_field/place.py +426 -0
- sage/rings/function_field/place_rational.py +181 -0
- sage/rings/generic.py +320 -0
- sage/rings/homset.py +332 -0
- sage/rings/ideal.py +1885 -0
- sage/rings/ideal_monoid.py +215 -0
- sage/rings/infinity.py +1890 -0
- sage/rings/integer.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/integer.pxd +45 -0
- sage/rings/integer.pyx +7874 -0
- sage/rings/integer_ring.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/integer_ring.pxd +8 -0
- sage/rings/integer_ring.pyx +1693 -0
- sage/rings/laurent_series_ring.py +931 -0
- sage/rings/laurent_series_ring_element.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/laurent_series_ring_element.pxd +11 -0
- sage/rings/laurent_series_ring_element.pyx +1927 -0
- sage/rings/lazy_series.py +7815 -0
- sage/rings/lazy_series_ring.py +4356 -0
- sage/rings/localization.py +1043 -0
- sage/rings/morphism.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/morphism.pxd +39 -0
- sage/rings/morphism.pyx +3299 -0
- sage/rings/multi_power_series_ring.py +1145 -0
- sage/rings/multi_power_series_ring_element.py +2184 -0
- sage/rings/noncommutative_ideals.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/noncommutative_ideals.pyx +423 -0
- sage/rings/number_field/all__sagemath_categories.py +1 -0
- sage/rings/number_field/number_field_base.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/number_field/number_field_base.pxd +8 -0
- sage/rings/number_field/number_field_base.pyx +507 -0
- sage/rings/number_field/number_field_element_base.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/number_field/number_field_element_base.pxd +6 -0
- sage/rings/number_field/number_field_element_base.pyx +36 -0
- sage/rings/number_field/number_field_ideal.py +3550 -0
- sage/rings/padics/all__sagemath_categories.py +4 -0
- sage/rings/padics/local_generic.py +1670 -0
- sage/rings/padics/local_generic_element.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/padics/local_generic_element.pxd +5 -0
- sage/rings/padics/local_generic_element.pyx +1017 -0
- sage/rings/padics/misc.py +256 -0
- sage/rings/padics/padic_generic.py +1911 -0
- sage/rings/padics/pow_computer.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/padics/pow_computer.pxd +38 -0
- sage/rings/padics/pow_computer.pyx +671 -0
- sage/rings/padics/precision_error.py +24 -0
- sage/rings/polynomial/all__sagemath_categories.py +25 -0
- sage/rings/polynomial/commutative_polynomial.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/commutative_polynomial.pxd +6 -0
- sage/rings/polynomial/commutative_polynomial.pyx +24 -0
- sage/rings/polynomial/cyclotomic.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/cyclotomic.pyx +404 -0
- sage/rings/polynomial/flatten.py +711 -0
- sage/rings/polynomial/ideal.py +102 -0
- sage/rings/polynomial/infinite_polynomial_element.py +1768 -0
- sage/rings/polynomial/infinite_polynomial_ring.py +1653 -0
- sage/rings/polynomial/laurent_polynomial.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/laurent_polynomial.pxd +18 -0
- sage/rings/polynomial/laurent_polynomial.pyx +2190 -0
- sage/rings/polynomial/laurent_polynomial_ideal.py +590 -0
- sage/rings/polynomial/laurent_polynomial_ring.py +832 -0
- sage/rings/polynomial/laurent_polynomial_ring_base.py +708 -0
- sage/rings/polynomial/multi_polynomial.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/multi_polynomial.pxd +12 -0
- sage/rings/polynomial/multi_polynomial.pyx +3082 -0
- sage/rings/polynomial/multi_polynomial_element.py +2570 -0
- sage/rings/polynomial/multi_polynomial_ideal.py +5771 -0
- sage/rings/polynomial/multi_polynomial_ring.py +947 -0
- sage/rings/polynomial/multi_polynomial_ring_base.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/multi_polynomial_ring_base.pxd +15 -0
- sage/rings/polynomial/multi_polynomial_ring_base.pyx +1855 -0
- sage/rings/polynomial/multi_polynomial_sequence.py +2204 -0
- sage/rings/polynomial/polydict.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/polydict.pxd +45 -0
- sage/rings/polynomial/polydict.pyx +2701 -0
- sage/rings/polynomial/polynomial_compiled.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/polynomial_compiled.pxd +59 -0
- sage/rings/polynomial/polynomial_compiled.pyx +509 -0
- sage/rings/polynomial/polynomial_element.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/polynomial_element.pxd +64 -0
- sage/rings/polynomial/polynomial_element.pyx +13255 -0
- sage/rings/polynomial/polynomial_element_generic.py +1637 -0
- sage/rings/polynomial/polynomial_fateman.py +97 -0
- sage/rings/polynomial/polynomial_quotient_ring.py +2465 -0
- sage/rings/polynomial/polynomial_quotient_ring_element.py +779 -0
- sage/rings/polynomial/polynomial_ring.py +3784 -0
- sage/rings/polynomial/polynomial_ring_constructor.py +1051 -0
- sage/rings/polynomial/polynomial_ring_homomorphism.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/polynomial_ring_homomorphism.pxd +5 -0
- sage/rings/polynomial/polynomial_ring_homomorphism.pyx +121 -0
- sage/rings/polynomial/polynomial_singular_interface.py +549 -0
- sage/rings/polynomial/symmetric_ideal.py +989 -0
- sage/rings/polynomial/symmetric_reduction.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/symmetric_reduction.pxd +8 -0
- sage/rings/polynomial/symmetric_reduction.pyx +669 -0
- sage/rings/polynomial/term_order.py +2279 -0
- sage/rings/polynomial/toy_buchberger.py +449 -0
- sage/rings/polynomial/toy_d_basis.py +387 -0
- sage/rings/polynomial/toy_variety.py +362 -0
- sage/rings/power_series_mpoly.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/power_series_mpoly.pxd +9 -0
- sage/rings/power_series_mpoly.pyx +161 -0
- sage/rings/power_series_poly.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/power_series_poly.pxd +10 -0
- sage/rings/power_series_poly.pyx +1317 -0
- sage/rings/power_series_ring.py +1441 -0
- sage/rings/power_series_ring_element.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/power_series_ring_element.pxd +12 -0
- sage/rings/power_series_ring_element.pyx +3028 -0
- sage/rings/puiseux_series_ring.py +487 -0
- sage/rings/puiseux_series_ring_element.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/puiseux_series_ring_element.pxd +7 -0
- sage/rings/puiseux_series_ring_element.pyx +1055 -0
- sage/rings/qqbar_decorators.py +167 -0
- sage/rings/quotient_ring.py +1598 -0
- sage/rings/quotient_ring_element.py +979 -0
- sage/rings/rational.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/rational.pxd +20 -0
- sage/rings/rational.pyx +4284 -0
- sage/rings/rational_field.py +1730 -0
- sage/rings/real_double.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/real_double.pxd +16 -0
- sage/rings/real_double.pyx +2218 -0
- sage/rings/real_lazy.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/real_lazy.pxd +30 -0
- sage/rings/real_lazy.pyx +1773 -0
- sage/rings/ring.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/ring.pxd +30 -0
- sage/rings/ring.pyx +850 -0
- sage/rings/semirings/all.py +3 -0
- sage/rings/semirings/non_negative_integer_semiring.py +107 -0
- sage/rings/semirings/tropical_mpolynomial.py +972 -0
- sage/rings/semirings/tropical_polynomial.py +997 -0
- sage/rings/semirings/tropical_semiring.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/semirings/tropical_semiring.pyx +676 -0
- sage/rings/semirings/tropical_variety.py +1701 -0
- sage/rings/sum_of_squares.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/sum_of_squares.pxd +3 -0
- sage/rings/sum_of_squares.pyx +336 -0
- sage/rings/tests.py +504 -0
- sage/schemes/affine/affine_homset.py +508 -0
- sage/schemes/affine/affine_morphism.py +1574 -0
- sage/schemes/affine/affine_point.py +460 -0
- sage/schemes/affine/affine_rational_point.py +308 -0
- sage/schemes/affine/affine_space.py +1264 -0
- sage/schemes/affine/affine_subscheme.py +592 -0
- sage/schemes/affine/all.py +25 -0
- sage/schemes/all__sagemath_categories.py +5 -0
- sage/schemes/generic/algebraic_scheme.py +2092 -0
- sage/schemes/generic/all.py +5 -0
- sage/schemes/generic/ambient_space.py +400 -0
- sage/schemes/generic/divisor.py +465 -0
- sage/schemes/generic/divisor_group.py +313 -0
- sage/schemes/generic/glue.py +84 -0
- sage/schemes/generic/homset.py +820 -0
- sage/schemes/generic/hypersurface.py +234 -0
- sage/schemes/generic/morphism.py +2107 -0
- sage/schemes/generic/point.py +237 -0
- sage/schemes/generic/scheme.py +1190 -0
- sage/schemes/generic/spec.py +199 -0
- sage/schemes/product_projective/all.py +6 -0
- sage/schemes/product_projective/homset.py +236 -0
- sage/schemes/product_projective/morphism.py +517 -0
- sage/schemes/product_projective/point.py +568 -0
- sage/schemes/product_projective/rational_point.py +550 -0
- sage/schemes/product_projective/space.py +1301 -0
- sage/schemes/product_projective/subscheme.py +466 -0
- sage/schemes/projective/all.py +24 -0
- sage/schemes/projective/proj_bdd_height.py +453 -0
- sage/schemes/projective/projective_homset.py +718 -0
- sage/schemes/projective/projective_morphism.py +2792 -0
- sage/schemes/projective/projective_point.py +1484 -0
- sage/schemes/projective/projective_rational_point.py +569 -0
- sage/schemes/projective/projective_space.py +2571 -0
- sage/schemes/projective/projective_subscheme.py +1574 -0
- sage/sets/all.py +17 -0
- sage/sets/cartesian_product.py +376 -0
- sage/sets/condition_set.py +525 -0
- sage/sets/disjoint_set.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/sets/disjoint_set.pxd +36 -0
- sage/sets/disjoint_set.pyx +998 -0
- sage/sets/disjoint_union_enumerated_sets.py +625 -0
- sage/sets/family.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/sets/family.pxd +12 -0
- sage/sets/family.pyx +1556 -0
- sage/sets/finite_enumerated_set.py +406 -0
- sage/sets/finite_set_map_cy.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/sets/finite_set_map_cy.pxd +34 -0
- sage/sets/finite_set_map_cy.pyx +708 -0
- sage/sets/finite_set_maps.py +591 -0
- sage/sets/image_set.py +448 -0
- sage/sets/integer_range.py +829 -0
- sage/sets/non_negative_integers.py +241 -0
- sage/sets/positive_integers.py +93 -0
- sage/sets/primes.py +188 -0
- sage/sets/real_set.py +2760 -0
- sage/sets/recursively_enumerated_set.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/sets/recursively_enumerated_set.pxd +31 -0
- sage/sets/recursively_enumerated_set.pyx +2082 -0
- sage/sets/set.py +2083 -0
- sage/sets/set_from_iterator.py +1021 -0
- sage/sets/totally_ordered_finite_set.py +329 -0
- sage/symbolic/all__sagemath_categories.py +1 -0
- sage/symbolic/function.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/symbolic/function.pxd +29 -0
- sage/symbolic/function.pyx +1488 -0
- sage/symbolic/symbols.py +56 -0
- sage/tests/all__sagemath_categories.py +1 -0
- sage/tests/cython.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/tests/cython.pyx +37 -0
- sage/tests/stl_vector.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/tests/stl_vector.pyx +171 -0
- sage/typeset/all.py +6 -0
- sage/typeset/ascii_art.py +295 -0
- sage/typeset/character_art.py +789 -0
- sage/typeset/character_art_factory.py +572 -0
- sage/typeset/symbols.py +334 -0
- sage/typeset/unicode_art.py +183 -0
- sage/typeset/unicode_characters.py +101 -0
|
@@ -0,0 +1,1833 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-categories
|
|
2
|
+
r"""
|
|
3
|
+
Standalone LaTeX Document class and TikzPicture
|
|
4
|
+
|
|
5
|
+
This module contains two Python classes. Firstly, it contains a class
|
|
6
|
+
:class:`Standalone` to represent a LaTeX file using the standalone__
|
|
7
|
+
document class.
|
|
8
|
+
|
|
9
|
+
__ http://www.ctan.org/pkg/standalone
|
|
10
|
+
|
|
11
|
+
From its documentation:
|
|
12
|
+
|
|
13
|
+
*The standalone bundle allows users to easily place picture environments
|
|
14
|
+
or other material in own source files and compile these on their own or as
|
|
15
|
+
part of a main document. A special standalone class is provided for use
|
|
16
|
+
with such files, which by default crops the resulting output file to the
|
|
17
|
+
content. The standalone package enables the user to simply load the
|
|
18
|
+
standalone files using ``\input`` inside a main document.*
|
|
19
|
+
|
|
20
|
+
Secondly, it contains a class :class:`TikzPicture` which inherits from
|
|
21
|
+
:class:`Standalone` that represents a LaTeX file using the standalone
|
|
22
|
+
document class and containing a tikzpicture.
|
|
23
|
+
|
|
24
|
+
A Python Module for PGF/Tikz pictures. A TikzPicture object is created from
|
|
25
|
+
a string starting with ``r'\begin{tikzpicture}'`` and ending with
|
|
26
|
+
``r'\end{tikzpicture}'``.
|
|
27
|
+
|
|
28
|
+
The module allows to convert a standalone LaTeX document class file,
|
|
29
|
+
including tikzpictures, to an image. It allows conversion to pdf, png and
|
|
30
|
+
svg formats. It also show them automatically in Jupyter using rich
|
|
31
|
+
representation.
|
|
32
|
+
|
|
33
|
+
According to wikipedia, `PGF/TikZ`__ is a pair of languages for producing
|
|
34
|
+
vector graphics (e.g., technical illustrations and drawings) from a
|
|
35
|
+
geometric/algebraic description, with standard features including the
|
|
36
|
+
drawing of points, lines, arrows, paths, circles, ellipses and polygons.
|
|
37
|
+
|
|
38
|
+
__ https://www.ctan.org/pkg/pgf
|
|
39
|
+
|
|
40
|
+
EXAMPLES:
|
|
41
|
+
|
|
42
|
+
Standalone LaTeX document class
|
|
43
|
+
-------------------------------
|
|
44
|
+
|
|
45
|
+
First *Hello World* example::
|
|
46
|
+
|
|
47
|
+
sage: from sage.misc.latex_standalone import Standalone
|
|
48
|
+
sage: Standalone('Hello World')
|
|
49
|
+
\documentclass{standalone}
|
|
50
|
+
\begin{document}
|
|
51
|
+
Hello World
|
|
52
|
+
\end{document}
|
|
53
|
+
|
|
54
|
+
Loading a few latex packages::
|
|
55
|
+
|
|
56
|
+
sage: Standalone('Hello World', usepackage=['amsmath', 'amsfont'])
|
|
57
|
+
\documentclass{standalone}
|
|
58
|
+
\usepackage{amsmath}
|
|
59
|
+
\usepackage{amsfont}
|
|
60
|
+
\begin{document}
|
|
61
|
+
Hello World
|
|
62
|
+
\end{document}
|
|
63
|
+
|
|
64
|
+
Setting few standalone options (see documentation of standalone for a
|
|
65
|
+
complete list)::
|
|
66
|
+
|
|
67
|
+
sage: Standalone('Hello World', standalone_config=["border=4mm", "beamer=true"])
|
|
68
|
+
\documentclass{standalone}
|
|
69
|
+
\standaloneconfig{border=4mm}
|
|
70
|
+
\standaloneconfig{beamer=true}
|
|
71
|
+
\begin{document}
|
|
72
|
+
Hello World
|
|
73
|
+
\end{document}
|
|
74
|
+
|
|
75
|
+
Adding your own list of macros::
|
|
76
|
+
|
|
77
|
+
sage: Standalone('Hello World', macros=[r'\newcommand{\ZZ}{\mathbb{Z}}'])
|
|
78
|
+
\documentclass{standalone}
|
|
79
|
+
\newcommand{\ZZ}{\mathbb{Z}}
|
|
80
|
+
\begin{document}
|
|
81
|
+
Hello World
|
|
82
|
+
\end{document}
|
|
83
|
+
|
|
84
|
+
It provides conversion to images of different format::
|
|
85
|
+
|
|
86
|
+
sage: from sage.misc.latex_standalone import Standalone
|
|
87
|
+
sage: s = Standalone('Hello World')
|
|
88
|
+
sage: _ = s.pdf() # not tested
|
|
89
|
+
sage: _ = s.png() # not tested
|
|
90
|
+
sage: _ = s.svg() # not tested
|
|
91
|
+
sage: s # not tested, in Jupyter, this shows the image directly below the cell
|
|
92
|
+
|
|
93
|
+
TikzPicture
|
|
94
|
+
-----------
|
|
95
|
+
|
|
96
|
+
This module also contains a class :class:`TikzPicture` which inherits from
|
|
97
|
+
:class:`Standalone` to represent more specifically a tikzpicture which is
|
|
98
|
+
within a standalone document class.
|
|
99
|
+
|
|
100
|
+
First construct a string describing a tikzpicture::
|
|
101
|
+
|
|
102
|
+
sage: lines = []
|
|
103
|
+
sage: lines.append(r'\begin{tikzpicture}')
|
|
104
|
+
sage: lines.append(r'\draw[very thick,orange,->] (0,0) -- (1,1);')
|
|
105
|
+
sage: lines.append(r'\end{tikzpicture}')
|
|
106
|
+
sage: s = '\n'.join(lines)
|
|
107
|
+
sage: print(s)
|
|
108
|
+
\begin{tikzpicture}
|
|
109
|
+
\draw[very thick,orange,->] (0,0) -- (1,1);
|
|
110
|
+
\end{tikzpicture}
|
|
111
|
+
|
|
112
|
+
One may provide it as input to ``TikzPicture``::
|
|
113
|
+
|
|
114
|
+
sage: from sage.misc.latex_standalone import TikzPicture
|
|
115
|
+
sage: t = TikzPicture(s)
|
|
116
|
+
|
|
117
|
+
In the terminal, the following shows the content of the standalone
|
|
118
|
+
document class tex file which contains the tikzpicture. In Jupyter, it
|
|
119
|
+
shows the picture itself::
|
|
120
|
+
|
|
121
|
+
sage: t
|
|
122
|
+
\documentclass[tikz]{standalone}
|
|
123
|
+
\begin{document}
|
|
124
|
+
\begin{tikzpicture}
|
|
125
|
+
\draw[very thick,orange,->] (0,0) -- (1,1);
|
|
126
|
+
\end{tikzpicture}
|
|
127
|
+
\end{document}
|
|
128
|
+
|
|
129
|
+
As it is the case for :class:`Standalone`, the constructor of
|
|
130
|
+
``TikzPicture`` has many arguments allowing for example to add some more
|
|
131
|
+
``\usepackage`` lines::
|
|
132
|
+
|
|
133
|
+
sage: t = TikzPicture(s, usepackage=['amsmath'])
|
|
134
|
+
sage: t
|
|
135
|
+
\documentclass[tikz]{standalone}
|
|
136
|
+
\usepackage{amsmath}
|
|
137
|
+
\begin{document}
|
|
138
|
+
\begin{tikzpicture}
|
|
139
|
+
\draw[very thick,orange,->] (0,0) -- (1,1);
|
|
140
|
+
\end{tikzpicture}
|
|
141
|
+
\end{document}
|
|
142
|
+
|
|
143
|
+
Moreover, it allows to load some tikz libraries::
|
|
144
|
+
|
|
145
|
+
sage: t = TikzPicture(s, usetikzlibrary=['arrows'])
|
|
146
|
+
sage: t
|
|
147
|
+
\documentclass[tikz]{standalone}
|
|
148
|
+
\usetikzlibrary{arrows}
|
|
149
|
+
\begin{document}
|
|
150
|
+
\begin{tikzpicture}
|
|
151
|
+
\draw[very thick,orange,->] (0,0) -- (1,1);
|
|
152
|
+
\end{tikzpicture}
|
|
153
|
+
\end{document}
|
|
154
|
+
|
|
155
|
+
The following example illustrates that it works when providing the
|
|
156
|
+
tikzpicture code generated by Sage from some polyhedron::
|
|
157
|
+
|
|
158
|
+
sage: from sage.misc.latex_standalone import TikzPicture
|
|
159
|
+
sage: V = [[1,0,1], [1,0,0], [1,1,0], [0,0,-1],
|
|
160
|
+
....: [0,1,0], [-1,0,0], [0,1,1], [0,0,1], [0,-1,0]]
|
|
161
|
+
sage: P = Polyhedron(vertices=V).polar() # needs sage.geometry.polyhedron
|
|
162
|
+
sage: s1 = P.projection().tikz([674,108,-731],112, output_type='LatexExpr') # needs sage.geometry.polyhedron sage.plot
|
|
163
|
+
sage: t1 = TikzPicture(s1) # needs sage.geometry.polyhedron sage.plot
|
|
164
|
+
|
|
165
|
+
Open the image in a viewer (the returned value is a string giving the
|
|
166
|
+
absolute path to the file in some temporary directory)::
|
|
167
|
+
|
|
168
|
+
sage: path_to_file = t1.pdf() # not tested # needs sage.geometry.polyhedron sage.plot
|
|
169
|
+
|
|
170
|
+
Instead, you may save a pdf of the tikzpicture into a file of your choice
|
|
171
|
+
(but this does not open the viewer)::
|
|
172
|
+
|
|
173
|
+
sage: _ = t1.pdf('tikz_polytope.pdf') # not tested # needs sage.geometry.polyhedron sage.plot
|
|
174
|
+
|
|
175
|
+
Opening the image in a viewer can be turned off::
|
|
176
|
+
|
|
177
|
+
sage: _ = t1.pdf(view=False) # long time (2s), optional - latex, needs sage.geometry.polyhedron sage.plot
|
|
178
|
+
|
|
179
|
+
The same can be done with png format (translated from pdf with convert
|
|
180
|
+
command which needs the installation of imagemagick)::
|
|
181
|
+
|
|
182
|
+
sage: _ = t1.png(view=False) # long time (2s), optional - imagemagick latex, needs sage.geometry.polyhedron sage.plot
|
|
183
|
+
|
|
184
|
+
The string representation gives the header (5 lines) and tail (5 lines) of
|
|
185
|
+
the tikzpicture. In Jupyter, it will instead use rich representation and
|
|
186
|
+
show the image directly below the cell in png or svg format::
|
|
187
|
+
|
|
188
|
+
sage: t1 # needs sage.geometry.polyhedron sage.plot
|
|
189
|
+
\documentclass[tikz]{standalone}
|
|
190
|
+
\begin{document}
|
|
191
|
+
\begin{tikzpicture}%
|
|
192
|
+
[x={(0.249656cm, -0.577639cm)},
|
|
193
|
+
y={(0.777700cm, -0.358578cm)},
|
|
194
|
+
z={(-0.576936cm, -0.733318cm)},
|
|
195
|
+
...
|
|
196
|
+
\node[vertex] at (0.00000, -1.00000, 0.00000) {};
|
|
197
|
+
\node[vertex] at (-0.50000, -0.50000, -0.50000) {};
|
|
198
|
+
%%
|
|
199
|
+
%%
|
|
200
|
+
\end{tikzpicture}
|
|
201
|
+
\end{document}
|
|
202
|
+
|
|
203
|
+
Use ``print(t)`` to see the complete content of the file::
|
|
204
|
+
|
|
205
|
+
sage: print(t1) # not tested # needs sage.geometry.polyhedron sage.plot
|
|
206
|
+
|
|
207
|
+
Adding a border in the options avoids cropping the vertices of a graph::
|
|
208
|
+
|
|
209
|
+
sage: # needs sage.graphs
|
|
210
|
+
sage: g = graphs.PetersenGraph()
|
|
211
|
+
sage: s2 = latex(g) # takes 3s but the result is cached # optional - latex
|
|
212
|
+
sage: t2 = TikzPicture(s2, standalone_config=["border=4mm"], # optional - latex
|
|
213
|
+
....: usepackage=['tkz-graph'])
|
|
214
|
+
sage: _ = t2.pdf() # not tested
|
|
215
|
+
|
|
216
|
+
The current latex representation of a transducer is a tikzpicture using
|
|
217
|
+
the tikz library automata. The string can be used as input::
|
|
218
|
+
|
|
219
|
+
sage: # needs sage.graphs sage.modules
|
|
220
|
+
sage: s3 = latex(transducers.GrayCode())
|
|
221
|
+
sage: t3 = TikzPicture(s3, usetikzlibrary=['automata'])
|
|
222
|
+
sage: _ = t3.pdf(view=False) # long time (2s) # optional - latex
|
|
223
|
+
|
|
224
|
+
AUTHORS:
|
|
225
|
+
|
|
226
|
+
- Sébastien Labbé, initial version in slabbe-0.2.spkg, nov 2015.
|
|
227
|
+
- Sébastien Labbé, inclusion into SageMath from slabbe-0.6.2, July 2021.
|
|
228
|
+
"""
|
|
229
|
+
|
|
230
|
+
# ****************************************************************************
|
|
231
|
+
# Copyright (C) 2015-2022 Sébastien Labbé <slabqc@gmail.com>
|
|
232
|
+
#
|
|
233
|
+
# Distributed under the terms of the GNU General Public License (GPL)
|
|
234
|
+
# as published by the Free Software Foundation; either version 2 of
|
|
235
|
+
# the License, or (at your option) any later version.
|
|
236
|
+
# https://www.gnu.org/licenses/
|
|
237
|
+
# ****************************************************************************
|
|
238
|
+
from subprocess import run
|
|
239
|
+
import os
|
|
240
|
+
|
|
241
|
+
from sage.structure.sage_object import SageObject
|
|
242
|
+
from sage.misc.superseded import experimental
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
class Standalone(SageObject):
|
|
246
|
+
r"""
|
|
247
|
+
LaTeX standalone document class.
|
|
248
|
+
|
|
249
|
+
INPUT:
|
|
250
|
+
|
|
251
|
+
- ``content`` -- string; the content to be added in the document
|
|
252
|
+
between lines ``r'\begin{document}'`` and ``r'\end{document}'``
|
|
253
|
+
- ``document_class_options`` -- list of strings (default: ``[]``);
|
|
254
|
+
latex document class standalone options. Such options appear on the
|
|
255
|
+
line ``\documentclass[...]{standalone}`` between the brackets.
|
|
256
|
+
- ``standalone_config`` -- list of strings (default: ``[]``);
|
|
257
|
+
standalone configuration options. Such options are defined with
|
|
258
|
+
``\standaloneconfig{...}``.
|
|
259
|
+
- ``usepackage`` -- list of strings (default: ``[]``); latex packages
|
|
260
|
+
- ``macros`` -- list of strings (default: ``[]``); stuff you need for the picture
|
|
261
|
+
- ``use_sage_preamble`` -- boolean (default: ``False``); whether to include sage
|
|
262
|
+
latex preamble and sage latex macros, that is, the content of
|
|
263
|
+
:func:`sage.misc.latex.extra_preamble()`,
|
|
264
|
+
:func:`sage.misc.latex.extra_macros()` and
|
|
265
|
+
:func:`sage.misc.latex_macros.sage_latex_macros()`
|
|
266
|
+
|
|
267
|
+
EXAMPLES::
|
|
268
|
+
|
|
269
|
+
sage: from sage.misc.latex_standalone import Standalone
|
|
270
|
+
sage: content = "\\section{Intro}\nTest\n"
|
|
271
|
+
sage: t = Standalone(content)
|
|
272
|
+
sage: t
|
|
273
|
+
\documentclass{standalone}
|
|
274
|
+
\begin{document}
|
|
275
|
+
\section{Intro}
|
|
276
|
+
Test
|
|
277
|
+
\end{document}
|
|
278
|
+
|
|
279
|
+
::
|
|
280
|
+
|
|
281
|
+
sage: t = Standalone(content, standalone_config=["border=4mm"],
|
|
282
|
+
....: usepackage=['amsmath'])
|
|
283
|
+
sage: t
|
|
284
|
+
\documentclass{standalone}
|
|
285
|
+
\standaloneconfig{border=4mm}
|
|
286
|
+
\usepackage{amsmath}
|
|
287
|
+
\begin{document}
|
|
288
|
+
\section{Intro}
|
|
289
|
+
Test
|
|
290
|
+
\end{document}
|
|
291
|
+
"""
|
|
292
|
+
def __init__(self, content, document_class_options=None,
|
|
293
|
+
standalone_config=None, usepackage=None, macros=None,
|
|
294
|
+
use_sage_preamble=False):
|
|
295
|
+
r"""
|
|
296
|
+
See :class:`Standalone` for full information.
|
|
297
|
+
|
|
298
|
+
EXAMPLES::
|
|
299
|
+
|
|
300
|
+
sage: from sage.misc.latex_standalone import Standalone
|
|
301
|
+
sage: content = "\\section{Intro}\n\nTest\n"
|
|
302
|
+
sage: t = Standalone(content)
|
|
303
|
+
"""
|
|
304
|
+
self._content = content
|
|
305
|
+
self._document_class_options = [] if document_class_options is None else list(document_class_options)
|
|
306
|
+
self._standalone_config = [] if standalone_config is None else standalone_config
|
|
307
|
+
self._usepackage = [] if usepackage is None else usepackage
|
|
308
|
+
self._macros = [] if macros is None else macros
|
|
309
|
+
if use_sage_preamble:
|
|
310
|
+
from sage.misc.latex import _Latex_prefs
|
|
311
|
+
for key in ['preamble', 'macros']:
|
|
312
|
+
s = _Latex_prefs._option[key]
|
|
313
|
+
if s:
|
|
314
|
+
self._macros.append(s)
|
|
315
|
+
from sage.misc.latex_macros import sage_latex_macros
|
|
316
|
+
self._macros.extend(sage_latex_macros())
|
|
317
|
+
|
|
318
|
+
def _latex_file_header_lines(self):
|
|
319
|
+
r"""
|
|
320
|
+
EXAMPLES::
|
|
321
|
+
|
|
322
|
+
sage: latex.extra_preamble('')
|
|
323
|
+
sage: from sage.misc.latex_standalone import Standalone
|
|
324
|
+
sage: s = "\\begin{tikzpicture}\n\\draw (0,0) -- (1,1);\n\\end{tikzpicture}"
|
|
325
|
+
sage: A = ['tikz']
|
|
326
|
+
sage: B = ["border=4mm"]
|
|
327
|
+
sage: C = ['amsmath']
|
|
328
|
+
sage: t = Standalone(s, document_class_options=A, standalone_config=B, usepackage=C)
|
|
329
|
+
sage: t._latex_file_header_lines()[:6]
|
|
330
|
+
['\\documentclass[tikz]{standalone}',
|
|
331
|
+
'\\standaloneconfig{border=4mm}',
|
|
332
|
+
'\\usepackage{amsmath}']
|
|
333
|
+
"""
|
|
334
|
+
lines = []
|
|
335
|
+
if self._document_class_options:
|
|
336
|
+
options = ','.join(self._document_class_options)
|
|
337
|
+
lines.append(r"\documentclass[{}]{{standalone}}".format(options))
|
|
338
|
+
else:
|
|
339
|
+
lines.append(r"\documentclass{standalone}")
|
|
340
|
+
lines.extend(r"\standaloneconfig{{{}}}".format(config)
|
|
341
|
+
for config in self._standalone_config)
|
|
342
|
+
lines.extend(r"\usepackage{{{}}}".format(package)
|
|
343
|
+
for package in self._usepackage)
|
|
344
|
+
lines.extend(self._macros)
|
|
345
|
+
return lines
|
|
346
|
+
|
|
347
|
+
def _repr_(self):
|
|
348
|
+
r"""
|
|
349
|
+
Return a string representation of the Standalone file.
|
|
350
|
+
|
|
351
|
+
It contains the first few and last few lines of the content.
|
|
352
|
+
|
|
353
|
+
.. NOTE::
|
|
354
|
+
|
|
355
|
+
Use ``print(t)`` or ``str(t)`` to show or get the full content.
|
|
356
|
+
|
|
357
|
+
EXAMPLES:
|
|
358
|
+
|
|
359
|
+
When the content has 10 lines or less, it shows it all::
|
|
360
|
+
|
|
361
|
+
sage: from sage.misc.latex_standalone import Standalone
|
|
362
|
+
sage: s = "\\begin{tikzpicture}\n\\draw (0,0) -- (1,1);\n\\end{tikzpicture}"
|
|
363
|
+
sage: t = Standalone(s, document_class_options=['tikz'], standalone_config=["border=4mm"], usepackage=['amsmath'])
|
|
364
|
+
sage: t
|
|
365
|
+
\documentclass[tikz]{standalone}
|
|
366
|
+
\standaloneconfig{border=4mm}
|
|
367
|
+
\usepackage{amsmath}
|
|
368
|
+
\begin{document}
|
|
369
|
+
\begin{tikzpicture}
|
|
370
|
+
\draw (0,0) -- (1,1);
|
|
371
|
+
\end{tikzpicture}
|
|
372
|
+
\end{document}
|
|
373
|
+
|
|
374
|
+
When the content more than 10 lines, it shows the head (first 5
|
|
375
|
+
lines) and tail (last 5 lines) of the content together with the
|
|
376
|
+
complete header of the standalone latex document. The number of
|
|
377
|
+
missing lines and the number of characters in the content is
|
|
378
|
+
written allowing to detect a change if needed::
|
|
379
|
+
|
|
380
|
+
sage: lines = []
|
|
381
|
+
sage: lines.append(r'\begin{tikzpicture}')
|
|
382
|
+
sage: lines.append(r'\draw[->] (-.5,0) -- (20,0);')
|
|
383
|
+
sage: lines.extend(r'\draw({i},-.5) -- ({i},.5);'.format(i=i) for i in range(20))
|
|
384
|
+
sage: lines.append(r'\end{tikzpicture}')
|
|
385
|
+
sage: t = Standalone('\n'.join(lines), document_class_options=['tikz'])
|
|
386
|
+
sage: t
|
|
387
|
+
\documentclass[tikz]{standalone}
|
|
388
|
+
\begin{document}
|
|
389
|
+
\begin{tikzpicture}
|
|
390
|
+
\draw[->] (-.5,0) -- (20,0);
|
|
391
|
+
\draw(0,-.5) -- (0,.5);
|
|
392
|
+
\draw(1,-.5) -- (1,.5);
|
|
393
|
+
\draw(2,-.5) -- (2,.5);
|
|
394
|
+
---
|
|
395
|
+
13 lines not printed (566 characters in total).
|
|
396
|
+
Use print to see the full content.
|
|
397
|
+
---
|
|
398
|
+
\draw(16,-.5) -- (16,.5);
|
|
399
|
+
\draw(17,-.5) -- (17,.5);
|
|
400
|
+
\draw(18,-.5) -- (18,.5);
|
|
401
|
+
\draw(19,-.5) -- (19,.5);
|
|
402
|
+
\end{tikzpicture}
|
|
403
|
+
\end{document}
|
|
404
|
+
"""
|
|
405
|
+
lines = self._latex_file_header_lines()
|
|
406
|
+
lines.append(r"\begin{document}")
|
|
407
|
+
L = self._content.splitlines()
|
|
408
|
+
if len(L) <= 10:
|
|
409
|
+
lines.extend(L)
|
|
410
|
+
else:
|
|
411
|
+
lines.extend(L[:5])
|
|
412
|
+
lines.append('---')
|
|
413
|
+
lines.append('{} lines not printed ({} characters in total).'.format(len(L) - 10,
|
|
414
|
+
len(self._content)))
|
|
415
|
+
lines.append('Use print to see the full content.')
|
|
416
|
+
lines.append('---')
|
|
417
|
+
lines.extend(L[-5:])
|
|
418
|
+
lines.append(r"\end{document}")
|
|
419
|
+
return '\n'.join(lines)
|
|
420
|
+
|
|
421
|
+
def _rich_repr_(self, display_manager, **kwds):
|
|
422
|
+
r"""
|
|
423
|
+
Rich Output Magic Method.
|
|
424
|
+
|
|
425
|
+
See :mod:`sage.repl.rich_output` for details.
|
|
426
|
+
|
|
427
|
+
EXAMPLES::
|
|
428
|
+
|
|
429
|
+
sage: from sage.repl.rich_output import get_display_manager
|
|
430
|
+
sage: dm = get_display_manager()
|
|
431
|
+
sage: dm.is_in_terminal()
|
|
432
|
+
False
|
|
433
|
+
|
|
434
|
+
sage: from sage.misc.latex_standalone import TikzPicture
|
|
435
|
+
sage: lines = []
|
|
436
|
+
sage: lines.append(r'\begin{tikzpicture}')
|
|
437
|
+
sage: lines.append(r'\draw[very thick,orange,->] (0,0) -- (1,1);')
|
|
438
|
+
sage: lines.append(r'\end{tikzpicture}')
|
|
439
|
+
sage: s = '\n'.join(lines)
|
|
440
|
+
sage: t = TikzPicture(s)
|
|
441
|
+
sage: t._rich_repr_(dm) # random result is Text in doctest
|
|
442
|
+
OutputImagePng container
|
|
443
|
+
|
|
444
|
+
Using vector svg instead of png::
|
|
445
|
+
|
|
446
|
+
sage: dm.preferences.graphics = 'vector'
|
|
447
|
+
sage: t._rich_repr_(dm) # random result is Text in doctest
|
|
448
|
+
OutputImageSvg container
|
|
449
|
+
sage: dm.preferences.graphics = 'raster'
|
|
450
|
+
"""
|
|
451
|
+
# Do not use rich output in the terminal
|
|
452
|
+
if display_manager.is_in_terminal():
|
|
453
|
+
return
|
|
454
|
+
# Do not use rich output if not in IPython notebook (Jupyter)
|
|
455
|
+
from sage.repl.rich_output.backend_ipython import BackendIPythonNotebook
|
|
456
|
+
if not isinstance(display_manager._backend, BackendIPythonNotebook):
|
|
457
|
+
return
|
|
458
|
+
|
|
459
|
+
types = display_manager.types
|
|
460
|
+
prefer_raster = (
|
|
461
|
+
('png', types.OutputImagePng),
|
|
462
|
+
)
|
|
463
|
+
prefer_vector = (
|
|
464
|
+
('svg', types.OutputImageSvg),
|
|
465
|
+
('pdf', types.OutputImagePdf),
|
|
466
|
+
)
|
|
467
|
+
graphics = display_manager.preferences.graphics
|
|
468
|
+
if graphics == 'disable':
|
|
469
|
+
return
|
|
470
|
+
elif graphics == 'raster' or graphics is None:
|
|
471
|
+
preferred = prefer_raster + prefer_vector
|
|
472
|
+
elif graphics == 'vector':
|
|
473
|
+
preferred = prefer_vector + prefer_raster
|
|
474
|
+
else:
|
|
475
|
+
raise ValueError('unknown graphics output preference')
|
|
476
|
+
|
|
477
|
+
for format, output_container in preferred:
|
|
478
|
+
if output_container in display_manager.supported_output():
|
|
479
|
+
filename = getattr(self, format)(view=False, **kwds)
|
|
480
|
+
from sage.repl.rich_output.buffer import OutputBuffer
|
|
481
|
+
buf = OutputBuffer.from_file(filename)
|
|
482
|
+
return output_container(buf)
|
|
483
|
+
|
|
484
|
+
def __str__(self):
|
|
485
|
+
r"""
|
|
486
|
+
Return the complete string of the standalone document class file.
|
|
487
|
+
|
|
488
|
+
EXAMPLES::
|
|
489
|
+
|
|
490
|
+
sage: from sage.misc.latex_standalone import Standalone
|
|
491
|
+
sage: s = "\\begin{tikzpicture}\n\\draw (0,0) -- (1,1);\n\\end{tikzpicture}"
|
|
492
|
+
sage: t = Standalone(s, document_class_options=['tikz'])
|
|
493
|
+
sage: print(t)
|
|
494
|
+
\RequirePackage{luatex85}
|
|
495
|
+
\documentclass[tikz]{standalone}
|
|
496
|
+
\begin{document}
|
|
497
|
+
\begin{tikzpicture}
|
|
498
|
+
\draw (0,0) -- (1,1);
|
|
499
|
+
\end{tikzpicture}
|
|
500
|
+
\end{document}
|
|
501
|
+
"""
|
|
502
|
+
lines = []
|
|
503
|
+
# LuaLaTeX, TeXLive 2016, standalone: undefined control sequence
|
|
504
|
+
# https://tex.stackexchange.com/questions/315025
|
|
505
|
+
# fixed in 2018, meanwhile, we add the fix here
|
|
506
|
+
lines.append(r"\RequirePackage{luatex85}")
|
|
507
|
+
lines.extend(self._latex_file_header_lines())
|
|
508
|
+
lines.append(r"\begin{document}")
|
|
509
|
+
lines.append(self._content)
|
|
510
|
+
lines.append(r"\end{document}")
|
|
511
|
+
return '\n'.join(lines)
|
|
512
|
+
|
|
513
|
+
def content(self):
|
|
514
|
+
r"""
|
|
515
|
+
Return the content of the standalone document class file.
|
|
516
|
+
|
|
517
|
+
EXAMPLES::
|
|
518
|
+
|
|
519
|
+
sage: from sage.misc.latex_standalone import Standalone
|
|
520
|
+
sage: t = Standalone('Hello World')
|
|
521
|
+
sage: t.content()
|
|
522
|
+
'Hello World'
|
|
523
|
+
|
|
524
|
+
::
|
|
525
|
+
|
|
526
|
+
sage: from sage.misc.latex_standalone import TikzPicture
|
|
527
|
+
sage: s = "\\begin{tikzpicture}\n\\draw (0,0) -- (1,1);\n\\end{tikzpicture}"
|
|
528
|
+
sage: t = TikzPicture(s)
|
|
529
|
+
sage: print(t.content())
|
|
530
|
+
\begin{tikzpicture}
|
|
531
|
+
\draw (0,0) -- (1,1);
|
|
532
|
+
\end{tikzpicture}
|
|
533
|
+
"""
|
|
534
|
+
return self._content
|
|
535
|
+
|
|
536
|
+
def add_document_class_option(self, option):
|
|
537
|
+
r"""
|
|
538
|
+
Add a document class option.
|
|
539
|
+
|
|
540
|
+
INPUT:
|
|
541
|
+
|
|
542
|
+
- ``option`` -- string
|
|
543
|
+
|
|
544
|
+
EXAMPLES::
|
|
545
|
+
|
|
546
|
+
sage: from sage.misc.latex_standalone import Standalone
|
|
547
|
+
sage: t = Standalone('Hello World')
|
|
548
|
+
sage: t.add_document_class_option('beamer')
|
|
549
|
+
sage: t
|
|
550
|
+
\documentclass[beamer]{standalone}
|
|
551
|
+
\begin{document}
|
|
552
|
+
Hello World
|
|
553
|
+
\end{document}
|
|
554
|
+
"""
|
|
555
|
+
self._document_class_options.append(option)
|
|
556
|
+
|
|
557
|
+
def add_standalone_config(self, config):
|
|
558
|
+
r"""
|
|
559
|
+
Add a standalone config.
|
|
560
|
+
|
|
561
|
+
INPUT:
|
|
562
|
+
|
|
563
|
+
- ``config`` -- string
|
|
564
|
+
|
|
565
|
+
EXAMPLES::
|
|
566
|
+
|
|
567
|
+
sage: from sage.misc.latex_standalone import Standalone
|
|
568
|
+
sage: t = Standalone('Hello World')
|
|
569
|
+
sage: t.add_standalone_config("border=4mm")
|
|
570
|
+
sage: t
|
|
571
|
+
\documentclass{standalone}
|
|
572
|
+
\standaloneconfig{border=4mm}
|
|
573
|
+
\begin{document}
|
|
574
|
+
Hello World
|
|
575
|
+
\end{document}
|
|
576
|
+
"""
|
|
577
|
+
self._standalone_config.append(config)
|
|
578
|
+
|
|
579
|
+
def add_usepackage(self, package):
|
|
580
|
+
r"""
|
|
581
|
+
Add a ``usepackage`` line.
|
|
582
|
+
|
|
583
|
+
INPUT:
|
|
584
|
+
|
|
585
|
+
- ``package`` -- string, name of package
|
|
586
|
+
|
|
587
|
+
EXAMPLES::
|
|
588
|
+
|
|
589
|
+
sage: from sage.misc.latex_standalone import Standalone
|
|
590
|
+
sage: t = Standalone('Hello World')
|
|
591
|
+
sage: t.add_usepackage('amsmath')
|
|
592
|
+
sage: t
|
|
593
|
+
\documentclass{standalone}
|
|
594
|
+
\usepackage{amsmath}
|
|
595
|
+
\begin{document}
|
|
596
|
+
Hello World
|
|
597
|
+
\end{document}
|
|
598
|
+
"""
|
|
599
|
+
self._usepackage.append(package)
|
|
600
|
+
|
|
601
|
+
def add_macro(self, macro):
|
|
602
|
+
r"""
|
|
603
|
+
Add a macro.
|
|
604
|
+
|
|
605
|
+
INPUT:
|
|
606
|
+
|
|
607
|
+
- ``macro`` -- string, newcommand line
|
|
608
|
+
|
|
609
|
+
EXAMPLES::
|
|
610
|
+
|
|
611
|
+
sage: from sage.misc.latex_standalone import Standalone
|
|
612
|
+
sage: t = Standalone('Hello World')
|
|
613
|
+
sage: t.add_macro(r'\newcommand{\ZZ}{\mathbb{Z}}')
|
|
614
|
+
sage: t
|
|
615
|
+
\documentclass{standalone}
|
|
616
|
+
\newcommand{\ZZ}{\mathbb{Z}}
|
|
617
|
+
\begin{document}
|
|
618
|
+
Hello World
|
|
619
|
+
\end{document}
|
|
620
|
+
"""
|
|
621
|
+
self._macros.append(macro)
|
|
622
|
+
|
|
623
|
+
def pdf(self, filename=None, view=True, program=None):
|
|
624
|
+
r"""
|
|
625
|
+
Compile the latex code with pdflatex and create a pdf file.
|
|
626
|
+
|
|
627
|
+
INPUT:
|
|
628
|
+
|
|
629
|
+
- ``filename`` -- string (default: ``None``); the output filename.
|
|
630
|
+
If ``None``, it saves the file in a temporary directory.
|
|
631
|
+
|
|
632
|
+
- ``view`` -- boolean (default: ``True``); whether to open the file in a
|
|
633
|
+
pdf viewer. This option is ignored and automatically set to
|
|
634
|
+
``False`` if ``filename`` is not ``None``.
|
|
635
|
+
|
|
636
|
+
- ``program`` -- string (default: ``None``); ``'pdflatex'`` or
|
|
637
|
+
``'lualatex'``. If ``None``, it uses ``'lualatex'`` if it is
|
|
638
|
+
available, otherwise ``'pdflatex'``.
|
|
639
|
+
|
|
640
|
+
OUTPUT: string, path to pdf file
|
|
641
|
+
|
|
642
|
+
EXAMPLES::
|
|
643
|
+
|
|
644
|
+
sage: from sage.misc.latex_standalone import Standalone
|
|
645
|
+
sage: t = Standalone('Hello World')
|
|
646
|
+
sage: _ = t.pdf(view=False) # long time (1s) # optional - latex
|
|
647
|
+
|
|
648
|
+
Same for instances of :class:`TikzPicture`::
|
|
649
|
+
|
|
650
|
+
sage: from sage.misc.latex_standalone import TikzPicture
|
|
651
|
+
sage: s = "\\begin{tikzpicture}\n\\draw (0,0) -- (1,1);\n\\end{tikzpicture}"
|
|
652
|
+
sage: t = TikzPicture(s)
|
|
653
|
+
sage: _ = t.pdf(view=False) # not tested
|
|
654
|
+
|
|
655
|
+
A filename may be provided where to save the file, in which case
|
|
656
|
+
the viewer does not open the file::
|
|
657
|
+
|
|
658
|
+
sage: from sage.misc.temporary_file import tmp_filename
|
|
659
|
+
sage: filename = tmp_filename('temp','.pdf')
|
|
660
|
+
sage: path_to_file = t.pdf(filename) # long time (1s) # optional - latex
|
|
661
|
+
sage: path_to_file[-4:] # long time (fast) # optional - latex
|
|
662
|
+
'.pdf'
|
|
663
|
+
|
|
664
|
+
The filename may contain spaces::
|
|
665
|
+
|
|
666
|
+
sage: filename = tmp_filename('filename with spaces','.pdf')
|
|
667
|
+
sage: path_to_file = t.pdf(filename) # long time (1s) # optional - latex
|
|
668
|
+
|
|
669
|
+
TESTS:
|
|
670
|
+
|
|
671
|
+
We test the behavior when a wrong tex string is provided::
|
|
672
|
+
|
|
673
|
+
sage: s = "\\begin{tikzpicture}\n\\draw (0,0) -- (1,1);\n\\end{tikzpicture}"
|
|
674
|
+
sage: s_missing_last_character = s[:-1]
|
|
675
|
+
sage: t = TikzPicture(s_missing_last_character)
|
|
676
|
+
sage: _ = t.pdf() # optional - latex
|
|
677
|
+
Traceback (most recent call last):
|
|
678
|
+
...
|
|
679
|
+
CalledProcessError: Command '['...latex', '-interaction=nonstopmode',
|
|
680
|
+
'tikz_...tex']' returned non-zero exit status 1.
|
|
681
|
+
"""
|
|
682
|
+
from sage.features.latex import lualatex, pdflatex
|
|
683
|
+
|
|
684
|
+
# Set default program
|
|
685
|
+
if program is None:
|
|
686
|
+
if lualatex().is_present():
|
|
687
|
+
program = 'lualatex'
|
|
688
|
+
else:
|
|
689
|
+
program = 'pdflatex'
|
|
690
|
+
|
|
691
|
+
# Check availability of programs
|
|
692
|
+
if program == 'pdflatex':
|
|
693
|
+
pdflatex().require()
|
|
694
|
+
elif program == 'lualatex':
|
|
695
|
+
lualatex().require()
|
|
696
|
+
else:
|
|
697
|
+
raise ValueError("program(={}) should be pdflatex or lualatex".format(program))
|
|
698
|
+
|
|
699
|
+
# set up filenames
|
|
700
|
+
from sage.misc.temporary_file import tmp_filename
|
|
701
|
+
temp_filename_tex = tmp_filename('tikz_', '.tex')
|
|
702
|
+
with open(temp_filename_tex, 'w') as f:
|
|
703
|
+
f.write(str(self))
|
|
704
|
+
base, temp_filename_tex = os.path.split(temp_filename_tex)
|
|
705
|
+
temp_filename, ext = os.path.splitext(temp_filename_tex)
|
|
706
|
+
|
|
707
|
+
# running pdflatex or lualatex
|
|
708
|
+
cmd = [program, '-interaction=nonstopmode', temp_filename_tex]
|
|
709
|
+
result = run(cmd, cwd=base, capture_output=True, text=True)
|
|
710
|
+
|
|
711
|
+
# If a problem with the tex source occurs, provide the log
|
|
712
|
+
if result.returncode != 0:
|
|
713
|
+
print("Command \n"
|
|
714
|
+
" '{}'\n"
|
|
715
|
+
"returned nonzero exit status {}.\n"
|
|
716
|
+
"Here is the content of the stderr:{}\n"
|
|
717
|
+
"Here is the content of the stdout:"
|
|
718
|
+
"{}\n".format(' '.join(result.args),
|
|
719
|
+
result.returncode,
|
|
720
|
+
result.stderr.strip(),
|
|
721
|
+
result.stdout.strip()))
|
|
722
|
+
result.check_returncode()
|
|
723
|
+
temp_filename_pdf = os.path.join(base, temp_filename + '.pdf')
|
|
724
|
+
|
|
725
|
+
# move the pdf into the good location
|
|
726
|
+
if filename:
|
|
727
|
+
filename = os.path.abspath(filename)
|
|
728
|
+
import shutil
|
|
729
|
+
shutil.move(temp_filename_pdf, filename)
|
|
730
|
+
return filename
|
|
731
|
+
|
|
732
|
+
# open the tmp pdf
|
|
733
|
+
elif view:
|
|
734
|
+
from sage.misc.viewer import pdf_viewer
|
|
735
|
+
cmd = pdf_viewer().split()
|
|
736
|
+
cmd.append(temp_filename_pdf)
|
|
737
|
+
# we use check_call as opposed to run, because
|
|
738
|
+
# it gives the sage prompt back to the user
|
|
739
|
+
# see https://stackoverflow.com/a/71342967
|
|
740
|
+
# run(cmd, cwd=base, capture_output=True, check=True)
|
|
741
|
+
from subprocess import check_call, PIPE
|
|
742
|
+
check_call(cmd, cwd=base, stdout=PIPE, stderr=PIPE)
|
|
743
|
+
|
|
744
|
+
return temp_filename_pdf
|
|
745
|
+
|
|
746
|
+
def dvi(self, filename=None, view=True, program='latex'):
|
|
747
|
+
r"""
|
|
748
|
+
Compile the latex code with latex and create a dvi file.
|
|
749
|
+
|
|
750
|
+
INPUT:
|
|
751
|
+
|
|
752
|
+
- ``filename`` -- string (default: ``None``); the output filename.
|
|
753
|
+
If ``None``, it saves the file in a temporary directory
|
|
754
|
+
|
|
755
|
+
- ``view`` -- boolean (default: ``True``); whether to open the file in a
|
|
756
|
+
dvi viewer. This option is ignored and automatically set to
|
|
757
|
+
``False`` if ``filename`` is not ``None``.
|
|
758
|
+
|
|
759
|
+
- ``program`` -- string (default: ``'latex'``); ``'latex'``
|
|
760
|
+
|
|
761
|
+
OUTPUT: string, path to dvi file
|
|
762
|
+
|
|
763
|
+
EXAMPLES::
|
|
764
|
+
|
|
765
|
+
sage: from sage.misc.latex_standalone import Standalone
|
|
766
|
+
sage: t = Standalone('Hello World')
|
|
767
|
+
sage: _ = t.dvi(view=False) # long time (1s) # optional - latex
|
|
768
|
+
|
|
769
|
+
Same for instances of :class:`TikzPicture`::
|
|
770
|
+
|
|
771
|
+
sage: from sage.misc.latex_standalone import TikzPicture
|
|
772
|
+
sage: s = "\\begin{tikzpicture}\n\\draw (0,0) -- (1,1);\n\\end{tikzpicture}"
|
|
773
|
+
sage: t = TikzPicture(s)
|
|
774
|
+
sage: _ = t.dvi(view=False) # not tested
|
|
775
|
+
|
|
776
|
+
A filename may be provided where to save the file, in which case
|
|
777
|
+
the viewer does not open the file::
|
|
778
|
+
|
|
779
|
+
sage: from sage.misc.temporary_file import tmp_filename
|
|
780
|
+
sage: filename = tmp_filename('temp','.dvi')
|
|
781
|
+
sage: path_to_file = t.dvi(filename) # long time (1s) # optional - latex
|
|
782
|
+
sage: path_to_file[-4:] # long time (fast) # optional - latex
|
|
783
|
+
'.dvi'
|
|
784
|
+
|
|
785
|
+
The filename may contain spaces::
|
|
786
|
+
|
|
787
|
+
sage: filename = tmp_filename('filename with spaces','.dvi')
|
|
788
|
+
sage: path_to_file = t.dvi(filename) # long time (1s) # optional - latex
|
|
789
|
+
|
|
790
|
+
TESTS:
|
|
791
|
+
|
|
792
|
+
We test the behavior when a wrong tex string is provided::
|
|
793
|
+
|
|
794
|
+
sage: s = "\\begin{tikzpicture}\n\\draw (0,0) -- (1,1);\n\\end{tikzpicture}"
|
|
795
|
+
sage: s_missing_last_character = s[:-1]
|
|
796
|
+
sage: t = TikzPicture(s_missing_last_character)
|
|
797
|
+
sage: _ = t.dvi() # optional - latex
|
|
798
|
+
Traceback (most recent call last):
|
|
799
|
+
...
|
|
800
|
+
CalledProcessError: Command '['latex', '-interaction=nonstopmode',
|
|
801
|
+
'tikz_...tex']' returned non-zero exit status 1.
|
|
802
|
+
|
|
803
|
+
We test the behavior when a wrong value is provided::
|
|
804
|
+
|
|
805
|
+
sage: t = Standalone('Hello World')
|
|
806
|
+
sage: _ = t.dvi(program='farniente')
|
|
807
|
+
Traceback (most recent call last):
|
|
808
|
+
...
|
|
809
|
+
ValueError: program(=farniente) should be latex
|
|
810
|
+
"""
|
|
811
|
+
from sage.features.latex import latex
|
|
812
|
+
|
|
813
|
+
# Set default program
|
|
814
|
+
if program is None:
|
|
815
|
+
program = 'latex'
|
|
816
|
+
|
|
817
|
+
# Check availability of programs
|
|
818
|
+
if program == 'latex':
|
|
819
|
+
latex().require()
|
|
820
|
+
else:
|
|
821
|
+
raise ValueError("program(={}) should be latex".format(program))
|
|
822
|
+
|
|
823
|
+
# set up filenames
|
|
824
|
+
from sage.misc.temporary_file import tmp_filename
|
|
825
|
+
temp_filename_tex = tmp_filename('tikz_', '.tex')
|
|
826
|
+
with open(temp_filename_tex, 'w') as f:
|
|
827
|
+
f.write(str(self))
|
|
828
|
+
base, temp_filename_tex = os.path.split(temp_filename_tex)
|
|
829
|
+
temp_filename, ext = os.path.splitext(temp_filename_tex)
|
|
830
|
+
|
|
831
|
+
# running pdflatex or lualatex
|
|
832
|
+
cmd = [program, '-interaction=nonstopmode', temp_filename_tex]
|
|
833
|
+
result = run(cmd, cwd=base, capture_output=True, text=True)
|
|
834
|
+
|
|
835
|
+
# If a problem with the tex source occurs, provide the log
|
|
836
|
+
if result.returncode != 0:
|
|
837
|
+
print("Command \n"
|
|
838
|
+
" '{}'\n"
|
|
839
|
+
"returned nonzero exit status {}.\n"
|
|
840
|
+
"Here is the content of the stderr:{}\n"
|
|
841
|
+
"Here is the content of the stdout:"
|
|
842
|
+
"{}\n".format(' '.join(result.args),
|
|
843
|
+
result.returncode,
|
|
844
|
+
result.stderr.strip(),
|
|
845
|
+
result.stdout.strip()))
|
|
846
|
+
result.check_returncode()
|
|
847
|
+
temp_filename_dvi = os.path.join(base, temp_filename + '.dvi')
|
|
848
|
+
|
|
849
|
+
# move the pdf into the good location
|
|
850
|
+
if filename:
|
|
851
|
+
filename = os.path.abspath(filename)
|
|
852
|
+
import shutil
|
|
853
|
+
shutil.move(temp_filename_dvi, filename)
|
|
854
|
+
return filename
|
|
855
|
+
|
|
856
|
+
# open the tmp dvi
|
|
857
|
+
elif view:
|
|
858
|
+
from sage.misc.viewer import dvi_viewer
|
|
859
|
+
cmd = dvi_viewer().split()
|
|
860
|
+
cmd.append(temp_filename_dvi)
|
|
861
|
+
# we use check_call as opposed to run, because
|
|
862
|
+
# it gives the sage prompt back to the user
|
|
863
|
+
# see https://stackoverflow.com/a/71342967
|
|
864
|
+
# run(cmd, cwd=base, capture_output=True, check=True)
|
|
865
|
+
from subprocess import check_call, PIPE
|
|
866
|
+
check_call(cmd, cwd=base, stdout=PIPE, stderr=PIPE)
|
|
867
|
+
|
|
868
|
+
return temp_filename_dvi
|
|
869
|
+
|
|
870
|
+
def png(self, filename=None, density=150, view=True):
|
|
871
|
+
r"""
|
|
872
|
+
Compile the latex code with pdflatex and converts to a png file.
|
|
873
|
+
|
|
874
|
+
INPUT:
|
|
875
|
+
|
|
876
|
+
- ``filename`` -- string (default: ``None``); the output filename.
|
|
877
|
+
If ``None``, it saves the file in a temporary directory.
|
|
878
|
+
|
|
879
|
+
- ``density`` -- integer (default: ``150``); horizontal and vertical
|
|
880
|
+
density of the image
|
|
881
|
+
|
|
882
|
+
- ``view`` -- boolean (default: ``True``); whether to open the file in a
|
|
883
|
+
png viewer. This option is ignored and automatically set to
|
|
884
|
+
``False`` if ``filename`` is not ``None``.
|
|
885
|
+
|
|
886
|
+
OUTPUT: string, path to png file
|
|
887
|
+
|
|
888
|
+
EXAMPLES::
|
|
889
|
+
|
|
890
|
+
sage: from sage.misc.latex_standalone import Standalone
|
|
891
|
+
sage: t = Standalone('Hello World')
|
|
892
|
+
sage: _ = t.png(view=False) # long time (1s) # optional - latex imagemagick
|
|
893
|
+
|
|
894
|
+
Same for instances of :class:`TikzPicture`::
|
|
895
|
+
|
|
896
|
+
sage: from sage.misc.latex_standalone import TikzPicture
|
|
897
|
+
sage: s = "\\begin{tikzpicture}\n\\draw (0,0) -- (1,1);\n\\end{tikzpicture}"
|
|
898
|
+
sage: t = TikzPicture(s)
|
|
899
|
+
sage: _ = t.png(view=False) # not tested
|
|
900
|
+
|
|
901
|
+
::
|
|
902
|
+
|
|
903
|
+
sage: from sage.misc.temporary_file import tmp_filename
|
|
904
|
+
sage: filename = tmp_filename('temp','.png')
|
|
905
|
+
sage: path_to_file = t.png(filename) # long time (1s) # optional - latex imagemagick
|
|
906
|
+
sage: path_to_file[-4:] # long time (fast) # optional - latex imagemagick
|
|
907
|
+
'.png'
|
|
908
|
+
"""
|
|
909
|
+
from sage.features.imagemagick import ImageMagick
|
|
910
|
+
ImageMagick().require()
|
|
911
|
+
|
|
912
|
+
temp_filename_pdf = self.pdf(filename=None, view=False)
|
|
913
|
+
temp_filename, ext = os.path.splitext(temp_filename_pdf)
|
|
914
|
+
temp_filename_png = temp_filename + '.png'
|
|
915
|
+
|
|
916
|
+
# convert to png
|
|
917
|
+
cmd = ['convert', '-density',
|
|
918
|
+
'{0}x{0}'.format(density), '-trim', temp_filename_pdf,
|
|
919
|
+
temp_filename_png]
|
|
920
|
+
result = run(cmd, capture_output=True, text=True)
|
|
921
|
+
|
|
922
|
+
# If a problem occurs, provide the log
|
|
923
|
+
if result.returncode != 0:
|
|
924
|
+
print("Command \n"
|
|
925
|
+
" '{}'\n"
|
|
926
|
+
"returned nonzero exit status {}.\n"
|
|
927
|
+
"Here is the content of the stderr:{}\n"
|
|
928
|
+
"Here is the content of the stdout:"
|
|
929
|
+
"{}\n".format(' '.join(result.args),
|
|
930
|
+
result.returncode,
|
|
931
|
+
result.stderr.strip(),
|
|
932
|
+
result.stdout.strip()))
|
|
933
|
+
result.check_returncode()
|
|
934
|
+
|
|
935
|
+
# move the png into the good location
|
|
936
|
+
if filename:
|
|
937
|
+
filename = os.path.abspath(filename)
|
|
938
|
+
import shutil
|
|
939
|
+
shutil.move(temp_filename_png, filename)
|
|
940
|
+
return filename
|
|
941
|
+
|
|
942
|
+
# open the tmp png
|
|
943
|
+
elif view:
|
|
944
|
+
from sage.misc.viewer import png_viewer
|
|
945
|
+
cmd = png_viewer().split()
|
|
946
|
+
cmd.append(temp_filename_png)
|
|
947
|
+
# we use check_call as opposed to run, because
|
|
948
|
+
# it gives the sage prompt back to the user
|
|
949
|
+
# see https://stackoverflow.com/a/71342967
|
|
950
|
+
# run(cmd, capture_output=True, check=True)
|
|
951
|
+
from subprocess import check_call, PIPE
|
|
952
|
+
check_call(cmd, stdout=PIPE, stderr=PIPE)
|
|
953
|
+
|
|
954
|
+
return temp_filename_png
|
|
955
|
+
|
|
956
|
+
def svg(self, filename=None, view=True, program='pdftocairo'):
|
|
957
|
+
r"""
|
|
958
|
+
Compile the latex code with pdflatex and converts to a svg file.
|
|
959
|
+
|
|
960
|
+
INPUT:
|
|
961
|
+
|
|
962
|
+
- ``filename`` -- string (default: ``None``); the output filename.
|
|
963
|
+
If ``None``, it saves the file in a temporary directory.
|
|
964
|
+
|
|
965
|
+
- ``view`` -- boolean (default: ``True``); whether to open the file in
|
|
966
|
+
a browser. This option is ignored and automatically set to
|
|
967
|
+
``False`` if ``filename`` is not ``None``.
|
|
968
|
+
|
|
969
|
+
- ``program`` -- string (default: ``'pdftocairo'``); ``'pdftocairo'`` or
|
|
970
|
+
``'pdf2svg'``
|
|
971
|
+
|
|
972
|
+
OUTPUT: string, path to svg file
|
|
973
|
+
|
|
974
|
+
EXAMPLES::
|
|
975
|
+
|
|
976
|
+
sage: from sage.misc.latex_standalone import Standalone
|
|
977
|
+
sage: t = Standalone('Hello World')
|
|
978
|
+
sage: _ = t.svg(view=False) # not tested
|
|
979
|
+
|
|
980
|
+
Same for instances of :class:`TikzPicture`::
|
|
981
|
+
|
|
982
|
+
sage: from sage.misc.latex_standalone import TikzPicture
|
|
983
|
+
sage: s = "\\begin{tikzpicture}\n\\draw (0,0) -- (1,1);\n\\end{tikzpicture}"
|
|
984
|
+
sage: t = TikzPicture(s)
|
|
985
|
+
sage: _ = t.svg(view=False) # not tested
|
|
986
|
+
|
|
987
|
+
::
|
|
988
|
+
|
|
989
|
+
sage: from sage.misc.temporary_file import tmp_filename
|
|
990
|
+
sage: filename = tmp_filename('temp', '.svg')
|
|
991
|
+
sage: path_to_file = t.svg(filename, # long time (1s) # optional - latex pdf2svg
|
|
992
|
+
....: program='pdf2svg')
|
|
993
|
+
sage: path_to_file[-4:] # long time (fast) # optional - latex pdf2svg
|
|
994
|
+
'.svg'
|
|
995
|
+
sage: path_to_file = t.svg(filename, # long time (1s) # optional - latex pdftocairo
|
|
996
|
+
....: program='pdftocairo')
|
|
997
|
+
sage: path_to_file[-4:] # long time (fast) # optional - latex pdftocairo
|
|
998
|
+
'.svg'
|
|
999
|
+
"""
|
|
1000
|
+
# set the temporary filenames
|
|
1001
|
+
temp_filename_pdf = self.pdf(filename=None, view=False)
|
|
1002
|
+
temp_filename, ext = os.path.splitext(temp_filename_pdf)
|
|
1003
|
+
temp_filename_svg = temp_filename + '.svg'
|
|
1004
|
+
|
|
1005
|
+
# set the command
|
|
1006
|
+
if program == 'pdftocairo':
|
|
1007
|
+
from sage.features.poppler import pdftocairo
|
|
1008
|
+
pdftocairo().require()
|
|
1009
|
+
cmd = ['pdftocairo', '-svg', temp_filename_pdf, temp_filename_svg]
|
|
1010
|
+
elif program == 'pdf2svg':
|
|
1011
|
+
from sage.features.pdf2svg import pdf2svg
|
|
1012
|
+
pdf2svg().require()
|
|
1013
|
+
cmd = ['pdf2svg', temp_filename_pdf, temp_filename_svg]
|
|
1014
|
+
else:
|
|
1015
|
+
raise ValueError("program(={}) should be 'pdftocairo' or"
|
|
1016
|
+
" 'pdf2svg'".format(program))
|
|
1017
|
+
|
|
1018
|
+
# convert to svg
|
|
1019
|
+
result = run(cmd, capture_output=True, text=True)
|
|
1020
|
+
|
|
1021
|
+
# If a problem occurs, provide the log
|
|
1022
|
+
if result.returncode != 0:
|
|
1023
|
+
print("Command \n"
|
|
1024
|
+
" '{}'\n"
|
|
1025
|
+
"returned nonzero exit status {}.\n"
|
|
1026
|
+
"Here is the content of the stderr:{}\n"
|
|
1027
|
+
"Here is the content of the stdout:"
|
|
1028
|
+
"{}\n".format(' '.join(result.args),
|
|
1029
|
+
result.returncode,
|
|
1030
|
+
result.stderr.strip(),
|
|
1031
|
+
result.stdout.strip()))
|
|
1032
|
+
result.check_returncode()
|
|
1033
|
+
|
|
1034
|
+
# move the svg into the good location
|
|
1035
|
+
if filename:
|
|
1036
|
+
filename = os.path.abspath(filename)
|
|
1037
|
+
import shutil
|
|
1038
|
+
shutil.move(temp_filename_svg, filename)
|
|
1039
|
+
return filename
|
|
1040
|
+
|
|
1041
|
+
# open the tmp svg
|
|
1042
|
+
elif view:
|
|
1043
|
+
from sage.misc.viewer import browser
|
|
1044
|
+
cmd = browser().split()
|
|
1045
|
+
cmd.append(temp_filename_svg)
|
|
1046
|
+
# we use check_call as opposed to run, because
|
|
1047
|
+
# it gives the sage prompt back to the user
|
|
1048
|
+
# see https://stackoverflow.com/a/71342967
|
|
1049
|
+
# run(cmd, capture_output=True, check=True)
|
|
1050
|
+
from subprocess import check_call, PIPE
|
|
1051
|
+
check_call(cmd, stdout=PIPE, stderr=PIPE)
|
|
1052
|
+
|
|
1053
|
+
return temp_filename_svg
|
|
1054
|
+
|
|
1055
|
+
def eps(self, filename=None, view=True, program='dvips'):
|
|
1056
|
+
r"""
|
|
1057
|
+
Compile the latex code with pdflatex and converts to a eps file.
|
|
1058
|
+
|
|
1059
|
+
INPUT:
|
|
1060
|
+
|
|
1061
|
+
- ``filename`` -- string (default: ``None``); the output filename.
|
|
1062
|
+
If ``None``, it saves the file in a temporary directory
|
|
1063
|
+
|
|
1064
|
+
- ``view`` -- boolean (default: ``True``); whether to open the file in
|
|
1065
|
+
a browser. This option is ignored and automatically set to
|
|
1066
|
+
``False`` if ``filename`` is not ``None``.
|
|
1067
|
+
|
|
1068
|
+
- ``program`` -- string (default: ``'dvips'``);
|
|
1069
|
+
``'pdftocairo'`` or ``'dvips'``
|
|
1070
|
+
|
|
1071
|
+
OUTPUT: string, path to eps file
|
|
1072
|
+
|
|
1073
|
+
EXAMPLES::
|
|
1074
|
+
|
|
1075
|
+
sage: from sage.misc.latex_standalone import Standalone
|
|
1076
|
+
sage: t = Standalone('Hello World')
|
|
1077
|
+
sage: _ = t.eps(view=False) # not tested
|
|
1078
|
+
|
|
1079
|
+
Same for instances of :class:`TikzPicture`::
|
|
1080
|
+
|
|
1081
|
+
sage: from sage.misc.latex_standalone import TikzPicture
|
|
1082
|
+
sage: s = "\\begin{tikzpicture}\n\\draw (0,0) -- (1,1);\n\\end{tikzpicture}"
|
|
1083
|
+
sage: t = TikzPicture(s)
|
|
1084
|
+
sage: _ = t.eps(view=False) # not tested
|
|
1085
|
+
|
|
1086
|
+
We test the creation of the files::
|
|
1087
|
+
|
|
1088
|
+
sage: from sage.misc.temporary_file import tmp_filename
|
|
1089
|
+
sage: filename = tmp_filename('temp', '.eps')
|
|
1090
|
+
sage: path_to_file = t.eps(filename, # long time (1s) # optional - latex dvips
|
|
1091
|
+
....: program='dvips')
|
|
1092
|
+
sage: path_to_file[-4:] # long time (fast) # optional - latex dvips
|
|
1093
|
+
'.eps'
|
|
1094
|
+
sage: path_to_file = t.eps(filename, # long time (1s) # optional - latex pdftocairo
|
|
1095
|
+
....: program='pdftocairo')
|
|
1096
|
+
sage: path_to_file[-4:] # long time (fast) # optional - latex pdftocairo
|
|
1097
|
+
'.eps'
|
|
1098
|
+
|
|
1099
|
+
TESTS:
|
|
1100
|
+
|
|
1101
|
+
We test the behavior when a wrong value is provided::
|
|
1102
|
+
|
|
1103
|
+
sage: t = Standalone('Hello World')
|
|
1104
|
+
sage: _ = t.eps(program='convert')
|
|
1105
|
+
Traceback (most recent call last):
|
|
1106
|
+
...
|
|
1107
|
+
ValueError: program(=convert) should be 'pdftocairo' or 'dvips'
|
|
1108
|
+
"""
|
|
1109
|
+
|
|
1110
|
+
if program == 'pdftocairo':
|
|
1111
|
+
from sage.features.poppler import pdftocairo
|
|
1112
|
+
pdftocairo().require()
|
|
1113
|
+
# set the temporary filenames
|
|
1114
|
+
temp_filename_pdf = self.pdf(filename=None, view=False)
|
|
1115
|
+
temp_filename, ext = os.path.splitext(temp_filename_pdf)
|
|
1116
|
+
temp_filename_eps = temp_filename + '.eps'
|
|
1117
|
+
# set the command
|
|
1118
|
+
cmd = ['pdftocairo', '-eps', temp_filename_pdf, temp_filename_eps]
|
|
1119
|
+
elif program == 'dvips':
|
|
1120
|
+
from sage.features.latex import dvips
|
|
1121
|
+
dvips().require()
|
|
1122
|
+
# set the temporary filenames
|
|
1123
|
+
temp_filename_dvi = self.dvi(filename=None, view=False)
|
|
1124
|
+
temp_filename, ext = os.path.splitext(temp_filename_dvi)
|
|
1125
|
+
temp_filename_eps = temp_filename + '.eps'
|
|
1126
|
+
# set the command
|
|
1127
|
+
cmd = ['dvips', '-E', '-o', temp_filename_eps, temp_filename_dvi]
|
|
1128
|
+
else:
|
|
1129
|
+
raise ValueError("program(={}) should be 'pdftocairo' or"
|
|
1130
|
+
" 'dvips'".format(program))
|
|
1131
|
+
|
|
1132
|
+
# convert to eps
|
|
1133
|
+
result = run(cmd, capture_output=True, text=True)
|
|
1134
|
+
|
|
1135
|
+
# If a problem occurs, provide the log
|
|
1136
|
+
if result.returncode != 0:
|
|
1137
|
+
print("Command \n"
|
|
1138
|
+
" '{}'\n"
|
|
1139
|
+
"returned nonzero exit status {}.\n"
|
|
1140
|
+
"Here is the content of the stderr:{}\n"
|
|
1141
|
+
"Here is the content of the stdout:"
|
|
1142
|
+
"{}\n".format(' '.join(result.args),
|
|
1143
|
+
result.returncode,
|
|
1144
|
+
result.stderr.strip(),
|
|
1145
|
+
result.stdout.strip()))
|
|
1146
|
+
result.check_returncode()
|
|
1147
|
+
|
|
1148
|
+
# move the eps into the good location
|
|
1149
|
+
if filename:
|
|
1150
|
+
filename = os.path.abspath(filename)
|
|
1151
|
+
import shutil
|
|
1152
|
+
shutil.move(temp_filename_eps, filename)
|
|
1153
|
+
return filename
|
|
1154
|
+
|
|
1155
|
+
# open the tmp eps
|
|
1156
|
+
elif view:
|
|
1157
|
+
from sage.misc.viewer import viewer
|
|
1158
|
+
cmd = viewer().split()
|
|
1159
|
+
cmd.append(temp_filename_eps)
|
|
1160
|
+
# we use check_call as opposed to run, because
|
|
1161
|
+
# it gives the sage prompt back to the user
|
|
1162
|
+
# see https://stackoverflow.com/a/71342967
|
|
1163
|
+
# run(cmd, capture_output=True, check=True)
|
|
1164
|
+
from subprocess import check_call, PIPE
|
|
1165
|
+
check_call(cmd, stdout=PIPE, stderr=PIPE)
|
|
1166
|
+
|
|
1167
|
+
return temp_filename_eps
|
|
1168
|
+
|
|
1169
|
+
def tex(self, filename=None, content_only=False, include_header=None):
|
|
1170
|
+
r"""
|
|
1171
|
+
Writes the latex code to a file.
|
|
1172
|
+
|
|
1173
|
+
INPUT:
|
|
1174
|
+
|
|
1175
|
+
- ``filename`` -- string (default: ``None``); the output filename.
|
|
1176
|
+
If ``None``, it saves the file in a temporary directory.
|
|
1177
|
+
- ``content_only`` -- boolean (default: ``False``); whether to include
|
|
1178
|
+
the header latex part. If ``True``, it prints only the
|
|
1179
|
+
content to the file.
|
|
1180
|
+
|
|
1181
|
+
OUTPUT: string, path to tex file
|
|
1182
|
+
|
|
1183
|
+
EXAMPLES::
|
|
1184
|
+
|
|
1185
|
+
sage: from sage.misc.latex_standalone import Standalone
|
|
1186
|
+
sage: t = Standalone('Hello World')
|
|
1187
|
+
sage: _ = t.tex()
|
|
1188
|
+
sage: _ = t.tex(content_only=True)
|
|
1189
|
+
|
|
1190
|
+
Same for instances of :class:`TikzPicture`::
|
|
1191
|
+
|
|
1192
|
+
sage: from sage.misc.latex_standalone import TikzPicture
|
|
1193
|
+
sage: s = "\\begin{tikzpicture}\n\\draw (0,0) -- (1,1);\n\\end{tikzpicture}"
|
|
1194
|
+
sage: t = TikzPicture(s)
|
|
1195
|
+
sage: _ = t.tex()
|
|
1196
|
+
sage: _ = t.tex(content_only=True)
|
|
1197
|
+
|
|
1198
|
+
Write to a given filename::
|
|
1199
|
+
|
|
1200
|
+
sage: from sage.misc.temporary_file import tmp_filename
|
|
1201
|
+
sage: filename = tmp_filename('temp','.tex')
|
|
1202
|
+
sage: path_to_file = t.tex(filename)
|
|
1203
|
+
sage: path_to_file[-4:]
|
|
1204
|
+
'.tex'
|
|
1205
|
+
"""
|
|
1206
|
+
if filename is None:
|
|
1207
|
+
from sage.misc.temporary_file import tmp_filename
|
|
1208
|
+
filename = tmp_filename('tikz_', '.tex')
|
|
1209
|
+
else:
|
|
1210
|
+
filename = os.path.abspath(filename)
|
|
1211
|
+
|
|
1212
|
+
if include_header is not None:
|
|
1213
|
+
content_only = not include_header
|
|
1214
|
+
from sage.misc.superseded import deprecation
|
|
1215
|
+
deprecation(20343, "When merging this code from slabbe into "
|
|
1216
|
+
"SageMath the argument include_header=False was "
|
|
1217
|
+
"replaced by content_only=True. Please update your code "
|
|
1218
|
+
"before include_header option gets removed from SageMath.")
|
|
1219
|
+
|
|
1220
|
+
if content_only:
|
|
1221
|
+
output = self.content()
|
|
1222
|
+
else:
|
|
1223
|
+
output = str(self)
|
|
1224
|
+
|
|
1225
|
+
with open(filename, 'w') as f:
|
|
1226
|
+
f.write(output)
|
|
1227
|
+
|
|
1228
|
+
return filename
|
|
1229
|
+
|
|
1230
|
+
def save(self, filename, **kwds):
|
|
1231
|
+
r"""
|
|
1232
|
+
Save the graphics to an image file.
|
|
1233
|
+
|
|
1234
|
+
INPUT:
|
|
1235
|
+
|
|
1236
|
+
- ``filename`` -- string. The filename and the image format
|
|
1237
|
+
given by the extension, which can be one of the following:
|
|
1238
|
+
|
|
1239
|
+
* ``.pdf``,
|
|
1240
|
+
* ``.png``,
|
|
1241
|
+
* ``.svg``,
|
|
1242
|
+
* ``.eps``,
|
|
1243
|
+
* ``.dvi``,
|
|
1244
|
+
* ``.sobj`` (for a Sage object you can load later),
|
|
1245
|
+
* empty extension will be treated as ``.sobj``.
|
|
1246
|
+
|
|
1247
|
+
All other keyword arguments will be passed to the plotter.
|
|
1248
|
+
|
|
1249
|
+
OUTPUT: none
|
|
1250
|
+
|
|
1251
|
+
.. NOTE::
|
|
1252
|
+
|
|
1253
|
+
This method follows the signature of the method
|
|
1254
|
+
:meth:`sage.plot.Graphics.save` in order to be compatible with
|
|
1255
|
+
with sagetex. In particular so that ``\sageplot{t}`` written
|
|
1256
|
+
in a ``tex`` file works when ``t`` is an instance of
|
|
1257
|
+
:class:`Standalone` or :class:`TikzPicture`.
|
|
1258
|
+
|
|
1259
|
+
EXAMPLES::
|
|
1260
|
+
|
|
1261
|
+
sage: from sage.misc.temporary_file import tmp_filename
|
|
1262
|
+
sage: from sage.misc.latex_standalone import Standalone
|
|
1263
|
+
sage: t = Standalone('Hello World')
|
|
1264
|
+
sage: filename = tmp_filename('temp','.pdf')
|
|
1265
|
+
sage: t.save(filename) # long time (1s) # optional - latex
|
|
1266
|
+
sage: filename = tmp_filename('temp','.eps')
|
|
1267
|
+
sage: t.save(filename) # long time (1s) # optional - latex dvips
|
|
1268
|
+
"""
|
|
1269
|
+
ext = os.path.splitext(filename)[1].lower()
|
|
1270
|
+
if ext == '' or ext == '.sobj':
|
|
1271
|
+
raise NotImplementedError()
|
|
1272
|
+
elif ext == '.pdf':
|
|
1273
|
+
self.pdf(filename, **kwds)
|
|
1274
|
+
elif ext == '.png':
|
|
1275
|
+
self.png(filename, **kwds)
|
|
1276
|
+
elif ext == '.svg':
|
|
1277
|
+
self.svg(filename, **kwds)
|
|
1278
|
+
elif ext == '.eps':
|
|
1279
|
+
self.eps(filename, **kwds)
|
|
1280
|
+
elif ext == '.dvi':
|
|
1281
|
+
self.dvi(filename, **kwds)
|
|
1282
|
+
else:
|
|
1283
|
+
raise ValueError("allowed file extensions for images are "
|
|
1284
|
+
".pdf, .png, .svg, .eps, .dvi!")
|
|
1285
|
+
|
|
1286
|
+
|
|
1287
|
+
class TikzPicture(Standalone):
|
|
1288
|
+
r"""
|
|
1289
|
+
A TikzPicture embedded in a LaTeX standalone document class.
|
|
1290
|
+
|
|
1291
|
+
INPUT:
|
|
1292
|
+
|
|
1293
|
+
- ``content`` -- string, tikzpicture code starting with ``r'\begin{tikzpicture}'``
|
|
1294
|
+
and ending with ``r'\end{tikzpicture}'``
|
|
1295
|
+
- ``standalone_config`` -- list of strings (default: ``[]``);
|
|
1296
|
+
latex document class standalone configuration options
|
|
1297
|
+
- ``usepackage`` -- list of strings (default: ``[]``); latex
|
|
1298
|
+
packages
|
|
1299
|
+
- ``usetikzlibrary`` -- list of strings (default: ``[]``); tikz libraries
|
|
1300
|
+
to use
|
|
1301
|
+
- ``macros`` -- list of strings (default: ``[]``); stuff you need for the picture
|
|
1302
|
+
- ``use_sage_preamble`` -- boolean (default: ``False``); whether to include sage
|
|
1303
|
+
latex preamble and sage latex macros, that is, the content of
|
|
1304
|
+
:func:`sage.misc.latex.extra_preamble()`,
|
|
1305
|
+
:func:`sage.misc.latex.extra_macros()` and
|
|
1306
|
+
:func:`sage.misc.latex_macros.sage_latex_macros()`
|
|
1307
|
+
|
|
1308
|
+
EXAMPLES:
|
|
1309
|
+
|
|
1310
|
+
Create your own tikz string from scratch and provide it::
|
|
1311
|
+
|
|
1312
|
+
sage: from sage.misc.latex_standalone import TikzPicture
|
|
1313
|
+
sage: lines = []
|
|
1314
|
+
sage: lines.append(r'\begin{tikzpicture}')
|
|
1315
|
+
sage: lines.append(r'\draw[very thick,orange,->] (0,0) -- (1,1);')
|
|
1316
|
+
sage: lines.append(r'\end{tikzpicture}')
|
|
1317
|
+
sage: s = '\n'.join(lines)
|
|
1318
|
+
sage: t = TikzPicture(s)
|
|
1319
|
+
sage: t
|
|
1320
|
+
\documentclass[tikz]{standalone}
|
|
1321
|
+
\begin{document}
|
|
1322
|
+
\begin{tikzpicture}
|
|
1323
|
+
\draw[very thick,orange,->] (0,0) -- (1,1);
|
|
1324
|
+
\end{tikzpicture}
|
|
1325
|
+
\end{document}
|
|
1326
|
+
|
|
1327
|
+
Then use it by exporting the tikzpicture to other formats, all of the
|
|
1328
|
+
below methods return a string providing the path to the filename, which
|
|
1329
|
+
is by default in a temporary folder::
|
|
1330
|
+
|
|
1331
|
+
sage: # not tested
|
|
1332
|
+
sage: _ = t.pdf()
|
|
1333
|
+
sage: _ = t.png()
|
|
1334
|
+
sage: _ = t.svg()
|
|
1335
|
+
sage: _ = t.tex()
|
|
1336
|
+
sage: _ = t.pdf(filename='abc.pdf')
|
|
1337
|
+
|
|
1338
|
+
Here we create a tikzpicture for the latex representation of a graph.
|
|
1339
|
+
This is using tkz-graph tex library::
|
|
1340
|
+
|
|
1341
|
+
sage: # needs sage.graphs
|
|
1342
|
+
sage: g = graphs.PetersenGraph()
|
|
1343
|
+
sage: s = latex(g) # optional - latex
|
|
1344
|
+
sage: t = TikzPicture(s, standalone_config=["border=4mm"], # optional - latex
|
|
1345
|
+
....: usepackage=['tkz-graph'])
|
|
1346
|
+
sage: _ = t.pdf(view=False) # long time (2s), optional - latex latex_package_tkz_graph
|
|
1347
|
+
|
|
1348
|
+
Here are standalone configurations, packages, tikz libraries and macros
|
|
1349
|
+
that can be set::
|
|
1350
|
+
|
|
1351
|
+
sage: options = ['preview', 'border=4mm', 'beamer', 'float']
|
|
1352
|
+
sage: usepackage = ['nicefrac', 'amsmath', 'pifont', 'tikz-3dplot',
|
|
1353
|
+
....: 'pgfplots']
|
|
1354
|
+
sage: tikzlib = ['arrows', 'snakes', 'backgrounds', 'patterns',
|
|
1355
|
+
....: 'matrix', 'shapes', 'fit', 'calc', 'shadows', 'plotmarks',
|
|
1356
|
+
....: 'positioning', 'pgfplots.groupplots', 'mindmap']
|
|
1357
|
+
sage: macros = [r'\newcommand{\ZZ}{\mathbb{Z}}']
|
|
1358
|
+
sage: s = "\\begin{tikzpicture}\n\\draw (0,0) -- (1,1);\n\\end{tikzpicture}"
|
|
1359
|
+
sage: t = TikzPicture(s, standalone_config=options, usepackage=usepackage,
|
|
1360
|
+
....: usetikzlibrary=tikzlib, macros=macros)
|
|
1361
|
+
sage: _ = t.pdf(view=False) # long time (2s), optional - latex
|
|
1362
|
+
"""
|
|
1363
|
+
def __init__(self, content, standalone_config=None, usepackage=None,
|
|
1364
|
+
usetikzlibrary=None, macros=None, use_sage_preamble=False):
|
|
1365
|
+
r"""
|
|
1366
|
+
See :class:`TikzPicture` for full information.
|
|
1367
|
+
|
|
1368
|
+
EXAMPLES::
|
|
1369
|
+
|
|
1370
|
+
sage: from sage.misc.latex_standalone import TikzPicture
|
|
1371
|
+
sage: s = "\\begin{tikzpicture}\n\\draw (0,0) -- (1,1);\n\\end{tikzpicture}"
|
|
1372
|
+
sage: t = TikzPicture(s)
|
|
1373
|
+
"""
|
|
1374
|
+
Standalone.__init__(self, content, document_class_options=['tikz'],
|
|
1375
|
+
standalone_config=standalone_config, usepackage=usepackage,
|
|
1376
|
+
macros=macros, use_sage_preamble=use_sage_preamble)
|
|
1377
|
+
|
|
1378
|
+
self._usetikzlibrary = [] if usetikzlibrary is None else usetikzlibrary
|
|
1379
|
+
|
|
1380
|
+
def _latex_file_header_lines(self):
|
|
1381
|
+
r"""
|
|
1382
|
+
EXAMPLES::
|
|
1383
|
+
|
|
1384
|
+
sage: latex.extra_preamble('')
|
|
1385
|
+
sage: from sage.misc.latex_standalone import TikzPicture
|
|
1386
|
+
sage: s = "\\begin{tikzpicture}\n\\draw (0,0) -- (1,1);\n\\end{tikzpicture}"
|
|
1387
|
+
sage: t = TikzPicture(s, standalone_config=["border=4mm"], usepackage=['tkz-graph'])
|
|
1388
|
+
sage: t._latex_file_header_lines()[:6]
|
|
1389
|
+
['\\documentclass[tikz]{standalone}',
|
|
1390
|
+
'\\standaloneconfig{border=4mm}',
|
|
1391
|
+
'\\usepackage{tkz-graph}']
|
|
1392
|
+
"""
|
|
1393
|
+
lines = Standalone._latex_file_header_lines(self)
|
|
1394
|
+
for library in self._usetikzlibrary:
|
|
1395
|
+
lines.append(r"\usetikzlibrary{{{}}}".format(library))
|
|
1396
|
+
return lines
|
|
1397
|
+
|
|
1398
|
+
def add_usetikzlibrary(self, library):
|
|
1399
|
+
r"""
|
|
1400
|
+
Add a ``usetikzlibrary`` line.
|
|
1401
|
+
|
|
1402
|
+
INPUT:
|
|
1403
|
+
|
|
1404
|
+
- ``library`` -- string, name of library
|
|
1405
|
+
|
|
1406
|
+
EXAMPLES::
|
|
1407
|
+
|
|
1408
|
+
sage: from sage.misc.latex_standalone import TikzPicture
|
|
1409
|
+
sage: s = "\\begin{tikzpicture}\n\\draw (0,0) -- (1,1);\n\\end{tikzpicture}"
|
|
1410
|
+
sage: t = TikzPicture(s)
|
|
1411
|
+
sage: t.add_usetikzlibrary('arrows')
|
|
1412
|
+
sage: t
|
|
1413
|
+
\documentclass[tikz]{standalone}
|
|
1414
|
+
\usetikzlibrary{arrows}
|
|
1415
|
+
\begin{document}
|
|
1416
|
+
\begin{tikzpicture}
|
|
1417
|
+
\draw (0,0) -- (1,1);
|
|
1418
|
+
\end{tikzpicture}
|
|
1419
|
+
\end{document}
|
|
1420
|
+
"""
|
|
1421
|
+
self._usetikzlibrary.append(library)
|
|
1422
|
+
|
|
1423
|
+
@classmethod
|
|
1424
|
+
def from_dot_string(cls, dotdata, prog='dot'):
|
|
1425
|
+
r"""
|
|
1426
|
+
Convert a graph to a tikzpicture using graphviz and dot2tex.
|
|
1427
|
+
|
|
1428
|
+
.. NOTE::
|
|
1429
|
+
|
|
1430
|
+
Prerequisite: dot2tex optional Sage package and graphviz must be
|
|
1431
|
+
installed.
|
|
1432
|
+
|
|
1433
|
+
INPUT:
|
|
1434
|
+
|
|
1435
|
+
- ``dotdata`` -- dot format string
|
|
1436
|
+
- ``prog`` -- string (default: ``'dot'``); the program used for the
|
|
1437
|
+
layout corresponding to one of the software of the graphviz
|
|
1438
|
+
suite: ``'dot'``, ``'neato'``, ``'twopi'``, ``'circo'`` or ``'fdp'``
|
|
1439
|
+
|
|
1440
|
+
EXAMPLES::
|
|
1441
|
+
|
|
1442
|
+
sage: # needs sage.graphs
|
|
1443
|
+
sage: from sage.misc.latex_standalone import TikzPicture
|
|
1444
|
+
sage: G = graphs.PetersenGraph()
|
|
1445
|
+
sage: dotdata = G.graphviz_string()
|
|
1446
|
+
sage: tikz = TikzPicture.from_dot_string(dotdata) # long time (3s), optional - dot2tex graphviz
|
|
1447
|
+
sage: _ = tikz.pdf() # not tested
|
|
1448
|
+
|
|
1449
|
+
::
|
|
1450
|
+
|
|
1451
|
+
sage: # needs sage.graphs
|
|
1452
|
+
sage: dotdata = G.graphviz_string(labels='latex')
|
|
1453
|
+
sage: tikz = TikzPicture.from_dot_string(dotdata) # long time (3s), optional - dot2tex graphviz
|
|
1454
|
+
sage: _ = tikz.pdf() # not tested
|
|
1455
|
+
|
|
1456
|
+
::
|
|
1457
|
+
|
|
1458
|
+
sage: # needs sage.combinat sage.graphs sage.groups
|
|
1459
|
+
sage: W = CoxeterGroup(["A",2])
|
|
1460
|
+
sage: G = W.cayley_graph()
|
|
1461
|
+
sage: dotdata = G.graphviz_string()
|
|
1462
|
+
sage: tikz = TikzPicture.from_dot_string(dotdata) # long time (3s), optional - dot2tex graphviz
|
|
1463
|
+
sage: _ = tikz.pdf() # not tested
|
|
1464
|
+
|
|
1465
|
+
::
|
|
1466
|
+
|
|
1467
|
+
sage: # needs sage.combinat sage.graphs sage.groups
|
|
1468
|
+
sage: dotdata = G.graphviz_string(labels='latex')
|
|
1469
|
+
sage: tikz = TikzPicture.from_dot_string(dotdata) # long time (3s), optional - dot2tex graphviz
|
|
1470
|
+
sage: _ = tikz.pdf() # not tested
|
|
1471
|
+
"""
|
|
1472
|
+
from sage.features import PythonModule
|
|
1473
|
+
PythonModule("dot2tex").require()
|
|
1474
|
+
from sage.features.graphviz import Graphviz
|
|
1475
|
+
Graphviz().require()
|
|
1476
|
+
|
|
1477
|
+
import dot2tex
|
|
1478
|
+
tikz = dot2tex.dot2tex(dotdata,
|
|
1479
|
+
format='tikz',
|
|
1480
|
+
autosize=True,
|
|
1481
|
+
crop=True,
|
|
1482
|
+
figonly='True',
|
|
1483
|
+
prog=prog).strip()
|
|
1484
|
+
return TikzPicture(tikz, standalone_config=["border=4mm"],
|
|
1485
|
+
usetikzlibrary=['shapes'])
|
|
1486
|
+
|
|
1487
|
+
@classmethod
|
|
1488
|
+
@experimental(issue_number=20343)
|
|
1489
|
+
def from_graph(cls, graph, merge_multiedges=True,
|
|
1490
|
+
merge_label_function=tuple, **kwds):
|
|
1491
|
+
r"""
|
|
1492
|
+
Convert a graph to a tikzpicture using graphviz and dot2tex.
|
|
1493
|
+
|
|
1494
|
+
.. NOTE::
|
|
1495
|
+
|
|
1496
|
+
Prerequisite: dot2tex optional Sage package and graphviz must be
|
|
1497
|
+
installed.
|
|
1498
|
+
|
|
1499
|
+
.. WARNING::
|
|
1500
|
+
|
|
1501
|
+
This method might be deleted in the future in favor of a method
|
|
1502
|
+
in the graph class returning a tikz picture.
|
|
1503
|
+
|
|
1504
|
+
INPUT:
|
|
1505
|
+
|
|
1506
|
+
- ``graph`` -- graph
|
|
1507
|
+
- ``merge_multiedges`` -- boolean (default: ``True``); if the graph
|
|
1508
|
+
has multiple edges, whether to merge the multiedges into one
|
|
1509
|
+
single edge
|
|
1510
|
+
- ``merge_label_function`` -- function (default: ``tuple``); a
|
|
1511
|
+
function to apply to each list of labels to be merged. It is
|
|
1512
|
+
ignored if ``merge_multiedges`` is not ``True`` or if the graph
|
|
1513
|
+
has no multiple edges.
|
|
1514
|
+
|
|
1515
|
+
Other inputs are used for latex drawing with dot2tex and graphviz:
|
|
1516
|
+
|
|
1517
|
+
- ``prog`` -- string (default: ``'dot'``); the program used for the
|
|
1518
|
+
layout corresponding to one of the software of the graphviz
|
|
1519
|
+
suite: ``'dot'``, ``'neato'``, ``'twopi'``, ``'circo'`` or ``'fdp'``
|
|
1520
|
+
- ``edge_labels`` -- boolean (default: ``True``)
|
|
1521
|
+
- ``color_by_label`` -- boolean (default: ``False``)
|
|
1522
|
+
- ``rankdir`` -- string (default: ``'down'``)
|
|
1523
|
+
- ``subgraph_clusters`` -- (default: ``[]``) a list of lists of
|
|
1524
|
+
vertices, if supported by the layout engine, nodes belonging to
|
|
1525
|
+
the same cluster subgraph are drawn together, with the entire
|
|
1526
|
+
drawing of the cluster contained within a bounding rectangle.
|
|
1527
|
+
|
|
1528
|
+
EXAMPLES::
|
|
1529
|
+
|
|
1530
|
+
sage: # needs sage.graphs
|
|
1531
|
+
sage: from sage.misc.latex_standalone import TikzPicture
|
|
1532
|
+
sage: g = graphs.PetersenGraph()
|
|
1533
|
+
sage: tikz = TikzPicture.from_graph(g) # optional - dot2tex graphviz
|
|
1534
|
+
doctest:...: FutureWarning: This class/method/function is marked as experimental.
|
|
1535
|
+
It, its functionality or its interface might change without a formal deprecation.
|
|
1536
|
+
See https://github.com/sagemath/sage/issues/20343 for details.
|
|
1537
|
+
sage: _ = tikz.pdf() # not tested
|
|
1538
|
+
|
|
1539
|
+
Using ``prog``::
|
|
1540
|
+
|
|
1541
|
+
sage: # needs sage.graphs
|
|
1542
|
+
sage: tikz = TikzPicture.from_graph(g, prog='neato', # long time (3s), optional - dot2tex graphviz
|
|
1543
|
+
....: color_by_label=True)
|
|
1544
|
+
sage: _ = tikz.pdf() # not tested
|
|
1545
|
+
|
|
1546
|
+
Using ``rankdir``::
|
|
1547
|
+
|
|
1548
|
+
sage: tikz = TikzPicture.from_graph(g, rankdir='right') # long time (3s), optional - dot2tex graphviz, needs sage.graphs
|
|
1549
|
+
sage: _ = tikz.pdf() # not tested
|
|
1550
|
+
|
|
1551
|
+
Using ``merge_multiedges``::
|
|
1552
|
+
|
|
1553
|
+
sage: # needs sage.graphs sage.modules sage.symbolic
|
|
1554
|
+
sage: alpha = var('alpha')
|
|
1555
|
+
sage: m = matrix(2, range(4)); m.set_immutable()
|
|
1556
|
+
sage: G = DiGraph([(0,1,alpha), (0,1,0), (0,2,9), (0,2,m)],
|
|
1557
|
+
....: multiedges=True)
|
|
1558
|
+
sage: tikz = TikzPicture.from_graph(G, merge_multiedges=True) # optional - dot2tex graphviz
|
|
1559
|
+
sage: _ = tikz.pdf() # not tested
|
|
1560
|
+
|
|
1561
|
+
Using ``merge_multiedges`` with ``merge_label_function``::
|
|
1562
|
+
|
|
1563
|
+
sage: # needs sage.graphs
|
|
1564
|
+
sage: fn = lambda L: LatexExpr(','.join(map(str, L)))
|
|
1565
|
+
sage: edges = [(0,1,'a'), (0,1,'b'), (0,2,'c'), (0,2,'d')]
|
|
1566
|
+
sage: G = DiGraph(edges, multiedges=True)
|
|
1567
|
+
sage: tikz = TikzPicture.from_graph(G, # optional - dot2tex graphviz
|
|
1568
|
+
....: merge_multiedges=True, merge_label_function=fn)
|
|
1569
|
+
sage: _ = tikz.pdf() # not tested
|
|
1570
|
+
|
|
1571
|
+
Using subgraphs clusters (broken when using labels, see
|
|
1572
|
+
:issue:`22070`)::
|
|
1573
|
+
|
|
1574
|
+
sage: S = FiniteSetMaps(5)
|
|
1575
|
+
sage: I = S((0,1,2,3,4))
|
|
1576
|
+
sage: a = S((0,1,3,0,0))
|
|
1577
|
+
sage: b = S((0,2,4,1,0))
|
|
1578
|
+
sage: roots = [I]
|
|
1579
|
+
sage: succ = lambda v: [v*a,v*b,a*v,b*v]
|
|
1580
|
+
sage: R = RecursivelyEnumeratedSet(roots, succ)
|
|
1581
|
+
sage: G = R.to_digraph() # needs sage.graphs
|
|
1582
|
+
sage: G # needs sage.graphs
|
|
1583
|
+
Looped multi-digraph on 27 vertices
|
|
1584
|
+
sage: C = G.strongly_connected_components() # needs sage.graphs
|
|
1585
|
+
sage: tikz = TikzPicture.from_graph(G, # optional - dot2tex graphviz, needs sage.graphs
|
|
1586
|
+
....: merge_multiedges=False, subgraph_clusters=C)
|
|
1587
|
+
sage: _ = tikz.pdf() # not tested
|
|
1588
|
+
|
|
1589
|
+
An example coming from ``graphviz_string`` documentation in SageMath::
|
|
1590
|
+
|
|
1591
|
+
sage: # needs sage.graphs sage.symbolic
|
|
1592
|
+
sage: f(x) = -1 / x
|
|
1593
|
+
sage: g(x) = 1 / (x + 1)
|
|
1594
|
+
sage: G = DiGraph()
|
|
1595
|
+
sage: G.add_edges((i, f(i), f) for i in (1, 2, 1/2, 1/4))
|
|
1596
|
+
sage: G.add_edges((i, g(i), g) for i in (1, 2, 1/2, 1/4))
|
|
1597
|
+
sage: tikz = TikzPicture.from_graph(G) # optional - dot2tex graphviz
|
|
1598
|
+
sage: _ = tikz.pdf() # not tested
|
|
1599
|
+
sage: def edge_options(data):
|
|
1600
|
+
....: u, v, label = data
|
|
1601
|
+
....: options = {"color": {f: "red", g: "blue"}[label]}
|
|
1602
|
+
....: if (u,v) == (1/2, -2): options["label"] = "coucou"; options["label_style"] = "string"
|
|
1603
|
+
....: if (u,v) == (1/2,2/3): options["dot"] = "x=1,y=2"
|
|
1604
|
+
....: if (u,v) == (1, -1): options["label_style"] = "latex"
|
|
1605
|
+
....: if (u,v) == (1, 1/2): options["dir"] = "back"
|
|
1606
|
+
....: return options
|
|
1607
|
+
sage: tikz = TikzPicture.from_graph(G, edge_options=edge_options) # optional - dot2tex graphviz
|
|
1608
|
+
sage: _ = tikz.pdf() # not tested
|
|
1609
|
+
"""
|
|
1610
|
+
from sage.features.latex import pdflatex
|
|
1611
|
+
pdflatex().require()
|
|
1612
|
+
from sage.features.graphviz import Graphviz
|
|
1613
|
+
Graphviz().require()
|
|
1614
|
+
from sage.features import PythonModule
|
|
1615
|
+
PythonModule("dot2tex").require()
|
|
1616
|
+
|
|
1617
|
+
if merge_multiedges and graph.has_multiple_edges():
|
|
1618
|
+
from collections import defaultdict
|
|
1619
|
+
d = defaultdict(list)
|
|
1620
|
+
for (u, v, label) in graph.edges(sort=False):
|
|
1621
|
+
d[(u, v)].append(label)
|
|
1622
|
+
edges = [(u, v, merge_label_function(label_list)) for (u, v), label_list in d.items()]
|
|
1623
|
+
loops = graph.has_loops()
|
|
1624
|
+
if graph.is_directed():
|
|
1625
|
+
from sage.graphs.digraph import DiGraph
|
|
1626
|
+
graph = DiGraph(edges, format='list_of_edges', loops=loops)
|
|
1627
|
+
else:
|
|
1628
|
+
from sage.graphs.graph import Graph
|
|
1629
|
+
graph = Graph(edges, format='list_of_edges', loops=loops)
|
|
1630
|
+
|
|
1631
|
+
options = {'format': 'dot2tex', 'edge_labels': True,
|
|
1632
|
+
'color_by_label': False, 'prog': 'dot', 'rankdir': 'down'}
|
|
1633
|
+
options.update(kwds)
|
|
1634
|
+
|
|
1635
|
+
graph.latex_options().set_options(**options)
|
|
1636
|
+
tikz = graph._latex_()
|
|
1637
|
+
return TikzPicture(tikz, standalone_config=["border=4mm"])
|
|
1638
|
+
|
|
1639
|
+
@classmethod
|
|
1640
|
+
@experimental(issue_number=20343)
|
|
1641
|
+
def from_graph_with_pos(cls, graph, scale=1, merge_multiedges=True,
|
|
1642
|
+
merge_label_function=tuple):
|
|
1643
|
+
r"""
|
|
1644
|
+
Convert a graph with positions defined for vertices to a tikzpicture.
|
|
1645
|
+
|
|
1646
|
+
.. WARNING::
|
|
1647
|
+
|
|
1648
|
+
This method might be deleted in the future in favor of a method
|
|
1649
|
+
in the graph class returning a tikz picture.
|
|
1650
|
+
|
|
1651
|
+
INPUT:
|
|
1652
|
+
|
|
1653
|
+
- ``graph`` -- graph (with predefined positions)
|
|
1654
|
+
- ``scale`` -- number (default: ``1``); tikzpicture scale
|
|
1655
|
+
- ``merge_multiedges`` -- boolean (default: ``True``); if the graph
|
|
1656
|
+
has multiple edges, whether to merge the multiedges into one
|
|
1657
|
+
single edge
|
|
1658
|
+
- ``merge_label_function`` -- function (default: ``tuple``); a
|
|
1659
|
+
function to apply to each list of labels to be merged. It is
|
|
1660
|
+
ignored if ``merge_multiedges`` is not ``True`` or if the graph
|
|
1661
|
+
has no multiple edges.
|
|
1662
|
+
|
|
1663
|
+
EXAMPLES::
|
|
1664
|
+
|
|
1665
|
+
sage: from sage.misc.latex_standalone import TikzPicture
|
|
1666
|
+
|
|
1667
|
+
sage: # needs sage.graphs
|
|
1668
|
+
sage: g = graphs.PetersenGraph()
|
|
1669
|
+
sage: tikz = TikzPicture.from_graph_with_pos(g)
|
|
1670
|
+
doctest:...: FutureWarning: This class/method/function is marked as experimental.
|
|
1671
|
+
It, its functionality or its interface might change without a formal deprecation.
|
|
1672
|
+
See https://github.com/sagemath/sage/issues/20343 for details.
|
|
1673
|
+
|
|
1674
|
+
::
|
|
1675
|
+
|
|
1676
|
+
sage: # needs sage.graphs
|
|
1677
|
+
sage: edges = [(0,0,'a'),(0,1,'b'),(0,1,'c')]
|
|
1678
|
+
sage: kwds = dict(format='list_of_edges', loops=True, multiedges=True)
|
|
1679
|
+
sage: G = DiGraph(edges, **kwds)
|
|
1680
|
+
sage: G.set_pos({0:(0,0), 1:(1,0)})
|
|
1681
|
+
sage: f = lambda label:','.join(label)
|
|
1682
|
+
sage: TikzPicture.from_graph_with_pos(G, merge_label_function=f)
|
|
1683
|
+
\documentclass[tikz]{standalone}
|
|
1684
|
+
\standaloneconfig{border=4mm}
|
|
1685
|
+
\begin{document}
|
|
1686
|
+
\begin{tikzpicture}
|
|
1687
|
+
[auto,scale=1]
|
|
1688
|
+
% vertices
|
|
1689
|
+
\node (node_0) at (0, 0) {0};
|
|
1690
|
+
\node (node_1) at (1, 0) {1};
|
|
1691
|
+
% edges
|
|
1692
|
+
\draw[->] (node_0) -- node {b,c} (node_1);
|
|
1693
|
+
% loops
|
|
1694
|
+
\draw (node_0) edge [loop above] node {a} ();
|
|
1695
|
+
\end{tikzpicture}
|
|
1696
|
+
\end{document}
|
|
1697
|
+
|
|
1698
|
+
TESTS::
|
|
1699
|
+
|
|
1700
|
+
sage: # needs sage.graphs
|
|
1701
|
+
sage: edges = [(0,0,'a'),(0,1,'b'),(0,1,'c')]
|
|
1702
|
+
sage: kwds = dict(format='list_of_edges', loops=True, multiedges=True)
|
|
1703
|
+
sage: G = DiGraph(edges, **kwds)
|
|
1704
|
+
sage: TikzPicture.from_graph_with_pos(G)
|
|
1705
|
+
Traceback (most recent call last):
|
|
1706
|
+
...
|
|
1707
|
+
ValueError: vertex positions need to be set first
|
|
1708
|
+
"""
|
|
1709
|
+
pos = graph.get_pos()
|
|
1710
|
+
if pos is None:
|
|
1711
|
+
raise ValueError('vertex positions need to be set first')
|
|
1712
|
+
|
|
1713
|
+
if merge_multiedges and graph.has_multiple_edges():
|
|
1714
|
+
from collections import defaultdict
|
|
1715
|
+
d = defaultdict(list)
|
|
1716
|
+
for (u, v, label) in graph.edges(sort=True):
|
|
1717
|
+
d[(u, v)].append(label)
|
|
1718
|
+
edges = [(u, v, merge_label_function(label_list)) for (u, v), label_list in d.items()]
|
|
1719
|
+
loops = graph.has_loops()
|
|
1720
|
+
if graph.is_directed():
|
|
1721
|
+
from sage.graphs.digraph import DiGraph
|
|
1722
|
+
graph = DiGraph(edges, format='list_of_edges', loops=loops)
|
|
1723
|
+
else:
|
|
1724
|
+
from sage.graphs.graph import Graph
|
|
1725
|
+
graph = Graph(edges, format='list_of_edges', loops=loops)
|
|
1726
|
+
|
|
1727
|
+
keys_for_vertices = graph._keys_for_vertices()
|
|
1728
|
+
|
|
1729
|
+
lines = []
|
|
1730
|
+
lines.append(r'\begin{tikzpicture}')
|
|
1731
|
+
lines.append(r'[auto,scale={}]'.format(scale))
|
|
1732
|
+
|
|
1733
|
+
# vertices
|
|
1734
|
+
lines.append(r'% vertices')
|
|
1735
|
+
for u in graph.vertices(sort=False):
|
|
1736
|
+
line = r'\node ({}) at {} {{{}}};'.format(keys_for_vertices(u),
|
|
1737
|
+
pos[u], u)
|
|
1738
|
+
lines.append(line)
|
|
1739
|
+
|
|
1740
|
+
# edges
|
|
1741
|
+
lines.append(r'% edges')
|
|
1742
|
+
arrow = '->' if graph.is_directed() else ''
|
|
1743
|
+
for (u, v, label) in graph.edges(sort=True):
|
|
1744
|
+
if u == v:
|
|
1745
|
+
# loops are done below
|
|
1746
|
+
continue
|
|
1747
|
+
if label:
|
|
1748
|
+
line = r'\draw[{}] ({}) -- node {{{}}} ({});'.format(arrow,
|
|
1749
|
+
keys_for_vertices(u),
|
|
1750
|
+
label,
|
|
1751
|
+
keys_for_vertices(v))
|
|
1752
|
+
else:
|
|
1753
|
+
line = r'\draw[{}] ({}) -- ({});'.format(arrow,
|
|
1754
|
+
keys_for_vertices(u),
|
|
1755
|
+
keys_for_vertices(v))
|
|
1756
|
+
lines.append(line)
|
|
1757
|
+
|
|
1758
|
+
# loops
|
|
1759
|
+
lines.append(r'% loops')
|
|
1760
|
+
for (u, v, label) in graph.loop_edges():
|
|
1761
|
+
line = r'\draw ({}) edge [loop above] node {{{}}} ();'.format(
|
|
1762
|
+
keys_for_vertices(u), label)
|
|
1763
|
+
lines.append(line)
|
|
1764
|
+
|
|
1765
|
+
lines.append(r'\end{tikzpicture}')
|
|
1766
|
+
tikz = '\n'.join(lines)
|
|
1767
|
+
return TikzPicture(tikz, standalone_config=["border=4mm"])
|
|
1768
|
+
|
|
1769
|
+
@classmethod
|
|
1770
|
+
@experimental(issue_number=20343)
|
|
1771
|
+
def from_poset(cls, poset, **kwds):
|
|
1772
|
+
r"""
|
|
1773
|
+
Convert a poset to a tikzpicture using graphviz and dot2tex.
|
|
1774
|
+
|
|
1775
|
+
.. NOTE::
|
|
1776
|
+
|
|
1777
|
+
Prerequisite: dot2tex optional Sage package and graphviz must be
|
|
1778
|
+
installed.
|
|
1779
|
+
|
|
1780
|
+
.. WARNING::
|
|
1781
|
+
|
|
1782
|
+
This method might be deleted in the future in favor of a method
|
|
1783
|
+
in the graph class returning a tikz picture.
|
|
1784
|
+
|
|
1785
|
+
INPUT:
|
|
1786
|
+
|
|
1787
|
+
- ``poset`` -- poset
|
|
1788
|
+
- ``prog`` -- string (default: ``'dot'``); the program used for the
|
|
1789
|
+
layout corresponding to one of the software of the graphviz
|
|
1790
|
+
suite: ``'dot'``, ``'neato'``, ``'twopi'``, ``'circo'`` or ``'fdp'``
|
|
1791
|
+
- ``edge_labels`` -- boolean (default: ``True``)
|
|
1792
|
+
- ``color_by_label`` -- boolean (default: ``False``)
|
|
1793
|
+
- ``rankdir`` -- string (default: ``'down'``)
|
|
1794
|
+
|
|
1795
|
+
EXAMPLES::
|
|
1796
|
+
|
|
1797
|
+
sage: from sage.misc.latex_standalone import TikzPicture
|
|
1798
|
+
|
|
1799
|
+
sage: # needs sage.graphs sage.modules
|
|
1800
|
+
sage: P = posets.PentagonPoset()
|
|
1801
|
+
sage: tikz = TikzPicture.from_poset(P) # optional - dot2tex graphviz
|
|
1802
|
+
doctest:...: FutureWarning: This class/method/function is marked as experimental.
|
|
1803
|
+
It, its functionality or its interface might change without a formal deprecation.
|
|
1804
|
+
See https://github.com/sagemath/sage/issues/20343 for details.
|
|
1805
|
+
|
|
1806
|
+
::
|
|
1807
|
+
|
|
1808
|
+
sage: tikz = TikzPicture.from_poset(P, prog='neato', # long time (3s), optional - dot2tex, needs sage.graphs sage.modules
|
|
1809
|
+
....: color_by_label=True)
|
|
1810
|
+
|
|
1811
|
+
::
|
|
1812
|
+
|
|
1813
|
+
sage: # needs sage.graphs
|
|
1814
|
+
sage: P = posets.SymmetricGroupWeakOrderPoset(4)
|
|
1815
|
+
sage: tikz = TikzPicture.from_poset(P) # long time (4s), optional - dot2tex graphviz
|
|
1816
|
+
sage: tikz = TikzPicture.from_poset(P, prog='neato') # long time (4s), optional - dot2tex graphviz
|
|
1817
|
+
"""
|
|
1818
|
+
graph = poset.hasse_diagram()
|
|
1819
|
+
return cls.from_graph(graph, **kwds)
|
|
1820
|
+
|
|
1821
|
+
def tikz_picture_code(self):
|
|
1822
|
+
r"""
|
|
1823
|
+
EXAMPLES::
|
|
1824
|
+
|
|
1825
|
+
sage: from sage.misc.latex_standalone import TikzPicture
|
|
1826
|
+
sage: s = "\\begin{tikzpicture}\n\\draw (0,0) -- (1,1);\n\\end{tikzpicture}"
|
|
1827
|
+
sage: t = TikzPicture(s)
|
|
1828
|
+
sage: print(t.tikz_picture_code())
|
|
1829
|
+
\begin{tikzpicture}
|
|
1830
|
+
\draw (0,0) -- (1,1);
|
|
1831
|
+
\end{tikzpicture}
|
|
1832
|
+
"""
|
|
1833
|
+
return self.content()
|