2

I use the GAP-package QPA to obtain quivers (which are just directed graphs) and the QPA-output of a quiver looks for example as follows:

["v1","v2","v3","v4","v5","v6","v7","v8","v9","v10","v11","v12","v13","v14","v15"], [["v1","v3","a1"],["v2","v1","a2"],["v3","v8","a3"],["v4","v6","a4"],["v5","v6","a5"]\
,["v6","v4","a6"],["v6","v5","a7"],["v6","v8","a8"],["v7","v12","a9"],["v8","v9","a10"],["v8","v10","a11"],["v9","v7","a12"],["v9","v11","a13"],["v10","v7","a14"],["v10","v11","\
a15"],["v11","v12","a16"],["v12","v2","a17"],["v12","v13","a18"],["v13","v14","a19"],["v13","v15","a20"],["v14","v13","a21"],["v15","v13","a22"]]

Here the first list ["v1","v2","v3","v4","v5","v6","v7","v8","v9","v10","v11","v12","v13","v14","v15"]

is just the names of the vertices and the second list

[["v1","v3","a1"],["v2","v1","a2"],["v3","v8","a3"],["v4","v6","a4"],["v5","v6","a5"] ,["v6","v4","a6"],["v6","v5","a7"],["v6","v8","a8"],["v7","v12","a9"],["v8","v9","a10"],["v8","v10","a11"],["v9","v7","a12"],["v9","v11","a13"],["v10","v7","a14"],["v10","v11"," a15"],["v11","v12","a16"],["v12","v2","a17"],["v12","v13","a18"],["v13","v14","a19"],["v13","v15","a20"],["v14","v13","a21"],["v15","v13","a22"]]

are just the names of the arrows with where they start and end.

The main problem is to automatically translate this directed graph with some software into a nice latex pictures for tikz. Now one can use Sage to translate this quiver into tikz for latex as follows:

def from_QPA(Q):
    arrows = [(v.SourceOfPath(), v.TargetOfPath(), v) for v in Q.ArrowsOfQuiver() ]
    elements = Q.VerticesOfQuiver()
    return DiGraph([elements, arrows], loops=True, format='vertices_and_edges')

libgap.LoadPackage("QPA") Q = libgap.Quiver( ["v1","v2","v3","v4","v5","v6","v7","v8","v9","v10","v11","v12","v13","v14","v15"], [["v1","v3","a1"],["v2","v1","a2"],["v3","v8","a3"],["v4","v6","a4"],["v5","v6","a5"]
,["v6","v4","a6"],["v6","v5","a7"],["v6","v8","a8"],["v7","v12","a9"],["v8","v9","a10"],["v8","v10","a11"],["v9","v7","a12"],["v9","v11","a13"],["v10","v7","a14"],["v10","v11","
a15"],["v11","v12","a16"],["v12","v2","a17"],["v12","v13","a18"],["v13","v14","a19"], ["v13","v15","a20"],["v14","v13","a21"],["v15","v13","a22"]] ) U=from_QPA(Q) display(U.plot(edge_labels=True)) U.set_latex_options(edge_labels=True) display(latex(U))

You can input it for example into the Sage online cell https://sagecell.sagemath.org/ to see the result, which is the picture and the correponding tikz-code to obtain the quiver in latex.

Sadly for large quivers as in this example the result looks terrible.

Question 1: Is there an easy way to make the result look good in tikz for even complicated quivers?

For example it might be better when the names of the arrows are on top of the arrows and not inside them (also maybe they should be smaller).

Question 2: Is there maybe a better way than using Sage to directly obtain quivers from QPA in tikz using another program or maybe even tikz itself in some way?

Mare
  • 291
  • 1
  • 7
  • 1
    With regard to Question 1, you're using vague language like "looks terrible" and "looks good". To me, the specific problem I see is the graph is too small so everything is crowded together. You haven't changed figsize to make it look better; eg display(U.plot(edge_labels=True,figsize=[25,25])). Now the graph doesn't look terrible to me. – DJP Jan 10 '21 at 15:14
  • @DJP Thanks that already helps. But how can I also change the latex code so that it displays the latex code of the larger image? The following does not work: U.set_latex_options(edge_labels=True,figsize=[25,25]) display(latex(U)) – Mare Jan 10 '21 at 15:34
  • Also: Is there an easy way to make the vertices not look so big even when one makes the graph bigger? (Small dots with the vertex names above them might be enough). It also shouldnt be too big but displayed in a nice way to use it in a research article of the usual format. I will do some more experiments with the Sage options. – Mare Jan 10 '21 at 15:38
  • When I try to place the LaTeX code generated by your code into a document I run into errors because of the label. The strange labels like L=\hbox{$\text{\texttt{v1}}$} might be a result of creating a Digraph after QPA. Can you post your LaTeX code that runs the code snippet from latex(U)? – DJP Jan 10 '21 at 19:07
  • @DJP I just copied the output from the sage online cell I got when typing in the code. You have to use the following tikz packages to make it work: \usepackage{tikz} \usetikzlibrary{matrix,patterns,shapes,decorations.pathmorphing,decorations.pathreplacing,calc,arrows} \usepackage{tikz-cd} \usepackage{tkz-graph} – Mare Jan 10 '21 at 20:47
  • I get Undefined control sequence. \cmdGR@vertex@L ->\hbox {$\text {\texttt {v1}}$}. This will make it difficult for me to check. – DJP Jan 10 '21 at 21:12
  • @DJP Strange, for me it works without a problem with the above tikz packages. – Mare Jan 10 '21 at 21:13

1 Answers1

2

In your comment you mentioned using the graphics in a research article. That means working with Sage alone isn't good enough because journals are notoriously picky. Many don't want color and are specific about the font and fontsize you're using. LaTeX is the best tool. You can use Sage along with the sagetex package and tkz-graph and tkz-berge to do a lot of the difficult work for you. See Alain Matthes answer here for more on typesetting graphs. Here is some sample code using the preamble code mentioned in your comment above.

\documentclass[border={2mm 2mm 8mm 8mm}]{standalone}
\usepackage{sagetex,xcolor,tikz,tkz-graph,tkz-berge,tikz-cd}
\usetikzlibrary{matrix,patterns,shapes,decorations.pathmorphing,decorations.pathreplacing,calc,arrows}
\begin{document}
\begin{sagesilent}
def from_QPA(Q):
arrows = [(v.SourceOfPath(), v.TargetOfPath(), v) for v in Q.ArrowsOfQuiver() ]
elements = Q.VerticesOfQuiver()
return DiGraph([elements, arrows],loops=True,format='vertices_and_edges')

libgap.LoadPackage("QPA") Q = libgap.Quiver( ["v1","v2","v3","v4","v5","v6","v7","v8","v9","v10","v11","v12","v13","v14","v15"], [["v1","v3","a1"],["v2","v1","a2"],["v3","v8","a3"],["v4","v6","a4"],["v5","v6","a5"]
,["v6","v4","a6"],["v6","v5","a7"],["v6","v8","a8"],["v7","v12","a9"],["v8","v9","a10"],["v8","v10","a11"],["v9","v7","a12"],["v9","v11","a13"],["v10","v7","a14"],["v10","v11","
a15"],["v11","v12","a16"],["v12","v2","a17"],["v12","v13","a18"],["v13","v14","a19"], ["v13","v15","a20"],["v14","v13","a21"],["v15","v13","a22"]] ) U=from_QPA(Q) U.set_latex_options(graphic_size=(20,20), vertex_labels=True,edge_labels=True) Ustring = latex(U) \end{sagesilent} \sagestr{Ustring} \end{document}

The result running in Cocalc is: enter image description here

Notice that the picture shows that LaTeX is complaining of an error but a picture renders. You said you aren't getting errors; maybe a more current versions? Each time you Build the code you'll get a different drawing of the graph so you will want to capture the look in order for you to handle the almost certain revisions they will want you to make. When you find a picture which is close to your satisfaction, take the code from your .sout file: enter image description here Now you can copy this code (I have copied and modified code from a different Build) to get something like this:

\documentclass[11pt,border={10pt 10pt 10pt 10pt}]{standalone}
\usepackage{sagetex,xcolor,tikz,tkz-graph,tkz-berge,tikz-cd}
\usetikzlibrary{matrix,patterns,shapes,decorations.pathmorphing,decorations.pathreplacing,calc,arrows}
\begin{document}
\begin{sagesilent}
a = 3.75
b = 3.75
output = r"\begin{tikzpicture}"
output += r"\Vertex[style={minimum size=1.0cm,shape=circle},LabelOut=false,L=\hbox{$v_0$},x=%s cm,y=%s cm]{v0}"%(3.2737*a,0.5293*b)
output += r"\Vertex[style={minimum size=1.0cm,shape=circle},LabelOut=false,L=\hbox{$v_1$},x=%s cm,y= %s cm]{v1}"%(3.5269*a,1.7219*b)
output += r"\Vertex[style={minimum size=1.0cm,shape=circle},LabelOut=false,L=\hbox{$v_2$},x= %s cm,y=%s cm]{v2}"%(2.4491*a,0.527*b)
output += r"\Vertex[style={minimum size=1.0cm,shape=circle},LabelOut=false,L=\hbox{$v_3$},x=%s cm,y=%s cm]{v3}"%(0.0*a,0.9498*b)
output += r"\Vertex[style={minimum size=1.0cm,shape=circle},LabelOut=false,L=\hbox{$v_4$},x=%s cm,y=%s cm]{v4}"%(0.4106*a,0.0*b)
output += r"\Vertex[style={minimum size=1.0cm,shape=circle},LabelOut=false,L=\hbox{$v_5$},x=%s cm,y=%s cm]{v5}"%(0.8179*a,0.8914*b)
output += r"\Vertex[style={minimum size=1.0cm,shape=circle},LabelOut=false,L=\hbox{$v_6$},x=%s cm,y=%s cm]{v6}"%(2.3603*a,3.4245*b)
output += r"\Vertex[style={minimum size=1.0cm,shape=circle},LabelOut=false,L=\hbox{$v_7$},x=%s cm,y=%s cm]{v7}"%(1.7828*a,1.4959*b)
output += r"\Vertex[style={minimum size=1.0cm,shape=circle},LabelOut=false,L=\hbox{$v_8$},x=%s cm,y=%s cm]{v8}"%(1.7707*a,2.778*b)
output += r"\Vertex[style={minimum size=1.0cm,shape=circle},LabelOut=false,L=\hbox{$v_9$},x=%s cm,y=%s cm]{v9}"%(2.1004*a,2.4636*b)
output += r"\Vertex[style={minimum size=1.0cm,shape=circle},LabelOut=false,L=\hbox{$v_{10}$},x=%s cm,y=%s cm]{v10}"%(2.5107*a,2.9341*b)
output += r"\Vertex[style={minimum size=1.0cm,shape=circle},LabelOut=false,L=\hbox{$v_{11}$},x=%s cm,y=%s cm]{v11}"%(3.2906*a,3.092*b)
output += r"\Vertex[style={minimum size=1.0cm,shape=circle},LabelOut=false,L=\hbox{$v_{12}$},x=%s cm,y=%s cm]{v12}"%(4.2021*a,4.0255*b)
output += r"\Vertex[style={minimum size=1.0cm,shape=circle},LabelOut=false,L=\hbox{$v_{13}$},x=%s cm,y=%s cm]{v13}"%(4.485*a,5.0*b)
output += r"\Vertex[style={minimum size=1.0cm,shape=circle},LabelOut=false,L=\hbox{$v_{14}$},x=%s cm,y=%s cm]{v14}"%(5.0*a,4.1315*b)
output += r"\Edge[lw=0.1cm,style={post, bend right,},](v0)(v2)"
output += r"\Edge[lw=0.1cm,style={post, bend right,},](v1)(v0)"
output += r"\Edge[lw=0.1cm,style={post, bend right,},](v2)(v7)"
output += r"\Edge[lw=0.1cm,style={post, bend right,},](v3)(v5)"
output += r"\Edge[lw=0.1cm,style={post, bend right,},](v4)(v5)"
output += r"\Edge[lw=0.1cm,style={post, bend right,},](v5)(v3)"
output += r"\Edge[lw=0.1cm,style={post, bend right,},](v5)(v4)"
output += r"\Edge[lw=0.1cm,style={post, straight,},label=$a_8$](v5)(v7)"
output += r"\Edge[lw=0.1cm,style={post, bend right,},](v6)(v11)"
output += r"\Edge[lw=0.1cm,style={post, bend right,},](v7)(v8)"
output += r"\Edge[lw=0.1cm,style={post, bend right,},](v7)(v9)"
output += r"\Edge[lw=0.1cm,style={post, straight,},](v8)(v6)"
output += r"\Edge[lw=0.1cm,style={post, bend right,},](v8)(v10)"
output += r"\Edge[lw=0.1cm,style={post, straight,},](v9)(v6)"
output += r"\Edge[lw=0.1cm,style={post, bend right,},](v9)(v10)"
output += r"\Edge[lw=0.1cm,style={post, bend right,},](v10)(v11)"
output += r"\Edge[lw=0.1cm,style={post, bend right},](v11)(v1)"
output += r"\Edge[lw=0.1cm,style={post, straight,},label=$a_{18}$](v11)(v12)"
output += r"\Edge[lw=0.1cm,style={post, bend right,},](v12)(v13)"
output += r"\Edge[lw=0.1cm,style={post, bend right,},](v12)(v14)"
output += r"\Edge[lw=0.1cm,style={post, bend right,},](v13)(v12)"
output += r"\Edge[lw=0.1cm,style={post, bend right,},](v14)(v12)"
output += r"\end{tikzpicture}"
\end{sagesilent}
\sagestr{output}
\end{document}

enter image description here

Placing the code of each line in raw strings; e.g., output = r"\begin{tikzpicture}" is going to allow you to fine tune the positioning with the help of the coordinates you liked and picking your own values of a and b. I've taken the positions from a picture that looked satisfactory to me and by adjusting, such as in 3.2737*a,0.5293*b I can stretch the graph to make the graph even better. You can modify vertices, remove labels and make your directed edges straight, if you want. For example, output += r"\Edge[lw=0.1cm,style={post, straight,},label=$a_{18}$](v11)(v12)" creates a straight directed edge with a label.

The answer to Question 1 is then: Use the packages tkz-berge, tkz-graph, and sagetex to create your picture. Sage will do the calculations but LaTeX will handle the picture. With respect to Question 2, I don't think there is a better way than what I'm suggesting because Sage is doing the calculations using the GAP-package QPA.

DJP
  • 12,451
  • Hello. I have just seen your nice answer to this question and wanted to try it out. The first few steps work...but I get an error message at a later point: – Bernhard Boehmler Jan 16 '21 at 20:09
  • sage: Q = libgap.Quiver( ["v1","v2","v3","v4","v5","v6","v7","v8","v9","v10", ....: "v11","v12","v13","v14","v15"], [["v1","v3","a1"],["v2","v1","a2"],["v3", ....: "v8","a3"],["v4","v6","a4"],["v5","v6","a5"]
    ....: ,["v6","v4","a6"],["v6","v5","a7"],["v6","v8","a8"],["v7","v12","a9"],["v8 ....: ","v9","a10"],["v8","v10","a11"],["v9","v7","a12"],["v9","v11","a13"],["v1 ....: 0","v7","a14"],["v10","v11","
    ....: a15"],["v11","v12","a16"],["v12","v2","a17"],["v12","v13","a18"],["v13","v ....: 14","a19"], ["v13","v15","a20"],["v14","v13","a21"],["v15","v13","a22"]] ....: )
    – Bernhard Boehmler Jan 16 '21 at 20:09
  • AttributeError Traceback (most recent call last) in ()

    – Bernhard Boehmler Jan 16 '21 at 20:10
  • ----> 1 Q = libgap.Quiver( ["v1","v2","v3","v4","v5","v6","v7","v8","v9","v10","v11","v12","v13","v14","v15"], [["v1","v3","a1"],["v2","v1","a2"],["v3","v8","a3"],["v4","v6","a4"],["v5","v6","a5"],["v6","v4","a6"],["v6","v5","a7"],["v6","v8","a8"],["v7","v12","a9"],["v8","v9","a10"],["v8","v10","a11"],["v9","v7","a12"],["v9","v11","a13"],["v10","v7","a14"],["v10","v11","a15"],["v11","v12","a16"],["v12","v2","a17"],["v12","v13","a18"],["v13","v14","a19"], ["v13","v15","a20"],["v14","v13","a21"],["v15","v13","a22"]] ) – Bernhard Boehmler Jan 16 '21 at 20:10
  • /home/boehmler/Schreibtisch/Drarbeit/SAGE/local/lib/python2.7/site-packages/sage/misc/lazy_import.pyx in sage.misc.lazy_import.LazyImport.getattr (build/cythonized/sage/misc/lazy_import.c:3536)() 320 True 321 """ --> 322 return getattr(self.get_object(), attr) 323 324 # We need to wrap all the slot methods, as they are not forwarded – Bernhard Boehmler Jan 16 '21 at 20:10
  • /home/boehmler/Schreibtisch/Drarbeit/SAGE/local/lib/python2.7/site-packages/sage/libs/gap/libgap.pyx in sage.libs.gap.libgap.Gap.getattr (build/cythonized/sage/libs/gap/libgap.c:6599)() 691 g = make_any_gap_element(self, gap_eval(name)) 692 else: --> 693 raise AttributeError(f'No such attribute: {name}.') 694 695 self.dict[name] = g

    AttributeError: No such attribute: Quiver. sage:

    – Bernhard Boehmler Jan 16 '21 at 20:10
  • By the way, I am using: SageMath version 8.6, Release Date: 2019-01-15 , Using Python 2.7.15. Type "help()" for help. – Bernhard Boehmler Jan 16 '21 at 20:13
  • I would be thankful for any help / hint. – Bernhard Boehmler Jan 16 '21 at 20:13
  • 1
    Your error message No such attribute: Quiver seems to be saying it can't do Q = libgap.Quiver( because it doesn't know what that means. I would suspect that might have something to do with an older version but that's only a guess. The easiest way to try out the code is with a free Cocalc account. All you need to do is create a LaTeX document, copy/paste the code above, save it, Build it and you're done. – DJP Jan 16 '21 at 23:11
  • Ok, this worked nicely, thanks! – Bernhard Boehmler Jan 16 '21 at 23:34