Belle II Software  release-08-01-10
b2latex.py
1 #!/usr/bin/env python3
2 
3 
10 
11 import subprocess
12 
13 
15  """
16  Common base class of all Latex Wrapper objects
17  """
18 
19  def __init__(self):
20  """
21  Constructor, initialize output with empty string
22  """
23 
24  self.outputoutput = ''
25 
26  def __str__(self):
27  """
28  Transform object to string, in this case, just returns .the generated latex-code
29  """
30  return self.outputoutput
31 
32  def add(self):
33  """
34  Add latex-code to the output string.
35  This method is usually overriden in the subclasses
36  """
37  return self
38 
39  def finish(self):
40  """
41  Finishes the generation of latex-code.
42  E.g. adds end latex-commands
43  This method is usually overriden in the subclasses
44  """
45  return self
46 
47  def save(self, filename, compile=False):
48  """
49  Saves the latex-code into a file, adds preamble and end of document,
50  and compiles the code if requested.
51  @param filename latex-code is stored in this file, should end on .tex
52  @param compile compile the .tex file using pdflatex into a .pdf file
53  """
54  output = r"""
55  \documentclass[10pt,a4paper]{article}
56  \usepackage[latin1]{inputenc}
57  \usepackage[T1]{fontenc}
58  \usepackage{amsmath}
59  \usepackage{amsfonts}
60  \usepackage{amssymb}
61  \usepackage{graphicx}
62  \usepackage{caption}
63  \usepackage{lmodern}
64  \usepackage{placeins}
65  \usepackage{multicol}
66  \usepackage{tikz}
67  \usetikzlibrary{shapes.arrows,chains, positioning}
68  \usepackage{booktabs} %professional tables
69  \usepackage[left=2cm,right=2cm,top=2cm,bottom=2cm]{geometry}
70  \usepackage{microtype} %optimises spacing, needs to go after fonts
71  \usepackage{hyperref} %adds links (also in TOC), should be loaded at the very end
72  \usepackage{longtable}
73  \usepackage{color}
74  \usepackage{listings}
75 
76  \definecolor{gray}{rgb}{0.4,0.4,0.4}
77  \definecolor{darkblue}{rgb}{0.0,0.0,0.6}
78  \definecolor{cyan}{rgb}{0.0,0.6,0.6}
79 
80  \lstset{
81  basicstyle=\ttfamily\scriptsize,
82  columns=fullflexible,
83  showstringspaces=false,
84  commentstyle=\color{gray}\upshape
85  }
86 
87  \lstdefinelanguage{XML}
88  {
89  morestring=[b]",
90  morestring=[s]{>}{<},
91  morecomment=[s]{<?}{?>},
92  stringstyle=\color{black},
93  identifierstyle=\color{darkblue},
94  keywordstyle=\color{cyan},
95  morekeywords={xmlns,version,type}% list your attributes here
96  }
97 
98  \usepackage[load-configurations=abbreviations]{siunitx}
99  \makeatletter
100  % In newer versions of latex there is a problem with the calc package and tikz
101  % http://tex.stackexchange.com/questions/289551/how-to-resolve-conflict-between-versions-of-texlive-and-pgf
102  \def\pgfmathparse@#1{%
103  % Stuff for calc compatiability.
104  \let\real=\pgfmath@calc@real
105  \let\minof=\pgfmath@calc@minof
106  \let\maxof=\pgfmath@calc@maxof
107  \let\ratio=\pgfmath@calc@ratio
108  \let\widthof=\pgfmath@calc@widthof
109  \let\heightof=\pgfmath@calc@heightof
110  \let\depthof=\pgfmath@calc@depthof
111  % No (math) units yet.
112  \global\pgfmathunitsdeclaredfalse
113  \global\pgfmathmathunitsdeclaredfalse
114  % Expand expression so any reamining CSs are registers
115  % or box dimensions (i.e. |\wd|, |\ht|, |\dp|).
116  \edef\pgfmath@expression{#1}%
117  %
118  \expandafter\pgfmathparse@trynumber@loop\pgfmath@expression\pgfmath@parse@stop
119  %
120  % this here is the _real_ parser. it is invoked by
121  % \pgfmathparse@trynumber@loop if that says "this is no number"
122  %\pgfmathparse@@\pgfmath@parse@stop%
123  }
124  \makeatother
125  \begin{document}
126  """
127  output += self.outputoutput
128  output += r"\end{document}"
129 
130  with open(filename, 'w') as f:
131  f.write(output)
132  if compile:
133  for i in range(0, 2):
134  ret = subprocess.call(['pdflatex', '-halt-on-error', '-interaction=nonstopmode', filename])
135  if ret != 0:
136  raise RuntimeError("pdflatex failed to create FEI summary PDF, please check.")
137  return self
138 
139 
141  """
142  Convinience class implementing += operator, can be used instead of raw LatexObject to collect
143  all the latex code in your project which should go into a common file.
144  """
145 
146  def add(self, text=''):
147  """
148  Adds an object to the output
149  @param text string or object with implicit string conversion (like LatexObject)
150  """
151  self.outputoutput += str(text)
152  return self
153 
154  def __iadd__(self, text):
155  """
156  Adds an object to the output
157  @param text string or object with implicit string conversion (like LatexObject)
158  """
159  self.addaddadd(text)
160  return self
161 
162 
164  """
165  Used for wrapping conventionel text into latex-code.
166  Has to possibility to handle python-style format-placeholders
167  """
168 
169  def __init__(self, text=''):
170  """
171  Calls super-class initialize and adds initial text to output
172  @param text intial text, usually you want to give a raw string r"some text"
173  """
174  super().__init__()
175 
176  self.outputoutputoutput += str(text)
177 
178  def add(self, text=''):
179  """
180  Adds an object to the output, can contain python-placeholders
181  @param text string or object with implicit string conversion (like LatexObject)
182  """
183  self.outputoutputoutput += str(text)
184  return self
185 
186  def finish(self, **kwargs):
187  """
188  Finish the generation of the string by replacing possible placehholders with the given dictionary
189  @param kwargs dictionary used to replace placeholders
190  """
191 
192  self.outputoutputoutput = self.outputoutputoutput.format(**kwargs) + '\n'
193  return self
194 
195 
197  """
198  Used for wrapping code in a listing environment
199  """
200 
201  def __init__(self, language='XML'):
202  """
203  Calls super-class initialize and adds initial text to output
204  @param text intial text, usually you want to give a raw string r"some text"
205  """
206  super().__init__()
207 
208  self.outputoutput += r'\lstset{language=' + language + '}\n'
209  self.outputoutput += r'\begin{lstlisting}[breaklines=true]' + '\n'
210 
211  def add(self, text=''):
212  """
213  Adds code to the output
214  @param code which is wrapped in the listing environment
215  """
216  self.outputoutput += str(text)
217  return self
218 
219  def finish(self, **kwargs):
220  """
221  Finish the generation of the lsiting environment
222  """
223 
224  self.outputoutput += r'\end{lstlisting}'
225  return self
226 
227 
229  """
230  Defines the colourlist latex-command, which draws a bargraph with relative
231  fractions indicated by colours using tikz.
232  After including this object in you latex code the command \\bargraph is available.
233  You should include only one of these objects in your latex code.
234  """
235 
236 
237  colours = ["red", "green", "blue", "orange", "cyan", "purple"]
238 
239  def __init__(self):
240  """
241  Calls super-class init, adds definition of colourlist to latex code.
242  """
243  super().__init__()
244  self.outputoutput += r"\def\colourlist{{" + ', '.join('"%s"' % (c) for c in self.colourscolours) + r"}}" + '\n'
245  self.outputoutput += r"""
246  \tikzset{nodeStyle/.style={text height=\heightof{A},text depth=\depthof{g}, inner sep = 0pt, node distance = -0.15mm}}
247  \newcount\colourindex \colourindex=-1
248  \newcommand{\plotbar}[1]{
249  \begin{tikzpicture}[start chain=going right, nodes = {font=\sffamily}]
250  \global\colourindex=-1
251  \foreach \percent/\name in {
252  #1
253  } {
254  \ifx\percent\empty\else % If \percent is empty, do nothing
255  \global\advance\colourindex by 1
256  \ifnum"""
257  self.outputoutput += str(len(self.colourscolours) - 1)
258  self.outputoutput += r"""5<\colourindex %back to first colour if we run out
259  \global\colourindex=0
260  \fi
261  \pgfmathparse{\colourlist[\the\colourindex]} % Get color from cycle list
262  \edef\color{\pgfmathresult} % and store as \color
263  \node[nodeStyle, draw, on chain, fill={\color!40}, minimum width=\percent*1.0, minimum height=12] {\name};
264  \fi
265  };
266  \end{tikzpicture}
267  }
268  """
269 
270 
272  """
273  Adds a new section to your latex code with some additional commands
274  to force a pagebreak and add a barrier for figure objects.
275  """
276 
277  def __init__(self, name):
278  """
279  Calls super-class init and adds necessary latex commands to output.
280  """
281  super().__init__()
282  self.outputoutput += r"\raggedbottom" + '\n'
283  self.outputoutput += r"\pagebreak[0]" + '\n'
284  self.outputoutput += r"\FloatBarrier" + '\n'
285  self.outputoutput += r"\section{" + str(name) + r"}" + '\n'
286 
287 
289  """
290  Adds a new subsection to your latex code.
291  """
292 
293  def __init__(self, name):
294  """
295  Calls super-class init and adds necessary latex commands to output.
296  """
297  super().__init__()
298  self.outputoutput += r"\subsection{" + str(name) + r"}" + '\n'
299 
300 
302  """
303  Adds a new subsubsection to your latex code.
304  """
305 
306  def __init__(self, name):
307  """
308  Calls super-class init and adds necessary latex commands to output.
309  """
310  super().__init__()
311  self.outputoutput += r"\subsubsection{" + str(name) + r"}" + '\n'
312 
313 
315  """
316  Includes a series of image files into your latex code and centers them.
317  """
318 
319  def __init__(self):
320  """
321  Calls super-class init and begins centered environment.
322  """
323  super().__init__()
324  self.outputoutput += r"\begin{center}" + '\n'
325 
326  def add(self, filename, width=0.7):
327  """
328  Include a image file.
329  @param filename containing the image
330  @param width texwidth argument of includegraphics
331  """
332  self.outputoutput += r"\includegraphics[width=" + str(width) + r"\textwidth]"
333  self.outputoutput += r"{" + str(filename) + r"}" + '\n'
334  return self
335 
336  def finish(self):
337  """
338  Ends centered environment
339  """
340  self.outputoutput += r"\end{center}" + '\n'
341  return self
342 
343 
345  """
346  Creates a itemized list in latex.
347  """
348 
349  def __init__(self):
350  """
351  Calls super-class init and begins itemize
352  """
353  super().__init__()
354 
355  self.amountamount = 0
356  self.outputoutput += r"\begin{itemize}"
357 
358  def add(self, item):
359  """
360  Adds another item.
361  @param item string or object with implicit string conversion used as item
362  """
363  self.amountamount += 1
364  self.outputoutput += r"\item " + str(item) + '\n'
365  return self
366 
367  def finish(self):
368  """
369  Finishes the generation of latex-code.
370  """
371  if self.amountamount == 0:
372  return ''
373  self.outputoutput += r"\end{itemize}"
374  return self
375 
376 
378  """
379  Creates a longtable in latex. A longtable can span multiple pages
380  and is automatically wrapped.
381  """
382 
383  def __init__(self, columnspecs, caption, format_string, head):
384  """
385  Calls super-class init, begins centered environment and longtable environment.
386  Defines caption and head of the table.
387  @param columnspecs of the longtable, something like:
388  rclp{7cm} 4 columns, right-center-left aligned and one paragraph column with a width of 7cm
389  @param caption string or object with implicit string conversion used as caption.
390  @param format_string python-style format-string used to generate a new row out of a given dictionary.
391  @param head of the table
392  """
393  super().__init__()
394  self.outputoutput += r"\begin{center}" + '\n'
395  self.outputoutput += r"\begin{longtable}{" + str(columnspecs) + r"}" + '\n'
396  self.outputoutput += r"\caption{" + str(caption) + r"}\\" + '\n'
397  self.outputoutput += r"\toprule" + '\n'
398  self.outputoutput += head + r"\\" + '\n'
399  self.outputoutput += r"\midrule" + '\n'
400 
401  self.format_stringformat_string = format_string
402 
403  def add(self, *args, **kwargs):
404  """
405  Add a new row to the longtable by generating the row using the format_string given in init
406  and the provided dictionary.
407  @param args positional arguments used to generate the row using the python-style format string.
408  @param kwargs dictionary used to generate the row using the python-style format-string.
409  """
410  self.outputoutput += self.format_stringformat_string.format(*args, **kwargs) + r"\\" + '\n'
411  return self
412 
413  def finish(self, tail=''):
414  """
415  Adds optional tail of the table, ends longtable and centered environment.
416  @param tail optional tail, like head but at the bottom of the table.
417  """
418  self.outputoutput += r"\bottomrule" + '\n'
419  if str(tail) != '':
420  self.outputoutput += str(tail) + r"\\" + '\n'
421  self.outputoutput += r"\bottomrule" + '\n'
422  self.outputoutput += r"\end{longtable}" + '\n'
423  self.outputoutput += r"\end{center}" + '\n'
424  return self
425 
426 
428  """
429  Creates a latex title-page and optionally abstract and table-of-contents.
430  You should include only one of these objects in your latex code.
431  """
432 
433  def __init__(self, title, authors, abstract, add_table_of_contents=True, clearpage=True):
434  """
435  Sets author, date, title property, calls maketitle, optionalla adds abstract and table-of-contents.
436  @param title of the latex file.
437  @param authors of the latex file, so the person who write the corresponding python-code with this framework :-)
438  @param abstract optional abstract placed on the title-page.
439  @param add_table_of_contents bool indicating of table-of-contents should be included.
440  """
441  super().__init__()
442  self.outputoutput += r"\author{"
443  for author in authors:
444  self.outputoutput += author + r"\\"
445  self.outputoutput += r"}" + '\n'
446  self.outputoutput += r"\date{\today}" + '\n'
447  self.outputoutput += r"\title{" + title + r"}" + '\n'
448  self.outputoutput += r"\maketitle" + '\n'
449  if abstract:
450  self.outputoutput += r"\begin{abstract}" + '\n'
451  self.outputoutput += abstract
452  self.outputoutput += '\n' + r'\end{abstract}' + '\n'
453 
454  if clearpage:
455  self.outputoutput += r"\clearpage" + '\n'
456  if add_table_of_contents:
457  self.outputoutput += r"\tableofcontents" + '\n'
458  self.outputoutput += r"\FloatBarrier" + '\n'
459  if clearpage:
460  self.outputoutput += r"\clearpage" + '\n'
461 
462 
463 if __name__ == '__main__':
464  import random
465 
466  o = LatexFile()
467  o += TitlePage(title='Automatic Latex Code Example',
468  authors=['Thomas Keck'],
469  abstract='This is an example for automatic latex code generation in basf2.',
470  add_table_of_contents=True).finish()
471 
472  o += Section("LongTable").finish()
473  o += String(r"In the following subsection there's:")
474  o += Itemize().add("a really long table").add("a coloured table").add("nothing else").finish()
475  o += SubSection("A really long table")
476 
477  table = LongTable(r"lr", "A long table", "{name} & {value:.2f}", r"Name & Value in $\mathrm{cm}$")
478  for i in range(60):
479  table.add(name='test' + str(i), value=random.gauss(0.0, 1.0))
480  o += table.finish()
481 
482  o += SubSection("A table with color and tail")
483  colour_list = DefineColourList()
484  o += colour_list.finish()
485 
486  table = LongTable(columnspecs=r"lcrrr",
487  caption="A coloured table for " +
488  ', '.join((f'\\textcolor{{{c}}}{{{m}}}' for c, m in zip(colour_list.colours[:3], "RGB"))),
489  format_string="{name} & {bargraph} & {r:.2f} & {g:.2f} & {b:.2f}",
490  head=r"Name & Relative fractions & R - Value & G - Value & B - Value")
491  sr = sg = sb = 0
492  for i in range(10):
493  r = random.uniform(0.1, 0.9)
494  g = random.uniform(0.1, 0.9)
495  b = random.uniform(0.1, 0.9)
496  n = (r + g + b) / 100.0
497  sr += r
498  sg += g
499  sb += b
500  table.add(name='test' + str(i), bargraph=r'\plotbar{{ {:g}/, {:g}/, {:g}/,}}'.format(r / n, g / n, b / n), r=r, g=g, b=b)
501  n = (sr + sg + sb) / 100.0
502  o += table.finish(tail=r"Total & \plotbar{{ {:g}/, {:g}/, {:g}/,}} & {:g} & {:g} & {:g}".format(sr /
503  n, sg / n, sb / n, sr, sg, sb))
504 
505  o += Section("Graphic section")
506  graphics = Graphics()
507  images = subprocess.check_output("locate .png", shell=True).split('\n')[:-1]
508  for i in range(4):
509  image = random.choice(images)
510  graphics.add(image, width=0.49)
511  o += graphics.finish()
512 
513  from B2Tools import format
514  o += Section("Format section e.g. " + format.decayDescriptor("B+ ==> mu+ nu gamma"))
515  o += r"Some important channels in B physics"
516  items = Itemize()
517  items.add(format.decayDescriptor("B+ ==> mu+ nu gamma"))
518  items.add(format.decayDescriptor("B0 ==> J/Psi K_S0"))
519  items.add(format.decayDescriptor("B+ ==> tau+ nu"))
520  o += items.finish()
521 
522  o += r"Use format.variable to add hyphenations to long variable names, so latex can do line breaks "
523  o += format.variable("daughterProductOf(extraInfo(SignalProbability))")
524  o += r" . Use format.string for stuff that contains special latex characters like " + format.string(r"_ ^ \ ")
525  o += r" . Use format.duration for durations " + format.duration(20000) + " " + format.duration(0.00010)
526 
527  o.finish()
528  o.save("test.tex", compile=True)
list colours
6 default colours used for the bargraph
Definition: b2latex.py:237
def add(self, filename, width=0.7)
Definition: b2latex.py:326
def add(self, item)
Definition: b2latex.py:358
amount
number of items
Definition: b2latex.py:355
def add(self, text='')
Definition: b2latex.py:146
def __iadd__(self, text)
Definition: b2latex.py:154
output
Stores the outputted latex-code.
Definition: b2latex.py:24
def save(self, filename, compile=False)
Definition: b2latex.py:47
def add(self, text='')
Definition: b2latex.py:211
def finish(self, **kwargs)
Definition: b2latex.py:219
def __init__(self, language='XML')
Definition: b2latex.py:201
def __init__(self, columnspecs, caption, format_string, head)
Definition: b2latex.py:383
def add(self, *args, **kwargs)
Definition: b2latex.py:403
def finish(self, tail='')
Definition: b2latex.py:413
format_string
python-style format-string used to generate a new row out of a given dictionary.
Definition: b2latex.py:401
def __init__(self, name)
Definition: b2latex.py:277
def add(self, text='')
Definition: b2latex.py:178
def finish(self, **kwargs)
Definition: b2latex.py:186
def __init__(self, text='')
Definition: b2latex.py:169
output
output string
Definition: b2latex.py:192
def __init__(self, name)
Definition: b2latex.py:293
def __init__(self, name)
Definition: b2latex.py:306
def __init__(self, title, authors, abstract, add_table_of_contents=True, clearpage=True)
Definition: b2latex.py:433