sagemath/sage

Add file `sage/misc/latex_standalone.py` and class `TikzPicture`

Closed this issue · 211 comments

The goal of this ticket is to import the TikzPicture module from the optional SageMath package slabbe into SageMath. This module has been created in 2016 and has evolved to a stable state and it is mature enough to go into SageMath now.

Here is a demo inside a Jupyter notebook (notice that the import line was since changed to from sage.misc.latex_standalone import TikzPicture):

<img src="tikz-jupyter-demo.png" width=width=600>

More examples:

sage: from sage.misc.latex_standalone 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

An example of usage of this module can be found at this url:

associated to the preprint

published in Journal of Modern Dynamics at

Depends on #32650
Depends on #33005

CC: @dkrenn @jplab @slel @fchapoton

Component: misc

Author: Sébastien Labbé

Branch: 5c9b41c

Reviewer: Jean-Philippe Labbé, Xavier Caruso, Vincent Delecroix, Matthias Koeppe

Issue created by migration from https://trac.sagemath.org/ticket/20343

Description changed:

--- 
+++ 
@@ -1,3 +1,23 @@
-From my optional Sage package [1] slabbe-0.2.spkg.
+Importing a file from my optional Sage package [slabbe-0.2.spkg](https://github.com/seblabbe/slabbe) into Sage.
 
-[1] https://github.com/seblabbe/slabbe
+```
+sage: from sage.misc.tikz_picture 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()
+```
+
+```
+sage: g = graphs.PetersenGraph()
+sage: s = latex(g)
+sage: t = TikzPicture(s, standalone_configs=["border=4mm"], packages=['tkz-graph'])
+sage: _ = t.pdf()
+```
+
+If dot2tex and graphviz available:
+
+```
+sage: t = TikzPicture.from_graph(g)  # optional: dot2tex
+```

Commit: 476b574

New commits:

476b57420343: Adding tikzpicture.py in sage/misc

Description changed:

--- 
+++ 
@@ -1,7 +1,9 @@
-Importing a file from my optional Sage package [slabbe-0.2.spkg](https://github.com/seblabbe/slabbe) into Sage.
+Importing `TikzPicture` class from my optional Sage package [slabbe-0.2.spkg](https://github.com/seblabbe/slabbe) into Sage.
+
+One example:
 
 ```
-sage: from sage.misc.tikz_picture import TikzPicture
+sage: from sage.misc.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)
@@ -9,15 +11,27 @@
 sage: t.pdf()
 ```
 
+Second example:
+
 ```
 sage: g = graphs.PetersenGraph()
-sage: s = latex(g)
-sage: t = TikzPicture(s, standalone_configs=["border=4mm"], packages=['tkz-graph'])
-sage: _ = t.pdf()
+sage: %time _ = TikzPicture(latex(g), standalone_configs=["border=4mm"], packages=['tkz-graph']).pdf()
+CPU times: user 3.52 ms, sys: 12.7 ms, total: 16.2 ms
+Wall time: 2.24 s     
 ```
 
-If dot2tex and graphviz available:
+compared to using view (which crops the vertices and creates two pages pdf on mac):
 
 ```
-sage: t = TikzPicture.from_graph(g)  # optional: dot2tex
+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:
+
+```
+sage: t = TikzPicture.from_graph(g, prog='dot')  # optional: dot2tex
+```
+
+
comment:5

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

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

Replying to @seblabbe:

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.

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

Changed commit from 476b574 to 4ae7f63

Description changed:

--- 
+++ 
@@ -15,7 +15,7 @@
 
 ```
 sage: g = graphs.PetersenGraph()
-sage: %time _ = TikzPicture(latex(g), standalone_configs=["border=4mm"], packages=['tkz-graph']).pdf()
+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     
 ```

Changed commit from 4ae7f63 to none

Changed branch from u/slabbe/20343 to none

Description changed:

--- 
+++ 
@@ -34,4 +34,14 @@
 sage: t = TikzPicture.from_graph(g, prog='dot')  # optional: dot2tex
 ```
 
+To avoid losing my time, I will not post a branch here until somebody tells me he is willing to review this module. Meanwhile any user can use this tikzpicture module by installing my package:
 
+```
+sage -pip install slabbe
+```
+
+and
+
+```
+sage: from slabbe import TikzPicture
+```
comment:10

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.

Description changed:

--- 
+++ 
@@ -34,7 +34,9 @@
 sage: t = TikzPicture.from_graph(g, prog='dot')  # optional: dot2tex
 ```
 
-To avoid losing my time, I will not post a branch here until somebody tells me he is willing to review this module. Meanwhile any user can use this tikzpicture module by installing my package:
+I intend to make further improvements to this module during the next year. Also, I will wait until somebody tells me he is willing to review this module before publishing a branch here.
+
+Meanwhile any user can use this tikzpicture module by installing my package:
 
 ```
 sage -pip install slabbe
comment:11

Changing status to needs work.

jplab commented

Reviewer: Jean-Philippe Labbé

jplab commented
comment:12

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

comment:14

I'll be happy to revive this ticket.


New commits:

88c048cimport tikz_picture.py from slabbe gitlab repository

Commit: 88c048c

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

2917f4bdoctests pass

Changed commit from 88c048c to 2917f4b

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

8cfc834typos

Changed commit from 2917f4b to 8cfc834

comment:17

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

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

OK. Let's keep it for another ticket.

Changed reviewer from Jean-Philippe Labbé to Jean-Philippe Labbé, Xavier Caruso

comment:22

please no "from future import ..."

Returns should be Return

comment:23

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.

New commits:

665db0b20343: removed from `__future__` imports

Changed commit from 8cfc834 to 665db0b

Changed commit from 665db0b to 0022eb2

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

0022eb220343: Returns -> Return

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

03aa1bc20343: adding few optional tags

Changed commit from 0022eb2 to 03aa1bc

comment:27

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

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

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

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

7d5903420343: adding few optional latex tags

Changed commit from 03aa1bc to 7d59034

comment:31

Replying to @seblabbe:

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

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?

comment:33

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

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?

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

Changed commit from 7d59034 to 9f9f5ec

Description changed:

--- 
+++ 
@@ -1,17 +1,67 @@
-Importing `TikzPicture` class from my optional Sage package [slabbe-0.2.spkg](https://github.com/seblabbe/slabbe) into Sage.
+Importing `TikzPicture` module from optional [SageMath](../wiki/SageMath) package [slabbe-0.6.2](https://pypi.org/project/slabbe/) into [SageMath](../wiki/SageMath).
 
 One example:
 
 ```
-sage: from sage.misc.tikzpicture import TikzPicture
+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()
+sage: t.pdf()                  # opens the pdf in a viewer                                                        
+'/home/slabbe/.sage/temp/miami/5032/tikz_gvem9vu8.pdf'
+sage: t.pdf('image.pdf')                                                                                   
+'/home/slabbe/image.pdf'
 ```
 
-Second example:
+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: t.png()                                                                                              
+'/home/slabbe/.sage/temp/miami/5032/tikz_v0s5kl9l.png'
+sage: t.svg()                                                                                              
+'/home/slabbe/.sage/temp/miami/5032/tikz_sfww636u.svg'
+sage: t.tex()                                                                                              
+'/home/slabbe/.sage/temp/miami/5032/tikz_xxwqfjh5.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()
@@ -28,13 +78,13 @@
 Wall time: 6.06 s
 ```
 
-Also, if dot2tex and graphviz available:
+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
 ```
 
-I intend to make further improvements to this module during the next year. Also, I will wait until somebody tells me he is willing to review this module before publishing a branch here.
+The `tikzpicture.py` was developped within optional package `slabbe` for the last 6 years. Its interface should be stable enough to go into sage now.
 
 Meanwhile any user can use this tikzpicture module by installing my package:
 

Description changed:

--- 
+++ 
@@ -8,9 +8,9 @@
 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                                                        
+sage: t.pdf()             # opens the pdf in a viewer                                                        
 '/home/slabbe/.sage/temp/miami/5032/tikz_gvem9vu8.pdf'
-sage: t.pdf('image.pdf')                                                                                   
+sage: t.pdf('image.pdf')  # when a filename is provided, it does not open the pdf in a viewer                                            
 '/home/slabbe/image.pdf'
 ```
 

Description changed:

--- 
+++ 
@@ -10,7 +10,7 @@
 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 does not open the pdf in a viewer                                            
+sage: t.pdf('image.pdf')  # when a filename is provided, it doesn't open in a viewer                                            
 '/home/slabbe/image.pdf'
 ```
 

Description changed:

--- 
+++ 
@@ -17,12 +17,9 @@
 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: t.png()                                                                                              
-'/home/slabbe/.sage/temp/miami/5032/tikz_v0s5kl9l.png'
-sage: t.svg()                                                                                              
-'/home/slabbe/.sage/temp/miami/5032/tikz_sfww636u.svg'
-sage: t.tex()                                                                                              
-'/home/slabbe/.sage/temp/miami/5032/tikz_xxwqfjh5.tex'
+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):

Description changed:

--- 
+++ 
@@ -81,9 +81,9 @@
 sage: t = TikzPicture.from_graph(g, prog='dot')  # optional: dot2tex
 ```
 
-The `tikzpicture.py` was developped within optional package `slabbe` for the last 6 years. Its interface should be stable enough to go into sage now.
+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 my package:
+Meanwhile any user can use this tikzpicture module by installing the package:
 
 ```
 sage -pip install slabbe
comment:41

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

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

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.

Dependencies: #32650

Branch pushed to git repo; I updated commit sha1. Last 10 new commits:

a96e94d32650: Creating feature pdf2svg
870d46132650: Creating features latex, xelatex, pdflatex, lualatex
385569e32650: adding latex, xelatex, pdflatex, lualatex, pdf2svg, dvipng to doctest/external.py
f3291d832650: using features instead of have_program in misc/latex.py
d45599332650: using features in plot/animate.py
cf0209432650: using features in plot/graphics.py and plot/multigraphics.py
28f1f4a32650: deprecating have_* functions in misc/latex.py in favor of features
5d9414d32650: .. note -> .. NOTE
6d21ec7Merge branch #20343 onto #32650
80151c220343: using features instead of have_program, have_pdflatex, have_convert

Changed commit from 9f9f5ec to 80151c2

comment:48

I rebased on top of current #32650.

Current TODOS are:

  • verbosity when compilation breaks
  • add distro info stuff in pdf2svg (should be done in #32650)
  • improve rich repr to use svg not always png

Changed commit from 80151c2 to 997b8f1

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

997b8f120343: print the log when pdflatex fails compile the tikz image
comment:50

With the recent commit and subsequent work done in #32650, the remainings TODOs are:

  • improve rich repr to use svg not always png

and as I suggested before, this one could be dealt in another ticket as it is still functional with png's in the Jupyter notebook.

Needs review!

Description changed:

--- 
+++ 
@@ -94,3 +94,8 @@
 ```
 sage: from slabbe import TikzPicture
 ```
+
+An example of usage of this module can be found at this url:
+https://nbviewer.jupyter.org/url/www.slabbe.org/Publications/arXiv_1906_01104.ipynb
+associated to the preprint https://arxiv.org/abs/1906.01104 published in Journal of Modern Dynamics since one week at http://dx.doi.org/10.3934/jmd.2021017. It can be used to review the current ticket if one changes `from slabbe import TikzPicture` by `from sage.plot.tikzpicture import TikzPicture` at the beginning (oups! no, it will not work since the import is done within the package).
+For the review, one may check

Description changed:

--- 
+++ 
@@ -98,4 +98,3 @@
 An example of usage of this module can be found at this url:
 https://nbviewer.jupyter.org/url/www.slabbe.org/Publications/arXiv_1906_01104.ipynb
 associated to the preprint https://arxiv.org/abs/1906.01104 published in Journal of Modern Dynamics since one week at http://dx.doi.org/10.3934/jmd.2021017. It can be used to review the current ticket if one changes `from slabbe import TikzPicture` by `from sage.plot.tikzpicture import TikzPicture` at the beginning (oups! no, it will not work since the import is done within the package).
-For the review, one may check

Description changed:

--- 
+++ 
@@ -97,4 +97,4 @@
 
 An example of usage of this module can be found at this url:
 https://nbviewer.jupyter.org/url/www.slabbe.org/Publications/arXiv_1906_01104.ipynb
-associated to the preprint https://arxiv.org/abs/1906.01104 published in Journal of Modern Dynamics since one week at http://dx.doi.org/10.3934/jmd.2021017. It can be used to review the current ticket if one changes `from slabbe import TikzPicture` by `from sage.plot.tikzpicture import TikzPicture` at the beginning (oups! no, it will not work since the import is done within the package).
+associated to the preprint https://arxiv.org/abs/1906.01104 published in Journal of Modern Dynamics since one week at http://dx.doi.org/10.3934/jmd.2021017. It can be used to review the current ticket if one uses `from sage.plot.tikzpicture import TikzPicture` and check that tikzpicture created within slabbe still works within the tikzpicture module introduced in this ticket.
comment:54

In a similar direction as comment:17, I think that the from_graph... and from_poset class methods should rather be changed to methods of Graph and Poset.

comment:55

Also https://pypi.org/project/tikzplotlib/ looks interesting

Changed commit from 997b8f1 to 6a085cf

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

f9c949220343: few small improvements
6a085cf20343: improving first example shown in documentation
comment:57

I added two commits to do few improvements.

comment:58

Replying to @mkoeppe:

In a similar direction as comment:17, I think that the from_graph... and from_poset class methods should rather be changed to methods of Graph and Poset.

If you want to go in that direction, we need to have a design discussion before spending time changing the graph code. As you know,

sage: g = graphs.PetersenGraph()
sage: hasattr(g, '_latex_')
True

which returns an object of type:

sage: type(latex(g))
<class 'sage.misc.latex.LatexExpr'>

This latex expression starts with \begin{tikzpicture} and ends with \end{tikzpicture} which also depends on \usepackage{tkz-graph}:

sage: latex(g)
\begin{tikzpicture}                                                                                    
\definecolor{cv0}{rgb}{0.0,0.0,0.0}                                                                    
\definecolor{cfv0}{rgb}{1.0,1.0,1.0}                                                                   
...
\Edge[lw=0.1cm,style={color=cv6v9,},](v6)(v9)
\Edge[lw=0.1cm,style={color=cv7v9,},](v7)(v9)
%
\end{tikzpicture}

Notice that this output can be provided to TikzPicture with no problem with t = TikzPicture(latex(g), usepackage=['tkz-graph']) and t.pdf() works etc.

I don't think here we want to replace the output of g._latex_ by an object of type TikzPicture since a such change would break a lot of code.

An option is to create a new method def tikz(self) instead. I can do something like that. It could return the TikzPicture(latex(g), usepackage=['tkz-graph']) by default and if one asks, it could use the graphviz + dot2tex output instead. But, I was thinking of doing this in another ticket as a follow up, as this will open discussions that will just make longer before this ticket can go in.

Or maybe you would rather like to remove the from_graph and the from_poset methods to avoid to have to maintain them in the future? Well, currently, the from_graph also allows to merge the multiple edges which is something that would not go in the tikz method of a graph. Also, keeping the from_graph would make the passage from this module to sage easier for me because I have been using this method over and over and over in my research code.

comment:59

I created ticket #33002 for the addition of a method to return an object of type TikzPicture in graph, posets and polyhedron code.

Changed commit from 6a085cf to d6d473a

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

d6d473a20343: fixing a bug, png output was not working
comment:61

Replying to @seblabbe:

With the recent commit and subsequent work done in #32650, the remainings TODOs are:

  • improve rich repr to use svg not always png

and as I suggested before, this one could be dealt in another ticket as it is still functional with png's in the Jupyter notebook.

Also, I want to say that I believe that the sage.repl code is broken with respect to showing svg files.

# Jupyter cell 1
g = graphs.PetersenGraph()
from sage.plot.tikzpicture import TikzPicture
t = TikzPicture(latex(g), usepackage=['tkz-graph'])
t # works: it shows a png
# Jupyter cell 2
from sage.repl.rich_output import get_display_manager
dm = get_display_manager()
assert dm.preferences.graphics is None
dm.preferences.graphics = 'raster'
t  # works: it shows a png
# Jupyter cell 3
dm.preferences.graphics = 'vector'
t   # broken: it does not show anything

The following shows that the Jupyter notebook is able to handle a svg correctly:

# Jupyter cell 4
t.svg('a.svg')
from IPython.core.display import SVG
SVG(filename='a.svg')

I suggest to fix the issue with the showing of svg in another ticket.

Changed commit from d6d473a to 2da56a8

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

2da56a820343: using pdftocairo instead of pdf2svg

Changed dependencies from #32650 to #32650, #33005

comment:64

Replying to @seblabbe:

Replying to @mkoeppe:

In a similar direction as comment:17, I think that the from_graph... and from_poset class methods should rather be changed to methods of Graph and Poset.

I don't think here we want to replace the output of g._latex_ by an object of type TikzPicture since a such change would break a lot of code.

I agree

An option is to create a new method def tikz(self) instead. I can do something like that.

Yes, this is what I meant

Branch pushed to git repo; I updated commit sha1. This was a forced push. Last 10 new commits:

d4ca003from misc.tikz_picture -> from plot.tikzpicture
42011d6updated authors and copyright
6894a5b20343: redoing recent changes by Vincent Delecroix in slabbe package (check_call -> run); improved header documentation
2c0792520343: using features instead of have_program, have_pdflatex, have_convert
83b917320343: print the log when pdflatex fails compile the tikz image
b26bc3f20343: few small improvements
ae7b9bf20343: improving first example shown in documentation
9f91d2220343: fixing a bug, png output was not working
f39e07a20343: using pdftocairo instead of pdf2svg
908177720343:fixing 2 doctests + wrong trailing colons

Changed commit from 2da56a8 to 9081777

comment:67

There was a syntax error in the file due to the previous commit. I fixed that.

I also rebased the branch on top of 9.5.beta9.

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

b2388a120343: change default from pdf2svg to pdftocairo
a78e9ce20343: provide log if an error occurs in method png

Changed commit from 9081777 to a78e9ce

comment:69

I confirm it works on my side:

$ sage -t tikzpicture.py 
[...]
Doctesting 1 file.
sage -t --random-seed=33963620693510224516081799230454604818 tikzpicture.py
    [158 tests, 4.59 s]
----------------------------------------------------------------------
All tests passed!
----------------------------------------------------------------------
Features detected for doctesting: 

and

$ sage -t --show-skipped --long --optional=sage,optional,external tikzpicture.py 
[...]
Doctesting 1 file.
sage -t --long --random-seed=204572532264437349038334999704478431314 tikzpicture.py
    24 not tested tests not run
    2 pdftocairo tests not run
    0 tests not run because we ran out of time
    [188 tests, 15.97 s]
----------------------------------------------------------------------
All tests passed!
----------------------------------------------------------------------
Features detected for doctesting: imagemagick,latex,pdf2svg

Description changed:

--- 
+++ 
@@ -1,6 +1,10 @@
-Importing `TikzPicture` module from optional [SageMath](../wiki/SageMath) package [slabbe-0.6.2](https://pypi.org/project/slabbe/) into [SageMath](../wiki/SageMath).
+The goal of this ticket is to import the `TikzPicture` module from the optional [SageMath](../wiki/SageMath) package [slabbe](https://pypi.org/project/slabbe/) into [SageMath](../wiki/SageMath). This module has been created in 2016 and has evolved to a stable  state now and it is mature enough to go into [SageMath](../wiki/SageMath).
 
-One example:
+Here is a demo inside a Jupyter notebook:
+
+<img src="tikz-jupyter-demo.png" width=width=600>
+
+More examples:
 
 ```
 sage: from sage.plot.tikzpicture import TikzPicture
comment:70

Updating the description: adding a screenshot of the behavior in Jupyter, hoping it motivates someone to review the ticket.

Description changed:

--- 
+++ 
@@ -1,4 +1,4 @@
-The goal of this ticket is to import the `TikzPicture` module from the optional [SageMath](../wiki/SageMath) package [slabbe](https://pypi.org/project/slabbe/) into [SageMath](../wiki/SageMath). This module has been created in 2016 and has evolved to a stable  state now and it is mature enough to go into [SageMath](../wiki/SageMath).
+The goal of this ticket is to import the `TikzPicture` module from the optional SageMath package [slabbe](https://pypi.org/project/slabbe/) into SageMath. This module has been created in 2016 and has evolved to a stable  state now and it is mature enough to go into SageMath.
 
 Here is a demo inside a Jupyter notebook:
 

Description changed:

--- 
+++ 
@@ -1,4 +1,4 @@
-The goal of this ticket is to import the `TikzPicture` module from the optional SageMath package [slabbe](https://pypi.org/project/slabbe/) into SageMath. This module has been created in 2016 and has evolved to a stable  state now and it is mature enough to go into SageMath.
+The goal of this ticket is to import the `TikzPicture` module from the optional SageMath package [slabbe](https://pypi.org/project/slabbe/) into SageMath. This module has been created in 2016 and has evolved to a stable  state and it is mature enough to go into SageMath now.
 
 Here is a demo inside a Jupyter notebook:
 

Description changed:

--- 
+++ 
@@ -101,4 +101,4 @@
 
 An example of usage of this module can be found at this url:
 https://nbviewer.jupyter.org/url/www.slabbe.org/Publications/arXiv_1906_01104.ipynb
-associated to the preprint https://arxiv.org/abs/1906.01104 published in Journal of Modern Dynamics since one week at http://dx.doi.org/10.3934/jmd.2021017. It can be used to review the current ticket if one uses `from sage.plot.tikzpicture import TikzPicture` and check that tikzpicture created within slabbe still works within the tikzpicture module introduced in this ticket.
+associated to the preprint https://arxiv.org/abs/1906.01104 published in Journal of Modern Dynamics at http://dx.doi.org/10.3934/jmd.2021017.
comment:74

Why this default usepackage=['amsmath']?

comment:75

Moreover, you should never have a list as a default argument which is plugged as an attribute

sage: class A():
....:     def __init__(self, a=[]):
....:         self.a = a
sage: x = A()
sage: x.a.append(2)
sage: y = A()
sage: y.a
[2]

Changed commit from a78e9ce to fc47455

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

a3dec9220343: change default value of usepackage to None
fc4745520343: use shell=False instead
comment:77

You are right. I also avoided the usage of shell=True for security reasons, see https://docs.python.org/3/library/subprocess.html#security-considerations

Doing so, the cmd needs to be a list and not a string. This is better also because it allows filenames to contain spaces: "Providing a sequence of arguments is generally preferred, as it allows the module to take care of any required escaping and quoting of arguments (e.g. to permit spaces in file names)", see https://docs.python.org/3/library/subprocess.html#frequently-used-arguments

comment:78

Replying to @seblabbe:

[...]
This is better also because it allows filenames to contain spaces
[...]

If 'm y p i c t u r e.pdf' is an explicitely supported filename, it would make sense to mention it and test it. If it is an obscure feature, nevermind.