import copy
import dot2tex
from pylatex import Command, Document, Section, Subsection
from pylatex.utils import NoEscape, italic
from pyfeyn2.render.latex import LatexRender
from pyfeyn2.render.render import Render
[docs]map_feyn_to_tikz = {
"photon": "snake",
"gluon": "coil,aspect=0.3,segment length=1mm",
}
[docs]def feynman_adjust_points(feyndiag, size=5):
# deepcopy
fd = copy.deepcopy(feyndiag)
norm = size
dot = feynman_to_dot(fd)
positions = dot_to_positions(dot)
max = 0
for i, p in positions.items():
if p[0] > max:
max = p[0]
if p[1] > max:
max = p[1]
for v in fd.vertices:
if v.id in positions:
v.x = positions[v.id][0] / max * norm
v.y = positions[v.id][1] / max * norm
for l in fd.legs:
l.x = positions[l.id][0] / max * norm
l.y = positions[l.id][1] / max * norm
return fd
[docs]def dot_to_positions(dot):
return dot2tex.dot2tex(dot, format="positions")
[docs]def dot_to_tikz(dot):
return dot2tex.dot2tex(dot, format="tikz", figonly=True)
[docs]def feynman_to_dot(fd):
# TODO better use pydot? still alive?
# TODO style pick neato or dot or whatever
src = "graph G {\n"
src += "rankdir=LR;\n"
src += "layout=neato;\n"
# src += "mode=hier;\n"
src += 'node [style="invis"];\n'
for l in fd.legs:
if l.x is not None and l.y is not None:
src += f'\t\t{l.id} [ pos="{l.x},{l.y}!"];\n'
for p in fd.propagators:
src += 'edge [style="decorate,decoration={}"];\n'.format(
map_feyn_to_tikz[p.type]
)
src += f"\t\t{p.source} -- {p.target};\n"
rank_in = "{rank=min; "
rank_out = "{rank=max; "
for l in fd.legs:
if l.sense == "incoming":
src += 'edge [style="decorate,decoration={}"];\n'.format(
map_feyn_to_tikz[p.type]
)
src += f"\t\t{l.id} -- {l.target};\n"
rank_in += f"{l.id} "
elif l.sense == "outgoing":
src += 'edge [style="decorate,decoration={}"];\n'.format(
map_feyn_to_tikz[p.type]
)
src += f"\t\t{l.target} -- {l.id};\n"
rank_out += f"{l.id} ;"
else:
# TODO maybe not error but just use the default
raise Exception("Unknown sense")
src += rank_in + "}\n"
src += rank_out + "}\n"
src += "}"
return src
[docs]class DotRender(LatexRender):
def __init__(
self,
fd,
documentclass="standalone",
document_options=["preview", "crop", "tikz"],
*args,
**kwargs,
):
super().__init__(
*args,
fd=fd,
documentclass=documentclass,
document_options=document_options,
**kwargs,
)
# super(Render,self).__init__(*args, fd=fd,**kwargs)
self.preamble.append(Command("usepackage", NoEscape("tikz")))
self.preamble.append(
Command("usetikzlibrary", NoEscape("snakes,arrows,shapes"))
)
self.preamble.append(Command("usepackage", NoEscape("amsmath")))
self.src_dot = feynman_to_dot(fd)
self.set_src_diag(dot_to_tikz(self.src_dot))
[docs] def get_src_dot(self):
return self.src_dot