Opened 6 years ago

Last modified 3 months ago

#20343 needs_work enhancement

Adding sage/plot/tikzpicture.py

Reported by: slabbe Owned by:
Priority: major Milestone: sage-9.5
Component: misc Keywords:
Cc: dkrenn, jipilab, slelievre Merged in:
Authors: Sébastien Labbé Reviewers: Jean-Philippe Labbé, Xavier Caruso
Report Upstream: N/A Work issues:
Branch: u/slabbe/20343 (Commits, GitHub, GitLab) Commit: 9f9f5ec90bd47bae4ffe1a3e838f1cad229619a2
Dependencies: Stopgaps:

Status badges

Description (last modified by slabbe)

Importing TikzPicture module from optional SageMath package slabbe-0.6.2 into SageMath.

One example:

sage: from sage.plot.tikzpicture import TikzPicture
sage: V = [[1,0,1],[1,0,0],[1,1,0],[0,0,-1],[0,1,0],[-1,0,0],[0,1,1],[0,0,1],[0,-1,0]]
sage: P = Polyhedron(vertices=V).polar()
sage: s = P.projection().tikz([674,108,-731],112)
sage: t = TikzPicture(s)
sage: t.pdf()             # opens the pdf in a viewer                                                        
'/home/slabbe/.sage/temp/miami/5032/tikz_gvem9vu8.pdf'
sage: t.pdf('image.pdf')  # when a filename is provided, it doesn't open in a viewer                                            
'/home/slabbe/image.pdf'

It may create the image into png format (translation pdf -> png made with convert from imagemagick) or svg format (translation pdf -> svg made with pdf2svg):

sage: path_to_file = t.png()                                              
sage: path_to_file = t.svg()
sage: path_to_file = t.tex()

In a Jupyter notebook, this shows the picture below the cell (using rich repr):

sage: t

In the terminal, this shows the header and tail of the tikzpicture code:

sage: t                                                                                                    
\documentclass[tikz]{standalone}
\usepackage{amsmath}
\begin{document}
\begin{tikzpicture}%
	[x={(0.249656cm, -0.577639cm)},
	y={(0.777700cm, -0.358578cm)},
	z={(-0.576936cm, -0.733318cm)},
	scale=1.000000,
---
91 lines not printed (5169 characters in total).
Use print to see the full content.
---
\node[vertex] at (0.00000, -1.00000, 0.00000)     {};
\node[vertex] at (-0.50000, -0.50000, -0.50000)     {};
%%
%%
\end{tikzpicture}
\end{document}

Use print to see the full content:

sage: print(t) 

A second example shows that it is faster than view and better (avoids to crop the vertices):

sage: g = graphs.PetersenGraph()
sage: %time _ = TikzPicture(latex(g), standalone_options=["border=4mm"], usepackage=['tkz-graph']).pdf()
CPU times: user 3.52 ms, sys: 12.7 ms, total: 16.2 ms
Wall time: 2.24 s     

compared to using view (which crops the vertices and creates two pages pdf on mac):

sage: %time view(g, tightpage=True)               
CPU times: user 126 ms, sys: 85 ms, total: 211 ms 
Wall time: 6.06 s

Also, if dot2tex and graphviz available, one may directly construct a tikzpicture from a sagemath graph:

sage: t = TikzPicture.from_graph(g, prog='dot')  # optional: dot2tex

The tikzpicture.py was developped within optional package slabbe since 2015. Its interface should be stable enough to go into sage now.

Meanwhile any user can use this tikzpicture module by installing the package:

sage -pip install slabbe

and

sage: from slabbe import TikzPicture

Change History (45)

comment:1 Changed 6 years ago by slabbe

  • Description modified (diff)

comment:2 Changed 6 years ago by slabbe

  • Branch set to u/slabbe/20343
  • Commit set to 476b574c4198115e6e98e3396ed32f4b95077c35
  • Status changed from new to needs_review

New commits:

476b57420343: Adding tikzpicture.py in sage/misc

comment:3 Changed 6 years ago by slabbe

  • Description modified (diff)

comment:4 Changed 6 years ago by slabbe

  • Summary changed from Adding sage/misc/tikz_picture.py to Adding sage/misc/tikzpicture.py

comment:5 follow-up: Changed 6 years ago by dkrenn

  • Cc dkrenn added

A comment:

t = TikzPicture(latex(transducers.GrayCode()))
t.pdf()

does not work as the preamble is not set correctly. However, there is

from sage.combinat.finite_state_machine import setup_latex_preamble
setup_latex_preamble()

(as well as the corresponding function in sage.graphs.graph_latex) to set this correctly, but it seems to be ignored by TikzPicture.

In contrast,

view(transducers.GrayCode())

works, but I have no idea if setup_latex_preamble is called (not needed to be done manually) or if tikz is included anyways.

comment:6 in reply to: ↑ 5 ; follow-up: Changed 6 years ago by slabbe

Replying to dkrenn:

A comment:

t = TikzPicture(latex(transducers.GrayCode()))
t.pdf()

does not work as the preamble is not set correctly.

As it is now, the user must set the libraries. This should work:

t = TikzPicture(latex(transducers.GrayCode()), tikzlibraries=['automata'])
t.pdf()

I am still not sure about the proper way to choose the arguments for the __init__ function and their especially their default values. Should the arguments be empty by default? equal to the current sage latex preamble? or full of a big load of libraries?

comment:7 in reply to: ↑ 6 Changed 6 years ago by dkrenn

Replying to slabbe:

Replying to dkrenn:

A comment:

t = TikzPicture(latex(transducers.GrayCode()))
t.pdf()

does not work as the preamble is not set correctly.

As it is now, the user must set the libraries. This should work:

t = TikzPicture(latex(transducers.GrayCode()), tikzlibraries=['automata'])
t.pdf()

Works, thanks.

I am still not sure about the proper way to choose the arguments for the __init__ function and their especially their default values. Should the arguments be empty by default? equal to the current sage latex preamble? or full of a big load of libraries?

Without much thinking, I vote for: The second, equal to the current sage latex preamble.

comment:8 Changed 6 years ago by git

  • Commit changed from 476b574c4198115e6e98e3396ed32f4b95077c35 to 4ae7f63de1517e4c483e500757989b6efde5b785

Branch pushed to git repo; I updated commit sha1. New commits:

751209120343: Adding tikzpicture.py in sage/misc
4ae7f6320343: improving the default argument choices for TikzPicture

comment:9 Changed 6 years ago by slabbe

  • Description modified (diff)

comment:10 Changed 5 years ago by slabbe

  • Branch u/slabbe/20343 deleted
  • Commit 4ae7f63de1517e4c483e500757989b6efde5b785 deleted
  • Description modified (diff)

My module has evolved in my package slabbe, therefore the branch here is not up to date anymore. Also, I intend to make it more general during the next year allowing any content not only tikzpicture code. Therefore, I deleted the branch posted here.

comment:11 Changed 5 years ago by slabbe

  • Description modified (diff)
  • Status changed from needs_review to needs_work

Changing status to needs work.

comment:12 Changed 5 years ago by jipilab

  • Cc jipilab added
  • Reviewers set to Jean-Philippe Labbé

As a follow-up ticket to make use of this is #22506.

comment:13 Changed 7 months ago by caruso

  • Branch set to u/caruso/tikzpicture

comment:14 Changed 7 months ago by caruso

  • Commit set to 88c048c2a33618220a586f708273e41fd803f6bc

I'll be happy to revive this ticket.


New commits:

88c048cimport tikz_picture.py from slabbe gitlab repository

comment:15 Changed 7 months ago by git

  • Commit changed from 88c048c2a33618220a586f708273e41fd803f6bc to 2917f4b60238afcb4f097f3a256f734141aabe02

Branch pushed to git repo; I updated commit sha1. New commits:

2917f4bdoctests pass

comment:16 Changed 7 months ago by git

  • Commit changed from 2917f4b60238afcb4f097f3a256f734141aabe02 to 8cfc83431a25394be8b0dbc890d0dc0f72f54f56

Branch pushed to git repo; I updated commit sha1. New commits:

8cfc834typos

comment:17 Changed 7 months ago by caruso

I'm not convinced by all the methods from_dot_string, from_graph, etc. in the class TikzPicture. I would say that this code should instead be in the classes implementing the object we want to display. E.g. it could be a method _tikz_, just as _latex_, and TikzPicture just calls it.

What's your opinion?

comment:18 Changed 7 months ago by slabbe

There is no class for dot strings. Graphs already have a _latex_ method which returns a tikz picture string. It is what is used with for instance view(G). The from_graph class method really is using dot2tex + graphviz which is not the same layout sometimes. It is true that maybe adding a _tikz_ would avoid to replace the current behavior of _latex_. But then, having two different behaviors will be non pedagogical (how to know there is another one). Also, changing the default behavior will lead to problems...

I think it will be easier to add the new module as is and later on, in other tickets, add such _tikz_ methods in other parts of sage where it makes sense.

comment:19 Changed 7 months ago by caruso

  • Status changed from needs_work to needs_review

OK. Let's keep it for another ticket.

comment:20 Changed 7 months ago by caruso

  • Status changed from needs_review to positive_review

comment:21 Changed 7 months ago by caruso

  • Milestone changed from sage-7.2 to sage-9.4
  • Reviewers changed from Jean-Philippe Labbé to Jean-Philippe Labbé, Xavier Caruso

comment:22 Changed 7 months ago by chapoton

please no "from future import ..."

Returns should be Return

comment:23 Changed 7 months ago by caruso

  • Status changed from positive_review to needs_work

Also if pdflatex is not installed on the machine, some doctests fail. I don't know if this should be fixed but I think so because otherwise patchbots complain.

comment:24 Changed 7 months ago by slabbe

  • Branch changed from u/caruso/tikzpicture to u/slabbe/20343
  • Commit changed from 8cfc83431a25394be8b0dbc890d0dc0f72f54f56 to 665db0b0dd19254278d3cd74d96423a617781223

New commits:

665db0b20343: removed from __future__ imports

comment:25 Changed 7 months ago by git

  • Commit changed from 665db0b0dd19254278d3cd74d96423a617781223 to 0022eb2e8333597e2f4004e6b3a2d9363713df88

Branch pushed to git repo; I updated commit sha1. New commits:

0022eb220343: Returns -> Return

comment:26 Changed 7 months ago by git

  • Commit changed from 0022eb2e8333597e2f4004e6b3a2d9363713df88 to 03aa1bccb5640263e1d23867ee742b1ce9ac3ae0

Branch pushed to git repo; I updated commit sha1. New commits:

03aa1bc20343: adding few optional tags

comment:27 Changed 7 months ago by slabbe

  • Status changed from needs_work to needs_review

I added a bunch of #optional latex and #optional imagemagick tags. That should fix most of the issues.

I also added one # optional pdf2svg for which I am not sure about. I don't know if the doctest framework know about this tag. I change to needs review to check that on the patchbot.

comment:28 Changed 7 months ago by vdelecroix

Why do you make it part of Sage and not an independent Python module? These could easily be declared as optional/standard packages afterwards.

comment:29 follow-up: Changed 7 months ago by slabbe

Yes, I agree with that option too. Lately, I was thinking more about this option.

But, the module also depends on many things that are in Sage which would make this module quite unusable outside of sage as it is currently. For example:

To check if Graphviz is there:

from sage.features.graphviz import Graphviz

To check if pdflatex, convert and other programs are available:

from sage.misc.latex import have_pdflatex, have_convert, have_program

To load the latex macros from sage:

from sage.misc.latex import _Latex_prefs
from sage.misc.latex_macros import sage_latex_macros

To create a temporary file inside the sage folder of temporary files:

from sage.misc.temporary_file import tmp_filename

To open viewers:

from sage.misc.viewer import browser
from sage.misc.viewer import pdf_viewer
from sage.misc.viewer import png_viewer

To check whether we are in the JupyterNotebook or not:

from sage.repl.rich_output.backend_ipython import BackendIPythonNotebook
from sage.repl.rich_output.buffer import OutputBuffer
Last edited 7 months ago by slabbe (previous) (diff)

comment:30 Changed 7 months ago by git

  • Commit changed from 03aa1bccb5640263e1d23867ee742b1ce9ac3ae0 to 7d590342121285b6fea577b0defc65aece99258e

Branch pushed to git repo; I updated commit sha1. New commits:

7d5903420343: adding few optional latex tags

comment:31 in reply to: ↑ 29 Changed 5 months ago by vdelecroix

Replying to slabbe:

Yes, I agree with that option too. Lately, I was thinking more about this option.

The main advantage with that option is that the package can change versions independently of sage.

But, the module also depends on many things that are in Sage which would make this module quite unusable outside of sage as it is currently. For example:

This would be a Python module that depends on sage. There is nothing bad with that situation. And this is not the only one.

comment:32 Changed 4 months ago by slabbe

I am thinking about what to do now, either work on this ticket or create a new package. If I create a sagemath-tikzpicture package that imports many parts of sagemath, I will be responsible for fixing the package each time sagemath changes something that I import. On the other hand, if that modules goes into sagemath, then, it will become the responsability of the person which changes the dependencies to also fix the tikzpicture module. I agree with the idea of modularization, but for the above reason, I would prefer to make it go into sage. What do you think?

Last edited 4 months ago by slabbe (previous) (diff)

comment:33 Changed 4 months ago by caruso

I prefer to have this directly in sage since I think that there are many other places in sage where it would be great to have a tikz output.

comment:34 Changed 4 months ago by mkoeppe

Because this module does not depend on any external libraries, there is nothing gained in the direction of modularization by making this a separate distribution package.

But perhaps you can find a better place for it than sage.misc? How about sage.typeset or sage.plot?

comment:35 Changed 3 months ago by git

  • Commit changed from 7d590342121285b6fea577b0defc65aece99258e to 9f9f5ec90bd47bae4ffe1a3e838f1cad229619a2

Branch pushed to git repo; I updated commit sha1. New commits:

d84b6a3Merge branch 'u/slabbe/20343' of trac.sagemath.org:sage into 20343
ee56d32adding optional tag latex to one doctest
269268520343:avoid use of doctest continuation since it is not one
2acfe6120343: misc/tikz_picture.py -> plot/tikzpicture.py
388a5f8from misc.tikz_picture -> from plot.tikzpicture
b04ea0dupdated authors and copyright
9f9f5ec20343: redoing recent changes by Vincent Delecroix in slabbe package (check_call -> run); improved header documentation

comment:36 Changed 3 months ago by slabbe

  • Description modified (diff)
  • Summary changed from Adding sage/misc/tikzpicture.py to Adding sage/plot/tikzpicture.py

comment:37 Changed 3 months ago by slabbe

  • Description modified (diff)

comment:38 Changed 3 months ago by slabbe

  • Description modified (diff)

comment:39 Changed 3 months ago by slabbe

  • Description modified (diff)

comment:40 Changed 3 months ago by slabbe

  • Description modified (diff)

comment:41 Changed 3 months ago by slabbe

I think we are close to it. The doctests work on my machine:

sage -t --optional=sage,optional,external --long --show-skipped tikzpicture.py 

gives

Using --optional=4ti2,ccache,cryptominisat,debian,dot2tex,e_antic,external,fricas,glucose,latte_int,lidia,normaliz,notedown,pandoc_attributes,pip,pycosat,pynormaliz,rst2ipynb,sage,sage_numerical_backends_coin,sage_spkg
External software to be detected: cplex,ffmpeg,graphviz,gurobi,imagemagick,internet,latex,macaulay2,magma,maple,mathematica,matlab,octave,pandoc,rubiks,scilab
Doctesting 1 file.
sage -t --long --random-seed=0 tikzpicture.py
    19 not tested tests not run
    1 pdf2svg test not run
    0 tests not run because we ran out of time
    [161 tests, 15.43 s]
----------------------------------------------------------------------
All tests passed!
----------------------------------------------------------------------
Total time for all tests: 15.6 seconds
    cpu time: 8.2 seconds
    cumulative wall time: 15.4 seconds
External software detected for doctesting: imagemagick,latex

TODO:

  • Let's see what the patchbot says.
  • The doctest tagged with pdf2svg is not recognized by the --optional=external. Maybe something needs to be done on the detection of external packages.
  • One issue is that the current _rich_repr_ always uses png instead of svg in the Jupyter Notebook even if I define 'svg' before 'png' in the prefer_vector tuple. I think that issue can be dealt in a later ticket.

That's it! Needs review!

comment:42 Changed 3 months ago by mkoeppe

  • Cc slelievre added

This ad-hoc system package advice

+        if not have_program('pdf2svg'):
+            raise RuntimeError("pdf2svg does not seem to be installed. "
+                    "Install it for example with ``brew install pdf2svg``"
+                    " or ``apt-get install pdf2svg``.")
+

should be replaced by a Feature and an spkg pdf2svg with distros/ information from https://repology.org/project/pdf2svg/versions

comment:43 Changed 3 months ago by slabbe

Ok, I will add a Feature for pdf2svg.

Also, patchbot says this:

src/sage/plot/tikzpicture.py:98:1 'subprocess.CalledProcessError' imported but unused
found 1 pyflakes errors in the modified files

Another TODO is to allow to get some verbosity useful when compilation of the picture breaks. I am writting it here not to forget.

I will work on that soon or later.

comment:44 Changed 3 months ago by mkoeppe

  • Status changed from needs_review to needs_work

comment:45 Changed 3 months ago by mkoeppe

  • Milestone changed from sage-9.4 to sage-9.5
Note: See TracTickets for help on using tickets.