] [-i] [-u] [-a]
51 | ipnb2tex.py (-h | --help)
52 |
53 | The ipnb2tex.py reads the IPython notebook and converts
54 | it to a \LaTeX{} set of files: a *.tex file and a number of images.
55 |
56 | Arguments:
57 | ipnbfilename [optional] is the name of the input Jupyter notebook file.
58 | If no input filename is supplied, all .ipynb files in current directory
59 | will be processed. In this event the output filenames will be the same
60 | as the .ipynb files, just with a tex filetype
61 |
62 | outfilename [optional] is the name of output LaTeX file. If none is
63 | given the output filename will be the same as the input file, but with
64 | the .tex extension.
65 |
66 | imagedir [optional] is the directory where images are written to.
67 | If not given, this image directory will be the ./pic directory.
68 |
69 | Options:
70 |
71 | -h, --help [optional] help information.
72 | -u [optional] add \\url{} to the bibtex entries.
73 | -i [optional], the lower case letter i, if this option is given the code
74 | listings are printed inline with the body text where they occur,
75 | otherwise listings are floated to the end of the document.
76 | -a [optional] append other bibtex entries to this one
77 |
78 | """
79 |
80 | standardHeader =\
81 | r"""
82 | \documentclass[english]{report}
83 |
84 | \usepackage{ragged2e}
85 | \usepackage{listings}
86 | \usepackage{color}
87 | \usepackage{graphicx}
88 | \usepackage{textcomp} % additional fonts, required for upquote in listings and \textmu
89 | \usepackage{placeins} % FloatBarrier
90 | \usepackage{url} % for websites
91 | \usepackage[detect-weight,detect-all=true]{siunitx} % nice! SI units and print numbers
92 | \usepackage{afterpage} % afterpage{\clearpage}
93 | \usepackage{gensymb} % get the degree symbol as in \celcius
94 | \usepackage{amsmath}
95 | \usepackage[printonlyused]{acronym}
96 | \usepackage{lastpage}
97 | \usepackage[Export]{adjustbox}
98 | \adjustboxset{max size={\textwidth}{0.7\textheight}}
99 |
100 | %the following is required for carriage return symbol
101 | %ftp://ftp.botik.ru/rented/znamensk/CTAN/fonts/mathabx/texinputs/mathabx.dcl
102 | %https://secure.kitserve.org.uk/content/mathabx-font-symbol-redefinition-clash-latex
103 | \DeclareFontFamily{U}{mathb}{\hyphenchar\font45}
104 | \DeclareFontShape{U}{mathb}{m}{n}{
105 | <5> <6> <7> <8> <9> <10> gen * mathb
106 | <10.95> mathb10 <12> <14.4> <17.28> <20.74> <24.88> mathb12
107 | }{}
108 | \DeclareSymbolFont{mathb}{U}{mathb}{m}{n}
109 | \DeclareMathSymbol{\dlsh}{3}{mathb}{"EA}
110 |
111 | \usepackage[T1]{fontenc}
112 |
113 | \definecolor{LightGrey}{rgb}{0.95,0.95,0.95}
114 | \definecolor{LightRed}{rgb}{1.0,0.9,0.9}
115 |
116 | \lstset{ %
117 | upquote=true, % gives the upquote instead of the curly quote
118 | basicstyle=\ttfamily\footnotesize, % the size of the fonts that are used for the code
119 | numbers=none, % where to put the line-numbers
120 | showspaces=false, % show spaces adding particular underscores
121 | showstringspaces=false, % underline spaces within strings
122 | showtabs=false, % show tabs within strings adding particular underscores
123 | frame=lines, % adds a frame around the code
124 | tabsize=4, % sets default tabsize to 2 spaces
125 | captionpos=b, % sets the caption-position to bottom
126 | framesep=1pt,
127 | xleftmargin=0pt,
128 | xrightmargin=0pt,
129 | captionpos=t, % sets the caption-position to top
130 | %deletekeywords={...}, % if you want to delete keywords from the given language
131 | %escapeinside={\%*}{*)}, % if you want to add LaTeX within your code
132 | %escapeinside={\%}{)}, % if you want to add a comment within your code
133 | breaklines=true, % sets automatic line breaking
134 | breakatwhitespace=false, % sets if automatic breaks should only happen at whitespace
135 | prebreak=\raisebox{0ex}[0ex][0ex]{$\dlsh$} % add linebreak symbol
136 | }
137 |
138 | \lstdefinestyle{incellstyle}{
139 | backgroundcolor=\color{LightGrey}, % choose the background color, add \usepackage{color}
140 | language=Python,
141 | }
142 |
143 | \lstdefinestyle{outcellstyle}{
144 | backgroundcolor=\color{LightRed}, % choose the background color; you must add \usepackage{color} or \usepackage{xcolor}
145 | }
146 |
147 | \usepackage[a4paper, margin=0.75in]{geometry}
148 | \newlength{\textwidthm}
149 | \setlength{\textwidthm}{\textwidth}
150 |
151 |
152 | % this is entered just before the end{document}
153 | \newcommand{\atendofdoc}{
154 | \bibliographystyle{IEEEtran}
155 | \bibliography{bibliography}
156 | }
157 |
158 | %and finally the document begin.
159 | \begin{document}
160 | \author{Author}
161 | \title{Title}
162 | \date{\today}
163 | \maketitle
164 | """
165 |
166 |
167 | # ################################################################################
168 | # #lists the files in a directory and subdirectories (from Python Cookbook)
169 | # def listFiles(root, patterns='*', recurse=1, return_folders=0):
170 | # """lists the files in a directory and subdirectories (from Python Cookbook)
171 |
172 | # Extensively reworked for Python 3.
173 | # """
174 | # # Expand patterns from semicolon-separated string to list
175 | # pattern_list = patterns.split(';')
176 | # filenames = []
177 | # filertn = []
178 |
179 | # for dirpath,dirnames,files in os.walk(root):
180 | # if dirpath==root or recurse:
181 | # for filen in files:
182 | # filenames.append(os.path.abspath(os.path.join(os.getcwd(),dirpath,filen)))
183 | # if return_folders:
184 | # for dirn in dirnames:
185 | # filenames.append(os.path.abspath(os.path.join(os.getcwd(),dirpath,dirn)))
186 | # for name in filenames:
187 | # if return_folders or os.path.isfile(name):
188 | # for pattern in pattern_list:
189 | # if fnmatch.fnmatch(name, pattern):
190 | # filertn.append(name)
191 | # break
192 |
193 | # return filertn
194 |
195 |
196 |
197 | ################################################################################
198 | def latexEscapeCaption(string):
199 |
200 | # https://stackoverflow.com/questions/18360976/match-latex-reserved-characters-with-regex
201 | # string = re.sub(r'((?', '|', '=']:
216 | string = string.replace(mathcar, '$'+mathcar+'$')
217 | #replace computer-style float with scientific notation
218 | matches = re.search(r'^([0-9,.,\-]+)e(\+|\-)([0-9]+)$', string.strip())
219 | if matches:
220 | lead, sign, pw = matches.groups()
221 | sign = sign.replace('+', '')
222 | # string = string.replace(matches.group(), lead + r'\times 10^{' + sign + pw.strip('0') + '}')
223 | string = string.replace(matches.group(), '$'+lead + r'\times 10^{' + sign + pw.strip('0') + '}'+'$')
224 | return string
225 |
226 |
227 | ################################################################################
228 | def pptree(e):
229 | print(ET.tostring(e, pretty_print=True))
230 | print()
231 |
232 | ################################################################################
233 | def convertHtmlTable(html, cell):
234 |
235 | global table_index
236 |
237 | # print()
238 | if not (isinstance(html, str)):
239 | html = lxml.html.tostring(html)
240 |
241 | if not b"" + html + b"
"
243 |
244 | html = html.replace(b"", b"").replace(b"", b"").replace(b"", b"").replace(b"", b"")
245 | # html = html.replace('overflow:auto;','').replace(' style="max-height:1000px;max-width:1500px;','')
246 | tree = lxml.html.fromstring(html)
247 |
248 | # print('pptree-html')
249 | # pptree(tree)
250 |
251 |
252 | # for tags in tree.getiterator():
253 | # print(tags.tag, tags.text)
254 |
255 |
256 | rtnString = ''
257 | for table in tree.findall("table"):
258 |
259 | # first lets traverse it and look for rowspan/colspans, find the shape
260 | row_counts = len(table.findall('tr'))
261 | col_counts = [0] * row_counts
262 | for ind, row in enumerate(table.findall('tr')):
263 | for tag in row:
264 | if not (tag.tag == 'td' or tag.tag == 'th'): continue
265 | if 'colspan' in tag.attrib:
266 | col_counts[ind] += int(tag.attrib['colspan']) - 1
267 | if 'rowspan' in tag.attrib:
268 | for j in range(int(tag.attrib['rowspan'])):
269 | col_counts[ind+j] += 1
270 | else:
271 | col_counts[ind] += 1
272 | if len(set(col_counts)) != 1:
273 | raise ValueError('inconsistent number of column counts')
274 | col_counts = col_counts[0]
275 |
276 | # print(row_counts, col_counts)
277 |
278 | if row_counts == 0 or col_counts == 0:
279 | continue
280 |
281 | #first determine arrays of colspan and row span
282 | # these arrays have nonzero values in spanned cell, no data here
283 | rowspan = np.zeros((row_counts, col_counts), dtype=np.int64)
284 | colspan = np.zeros((row_counts, col_counts), dtype=np.int64)
285 | irow = 0
286 | for row in table.findall('tr'):
287 | icol = 0
288 | for col in row:
289 | if col.tag != 'td' and col.tag != 'th':
290 | raise NotImplementedError('Expecting either TD or TH tag under row')
291 | if rowspan[irow,icol] != 0:
292 | colspan[irow,icol] = 0
293 | icol += 1
294 | colspan[irow,icol] = 0
295 | icol += 1
296 | if 'colspan' in col.attrib:
297 | icolspan = int(col.attrib['colspan'])
298 |
299 | for i in range(1,icolspan):
300 | colspan[irow,icol] = 1
301 | icol += 1
302 | if 'rowspan' in col.attrib:
303 | rowspan[irow,icol-1] = 0
304 | for i in range(1, int(col.attrib['rowspan'])):
305 | rowspan[irow+i,icol-1] = int(col.attrib['rowspan'])-i
306 | irow += 1
307 |
308 | # print('colspan=\n{}\n'.format(colspan))
309 | # print('rowspan=\n{}\n'.format(rowspan))
310 |
311 | formatStr = getMetaData(cell, table_index, 'tableCaption', 'format','')
312 | if not formatStr:
313 | formatStr = '|' + "|".join(['c'] * col_counts) + '|'
314 |
315 |
316 | terminator = '&'
317 | latexTabular = ""
318 | latexTabular += "\n\\begin{{tabular}}{{{}}}\n".format(formatStr)
319 | latexTabular += "\\hline\n"
320 | irow = 0
321 | for row_index, row in enumerate(table.findall('tr')):
322 | icol = 0
323 | for col_index, col in enumerate(row):
324 | while rowspan[irow,icol]:
325 | latexTabular += '&'
326 | icol += 1
327 |
328 | txt = latexEscapeForHtmlTableOutput(col.text_content().strip())
329 | if 'colspan' in col.attrib:
330 | icolspan = int(col.attrib['colspan'])
331 | txt = '\multicolumn{{{}}}{{|c|}}{{{}}}'.format(icolspan,txt)
332 | latexTabular += txt + '&'
333 | while(colspan[irow,icol]):
334 | icol += 1
335 | icol += 1
336 | #calculate the clines
337 | if irow==0 or irow==row_counts-1:
338 | hline = r'\hline'
339 | else:
340 | if np.count_nonzero(rowspan[irow+1,:])==0:
341 | hline = r'\hline'
342 | else:
343 | hline = ''
344 | clines = 1 - rowspan[irow+1,:]
345 | for i in range(0,clines.shape[0]):
346 | if clines[i] > 0:
347 | hline += '\\cline{{{}-{}}}'.format(i+1,i+1)
348 | irow += 1
349 | latexTabular = latexTabular[:-1] + '\\\\'+hline
350 | latexTabular += '\n'
351 | latexTabular += "\n"
352 | latexTabular += "\\end{tabular}\n"
353 |
354 | #process the caption string, either a string or a list of strings
355 | captionStr = getMetaData(cell, table_index, 'tableCaption', 'caption','')
356 | fontsizeStr = getMetaData(cell, table_index, 'tableCaption', 'fontsize','normalsize')
357 | locator = getMetaData(cell, table_index, 'tableCaption', 'locator', 'tb')
358 | labelStr = getMetaData(cell, table_index, 'tableCaption', 'label','')
359 | if labelStr:
360 | tlabstr = labelStr
361 | labelStr = '\\label{{{}-{}}}'.format(tlabstr, table_index)
362 | if table_index == 0:
363 | labelStr += '\\label{{{}}}'.format(tlabstr)
364 | table_index += 1
365 |
366 | texStr = ''
367 | if captionStr:
368 | texStr = texStr + '\n\\begin{table}['+locator+']\n'
369 | texStr += '\\centering\n'
370 | texStr += '\\caption{'+'{}{}'.format(latexEscapeCaption(captionStr),labelStr)+'}\n'
371 | else:
372 | texStr += '\\begin{center}\n'
373 |
374 | texStr += "\n\\begin{{{}}}\n".format(fontsizeStr)
375 | texStr += latexTabular
376 | texStr += "\\end{{{}}}\n".format(fontsizeStr)
377 |
378 | if captionStr:
379 | texStr += '\\end{table}\n\n'
380 | else:
381 | texStr += '\\end{center}\n\n'
382 |
383 | rtnString += texStr
384 |
385 | return rtnString
386 |
387 |
388 | ################################################################################
389 | def findAllStr(string, substr):
390 | ind = string.find(substr)
391 | while ind >= 0:
392 | yield ind
393 | ind = string.find(substr, ind+1)
394 |
395 |
396 | ################################################################################
397 | def findNotUsedChar(string):
398 | delims = '~!@#$%-+=:;'
399 |
400 |
401 | ################################################################################
402 | def processVerbatim(child):
403 | childtail = '' if child.tail==None else child.tail
404 | #multiline text must be in verbatim environment, not just \verb++
405 | if len(child.text.splitlines()) > 1:
406 | strVerb = r'\begin{verbatim}' + '\n' + child.text + r'\end{verbatim}' + childtail
407 | else:
408 | strVerb = r'\verb+' + child.text.rstrip() + r'+' + childtail
409 | return strVerb
410 |
411 |
412 |
413 |
414 |
415 | ################################################################
416 | def cleanFilename(sourcestring, removestring=r" %:/,.\[]"):
417 | """Clean a string by removing selected characters.
418 |
419 | Creates a legal and 'clean' source string from a string by removing some
420 | clutter and characters not allowed in filenames.
421 | A default set is given but the user can override the default string.
422 |
423 | Args:
424 | | sourcestring (string): the string to be cleaned.
425 | | removestring (string): remove all these characters from the string (optional).
426 |
427 | Returns:
428 | | (string): A cleaned-up string.
429 |
430 | Raises:
431 | | No exception is raised.
432 | """
433 | #remove the undesireable characters
434 | return ''.join([i for i in sourcestring if i not in removestring])
435 |
436 |
437 |
438 | def processLaTeXOutCell(cellOutput,output_index,outs,cell,addurlcommand):
439 | # see if this is a booktabs table
440 | global figure_index
441 | global table_index
442 |
443 | outstr = ''
444 | payload = cellOutput.data['text/latex']
445 | booktabstr = ''
446 | if 'bottomrule' in payload or 'toprule' in payload or 'midrule' in payload:
447 | booktabstr += '% to get unbroken vertical lines with booktabs, set separators to zero\n'
448 | booktabstr += '% also set all horizontal lines to same width\n'
449 | booktabstr += '\\aboverulesep=0ex\n'
450 | booktabstr += '\\belowrulesep=0ex\n'
451 | booktabstr += '\\heavyrulewidth=.05em\n'
452 | booktabstr += '\\lightrulewidth=.05em\n'
453 | booktabstr += '\\cmidrulewidth=.05em\n'
454 | booktabstr += '\\belowbottomsep=0pt\n'
455 | booktabstr += '\\abovetopsep=0pt\n'
456 |
457 | # get cell fontsize
458 | fontsizeStr = getMetaData(cell, output_index, 'latex', 'fontsize','normalsize')
459 |
460 | # process table with caption, either a string or a list of strings
461 | if getMetaData(cell, table_index, 'tableCaption', 'caption',''):
462 | captionStr = getMetaData(cell, table_index, 'tableCaption', 'caption','')
463 | fontsizeStr = getMetaData(cell, table_index, 'tableCaption', 'fontsize',fontsizeStr)
464 | locator = getMetaData(cell, table_index, 'tableCaption', 'locator', 'tb')
465 | labelStr = getMetaData(cell, table_index, 'tableCaption', 'label','')
466 | if labelStr:
467 | tlabstr = labelStr
468 | labelStr = '\\label{{{}-{}}}'.format(tlabstr, table_index)
469 | if table_index == 0:
470 | labelStr += '\\label{{{}}}'.format(tlabstr)
471 | table_index += 1
472 |
473 | outstr += '{\n'
474 | if captionStr:
475 | outstr = outstr + '\n\\begin{table}['+locator+']\n'
476 | outstr += '\\centering\n'
477 | outstr += '\\caption{'+'{}{}'.format(latexEscapeCaption(captionStr),labelStr)+'}\n'
478 | outstr += booktabstr
479 | outstr += '\n\\begin{{{}}}\n'.format(fontsizeStr)
480 | outstr += '\\renewcommand{\\arraystretch}{1.1}\n'
481 | outstr += payload + '\n'
482 | outstr += '\\renewcommand{\\arraystretch}{1}\n'
483 | outstr += '\\end{{{}}}\n'.format(fontsizeStr)
484 | if captionStr:
485 | outstr += '\\end{table}\n\n'
486 | outstr += '}\n\n'
487 |
488 | # process figure with caption, either a string or a list of strings
489 | elif getMetaData(cell, figure_index, 'figureCaption', 'caption',''):
490 | fstring, figure_index = prepareFigureFloat(cell,figure_index,filename=None,payload=payload,fontsizeStr=fontsizeStr)
491 | outstr += fstring
492 |
493 | elif booktabstr or '\\begin{tabular}' in payload:
494 | # no captioned latex, just output inline
495 | # check for tabular
496 | outstr += '{\n'
497 | outstr += '\\renewcommand{\\arraystretch}{1.1}\n'
498 | outstr += '\\centering\n'
499 | if booktabstr:
500 | outstr += booktabstr
501 | outstr += '\n\\begin{{{}}}\n'.format(fontsizeStr)
502 | outstr += payload + '\n'
503 | outstr += '\\end{{{}}}\n'.format(fontsizeStr)
504 | outstr += '\\renewcommand{\\arraystretch}{1}\n'
505 | outstr += '}\n\n'
506 | table_index += 1
507 | else:
508 | outstr += payload + '\n'
509 |
510 | return outstr
511 |
512 |
513 |
514 | ################################################################################
515 | def prepOutput(cellOutput, cell, cell_index, output_index, imagedir, infile,addurlcommand):
516 |
517 | captionStr = getMetaData(cell, 0, 'listingCaption', 'outputCaption','')
518 | labelStr = getMetaData(cell, 0, 'listingCaption', 'label','')
519 | if captionStr:
520 | captionStr = '{'+r'{} \label{{{}-out}}'.format(captionStr, labelStr)+'}'
521 |
522 | global figure_index
523 | global table_index
524 | table_index = 0
525 | figure_index = 0
526 |
527 | outstr = ''
528 | if 'text' in cellOutput.keys():
529 | outstr += encapsulateListing(cellOutput['text'], captionStr)
530 | elif 'data' in cellOutput.keys():
531 | if 'text/html' in cellOutput.data.keys():
532 | outs = cellOutput.data['text/html']
533 | outstr += processHTMLTree(outs,cell,addurlcommand)
534 | elif 'text/latex' in cellOutput.data.keys():
535 | lstr = processLaTeXOutCell(
536 | cellOutput,output_index,outstr,cell,addurlcommand)
537 | outstr += lstr
538 | elif 'text/plain' in cellOutput.data.keys():
539 | outstr += encapsulateListing(cellOutput.data['text/plain'], captionStr)
540 | else:
541 | raise NotImplementedError("Unable to process cell {}, \nlooking for subkeys: {}".\
542 | format(cellOutput, cellOutput.data.keys()))
543 | else:
544 | raise NotImplementedError("Unable to process cell {}, \nlooking for keys: {}".\
545 | format(cellOutput, cellOutput.keys()))
546 |
547 | outstr += '\n'
548 | return outstr
549 |
550 | ################################################################################
551 | def encapsulateListing(outstr, captionStr):
552 | outstr = unicodedata.normalize('NFKD',outstr).encode('ascii','ignore')
553 | rtnStr = u'\n\\begin{lstlisting}'
554 |
555 | outstr = outstr.decode("utf-8")
556 |
557 | if captionStr:
558 | rtnStr += '[style=outcellstyle,caption={:s}]\n{}\n'.format(captionStr,outstr)
559 | else:
560 | rtnStr += '[style=outcellstyle]\n{}\n'.format(outstr)
561 | rtnStr += '\\end{lstlisting}\n\n'
562 |
563 | return rtnStr
564 |
565 | ################################################################################
566 | def prepInput(cell, cell_index, inlinelistings):
567 | rtnStr = ''
568 | rtnSource = ''
569 | captiopurp = None
570 |
571 | if 'source' in cell.keys():
572 | lsting = cell.source
573 |
574 | captionStr = getMetaData(cell, 0, 'listingCaption', 'caption','')
575 | labelStr = getMetaData(cell, 0, 'listingCaption', 'label','')
576 |
577 | if not inlinelistings and not len(labelStr):
578 | labelStr = 'lst:autolistingcell{}'.format(cell_index)
579 |
580 | showListing = True
581 | if not inlinelistings: # and not captionStr:
582 | if len(lsting):
583 | lstistrp = lsting.split('\n')
584 | if lstistrp[0].startswith(('%%','% ')):
585 | commentLine = lstistrp[1]
586 | else:
587 | commentLine = lstistrp[0]
588 |
589 | if len(commentLine) > 0: # long enough string?
590 | if commentLine[0]=='#':
591 | if len(commentLine) > 1: # long enough string?
592 | if not commentLine[1]=='#':
593 | captiopurp = ' ' + commentLine[1:]
594 | if len(commentLine) > 2: # long enough string?
595 | if commentLine[2]=='#':
596 | showListing = False
597 | else:
598 | captiopurp = ''
599 | if not captionStr:
600 | captionStr = 'Code Listing in cell {}'.format(cell_index)
601 |
602 | if captionStr:
603 | captionStr = '{'+r'{}}}, label={}'.format(latexEscapeCaption(captionStr), labelStr)
604 |
605 | if showListing and len(lsting)>0:
606 | if inlinelistings:
607 | rtnStr += '\n\\begin{lstlisting}'
608 | rtnStr += '[style=incellstyle]\n{}\n'.format(lsting)
609 | rtnStr += '\\end{lstlisting}\n\n'
610 | else:
611 | rtnSource += '\n\\begin{lstlisting}'
612 | if captionStr:
613 | rtnSource += '[style=incellstyle,caption={}]\n{}\n'.format(captionStr,lsting)
614 | else:
615 | rtnSource += '[style=incellstyle]\n{}\n'.format(lsting)
616 | rtnSource += '\\end{lstlisting}\n\n'
617 | if captiopurp is not None:
618 | rtnStr += '\n\nSee Listing~\\ref{{{}}} for the code{}.\n\n'.format(labelStr,captiopurp)
619 |
620 | return rtnStr,rtnSource
621 |
622 | ################################################################################
623 | # def convertBytes2Str(instring):
624 | # """Convert a byte string to regular string (if in Python 3)
625 | # """
626 | # # print('1',type(instring))
627 | # if isinstance(instring, bytes):
628 | # instring = instring.decode("utf-8")
629 |
630 | # return instring
631 |
632 |
633 | ################################################################################
634 | def prepExecuteResult(cellOutput, cell, cell_index, output_index, imagedir, infile,addurlcommand):
635 |
636 | if 'html' in cellOutput.keys():
637 | return processHTMLTree(cellOutput['html'],cell,addurlcommand)
638 |
639 | if u'png' in cellOutput.keys():
640 | return processDisplayOutput(cellOutput, cell, cell_index, output_index, imagedir, infile,addurlcommand)
641 |
642 | return prepOutput(cellOutput, cell, cell_index, output_index, imagedir, infile,addurlcommand)
643 |
644 |
645 |
646 | # if 'text' in cellOutput.keys():
647 | # outstr = cellOutput['text']
648 | # elif 'data' in cellOutput.keys():
649 | # if 'text/html' in cellOutput.data.keys():
650 | # doListing = False
651 | # outstr = cellOutput.data['text/html']
652 | # outstr = processHTMLTree(outstr,cell,addurlcommand)
653 | # if 'text/plain' in cellOutput.data.keys():
654 | # outstr = cellOutput.data['text/plain']
655 | # else:
656 | # raise NotImplementedError("Unable to process cell {}, \nlooking for keys: {}".\
657 | # format(cellOutput, cellOutput.keys()))
658 |
659 |
660 |
661 | ################################################################################
662 | def prepError(cellOutput, cell, cell_index, output_index, imagedir, infile,addurlcommand):
663 | import os, re
664 | r= re.compile(r'\033\[[0-9;]+m')
665 | rtnStr = '\n\\begin{verbatim}\n'
666 | for output in cell["outputs"]:
667 | # v3 if output['output_type'] == 'error':
668 | if output['output_type'] == 'error':
669 | for trace in output['traceback']:
670 | #convert to ascii and remove control chars
671 | # rtnStr += re.sub(r'\033\[[0-9;]+m',"", bytes(trace).decode('ascii','ignore'))
672 | rtnStr += re.sub(r'\033\[[0-9;]+m',"", trace)
673 |
674 |
675 | rtnStr += '\\end{verbatim}\n'
676 | return rtnStr
677 |
678 | ################################################################################
679 | def prepNotYet(cellOutput, cell, cell_index, output_index, imagedir, infile,addurlcommand):
680 | for output in cell["outputs"]:
681 | raise NotImplementedError("Unable to process cell type {}".\
682 | format(output["output_type"]))
683 |
684 | ################################################################################
685 | def extractBibtexXref(cell):
686 |
687 | #read the citation cross-reference map
688 | if 'bibxref' in cell['metadata'].keys():
689 | for key in cell['metadata']['bibxref'].keys():
690 | bibxref[key] = cell['metadata']['bibxref'][key]
691 |
692 | #read user-supplied bibtex entries.
693 | if 'bibtexentry' in cell['metadata'].keys():
694 | for key in cell['metadata']['bibtexentry'].keys():
695 | bibtexlist.append(cell['metadata']['bibtexentry'][key] + '\n\n')
696 |
697 | ################################################################################
698 | def getMetaData(cell, output_index, captionID, metaID, defaultValue=''):
699 | """process the metadata string, either a single value or a list of values,
700 | and extract the value associated with output_index, if in a list
701 | """
702 |
703 | outVal = defaultValue
704 | if captionID in cell['metadata'].keys():
705 | if metaID in cell['metadata'][captionID].keys():
706 | inVal = cell['metadata'][captionID][metaID]
707 |
708 | # sometimes lists are correctly imported and sometimes not
709 | if isinstance(inVal, str) and '[' in inVal:
710 | import ast
711 | inVal = ast.literal_eval(inVal)
712 | # for it,item in enumerate(inVal):
713 | # if isinstance(item,str):
714 | # inVal[it] = item.replace('\\\\','\\')
715 | # else:
716 | # inVal[it] = item
717 |
718 | if isinstance(inVal, str):
719 | outVal = inVal
720 | else:
721 | if output_index < len(inVal):
722 | outVal = inVal[output_index]
723 | else:
724 | outVal = defaultValue
725 |
726 | return outVal
727 |
728 |
729 | ################################################################################
730 | def processDisplayOutput(cellOutput, cell, cell_index, output_index, imagedir, infile,addurlcommand):
731 | # print('********',cellOutput.keys())
732 |
733 | texStr = ''
734 |
735 | if 'name' in cellOutput.keys() :
736 | if cellOutput.name == 'stdout':
737 | if 'text' in cellOutput.keys() :
738 | return cellOutput.text
739 |
740 | if 'text/html' in cellOutput.keys() :
741 | return processHTMLTree(cellOutput['text/html'],cell,addurlcommand)
742 |
743 | #handle pdf image
744 | picCell = None
745 | #nbformat 4
746 | if 'data' in cellOutput.keys() and 'application/pdf' in cellOutput.data.keys():
747 | picCell = cellOutput.data['application/pdf']
748 | imageName = infile.replace('.ipynb', '') + \
749 | '_{}_{}.pdf'.format(cell_index, output_index)
750 | #nbformat 3
751 | if 'pdf' in cellOutput.keys():
752 | picCell = cellOutput.pdf
753 | imageName = infile.replace('.ipynb', '') + \
754 | '_{}_{}.pdf'.format(cell_index, output_index)
755 |
756 | #handle png images
757 | #nbformat 4
758 | if 'data' in cellOutput.keys() and 'image/png' in cellOutput.data.keys():
759 | picCell = cellOutput.data['image/png']
760 | imageName = infile.replace('.ipynb', '') + \
761 | '_{}_{}.png'.format(cell_index, output_index)
762 | #nbformat 3
763 | if 'png' in cellOutput.keys():
764 | picCell = cellOutput.png
765 | imageName = infile.replace('.ipynb', '') + \
766 | '_{}_{}.png'.format(cell_index, output_index)
767 |
768 | #handle jpeg images
769 | #nbformat 4
770 | if 'data' in cellOutput.keys() and 'image/jpeg' in cellOutput.data.keys():
771 | picCell = cellOutput.data['image/jpeg']
772 | imageName = infile.replace('.ipynb', '') + \
773 | '_{}_{}.jpeg'.format(cell_index, output_index)
774 | #nbformat 3
775 | if 'jpeg' in cellOutput.keys():
776 | picCell = cellOutput.jpeg
777 | imageName = infile.replace('.ipynb', '') + \
778 | '_{}_{}.jpeg'.format(cell_index, output_index)
779 |
780 | if picCell:
781 |
782 | filename = os.path.join(imagedir,imageName)
783 | with open(filename, 'wb') as fpng:
784 |
785 | fpng.write(base64.decodebytes(bytes(picCell, 'utf-8')))
786 | fstring, _ = prepareFigureFloat(cell,output_index,filename)
787 | texStr += fstring
788 |
789 | return texStr
790 |
791 |
792 |
793 | # not sure wht this is still here, there is another processor caught in
794 | # the 'data' key processing done further down below (processLaTeXOutCell)
795 | # #handle latex in output cell
796 | # #nbformat 4
797 | # if 'data' in cellOutput.keys() and 'text/latex' in cellOutput.data.keys():
798 | # print('process latex 2')
799 | # texStr += processLaTeX(cellOutput['data']['text/latex'],cell,addurlcommand)
800 | # return texStr
801 | # #nbformat 3
802 | # if 'latex' in cellOutput.keys():
803 | # texStr += processLaTeX(cellOutput['text/latex'],cell,addurlcommand)
804 | # return texStr
805 |
806 |
807 |
808 | if 'text/plain' in cellOutput.keys():
809 | return prepOutput(cellOutput, cell, cell_index, output_index, imagedir, infile,addurlcommand)
810 |
811 | if 'data' in cellOutput.keys():
812 | if 'text/plain' in cellOutput.data.keys():
813 | return prepOutput(cellOutput, cell, cell_index, output_index, imagedir, infile,addurlcommand)
814 |
815 | if 'display_data' in cellOutput['output_type']:
816 | if 'application/vnd.jupyter.widget-view+json' in cellOutput['data'].keys():
817 | if 'model_id' in cellOutput['data']['application/vnd.jupyter.widget-view+json'].keys():
818 | texStr += f"\n\nCell contains a Jupyter widget with model\_id "
819 | texStr += f"{cellOutput['data']['application/vnd.jupyter.widget-view+json']['model_id']} "
820 | texStr += f"please open the notebook for display of this widget.\n\n"
821 | return texStr
822 |
823 | strErr = f"""
824 | Unknown cell type(s) in this cell:
825 | cell_keys: {cell.keys()}
826 | cell_type: {cell['cell_type']}
827 | cell execution_count: {cell['execution_count']}
828 | cell source: {cell['source']}
829 |
830 | cell meta: {cell['metadata']}
831 | cellOutput keys: {cellOutput.keys()}
832 | cellOutput output_type: {cellOutput['output_type']}
833 | cellOutput data: {cellOutput['data']}
834 | cellOutput metadata: {cellOutput['metadata']}
835 | output_index: {output_index}
836 | """
837 | # cell output: {cell['outputs']}
838 |
839 | raise NotImplementedError(strErr)
840 |
841 |
842 | ################################################################################
843 | #process an html tree
844 | def processLaTeX(latex,cell,addurlcommand):
845 | # print('processLaTeX',latex)
846 | return latex
847 |
848 |
849 | ################################################################################
850 | def convertRawCell(cell, cell_index, imagedir, infile, inlinelistings,addurlcommand):
851 |
852 | extractBibtexXref(cell)
853 |
854 | strraw = cell['source']+'\n\n'
855 |
856 | return strraw , ''
857 |
858 | ################################################################################
859 | def convertCodeCell(cell, cell_index, imagedir, infile, inlinelistings,addurlcommand):
860 |
861 | extractBibtexXref(cell)
862 |
863 | output,lstoutput = prepInput(cell, cell_index, inlinelistings)
864 | for count, cellOutput in enumerate(cell.outputs):
865 | #output += "{}".format(cellOutput.output_type)
866 | if cellOutput.output_type not in fnTableOutput:
867 | print(cellOutput.output_type)
868 | raise NotImplementedError("Unknown output type {}.".format(cellOutput.output_type))
869 | output += fnTableOutput[cellOutput.output_type](cellOutput, cell, cell_index, count, imagedir, infile,addurlcommand)
870 |
871 | return output, lstoutput
872 |
873 | ################################################################################
874 | def convertMarkdownCell(cell, cell_index, imagedir, infile, inlinelistings,addurlcommand):
875 |
876 | extractBibtexXref(cell)
877 |
878 | mkd = cell['source']
879 |
880 | # the problem is markdown will escape out slashes in the math environments
881 | # to try to fix this, let's find all the math environments
882 | # run markdown on them independently, to know what to search/replace for
883 | # this will probably break kind of badly for poorly formatted input,
884 | # particularly if $ and begin{eq..} are mixed within each other, but
885 | # hopefully you'll notice your input is broken in the notebook already?
886 |
887 | math_envs = []
888 |
889 | #the following block replaces $$ with begin/end {equation} sequences
890 | repstring = [r'\begin{equation}',r'\end{equation}']
891 | i = 0
892 | nlines = []
893 | ddollars = list(findAllStr(mkd, '$$'))
894 | if len(ddollars) > 0:
895 | lines = mkd.split('\n')
896 | for line in lines:
897 | #ignore verbatim text
898 | if line[0:4] == ' ':
899 | nlines.append(line)
900 | else:
901 | #replace in sequence over one or more lines, one at a time
902 | while '$$' in line:
903 | line = line.replace('$$',repstring[i%2],1)
904 | i += 1
905 | nlines.append(line)
906 | #rebuild the markdown
907 | mkd = '\n'.join(nlines)
908 |
909 | dollars = list(findAllStr(mkd, '$'))
910 | ends = dollars[1::2]
911 | starts = dollars[::2]
912 | if len(starts) > len(ends):
913 | starts = starts[:-1]
914 | math_envs += [(s,e) for (s,e) in zip(starts, ends)]
915 |
916 | starts = list(findAllStr(mkd, '\\begin{equation}'))
917 | ends = [e + 13 for e in findAllStr(mkd, '\\end{equation}')]
918 | if len(starts) > len(ends):
919 | starts = starts[:-1]
920 | math_envs += [(s,e) for (s,e) in zip(starts, ends)]
921 | math_envs = sorted(math_envs)
922 |
923 | starts = list(findAllStr(mkd, '\\begin{equation*}'))
924 | ends = [e + 14 for e in findAllStr(mkd, '\\end{equation*}')]
925 | if len(starts) > len(ends):
926 | starts = starts[:-1]
927 | math_envs += [(s,e) for (s,e) in zip(starts, ends)]
928 | math_envs = sorted(math_envs)
929 |
930 | starts = list(findAllStr(mkd, '\\begin{eqnarray}'))
931 | ends = [e + 13 for e in findAllStr(mkd, '\\end{eqnarray}')]
932 | if len(starts) > len(ends):
933 | starts = starts[:-1]
934 | math_envs += [(s,e) for (s,e) in zip(starts, ends)]
935 | math_envs = sorted(math_envs)
936 |
937 | if math_envs:
938 | mkd_tmp = ""
939 | old_end = -1
940 | for start, end in math_envs:
941 | mkd_tmp += mkd[old_end+1:start]
942 | old_end = end
943 | cleaned = mkd[start:end+1]
944 | for escapeable in '\\`*_{}[]()#+-.!':
945 | cleaned = cleaned.replace(escapeable, '\\' + escapeable)
946 | cleaned = cleaned.replace('\n', '')
947 | mkd_tmp += cleaned
948 | mkd = mkd_tmp + mkd[end+1:]
949 |
950 | html = markdown.markdown(mkd, extensions=['extra'])
951 | tmp = processHTMLTree(html,cell,addurlcommand)
952 |
953 | # lines = tmp.split('\n')
954 | # for line in lines:
955 | # if 'http' in line and r'\cite' in line:
956 | # print(line)
957 |
958 | return tmp,''
959 |
960 |
961 |
962 |
963 | ################################################################################
964 | #process an html tree
965 | def processHTMLTree(html,cell,addurlcommand):
966 |
967 | global figure_index
968 | global table_index
969 | figure_index = 0
970 | table_index = 0
971 |
972 | tree = lxml.html.fromstring(""+html+"
")
973 | # pptree(tree)
974 | tmp = ""
975 |
976 | for child in tree:
977 | # print('------------------------------------')
978 | # print('child.tag={}'.format(child.tag),type(child.tag))
979 | # print('child.text={}'.format(child.text))
980 | # print('child.tail={}'.format(child.tail))
981 | # print(cell)
982 |
983 | if child.tag == 'h1' or (cell['cell_type']=="heading" and cell['level']==1):
984 | tmp += processHeading(r'\chapter', child.text_content())
985 |
986 | elif child.tag == 'h2' or (cell['cell_type']=="heading" and cell['level']==2):
987 | tmp += processHeading(r'\section', child.text_content())
988 |
989 | elif child.tag == 'h3' or (cell['cell_type']=="heading" and cell['level']==3):
990 | tmp += processHeading(r'\subsection', child.text_content())
991 |
992 | elif child.tag == 'h4' or (cell['cell_type']=="heading" and cell['level']==4):
993 | tmp += processHeading(r'\subsubsection', child.text_content())
994 |
995 | elif child.tag == 'h5' or (cell['cell_type']=="heading" and cell['level']==5):
996 | tmp += processHeading(r'\paragraph', child.text_content())
997 |
998 | elif child.tag == 'h6' or (cell['cell_type']=="heading" and cell['level']==6):
999 | tmp += processHeading(r'\subparagraph', child.text_content())
1000 |
1001 | elif child.tag == 'p' or child.tag == 'pre':
1002 | tmp += processParagraph(child,'',addurlcommand,cell) + '\n'
1003 |
1004 | #this call may be recursive for nested lists
1005 | #lists are not allowed inside paragraphs, handle them here
1006 | elif child.tag == 'ul' or child.tag == 'ol':
1007 | tmp += processList(child,addurlcommand,cell) + '\n'
1008 |
1009 | elif child.tag == 'blockquote':
1010 | tmp += "\n\\begin{quote}\n" + processParagraph(child,'',addurlcommand,cell).strip() + "\\end{quote}\n\n"
1011 |
1012 | elif child.tag == 'table':
1013 | tmp += convertHtmlTable(child, cell)
1014 | table_index += 1
1015 |
1016 | elif child.tag == 'div':
1017 | pass
1018 | if cell is not None:
1019 | tmp += convertHtmlTable(child, cell)
1020 | table_index += 1
1021 |
1022 | elif child.tag == 'iframe':
1023 | # we only check for embedded pdf in iframe for now
1024 | lines = cell["source"].splitlines()
1025 | for line in lines:
1026 | if '.pdf' in line:
1027 | filename = re.search(r'"(.*?)"',line).group(1)
1028 | ftmp,figure_index = prepareFigureFloat(cell,figure_index,filename)
1029 | tmp += ftmp
1030 |
1031 | elif child.tag == 'br':
1032 | tmp += "\\newline"
1033 |
1034 | elif child.tag == 'img':
1035 | filename = child.attrib['src']
1036 | ftmp,figure_index = prepareFigureFloat(cell,figure_index,filename)
1037 | tmp += ftmp
1038 |
1039 | elif child.tag == 'style':
1040 | pass
1041 |
1042 | else:
1043 | print('Unknown tag in this cell:')
1044 | print(f'child.tag: {child.tag}')
1045 | print(f'child.text: {child.text}')
1046 | print(f'cell contents: {cell}')
1047 | print('')
1048 | raise ValueError("Unable to process tag of type ", child.tag)
1049 |
1050 | # fix the lxml parser ignoring the \ for the latex envs
1051 | #for env in ['equation']: # might want to extend this for other envs?
1052 | # tmp = tmp.replace('\nbegin{' + env + '}', '\n\\begin{' + env + '}')
1053 | # tmp = tmp.replace('\nend{' + env + '}', '\n\\end{' + env + '}')
1054 |
1055 | #first remove escaped \% if present, then do escape again on all % present
1056 | tmp = tmp.replace('\\%','%')
1057 | tmp = tmp.replace('%','\\%')
1058 |
1059 | # now do latex escapes - things markdown are fine with but latex isnt
1060 | # in particular, underscore outside math env
1061 | offset_count = 0
1062 | for loc in findAllStr(tmp, '_'):
1063 | # check for inline math
1064 | loc += offset_count
1065 | inline_count = sum([1 for i in findAllStr(tmp, '$') if i < loc])
1066 |
1067 | env_count = sum([1 for i in findAllStr(tmp, r'\begin{equation') if i < loc]) \
1068 | + sum([1 for i in findAllStr(tmp, r'\end{equation') if i < loc])
1069 | envs_count = sum([1 for i in findAllStr(tmp, r'\begin{equation*') if i < loc]) \
1070 | + sum([1 for i in findAllStr(tmp, r'\end{equation*') if i < loc])
1071 | enva_count = sum([1 for i in findAllStr(tmp, r'\begin{eqnarray') if i < loc]) \
1072 | + sum([1 for i in findAllStr(tmp, r'\end{eqnarray') if i < loc])
1073 | envg_count = sum([1 for i in findAllStr(tmp, protectEvnStringStart) if i < loc]) \
1074 | + sum([1 for i in findAllStr(tmp, protectEvnStringEnd) if i < loc])
1075 |
1076 | # replace _ with \_ if not in one of above environments
1077 | if (not inline_count % 2) and (not env_count % 2) and (not envs_count % 2) and (not enva_count % 2) and (not envg_count % 2) :
1078 | tmp = tmp[:loc] + '\\' + tmp[loc:]
1079 | offset_count += 1
1080 | tmp += '\n'
1081 | return tmp
1082 |
1083 |
1084 |
1085 | ################################################################################
1086 | def processHeading(hstring, cstring):
1087 | strtmp = "\n{}{{".format(hstring) + cstring + "}\n"
1088 | seclabel = cleanFilename(cstring, removestring=r" %:/,.\[]=?~!@#$^&*()-_{};")
1089 | strtmp += r'\label{sec:' + seclabel + '}\n\n'
1090 | return strtmp
1091 |
1092 |
1093 | ################################################################################
1094 | #this call may be recursive for nested lists
1095 | def processList(lnode,addurlcommand,cell):
1096 | # global listindentcurrent
1097 | # global listindentprevious
1098 |
1099 | tmp = ''
1100 | if lnode.tag == 'ul' or lnode.tag == 'ol':
1101 | envtype = 'itemize' if lnode.tag == 'ul' else 'enumerate'
1102 | tmp += "\n\\begin{" + envtype + "}\n"
1103 |
1104 | for li in lnode:
1105 |
1106 | if li.tag == 'ul' or li.tag == 'ol':
1107 | tmp += processList(li,addurlcommand,cell).strip() + '\n'
1108 |
1109 | elif li.tag == 'li':
1110 | # if listindentcurrent==listindentprevious:
1111 | # # if len(li.tail) == 0:
1112 | # li.tag = 'br'
1113 | # li.tail = li.text
1114 | # li.text = None
1115 | # print('*****************')
1116 | # # else:
1117 |
1118 | # print(f'Identlevels (p,c)=({listindentprevious}{listindentcurrent})')
1119 | # print(f' tag={li.tag}')
1120 | # print(f' text={li.text}')
1121 | # print(f' tail={li.tail}')
1122 |
1123 | tstr = r"\item " + processParagraph(li,'',addurlcommand,cell).strip() + '\n'
1124 | # print(tstr)
1125 | tmp += tstr
1126 |
1127 | else:
1128 | print('this should not be reached!')
1129 | pass
1130 |
1131 | if lnode.tag == 'ul' or lnode.tag == 'ol':
1132 | tmp += "\\end{" + envtype + "}\n"
1133 |
1134 | return tmp.strip() + '\n'
1135 |
1136 |
1137 | ################################################################################
1138 | def processParagraph(pnode, tmp, addurlcommand,cell):
1139 |
1140 | global bibtexindex
1141 | global figure_index
1142 |
1143 | # print('------------------------------------')
1144 | # tmp = ""
1145 | if pnode.text:
1146 | # print('pnode.text={}'.format(pnode.text))
1147 | tmp += pnode.text
1148 |
1149 |
1150 | for child in pnode:
1151 |
1152 | # print('child.tag={}'.format(child.tag))
1153 | # print('child.text={}'.format(child.text))
1154 | # print('child.tail={}'.format(child.tail))
1155 |
1156 | childtail = '' if child.tail==None else child.tail
1157 |
1158 | # if child.tag == 'ul':
1159 | # if len(child.getchildren()) > 0:
1160 | # raise ValueError('need to learn to deal with nested children in ',
1161 | # pnode, child, child.getchildren())
1162 |
1163 | if child.tag == 'em':
1164 | tmp += r"\textit{" + child.text + "}" + childtail
1165 |
1166 | elif child.tag == 'i':
1167 | tmp += r"\textit{" + child.text + "}" + childtail
1168 |
1169 | elif child.tag == 'b':
1170 | tmp += r"\textbf{" + child.text + "}" + childtail
1171 |
1172 | elif child.tag == 'p':
1173 | tmp += processParagraph(child, tmp, addurlcommand,cell).strip() + '\n\n' + childtail
1174 |
1175 | elif child.tag == 'br':
1176 | tmp += "\n\n" + childtail
1177 |
1178 | elif child.tag == 'code':
1179 | tmp += processVerbatim(child)
1180 |
1181 | elif child.tag == 'strong':
1182 | if child.text:
1183 | tmp += r"\textbf{" + child.text + "}" + childtail
1184 | else:
1185 | pass
1186 | # print(child.tag)
1187 | # print(child.tail)
1188 |
1189 | elif child.tag == 'font':
1190 | #currently ignore font attributes
1191 | tmp += child.text + childtail
1192 |
1193 | elif child.tag == 'a':
1194 | url = child.get('href')
1195 | if url is not None:
1196 | citelabel = cleanFilename(url, removestring =r" %:/,.\[]=?~!@#$^&*()-_{};")
1197 | # if the label is too long latex may choke
1198 | if len(citelabel) > 20:
1199 | citelabel = '{}{:05d}'.format(citelabel[:20],bibtexindex)
1200 | bibtexindex += 1
1201 | if citelabel in bibxref.keys():
1202 | pass
1203 | # tmp += child.text + r'\cite{{{0}}}'.format(bibxref[citelabel]) + childtail
1204 | else:
1205 | bibxref[citelabel] = citelabel
1206 | # raise ValueError('This key is not in the bibxref dict metadata:', citelabel)
1207 |
1208 | if addurlcommand:
1209 | url = r'\url{'+url+'}'
1210 |
1211 | bibtexentry = '@MISC{{{0},\n'.format(bibxref[citelabel]) + \
1212 | ' url = {{{0}}}\n}}\n\n'.format(url)
1213 | bibtexlist.append(bibtexentry)
1214 | # print('\nchild.text={}\nlabel={}\ntail={}\n'.format(child.text, r'\cite{{{0}}}'.format(bibxref[citelabel]), childtail))
1215 | if child.text:
1216 | childtext = child.text
1217 | if 'http' in childtext:
1218 | childtext = r'\url{'+childtext+'}'
1219 | tmp += childtext
1220 | tmp += r'\cite{{{0}}}'.format(bibxref[citelabel]) + childtail
1221 |
1222 | # handle embedded lists
1223 | elif child.tag == 'ul' or child.tag == 'ol':
1224 | tmp += processList(child,addurlcommand,cell) + childtail
1225 |
1226 | elif child.tag == 'pre':
1227 | tmp += "\n\\begin{verbatim}\n" + processParagraph(child,'',addurlcommand,cell).strip() + "\\end{verbatim}\n\n"
1228 |
1229 | elif child.tag == 'br':
1230 | tmp += "\\newline"
1231 |
1232 | elif child.tag == 'img':
1233 | filename = child.attrib['src']
1234 | filename = os.path.join('.',filename)
1235 | ftmp, figure_index = prepareFigureFloat(cell,figure_index,filename)
1236 | tmp += ftmp
1237 |
1238 | else:
1239 | strErr = f'so far={tmp}, need to learn to process this:'
1240 | raise ValueError(strErr, child.tag)
1241 |
1242 | if pnode.tail:
1243 | tmp += pnode.tail
1244 | return tmp.strip() + '\n\n'
1245 |
1246 | ################################################################################
1247 | # create the float code for a figure
1248 | def prepareFigureFloat(cell,figure_index,filename=None,payload=None,fontsizeStr='normalsize'):
1249 | """write the latex code to make a (non)float figure
1250 | """
1251 | if filename is None and payload is None:
1252 | print('In prepareFigureFloat: filename and payload cannot both be None')
1253 | exit(-1)
1254 | # print(filename)
1255 | # print(cell['metadata'])
1256 | fstring = ''
1257 | # print(payload,filename)
1258 | # print('------------------------------')
1259 | if filename is not None:
1260 | if '\\' in filename:
1261 | filename = filename.replace('\\','/')
1262 | if getMetaData(cell, figure_index, 'figureCaption', 'caption',''):
1263 | captionStr = getMetaData(cell, figure_index, 'figureCaption', 'caption','')
1264 | if '(###)' in captionStr:
1265 | captionStr = captionStr.replace('(###)',f'({figure_index+1})')
1266 | labelStr = getMetaData(cell, figure_index, 'figureCaption', 'label','')
1267 | if labelStr:
1268 | tlabstr = labelStr
1269 | labelStr = '\\label{{{}-{}}}'.format(tlabstr, figure_index)
1270 | if figure_index == 0:
1271 | labelStr += '\\label{{{}}}'.format(tlabstr)
1272 |
1273 | #build the complete bitmap size latex string
1274 | width = getMetaData(cell, figure_index, 'figureCaption', 'width', 0.9)
1275 | locator = getMetaData(cell, figure_index, 'figureCaption', 'locator', 'tb')
1276 | angle = getMetaData(cell, figure_index, 'figureCaption', 'angle', 0)
1277 |
1278 | fstring += '{\n'
1279 | fstring = fstring + '\n\\begin{figure}['+locator+']\n'
1280 | fstring += '\\centering\n'
1281 | fstring += '\n\\begin{{{}}}\n'.format(fontsizeStr)
1282 | if payload is None: # not a latex cell
1283 | fstring += protectEvnStringStart
1284 | fstring += '\\includegraphics[width='+f'{width}'+'\\textwidth, angle='+f'{angle}'+']{'+filename+'}\n'
1285 | fstring += protectEvnStringEnd
1286 | else:
1287 | # any figure here will not be a png, jpg or eps, so just dump
1288 | fstring += payload
1289 | fstring += '\\end{{{}}}\n'.format(fontsizeStr)
1290 | if captionStr:
1291 | fstring += '\\caption{'+'{}{}'.format(latexEscapeCaption(captionStr),labelStr)+'}\n'
1292 | fstring += '\\end{figure}\n\n'
1293 | fstring += '}\n\n'
1294 | else:
1295 | fstring += '\\begin{center}\n'
1296 | fstring += protectEvnStringStart
1297 | fstring += '\\includegraphics[width=0.9\\textwidth, angle=0]{'+filename+'}\n'
1298 | fstring += protectEvnStringEnd
1299 | fstring += '\\end{center}\n'
1300 |
1301 | figure_index += 1
1302 |
1303 | return fstring, figure_index
1304 |
1305 |
1306 |
1307 |
1308 | ################################################################################
1309 | #dict to call processing functions according to cell type
1310 | fnTableCell = {
1311 | 'code' : convertCodeCell,
1312 | 'markdown' : convertMarkdownCell,
1313 | 'heading' : convertMarkdownCell,
1314 | 'raw' : convertRawCell,
1315 | }
1316 |
1317 | ################################################################################
1318 | #dict to call processing functions according to cell output type
1319 | fnTableOutput = {
1320 | 'stream': prepOutput,
1321 | 'pyout': prepExecuteResult, # nbformat 3
1322 | 'execute_result': prepExecuteResult, # nbformat 4
1323 | 'display_data': processDisplayOutput,
1324 | 'pyerr': prepError, # nbformat 3
1325 | 'error': prepError, # nbformat 4
1326 | 'svg': prepNotYet,
1327 | 'png': prepNotYet,
1328 | # 'application/pdf': prepNotYet,
1329 | 'text': prepNotYet,
1330 | }
1331 |
1332 |
1333 | ################################################################################
1334 | # create the picture directory
1335 | def createImageDir(imagedir):
1336 | if imagedir is None:
1337 | imagedir = './pic/'
1338 |
1339 | # print(imagedir, imagedir[-1])
1340 |
1341 | if '\\' in imagedir[-1] or '/' in imagedir[-1]:
1342 | pass
1343 | else:
1344 | imagedir += '/'
1345 |
1346 | if not os.path.exists(imagedir):
1347 | os.makedirs(imagedir)
1348 |
1349 | return imagedir
1350 |
1351 | ################################################################################
1352 | # here we do one at at time
1353 | def processOneIPynbFile(infile, outfile, imagedir, inlinelistings, addurlcommand,appendbibtex):
1354 |
1355 | #if required by option create a chapter for floated listings
1356 | listingsstring = ''
1357 |
1358 | print('\nnotebook={}'.format(infile))
1359 | print('latex={}'.format(outfile))
1360 | print('imageDir={}'.format(imagedir))
1361 | print('inline listings={}'.format(inlinelistings))
1362 | print('add url to bibtex url={}'.format(addurlcommand))
1363 |
1364 | pdffile = outfile.replace('.tex', '.pdf')
1365 |
1366 | # nb = ipnbcurrent.read(io.open(infile, encoding='utf-8'), 'json')
1367 | # if len(nb.worksheets) > 1:
1368 | # raise NotImplementedError("Only one worksheet allowed")
1369 |
1370 | nb = nbformat.read(io.open(infile, encoding='utf-8'), nbformat.NO_CONVERT)
1371 | output = '\n'
1372 |
1373 | # for cell_index, cell in enumerate(nb.worksheets[0].cells):
1374 | if 'cells' not in nb:
1375 | print("This notebook is probably not in Notebook 3 format.")
1376 | if len(nb.worksheets) > 1:
1377 | raise NotImplementedError("Only one worksheet allowed in Notebook 2 format.")
1378 | nbcells = nb.worksheets[0].cells
1379 | else:
1380 | nbcells = nb.cells
1381 |
1382 | for cell_index, cell in enumerate(nbcells):
1383 | # add a default header, if not otherwise supplied
1384 | if cell_index==0:
1385 | if not 'raw' in cell.cell_type:
1386 | output += standardHeader
1387 | bibfile = 'bibliography.bib'
1388 | else:
1389 | bibfile = outfile.replace('.tex', '.bib')
1390 | print(f'bibfile is {bibfile}')
1391 |
1392 | # print('\n********','cell.cell_type ={} cell={}'.format(cell.cell_type,cell))
1393 | if cell.cell_type not in fnTableCell:
1394 | raise NotImplementedError("Unknown cell type: >{}<.".format(cell.cell_type))
1395 |
1396 | rtnString, rtnListing = fnTableCell[cell.cell_type](cell, cell_index, imagedir, infile, inlinelistings,addurlcommand)
1397 |
1398 | # remove the begin/end markers to protect latex special conversion
1399 | rtnString = re.sub(protectEvnStringStart,'',rtnString)
1400 | rtnString = re.sub(protectEvnStringEnd,'',rtnString)
1401 |
1402 | output += rtnString
1403 | listingsstring += rtnListing
1404 |
1405 | if len(listingsstring):
1406 | lstheader = '\n\n\chapter{Listings}\n\n' if not inlinelistings else ''
1407 | output += lstheader
1408 | output += listingsstring
1409 |
1410 | output += r'\atendofdoc'+'\n\n'
1411 |
1412 | output += r'\end{document}'+'\n\n'
1413 |
1414 | with io.open(outfile, 'w', encoding='utf-8') as f:
1415 | f.write(output)
1416 |
1417 | print('\nWriting bibtex file(s):')
1418 | if os.path.exists(bibfile):
1419 | os.remove(bibfile)
1420 | with io.open(bibfile, 'w', encoding='utf-8') as f:
1421 | filenames = []
1422 | if appendbibtex:
1423 | filenames = listFiles('.','*.bib',recurse=1)
1424 | # read any other bib files found in the root folder
1425 | if len(filenames)>0:
1426 | for filename in filenames:
1427 | if filename not in bibfile:
1428 | print(f' - appending contents from {filename} to {bibfile}')
1429 | with open(filename,'r') as fin:
1430 | lines = fin.read()
1431 | f.write(lines)
1432 |
1433 | #write the entries gathered from the notebook
1434 | if len(bibtexlist):
1435 | print(f' - writing contents from {bibfile}')
1436 | for bib in bibtexlist:
1437 | f.write(bib)
1438 |
1439 |
1440 |
1441 | ################################################################################
1442 | # here we get a list of all the input and outfiles
1443 | def getInfileNames(infile, outfile):
1444 |
1445 | infiles = []
1446 | outfiles = []
1447 |
1448 | if infile is not None:
1449 | if not infile.endswith(".ipynb"):
1450 | raise ValueError("Invalid notebook filename {}.".format(infile))
1451 |
1452 | if outfile is None:
1453 | outfile = infile.replace('.ipynb', '.tex')
1454 |
1455 | infiles.append(infile)
1456 | outfiles.append(outfile)
1457 |
1458 | else:
1459 | # no input filename supplied, get all
1460 | ipynbfiles = listFiles('.', patterns='*.ipynb', recurse=0, return_folders=0)
1461 | for ipynbfile in ipynbfiles:
1462 | ipynbfile = os.path.basename(ipynbfile)
1463 | infiles.append(ipynbfile)
1464 | outfiles.append(ipynbfile.replace('.ipynb', '.tex'))
1465 |
1466 |
1467 | return infiles, outfiles
1468 |
1469 | ################################################################
1470 | #lists the files in a directory and subdirectories
1471 | #this code is adapted from a recipe in the Python Cookbook
1472 | def listFiles(root, patterns='*', recurse=1, return_folders=0, useRegex=False):
1473 | """Lists the files/directories meeting specific requirement
1474 |
1475 | Returns a list of file paths to files in a file system, searching a
1476 | directory structure along the specified path, looking for files
1477 | that matches the glob pattern. If specified, the search will continue
1478 | into sub-directories. A list of matching names is returned. The
1479 | function supports a local or network reachable filesystem, but not URLs.
1480 |
1481 | Args:
1482 | | root (string): directory root from where the search must take place
1483 | | patterns (string): glob/regex pattern for filename matching. Multiple pattens
1484 | may be present, each one separated by ;
1485 | | recurse (unt): flag to indicate if subdirectories must also be searched (optional)
1486 | | return_folders (int): flag to indicate if folder names must also be returned (optional)
1487 | | useRegex (bool): flag to indicate if patterns areregular expression strings (optional)
1488 |
1489 | Returns:
1490 | | A list with matching file/directory names
1491 |
1492 | Raises:
1493 | | No exception is raised.
1494 | """
1495 | if useRegex:
1496 | import re
1497 |
1498 | # Expand patterns from semicolon-separated string to list
1499 | pattern_list = patterns.split(';')
1500 | filenames = []
1501 | filertn = []
1502 |
1503 | for dirpath,dirnames,files in os.walk(root):
1504 | if dirpath==root or recurse:
1505 | for filen in files:
1506 | # filenames.append(os.path.abspath(os.path.join(os.getcwd(),dirpath,filen)))
1507 | filenames.append(os.path.relpath(os.path.join(dirpath,filen)))
1508 | if return_folders:
1509 | for dirn in dirnames:
1510 | # filenames.append(os.path.abspath(os.path.join(os.getcwd(),dirpath,dirn)))
1511 | filenames.append(os.path.relpath(os.path.join(dirpath,dirn)))
1512 |
1513 | for name in filenames:
1514 | if return_folders or os.path.isfile(name):
1515 | for pattern in pattern_list:
1516 | if useRegex:
1517 | #search returns None is pattern not found
1518 | regex = re.compile(pattern)
1519 | if regex.search(name):
1520 | filertn.append(name)
1521 | break
1522 | else:
1523 | # split only the filename to compare, discard folder path
1524 | if fnmatch.fnmatch(os.path.basename(name), pattern):
1525 | filertn.append(name)
1526 | break
1527 | return filertn
1528 |
1529 | ################################################################################
1530 | ################################################################################
1531 | def main():
1532 | # args = docopt.docopt(__doc__)
1533 | args = docopt.docopt(docoptstring)
1534 |
1535 | # print(args)
1536 |
1537 | infile = args['']
1538 | outfile = args['']
1539 | imagedir = args['']
1540 | inlinelistings = args['-i']
1541 | addurlcommand = args['-u']
1542 | appendbibtex = args['-a']
1543 |
1544 | # find the image directory
1545 | imagedir = createImageDir(imagedir)
1546 |
1547 | # see if only one input file, or perhaps many
1548 | infiles, outfiles = getInfileNames(infile, outfile)
1549 |
1550 | #process the list of files found in spec
1551 | for infile, outfile in zip(infiles, outfiles):
1552 | processOneIPynbFile(infile, outfile, imagedir, inlinelistings, addurlcommand,appendbibtex)
1553 |
1554 | print('\nfini!')
1555 |
1556 | ###############################################################################
1557 | ################################################################################
1558 | if __name__ == "__main__":
1559 | main()
--------------------------------------------------------------------------------
/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NelisW/ipynb2tex/78598d4bc17a00286af24504b51e392b8e833175/logo.png
--------------------------------------------------------------------------------
/pic/.gitkeep:
--------------------------------------------------------------------------------
1 | This directory is where the images are written.
2 | We need this to force git to create the directory.
--------------------------------------------------------------------------------
/test2LaTeX.bib:
--------------------------------------------------------------------------------
1 | @MISC{gracec, author = {Grace Cathedral}, title = {The Cathedral Labyrinths}, url = {http://www.gracecathedral.org/labyrinth/}}
2 |
3 | @article{wing2006computational, title={Computational thinking}, author={Wing, Jeannette M}, journal={Communications of the ACM}, volume={49}, number={3}, pages={33--35}, year={2006}}
4 |
5 | @MISC{httpipythonorg,
6 | url = {http://ipython.org/}
7 | }
8 |
9 | @MISC{httpswwwyoutubecomwa00000,
10 | url = {https://www.youtube.com/watch?v=aIXED26Wppg}
11 | }
12 |
13 | @MISC{httppandaspydataorgp00001,
14 | url = {http://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.to_latex.html}
15 | }
16 |
17 | @MISC{httpsgithubcomJelteF00002,
18 | url = {https://github.com/JelteF/PyLaTeX/}
19 | }
20 |
21 | @MISC{httpsjeltefgithubioP00003,
22 | url = {https://jeltef.github.io/PyLaTeX/current/usage.html#the-classes}
23 | }
24 |
25 | @MISC{httpsenwikipediaorgw00004,
26 | url = {https://en.wikipedia.org/wiki/Wrapped_normal_distribution}
27 | }
28 |
29 |
--------------------------------------------------------------------------------
/test2LaTeX.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NelisW/ipynb2tex/78598d4bc17a00286af24504b51e392b8e833175/test2LaTeX.pdf
--------------------------------------------------------------------------------
/test2LaTeX.tex:
--------------------------------------------------------------------------------
1 |
2 | %This notebook demonstrates the use of the workpackage template, replace with your own.
3 |
4 | \documentclass[english]{workpackage}[1996/06/02]
5 |
6 | % input the common preamble content (required by the ipnb2latex converter)
7 | \input{header.tex}
8 |
9 | % the following three lines are required to support the tikz examples
10 | \usepackage{tikz}
11 | \usepackage{sansmath}
12 | \usetikzlibrary{shadings,intersections}
13 |
14 | % then follows the rest of the preamble to be placed before the begin document
15 | % this preamble content is special to the documentclass you defined above.
16 | \WPproject{My Project} % project name
17 | \WPequipment{Work package demonstrator} % equipment name
18 | \WPsubject{How to use the converter to create a work package} % main heading
19 | \WPconclusions{\begin{enumerate}
20 | \item This work package demonstrates the use of the converter.
21 | \item It was tested with and should work on Python 3.5 and up.
22 | \end{enumerate}}
23 | \WPclassification{Unclassified}
24 | \WPdocauthor{CJ Willers}
25 | \WPcurrentpackdate{\today}
26 | \WPcurrentpacknumber{0001} % work package number
27 | \WPdocnumber{} % this doc number hosts all the work packages
28 | \WPprevpackdate{} % work package which this one supersedes
29 | \WPprevpacknumber{} % work package which this one supersedes
30 | \WPsuperpackdate{} % work package which comes after this one
31 | \WPsuperpacknumber{} % work package which comes after this one
32 | \WPdocontractdetails{false}
33 | \WPcontractname{} % contract name
34 | \WPorderno{} % contract order number
35 | \WPmilestonenumber{} % contract milestone number
36 | \WPmilestonetitle{} % contract milestone title
37 | \WPcontractline{} % contract milestone line number
38 | \WPdocECPnumber{1234567} % ecp/ecr number
39 | \WPdistribution{
40 | %\vspace{0.1mm}
41 | %\begin{tabular}{lllll}
42 | %Name 1 & Name 12 & Name 3 & Name 4 & Name 5\\
43 | %Name 6 & Name 7 & \multicolumn{3}{l}{Master: some repo}\\
44 | %\end{tabular}
45 | }
46 |
47 | % bibfile added in this notebook
48 | %\addbibresource{./analyseRio.bib}
49 |
50 | % this is entered just before the end{document}
51 | \newcommand{\atendofdoc}{
52 | \bibliographystyle{IEEEtran}
53 | \bibliography{test2LaTeX}
54 | }
55 |
56 | %and finally the document begin.
57 | \begin{document}
58 | \WPlayout
59 |
60 |
61 | % some Latex code to be used verbatim
62 | \
63 | \vspace{50mm}
64 | \begin{center}
65 | \includegraphics[width=0.6\textwidth]{./images/keep-calm-and-code-python_BW.png}
66 | \end{center}
67 | \vspace{5mm}
68 | \begin{center}
69 | {\LARGE ipnb2tex}
70 | \end{center}
71 |
72 | \newpage
73 |
74 | \tableofcontents
75 | \listoffigures
76 | \listoftables
77 | \lstlistoflistings
78 |
79 |
80 |
81 | \chapter{The ipnb2tex.py Script}
82 | \label{sec:Theipnb2texpyScript}
83 |
84 |
85 | The \verb+ipnb2tex.py+ reads the IPython notebook and converts it to a \LaTeX{} set of files (a \verb+*.tex+ file and a number of images). The script is invoked as follows:
86 |
87 |
88 | \verb+python ipnb2tex.py file.ipynb file.tex imagedir -i -u -b+
89 |
90 |
91 | where
92 |
93 |
94 | \begin{itemize}
95 | \item \verb+file.ipynb+ [optional] is the name of the input IPython notebook file. If no input filename is supplied, all \verb+.ipynb+ files in current directory will be processed. In this event the output filenames will be the same as the \verb+.ipynb+ files, just with a \verb+tex+ filetype. The notebook filename must not have spaces.
96 | \item \verb+file.tex+ [optional] is the name of output \LaTeX{} file. If none is given the output filename will be the same as the input file, but with the \verb+.tex+ extension.
97 | \item \verb+imagedir+ [optional] is the directory where images are written to. If not given, this image directory will be the \verb+./pic+ directory.
98 | \item \verb+-i+ [optional], the lower case letter \verb+i+, if this option is given the code listings are printed inline with the body text where they occur, otherwise listings are floated to the end of the document.
99 | \item \verb+-u+ [optional] add \verb+\url{}+ to the bibtex entries, to obtain \verb+url = {\url{http://ipython.org/}}+, otherwise use the form
100 |
101 |
102 | \verb+url = {http://ipython.org/}+
103 | \item \verb+-b+ [optional] if given merge all the *.bib files in the folder root together. By default, don't merge all bibtex files, only use the \verb+file.bib+ file with the same name as the notebook file.
104 | \end{itemize}
105 |
106 | The options must follow after the filenames and dirname and the end of the command line string.
107 |
108 |
109 |
110 |
111 | \section{Known deficiencies}
112 | \label{sec:Knowndeficiencies}
113 |
114 | \begin{enumerate}
115 | \item Some complex cell-merged HTML tables may not render correctly in LaTeX (let me know if you have such a table).
116 | \item The following HTML elements are not currently processed, these elements are simply ignored: \verb+div+, \verb+img+.
117 | \item The \verb+iframe+ HTML element is tested for embedded PDF files which are then included as an image.
118 | \item Coloured text in HTML is not exported as coloured text in LaTeX.
119 | \item Many reserved LaTeX symbols such as hash, caret, underscore and dollar are 'legal' in normal markdown. When rendering to LaTeX these symbols cause errors unless escaped with backslash. In many cases these symbols are escaped, but not always because of context. If the symbols are escaped, they render incorrectly in normal Markdown. Therefore, choose your target renderer and enter the symbols accordingly, accepting problems in the alternative renderer.
120 | \end{enumerate}
121 |
122 |
123 |
124 | \chapter{Heading 1 nb2pdf}
125 | \label{sec:Heading1nb2pdf}
126 |
127 |
128 | Heading 1 is a \LaTeX{} chapter.
129 |
130 |
131 | Headings down to level 5 (\LaTeX{} paragraph) are supported.
132 | Headings at level 6 are treated as normal body text.
133 | If you don't need a chapter (i.e., for an article), just don't use a heading at level 1.
134 |
135 |
136 | When any level of section heading is formed, a label is automatically created from the text in the heading, removing all non-alpha characters. If the section heading is very long the the label will also be long, so keep it short. Also, don't use the same text twice as a heading.
137 |
138 |
139 |
140 |
141 | \section{Heading 2 Second-level heading}
142 | \label{sec:Heading2Secondlevelheading}
143 |
144 |
145 |
146 | \subsection{Heading 3}
147 | \label{sec:Heading3}
148 |
149 |
150 |
151 | \subsubsection{Heading 4}
152 | \label{sec:Heading4}
153 |
154 |
155 |
156 | \paragraph{Heading 5}
157 | \label{sec:Heading5}
158 |
159 |
160 |
161 | \subparagraph{Heading 6}
162 | \label{sec:Heading6}
163 |
164 |
165 | some more markdown.
166 |
167 |
168 |
169 |
170 | \chapter{Heading X}
171 | \label{sec:HeadingX}
172 |
173 |
174 | \section{Heading X2}
175 | \label{sec:HeadingX2}
176 |
177 |
178 | \subsection{Heading X3}
179 | \label{sec:HeadingX3}
180 |
181 |
182 | \subsubsection{Heading X4}
183 | \label{sec:HeadingX4}
184 |
185 |
186 | \paragraph{Heading X5}
187 | \label{sec:HeadingX5}
188 |
189 |
190 | \subparagraph{Heading X6}
191 | \label{sec:HeadingX6}
192 |
193 |
194 |
195 | \section{LaTeX Template Format and the Header File}
196 | \label{sec:LaTeXTemplateFormatandtheHeaderFile}
197 |
198 |
199 |
200 | \subsection{Default Style (Report)}
201 | \label{sec:DefaultStyleReport}
202 |
203 |
204 | The notebook can be converted to the LaTeX \verb+Report+ format with no additional files or document class. A 'standard' notebook, where the first cell is not \verb+Raw NBConvert+ will be prepended with a short section of LaTeX code for a standard LaTeX Report. A number of pacakges are also \verb+\usepackage{}+ed, as required by the converted LaTeX code.
205 |
206 |
207 |
208 |
209 | \subsection{User-Defined Style}
210 | \label{sec:UserDefinedStyle}
211 |
212 |
213 | The notebook can optionally be converted to a user-defined format with minimal effort. The example files included the GitHub distribution provides a 'work package' format class file (\verb+workpackage.cls+) and a header file (\verb+header.tex+).
214 |
215 |
216 | The first cell of the notebook must be a \verb+RawNBConvert+ cell with at least the following contents (see the first cell of this notebook for an example):
217 |
218 |
219 | \begin{verbatim}
220 | \documentclass that you want to use
221 | \input{header.tex}
222 | whatever preamble lines you require
223 | \begin{document}
224 | \end{verbatim}
225 |
226 |
227 | Then follows whatever content you need to use your document style, e.g., font style. Write/change this file to change the front matter and appearance of the document. The script adds the \verb+\end{document}+ line after the notebook cells' contents.
228 |
229 |
230 | The \verb+header.tex+ file provides the functionality required by the converter-created code. This content is input using the \LaTeX{} input command. A number of pacakges are \verb+\usepackage{}+ed, as required by the converted LaTeX code.
231 |
232 |
233 |
234 |
235 | \section{Company Logo}
236 | \label{sec:CompanyLogo}
237 |
238 |
239 | The work package template has a \verb+logo.png+ file which is used to define a logo on top of the page. The present image is empty, so no logo will show. You can add your own logo to this file.
240 |
241 |
242 |
243 |
244 | \section{The images directory}
245 | \label{sec:Theimagesdirectory}
246 |
247 |
248 | The script saves the png files in the \verb+./pic+ directory, and the \LaTeX{} code also expects to find the png files there. Hence, there must be an existing \verb+./pic+ directory in the directory where you run the script. If an alternative name is given on the command line, the alternative name will be used.
249 |
250 |
251 |
252 |
253 | \section{Using Python code}
254 | \label{sec:UsingPythoncode}
255 |
256 |
257 |
258 |
259 | See Listing~\ref{lst:listing1} for the code to prepare the environment.
260 |
261 |
262 | \begin{lstlisting}[style=outcellstyle,caption={Caption for first listing output \label{lst:listing1-out}}]
263 | The Zen of Python, by Tim Peters
264 |
265 | Beautiful is better than ugly.
266 | Explicit is better than implicit.
267 | Simple is better than complex.
268 | Complex is better than complicated.
269 | Flat is better than nested.
270 | Sparse is better than dense.
271 | Readability counts.
272 | Special cases aren't special enough to break the rules.
273 | Although practicality beats purity.
274 | Errors should never pass silently.
275 | Unless explicitly silenced.
276 | In the face of ambiguity, refuse the temptation to guess.
277 | There should be one-- and preferably only one --obvious way to do it.
278 | Although that way may not be obvious at first unless you're Dutch.
279 | Now is better than never.
280 | Although never is often better than *right* now.
281 | If the implementation is hard to explain, it's a bad idea.
282 | If the implementation is easy to explain, it may be a good idea.
283 | Namespaces are one honking great idea -- let's do more of those!
284 |
285 | \end{lstlisting}
286 |
287 |
288 | The following code block has the metadata
289 |
290 |
291 | \begin{verbatim}
292 | {
293 | "listingCaption": {
294 | "caption": "Caption text for second listing",
295 | "label": "lst:listing2"
296 | }
297 | }
298 | \end{verbatim}
299 |
300 |
301 | which will give the code block a caption and a label, but the output is not captioned.
302 |
303 |
304 | The code block also demonstrates how long lines are handled in this lstlistings configuration, with a linefeed symbol to mark the line.
305 |
306 |
307 | The output of the following cell is captured in a floating listing that can be referenced. The metadata is as follows:
308 |
309 |
310 | \begin{verbatim}
311 | {
312 | "listingCaption": {
313 | "caption": "Caption text for second listing",
314 | "label": "lst:listingrad",
315 | "outputCaption": "Output caption text for second listing"
316 | }
317 | }
318 | \end{verbatim}
319 |
320 |
321 | If the meta data has an \verb+entry and a+ entry the
322 |
323 |
324 |
325 |
326 | \begin{lstlisting}[style=outcellstyle,caption={Output caption text for second listing \label{lst:listingrad-out}}]
327 |
328 | Radius = 6
329 | Frontal area = 7 m2
330 | This is a very long line of python code, that is supposed to flow over to the next line, in order to test the listing display
331 |
332 | \end{lstlisting}
333 |
334 |
335 |
336 |
337 | See Listing~\ref{lst:listing3} for the code to print the value.
338 |
339 |
340 | \begin{lstlisting}[style=outcellstyle]
341 | a
342 | b
343 |
344 | \end{lstlisting}
345 |
346 |
347 |
348 | \begin{lstlisting}[style=outcellstyle]
349 | 0
350 | 1
351 |
352 | \end{lstlisting}
353 |
354 |
355 | The following code block has no metadata, and hence no captions on either the code or the output listings.
356 |
357 |
358 |
359 |
360 |
361 | See Listing~\ref{lst:autolistingcell30} for the code.
362 |
363 |
364 | \begin{lstlisting}[style=outcellstyle]
365 | code with no listing caption
366 |
367 | \end{lstlisting}
368 |
369 |
370 | Output emanating from different cells \textit{may} result in different output listings in \LaTeX{} even if they appear in a single output box in the notebook. The cells below attempt to recreate a similar scenario in a different application, but it does not seem to repeat the problem here.
371 |
372 |
373 |
374 |
375 |
376 | See Listing~\ref{lst:autolistingcell32} for the code.
377 |
378 |
379 |
380 | See Listing~\ref{lst:autolistingcell33} for the code.
381 |
382 |
383 | \begin{lstlisting}[style=outcellstyle]
384 | function output 1
385 | function output 2
386 | function output 3
387 | 9
388 | 3
389 |
390 | \end{lstlisting}
391 |
392 |
393 |
394 | \section{Raw NBConvert cells}
395 | \label{sec:RawNBConvertcells}
396 |
397 | The \verb+Raw NBConvert+ cell type can be used to propagate text without any modification to the output stream. The IPython notebook will not touch this text; it is passed on as-is to the converter code. This this case we can add \LaTeX{} code that will progress straight through to the \LaTeX{} compiler.
398 |
399 |
400 | This raw capability is very useful if the notebook is intended to be exported to \LaTeX{} as primary output. I find myself writing most of such documentation in raw latex in a 'Raw NBConvert' cell. In this mode most of the notebook cells are never rendered to HTML, since you are reading and editing the \LaTeX{} and it stays in \LaTeX{} for display purposes as well. So you get the full benefit of all \LaTeX{} functionality (except that it is not rendered inside the notebook) and all the other benefits of the notebook.
401 |
402 |
403 |
404 | Raw NBConvert cell. This could be raw \LaTeX{} as in
405 |
406 | \begin{equation}
407 | f_{WN}(\theta;\mu, \sigma) = \frac{1}{\sigma\sqrt{2\pi}}\sum^\infty_{k=-\infty} \exp\left[\frac{-(\theta-\mu+2\pi k)^2}{2\sigma^2}\right]
408 | \end{equation}
409 |
410 |
411 | \section{Captions}
412 | \label{sec:Captions}
413 |
414 | There are three objects that can have captions: listings, figures and tables.
415 |
416 |
417 | Figures and tables without captions are non-floating and appear in the text at the position it is found in the input file. Figures and tables with captions are floating.
418 |
419 |
420 | Listings are normally non-floating but can be floated (see below).
421 |
422 |
423 | A single cell can contain any combination of captions, and these are indicated in the metadata field of the cell.
424 | It seems that the means to access the metadata changes with every new release. Try one of the following:
425 |
426 |
427 | \begin{enumerate}
428 | \item Select the \verb+Edit Metadata+ drop-down option in the \verb+Cell Toolbar+ drop-down box (towards the right of the toolbar). This should expose metadata buttons on all the cells. Click on the button and type in the metadata.
429 | \item On the left panel click on the Property Inspector (gear icon) and open the \verb+Advanced Tools+ drop-down to expose the \verb+Cell Metadata+ text box.
430 | \end{enumerate}
431 |
432 | Enter the meta data into the text box. Ensure that the tabs and commas are all in the right places: if so, a small tick mark will appear for you to approve the new metadata, by clicking on the tick mark. If the tabs and commas are not exactly right, the text box boundary will be red (error) and the tick mark will not be shown.
433 | If the json structure has no errors, a tick mark will appear: click on the tick mark to save the changes (as long as there are errors you cannot save).
434 |
435 |
436 | The metadata has the following structure:
437 |
438 |
439 | \begin{verbatim}
440 | {
441 | "listingCaption": {
442 | "caption": "Comparison of effective drag parameters",
443 | "label": "lst:comparedrag",
444 | "outputCaption": ""
445 | },
446 | "figureCaption": {
447 | "caption": "Caption text for first figure",
448 | "label": "fig:lab1",
449 | "width": "0.2",
450 | "locator": "t"
451 | },
452 | "tableCaption": {
453 | "caption": "Caption text for first table",
454 | "label": "tab:lab1",
455 | "format": "{|p{10mm}|l|r|c|c|p{50mm}|p{20mm}|}",
456 | "fontsize": "normalsize",
457 | "locator": "t"
458 | }
459 | }
460 | \end{verbatim}
461 |
462 |
463 | Note the placement of commas. No newlines are allowed in a single string in the metadata.
464 |
465 |
466 |
467 |
468 | \section{Python code}
469 | \label{sec:Pythoncode}
470 |
471 | Python code blocks are printed using the \LaTeX{} \verb+listings+ package. The format details can be defined in the header template file. These code listings can be supplied with a caption and a label (but these code blocks are not floating entities).
472 |
473 |
474 | \begin{verbatim}
475 | {
476 | "listingCaption": {
477 | "caption": "Caption text for first listing",
478 | "label": "lst:listing1",
479 | "outputCaption": "Caption for first listing output"
480 | }
481 | }
482 | \end{verbatim}
483 |
484 |
485 | where the different fields have the following meanings:
486 |
487 |
488 | \begin{enumerate}
489 | \item \verb+caption+ specifies the text to be used in the listings caption. If this metadata field is not supplied, the listing will not be given a caption.
490 | \item \verb+label+ specifies the label to be used for the listing, which can be used in \LaTeX{} to reference the listing. The code block uses the label exactly as given in the metadata field. If the output listing is given an \verb+outputCaption+, the output caption is labelled by the a label starting with the \verb+label+ string given, but appended with the string \verb+-out+ (i.e., \verb+lst:listing1-out+ in this case).
491 | \item \verb+outputCaption+ specifies the label that is used for the output listing of the cell. If this metadata field is not supplied, the output listing will not be given a caption.
492 | \item Both the cell listing and the output listing share the same root label, but the output listing has \verb+-out+ appended to it.
493 | \end{enumerate}
494 |
495 | We can refer to Listings~\ref{lst:listing1}, \ref{lst:listingrad-out}, \ref{lst:listingrad}, and \ref{lst:listing3}.
496 |
497 |
498 | The default is to provide colour syntax highlighting. If you don't want colour in the listings, simply remove these lines from \verb+header.tex+
499 |
500 |
501 | \begin{verbatim}
502 | commentstyle=\color{mygreen}, \% comment style
503 | keywordstyle=\color{blue}, \% keyword style
504 | stringstyle=\color{mymauve}, \% string literal style
505 | \end{verbatim}
506 |
507 |
508 |
509 |
510 | \section{Floated code listings}
511 | \label{sec:Floatedcodelistings}
512 |
513 | In order to improve readability in the document, the code listings can be floated to the end of the document by using the \verb+-l+ switch on the command line. If this switch is used, the listing is appended to the \LaTeX{} document and the end of the conversion. At the location in the document where the code listing would have been, a reference sentence to the code is included. The sentence is constructed as follows:
514 |
515 |
516 | \verb+See Listing~\ref{lst:autolistingcellX} for the code {purpose}.+
517 |
518 |
519 | where the symbolic link is constructed using the cell number and the text used in the \verb+{purpose}+ part is taken from the first line of the code, if the first line is a comment with a single \verb+#+ followed by a space. Hence if the code in cell 3 starts with the lines
520 |
521 |
522 | \begin{verbatim}
523 | # to prepare the environment
524 | import numpy as np
525 | \end{verbatim}
526 |
527 |
528 | a text line of the following form will be created:
529 |
530 |
531 | \verb+See Listing~\ref{lst:autolistingcell3} for the code to prepare the environment.+
532 |
533 |
534 | Just maintain the discipline to write good comments in the first line, keeping in mind that the comment will end up in the body of the document with the reference.
535 |
536 |
537 | If a code cell does not start with a comment, no text will be inserted and the form will be
538 |
539 |
540 | \verb+See Listing~\ref{lst:autolistingcell24} for the code.+
541 |
542 |
543 | If the code cell starts with a comment of the form \verb+##+, the listing will output to the tex file, but there is no text entry in the location where the code cell was. i.e., no line starting with \verb+See Listing+...
544 |
545 |
546 | If the code cell starts with a comment of the form \verb+###+, neither the listing nor the text entry referring to it is written to the latex file. So if you don't want the code to be shown or a reference to it made, start the first code line with \verb+###+.
547 |
548 |
549 |
550 |
551 | \section{Figure captions and bitmaps}
552 | \label{sec:Figurecaptionsandbitmaps}
553 |
554 |
555 | PNG images, read in from externally or created by Matplotlib, are imported into the \LaTeX{} code with lines of the following form:
556 |
557 |
558 | \verb+\includegraphics[width=WIDTH\textwidth]{./pngs/test2LaTeX\_21\_0.png}+
559 |
560 |
561 | where the WIDTH determines the size of the image (obtained from metadata, see below), and the image file name is constructed from the notebook file name and cell information. The name is the concatenation of the notebook file name, the cell index (index number of the cell in the notebook file) and the sub-index image in the cell's output (there can be more than one image). All indices are zero based.
562 |
563 |
564 | The width is read from the metadata, which must be structured as follows:
565 |
566 |
567 | \begin{verbatim}
568 | {
569 | "figureCaption": {
570 | "caption": "Caption text for first figure",
571 | "label": "fig:lab1",
572 | "width": "0.2",
573 | "locator": "t"
574 | },
575 | "listingCaption": {
576 | "caption": "Listing caption in cell with a figure",
577 | "label": "lst:figurelisting",
578 | "outputCaption": "Output for a cell with a figure"
579 | }
580 | }
581 | \end{verbatim}
582 |
583 |
584 | Width is the fraction of \LaTeX{} textwidth, i.e., if width=1, the graphic will be the full width of the text on the page.
585 |
586 |
587 | The locator value is used in \verb+\begin{figure}[tb]+ or \verb+\begin{table}[tb]+ to locate the float on the page. Default value is 'tb', can be any combination of \verb+tbhp+.
588 |
589 |
590 | The metadata also contains a caption string, and a label for the figure. The type must be \verb+figure+.
591 |
592 |
593 | If the \verb+caption+ field is given (or has non-zero length), the image will be written to a \LaTeX{} float with a caption (and label). If the \verb+caption+ fields is not given, the image will not be encapsulated in the floating figure.
594 |
595 |
596 |
597 | If the caption string contains a substring \verb+(###)+ the substring will be replaced with the figure index (plus one) for the current cell. Hence, if there are multiple figures in the same cell, they can all use the same caption with with a running number, such as (1), (2), etc.
598 |
599 |
600 |
601 | Latex special characters in the caption strings must be properly escaped as per standard LaTeX use, it is not translated or manipulated in any way. For example, underscore \verb`_` must be escaped.
602 | However, keep in mind that JSON requires backslash to be escaped itself as a double backslash in order to survive the JSON parser. So if \verb`_` is required in the final document, it must be \verb`\\_` in the caption string. For exanple \verb`a\\_a\\_a b\\#b\\%b` in the JSON metadata becomes \verb`a_a_a b#b%b` in the final \LaTeX{} caption, as shown in Figure~\ref{fig:lab1}.
603 |
604 |
605 |
606 | See Listing~\ref{lst:figurelisting} for the code this figure is given meta data caption parameters, it will be floated in the latex export.
607 |
608 | {
609 |
610 | \begin{figure}[tb]
611 | \centering
612 |
613 | \begin{normalsize}
614 | \includegraphics[width=0.2\textwidth, angle=0]{./pic/test2LaTeX_43_0.png}
615 | \end{normalsize}
616 | \caption{Caption text for first figure, having a\_a\_a b\#b\%b\label{fig:lab1-0}\label{fig:lab1}}
617 | \end{figure}
618 |
619 | }
620 |
621 |
622 | \begin{lstlisting}[style=outcellstyle,caption={Output for a cell with a figure \label{lst:figurelisting-out}}]
623 | also force print output
624 |
625 | \end{lstlisting}
626 |
627 |
628 | Experimenting with embedded markdown images:
629 |
630 |
631 | \begin{center}
632 | \includegraphics[width=0.9\textwidth, angle=0]{./images/keep-calm-and-code-python_BW.png}
633 | \end{center}
634 |
635 |
636 |
637 | The following figure is not floating, but with narrower width.
638 |
639 |
640 | \begin{verbatim}
641 | {
642 | "figureCaption": {
643 | "width": "0.3"
644 | }
645 | }
646 | \end{verbatim}
647 |
648 |
649 |
650 |
651 |
652 | See Listing~\ref{lst:autolistingcell46} for the code this figure is not given meta data caption parameters, it will be inlined in the latex export.
653 |
654 | \begin{center}
655 | \includegraphics[width=0.9\textwidth, angle=0]{./pic/test2LaTeX_46_0.png}
656 | \end{center}
657 | The following Matplotlib plot is scaled to 40\% of text width and floating, but with the 'h' locator to force the location to here.
658 |
659 |
660 | \begin{verbatim}
661 | {
662 | "figureCaption": {
663 | "caption": "Caption text for third figure",
664 | "label": "fig:lab3",
665 | "width": "0.4",
666 | "locator": "h"
667 | }
668 | }
669 | \end{verbatim}
670 |
671 |
672 |
673 | {
674 |
675 | \begin{figure}[tpbh]
676 | \centering
677 |
678 | \begin{normalsize}
679 | \includegraphics[width=0.4\textwidth, angle=0]{./pic/test2LaTeX_48_0.png}
680 | \end{normalsize}
681 | \caption{Caption text for third figure\label{fig:lab3-0}\label{fig:lab3}}
682 | \end{figure}
683 |
684 | }
685 |
686 | \FloatBarrier
687 |
688 | JSON does not seem to like backslashes, so math embedded in the figure caption must be escaped with two backslashes, as shown in Figure~\ref{fig:lab3math}.
689 |
690 |
691 |
692 | \begin{lstlisting}
693 | {
694 | "figureCaption": {
695 | "caption": "Caption with math $\\pi$ $\\beta$, $\\rho$",
696 | "label": "fig:lab3math",
697 | "locator": "h",
698 | "width": "0.4"
699 | }
700 | }
701 | \end{lstlisting}
702 |
703 |
704 | {
705 |
706 | \begin{figure}[tbph]
707 | \centering
708 |
709 | \begin{normalsize}
710 | \includegraphics[width=0.4\textwidth, angle=0]{./pic/test2LaTeX_52_0.png}
711 | \end{normalsize}
712 | \caption{Caption with math $\pi$ $\beta$, $\rho$\label{fig:lab3math-0}\label{fig:lab3math}}
713 | \end{figure}
714 |
715 | }
716 |
717 | It is possible to have more than one plot in a single cell output. In this case each output can be made floating separately or be non-floated (you can even mix floating and non-floating). The captions are given in the metadata in the following format:
718 |
719 |
720 | \begin{verbatim}
721 | {
722 | "figureCaption": {
723 | "caption": "['Caption text for (first) fourth figure','',
724 | 'Caption text for (third) fourth figure']",
725 | "label": "fig:lab4",
726 | "width": "[0.5, 0.5, 0.5]"
727 | }
728 | }
729 | \end{verbatim}
730 |
731 |
732 | In this case the caption strings and scaling values are allocated to the sequence of images in the order given. If a caption string is zero length, that specific image will be non-floating (as in the example of instance \verb+b+ here).
733 |
734 |
735 | The float labels are determined from the root value given in the metadata, but with the output sub-index appended, as in \verb+fig:lab4-0+, \verb+fig:lab4-1+, \verb+fig:lab4-2+.
736 |
737 |
738 | The first image in a cell has two labels \verb+fig:lab4-0+ and \verb+fig:lab4+ (without the zero) so either form can be used.
739 | If you only have one figure in a cell there is no need to add the \verb+-0+. There two references should be the same:
740 | \ref{fig:lab4-0} and \ref{fig:lab4} because they are both attached to the first figure in the cell.
741 |
742 |
743 |
744 |
745 |
746 | See Listing~\ref{lst:autolistingcell54} for the code.
747 |
748 | {
749 |
750 | \begin{figure}[tb]
751 | \centering
752 |
753 | \begin{normalsize}
754 | \includegraphics[width=0.4\textwidth, angle=0]{./pic/test2LaTeX_54_0.png}
755 | \end{normalsize}
756 | \caption{Caption text for (first) fourth figure\label{fig:lab4-0}\label{fig:lab4}}
757 | \end{figure}
758 |
759 | }
760 |
761 | \begin{center}
762 | \includegraphics[width=0.9\textwidth, angle=0]{./pic/test2LaTeX_54_1.png}
763 | \end{center}
764 | {
765 |
766 | \begin{figure}[tb]
767 | \centering
768 |
769 | \begin{normalsize}
770 | \includegraphics[width=0.5\textwidth, angle=0]{./pic/test2LaTeX_54_2.png}
771 | \end{normalsize}
772 | \caption{Caption text for (third) fourth figure\label{fig:lab4-2}}
773 | \end{figure}
774 |
775 | }
776 |
777 | To use mathematics in cells with two outputs as in the following code, the backslashes must be escaped as for a single caption, but the strings in the list must also be marked as raw strings as in \verb+r'string'+
778 |
779 |
780 |
781 | \begin{lstlisting}
782 | {
783 | "figureCaption": {
784 | "caption": "[r'Caption text for $\\alpha$ figure',r'Caption text for $\\beta$ figure']",
785 | "label": "fig:lab4alpha",
786 | "width": "[0.3, 0.5]"
787 | }
788 | }
789 | \end{lstlisting}
790 |
791 |
792 |
793 |
794 | See Listing~\ref{lst:autolistingcell57} for the code.
795 |
796 | {
797 |
798 | \begin{figure}[tb]
799 | \centering
800 |
801 | \begin{normalsize}
802 | \includegraphics[width=0.3\textwidth, angle=0]{./pic/test2LaTeX_57_0.png}
803 | \end{normalsize}
804 | \caption{Caption text for $\alpha$ figure\label{fig:lab4alpha-0}\label{fig:lab4alpha}}
805 | \end{figure}
806 |
807 | }
808 |
809 | {
810 |
811 | \begin{figure}[tb]
812 | \centering
813 |
814 | \begin{normalsize}
815 | \includegraphics[width=0.5\textwidth, angle=0]{./pic/test2LaTeX_57_1.png}
816 | \end{normalsize}
817 | \caption{Caption text for $\beta$ figure\label{fig:lab4alpha-1}}
818 | \end{figure}
819 |
820 | }
821 |
822 | \clearpage
823 |
824 | Multiple pictures in the same cell can share the same caption, appended with (1), (2), etc.
825 | Use the substring \verb+(###)+ as a placeholder to be replaced with the running count number.
826 |
827 |
828 |
829 |
830 |
831 | See Listing~\ref{lst:autolistingcell60} for the code.
832 |
833 | {
834 |
835 | \begin{figure}[tbp]
836 | \centering
837 |
838 | \begin{normalsize}
839 | \includegraphics[width=0.2\textwidth, angle=0]{./pic/test2LaTeX_60_0.png}
840 | \end{normalsize}
841 | \caption{Shared caption (1)\label{fig:sharedcap-0}\label{fig:sharedcap}}
842 | \end{figure}
843 |
844 | }
845 |
846 | {
847 |
848 | \begin{figure}[tbp]
849 | \centering
850 |
851 | \begin{normalsize}
852 | \includegraphics[width=0.2\textwidth, angle=0]{./pic/test2LaTeX_60_1.png}
853 | \end{normalsize}
854 | \caption{Shared caption (2)\label{fig:sharedcap-1}}
855 | \end{figure}
856 |
857 | }
858 |
859 | {
860 |
861 | \begin{figure}[tbp]
862 | \centering
863 |
864 | \begin{normalsize}
865 | \includegraphics[width=0.2\textwidth, angle=0]{./pic/test2LaTeX_60_2.png}
866 | \end{normalsize}
867 | \caption{Shared caption (3)\label{fig:sharedcap-2}}
868 | \end{figure}
869 |
870 | }
871 |
872 | \FloatBarrier % message to latex, no floats past this barrier
873 |
874 |
875 | You can write HTML to the cell's output and have it displayed in the browser and also in the LaTeX file.
876 |
877 |
878 |
879 |
880 |
881 | See Listing~\ref{lst:autolistingcell63} for the code.
882 |
883 | \begin{center}
884 | \includegraphics[width=0.9\textwidth, angle=0]{./images/flow2-zzz.png}
885 | \end{center}
886 |
887 |
888 |
889 |
890 | There might be a picture before this text if the HTML pictures are exporting :-)
891 |
892 |
893 |
894 | Experimenting with embedded markdown images. The figures should be
895 | Figure~\ref{fig:keepcalm-0} and
896 | Figure~\ref{fig:keepcalm-1}.
897 |
898 |
899 | {
900 |
901 | \begin{figure}[t]
902 | \centering
903 |
904 | \begin{normalsize}
905 | \includegraphics[width=0.1\textwidth, angle=0]{./images/keep-calm-and-code-python_BW.png}
906 | \end{normalsize}
907 | \caption{Keep calm 1\label{fig:keepcalm-0}\label{fig:keepcalm}}
908 | \end{figure}
909 |
910 | }
911 |
912 |
913 | {
914 |
915 | \begin{figure}[t]
916 | \centering
917 |
918 | \begin{normalsize}
919 | \includegraphics[width=0.2\textwidth, angle=0]{./images/random-squares-2.png}
920 | \end{normalsize}
921 | \caption{Keep calm 2\label{fig:keepcalm-1}}
922 | \end{figure}
923 |
924 | }
925 |
926 |
927 |
928 |
929 | \section{Graphs as PDF documents}
930 | \label{sec:GraphsasPDFdocuments}
931 |
932 |
933 | Reports with many png images tends to create large PDF files. If the graphs are exported as PDF files by the backend, the files are vector graphics and not large bitmaps, resulting in a much smaller final PDF report file.
934 |
935 |
936 | The PDF export functionality worked well in brief testing, but it still needs more testing.
937 |
938 |
939 | \begin{enumerate}
940 | \item Set up the notebook to use the PDF backend:
941 | \%config InlineBackend.figure\_format = 'pdf'
942 | \item With the PDF backend the graphs are saved as PDF documents in the notebook. This converter script will export these as PDF files to the pictures directory.
943 | \item Compile the document with PDFLaTeX as usual. It will look for the graphics files as PDF files, not PNG files.
944 | \end{enumerate}
945 |
946 |
947 |
948 | \section{Embedded PDF documents}
949 | \label{sec:EmbeddedPDFdocuments}
950 |
951 | You can embed a PDF file in a notebook for display in the notebook with the following:
952 |
953 |
954 | \begin{verbatim}
955 | from IPython.display import IFrame
956 | IFrame("./images/discretestrata01.pdf", width=600, height=300)
957 | IFrame("./images/Bankedturn.pdf", width=600, height=300)
958 | \end{verbatim}
959 |
960 |
961 | This currently does not work in Chrome, but it does work in Firefox, provided you set the browser to open PDF files in the browser and not download the files.
962 |
963 |
964 | The above code displays only the second iframe in the browser, it seems to overwrite the first.
965 |
966 |
967 | The converter will export both of the above PDF filenames for display in the latex document.
968 |
969 |
970 |
971 | {
972 |
973 | \begin{figure}[tbp]
974 | \centering
975 |
976 | \begin{normalsize}
977 | \includegraphics[width=0.5\textwidth, angle=0]{./images/discretestrata01.pdf}
978 | \end{normalsize}
979 | \caption{Stratified atmosphere\label{fig:templabel-0}\label{fig:templabel}}
980 | \end{figure}
981 |
982 | }
983 |
984 | {
985 |
986 | \begin{figure}[tbp]
987 | \centering
988 |
989 | \begin{normalsize}
990 | \includegraphics[width=0.5\textwidth, angle=0]{./images/Bankedturn.pdf}
991 | \end{normalsize}
992 | \caption{Banked turn\label{fig:templabel-1}}
993 | \end{figure}
994 |
995 | }
996 |
997 |
998 |
999 |
1000 | \section{Cells with Python errors}
1001 | \label{sec:CellswithPythonerrors}
1002 |
1003 |
1004 | The following line must be uncommented to have effect.
1005 |
1006 |
1007 |
1008 |
1009 |
1010 | See Listing~\ref{lst:autolistingcell72} for the code type(eval("this is a test string")) is not list.
1011 |
1012 |
1013 | \section{Embedded code (verbatim text)}
1014 | \label{sec:Embeddedcodeverbatimtext}
1015 |
1016 |
1017 | Some firewalls are set up to grant \verb+localhost+ execution rights. In this case the server can be started with the command
1018 |
1019 |
1020 | \verb+ipython notebook --ip=localhost+
1021 |
1022 |
1023 | Once started, the pages are served from
1024 |
1025 |
1026 | \verb+http://localhost:8888/+
1027 |
1028 |
1029 | and not from \verb+http://127.0.0.1:8888/+.
1030 |
1031 |
1032 | Embedded code meant for illustration instead of execution in Python:
1033 |
1034 |
1035 | \begin{verbatim}
1036 | def hello\_ipython():
1037 | print "Hello IPython!"
1038 | \end{verbatim}
1039 |
1040 |
1041 |
1042 |
1043 | \section{Hyperlinks, references and citations}
1044 | \label{sec:Hyperlinksreferencesandcitations}
1045 |
1046 |
1047 |
1048 | \subsection{Embedded hyperlinks}
1049 | \label{sec:Embeddedhyperlinks}
1050 |
1051 | The IPython website\cite{httpipythonorg} is the central repository of all things IPython.
1052 | There are some really nice videos\cite{httpswwwyoutubecomwa00000} on YouTube.
1053 |
1054 |
1055 | For \textit{URI references}, the \verb+[IPython website](http://ipython.org/)+ markup structure is read and the URI is used to create a citation label (\verb+httpipythonorg+) and the URI (\verb+http://ipython.org/+) is written to a new \LaTeX{} bibtex file for the references in this notebook.
1056 |
1057 |
1058 | For \textit{other types of references} a workaround is required. IPython is currently weak in the area of other types of references, because of limitations in the markup language. The \verb+ipnb2tex.py+ script makes provision for including bibtex entries, by embedding the complete bibtex entry in a metadata field.
1059 |
1060 |
1061 | Using the above approach creates a new bibtex file using the data in the notebook. Perhaps you might want to reference an existing bibtex file, mapping to the citation labels used in the notebook.
1062 | The issue here is that the IPython notebook does not have access to your \LaTeX{} bibtex file, so it does not know the citation references you want to use (the ones in your existing bibtex file).
1063 |
1064 |
1065 | The approach taken here is to provide a look-up translation table in this or any prior cell of the notebook, to translate citation references from the local name to your existing bibtex name. This is done in a cross reference dictionary that maps the names created internally to the names in your external bibtex file.
1066 |
1067 |
1068 | The metadata has two different fields, one to do the citation label mapping and the other to embed complete bibtex entries in the metadata. The metadata field must have the following format:
1069 |
1070 |
1071 | \begin{verbatim}
1072 | {
1073 | "bibxref": {
1074 | "httpipythonorg": "httpipythonorg",
1075 | "httpswwwyoutubecomwatchvaIXED26Wppg": "httpswwwyoutubecomwatchvaIXED26Wppg",
1076 | "httpsenwikipediaorgwikiWrappednormaldistribution":
1077 | "httpsenwikipediaorgwikiWrappednormaldistribution"
1078 | },
1079 | "bibtexentry": {
1080 | "wing2006computational": "@article{wing2006computational, title={Computational thinking},
1081 | author={Wing, Jeannette M}, journal={Communications of the ACM}, volume={49},
1082 | number={3}, pages={33--35}, year={2006}}",
1083 | "gracec": "@MISC{gracec, author = {Grace Cathedral}, title = {The Cathedral Labyrinths},
1084 | url = {http://www.gracecathedral.org/labyrinth/}}"
1085 | }
1086 | }
1087 | \end{verbatim}
1088 |
1089 |
1090 | where (1) the bibxref keys are the local names and the values are the names in your existing bibtex file and (2) the bibtexentry keys are the citation labels used in the notebook. In the above example the bibxref maps to the same names, because I am using the locally generated bibtex file. Normally you would use your bibtex database entries.
1091 |
1092 |
1093 | Note that the IPython notebook is somewhat finicky on the json format; each single entry in the above metadata must be on a single line (line-feeds inside the strings are not allowed --- lines tend to be very long). Also, note the location of commas, there should be commas after all entries, except the last entry in a given scope.
1094 |
1095 |
1096 | The \verb+ipnb2tex.py+ script:
1097 |
1098 |
1099 | \begin{enumerate}
1100 | \item Loads/appends the bibxref translation table from any/all cells (if present).
1101 | \item Reads the \verb+[]()+ markup structure and then builds a citation reference from the URI (by removing some characters).
1102 | \item Create a bibtex entry for the reference (subsequently written to file).
1103 | \item Using bibxref, translates the local citation label to your existing citation label.
1104 | \end{enumerate}
1105 |
1106 | If you included bibtex items in the metadata, you can refer to them using the normal \LaTeX{} notation. Test \cite{wing2006computational} and \cite{gracec}.
1107 |
1108 |
1109 | At the conclusion of the processing the script reads all existing \verb+*.bib+ files in the cirrent folder and combine all of them into one file. This way you can include prior existing bib files.
1110 |
1111 |
1112 |
1113 |
1114 | \section{General markdown formatting}
1115 | \label{sec:Generalmarkdownformatting}
1116 |
1117 |
1118 | Markdown basics: lists, markup and code
1119 |
1120 |
1121 | \begin{itemize}
1122 | \item list item1 in markdown format.
1123 | \item list item2 \begin{itemize}
1124 | \item nested list item3 - font attributes not yet supported.
1125 | \end{itemize}
1126 | \item \textit{italics}
1127 | \item \textbf{bold}
1128 | \item \verb+fixed font+
1129 | \end{itemize}
1130 |
1131 |
1132 |
1133 |
1134 | \begin{enumerate}
1135 | \item Enumerated list item 1 in markdown format.\begin{enumerate}
1136 | \item sub lit element 1
1137 | \item sub lit element 2
1138 | \end{enumerate}
1139 | \item Enumerated list item 2.
1140 | \end{enumerate}
1141 |
1142 | The markup language (or the converter) breaks if an itemized list and an enumerated list are immediately adjacent --- we need to separate the lists by text with with a \verb++.
1143 |
1144 |
1145 |
1146 | Please note that the converter does not currently allow free standing (enter-twice) paragraphs inside lists. Please make the paragraphs touch and use double spaces at the end to force a new line. This will be converted to loose standing paragraphs in LaTeX.
1147 |
1148 |
1149 | \begin{enumerate}
1150 | \item list item1 in markdown format.
1151 | \item list item2
1152 |
1153 |
1154 | item2 new parra 1
1155 |
1156 |
1157 | item2 new parra 1
1158 | \item list item3
1159 |
1160 |
1161 | item3 new parra 1
1162 |
1163 |
1164 | item3 new parra 2
1165 | \item list item4 [ this does not work correctly ]
1166 |
1167 |
1168 | list item4 [ this does not work correctly ]
1169 |
1170 |
1171 | item4 new parra 1 [ this does not work correctly ]
1172 |
1173 |
1174 | list item4 [ this does not work correctly ]
1175 |
1176 |
1177 | list item4 [ this does not work correctly ]
1178 |
1179 |
1180 | item4 new parra 1 [ this does not work correctly ]
1181 |
1182 |
1183 | item4 new parra 2 [ this does not work correctly ]
1184 | \item list item5 [ this should work correctly ]
1185 |
1186 |
1187 | item5 new parra 1 [ this should work correctly ]. We reference Figure~\ref{fig:propflightpaths-0} here.
1188 |
1189 |
1190 | {
1191 |
1192 | \begin{figure}[t]
1193 | \centering
1194 |
1195 | \begin{normalsize}
1196 | \includegraphics[width=0.1\textwidth, angle=0]{./images/random-squares-2.png}
1197 | \end{normalsize}
1198 | \caption{Boxy picture\label{fig:propflightpaths-0}\label{fig:propflightpaths}}
1199 | \end{figure}
1200 |
1201 | }
1202 |
1203 |
1204 |
1205 |
1206 | item5 new parra 2 [ this should work correctly ]
1207 | \end{enumerate}
1208 |
1209 |
1210 | Lists in HTML format
1211 |
1212 |
1213 | \begin{itemize}
1214 | \item list item
1215 | \item list item
1216 | \begin{itemize}
1217 | \item nested list item
1218 | \end{itemize}
1219 | \item \textit{italics}
1220 | \item \textbf{bold}
1221 | \item \verb+fixed font+
1222 | \end{itemize}
1223 |
1224 | \begin{enumerate}
1225 | \item Enumerated list item 1.
1226 | \begin{enumerate}
1227 | \item sub lit element 1
1228 | \item sub lit element 2
1229 | \end{enumerate}
1230 | \item Enumerated list item 2.
1231 | \end{enumerate}
1232 |
1233 |
1234 |
1235 | \section{Tables}
1236 | \label{sec:Tables}
1237 |
1238 | The table in this cell is rendered in \LaTeX{} with the following metadata:
1239 |
1240 |
1241 | \begin{verbatim}
1242 | {
1243 | "tableCaption": {
1244 | "caption": "Caption text for first table",
1245 | "label": "tab:lab1",
1246 | "format": "{|p{10mm}|l|r|c|c|p{50mm}|p{20mm}|}",
1247 | "fontsize": "normalsize",
1248 | "locator": "t"
1249 | }
1250 | }
1251 | \end{verbatim}
1252 |
1253 |
1254 | A complex HTML table with row spans and column spans:
1255 |
1256 |
1257 |
1258 | \begin{table}[tb]
1259 | \centering
1260 | \caption{Caption text for first table\label{tab:lab1-0}\label{tab:lab1}}
1261 |
1262 | \begin{normalsize}
1263 |
1264 | \begin{tabular}{{|p{10mm}|l|r|c|c|p{50mm}|p{20mm}|}}
1265 | \hline
1266 | a&\multicolumn{2}{|c|}{b}&\multicolumn{3}{|c|}{c}&1\\\hline
1267 | e&f&\multicolumn{2}{|c|}{g}&h&i&2\\\cline{2-2}\cline{3-3}\cline{4-4}\cline{5-5}\cline{6-6}\cline{7-7}
1268 | &\multicolumn{2}{|c|}{j}&k&l&m&3\\\cline{1-1}\cline{2-2}\cline{3-3}\cline{4-4}\cline{6-6}\cline{7-7}
1269 | n&o&p&q&&r&4\\\hline
1270 | s&t&u&v&w&x&5\\\hline
1271 |
1272 | \end{tabular}
1273 | \end{normalsize}
1274 | \end{table}
1275 |
1276 |
1277 | The tables in this cell are rendered in \LaTeX{} with the following metadata:
1278 |
1279 |
1280 | \begin{verbatim}
1281 | {
1282 | "tableCaption": {
1283 | "caption": "['Caption text for (first) second table','','Caption text for (third) second table']",
1284 | "label": "tab:lab2",
1285 | "format": "['{|p{20mm}|r|}','','{|c|l|}']",
1286 | "fontsize": "['normalsize', 'tiny', 'Large']"
1287 | }
1288 | }
1289 | \end{verbatim}
1290 |
1291 |
1292 | Github flavoured markdown tables are supported in the IPython notebook (floating in \LaTeX{} as Table~\ref{tab:lab2-0}):
1293 |
1294 |
1295 |
1296 | \begin{table}[tb]
1297 | \centering
1298 | \caption{Caption text for (first) second table\label{tab:lab2-0}\label{tab:lab2}}
1299 |
1300 | \begin{normalsize}
1301 |
1302 | \begin{tabular}{{|p{20mm}|r|}}
1303 | \hline
1304 | This&is\\\hline
1305 | a&table\\\hline
1306 |
1307 | \end{tabular}
1308 | \end{normalsize}
1309 | \end{table}
1310 |
1311 | second table (non-floating in \LaTeX{}):
1312 |
1313 |
1314 |
1315 | \begin{table}[tb]
1316 | \centering
1317 | \caption{Caption text for (third) second table\label{tab:lab2-2}}
1318 |
1319 | \begin{Large}
1320 |
1321 | \begin{tabular}{{|c|l|}}
1322 | \hline
1323 | This&is\\\hline
1324 | a&small table\\\hline
1325 |
1326 | \end{tabular}
1327 | \end{Large}
1328 | \end{table}
1329 |
1330 | PHP Markdown Extra is also supported (floating in \LaTeX{} as Table~\ref{tab:lab2-2}):
1331 |
1332 |
1333 | \begin{center}
1334 |
1335 | \begin{normalsize}
1336 |
1337 | \begin{tabular}{|c|c|}
1338 | \hline
1339 | First Header&Second Header\\\hline
1340 | Content Cell&Content Cell\\\hline
1341 | Content Cell&Content Cell\\\hline
1342 |
1343 | \end{tabular}
1344 | \end{normalsize}
1345 | \end{center}
1346 |
1347 | Both of these markup extensions require Python Markdown 2.4.1 to render HTML.
1348 |
1349 |
1350 |
1351 | Table~\ref{tab:hiertab12-0} has an hierarchical structure on both columns and rows. The percentage and underline characters are also preserved.
1352 |
1353 |
1354 |
1355 | \begin{table}[tb]
1356 | \centering
1357 | \caption{Caption text for hierarchical table\label{tab:hiertab12-0}\label{tab:hiertab12}}
1358 |
1359 | \begin{normalsize}
1360 |
1361 | \begin{tabular}{|l|l|l|*{2}{>{\RaggedLeft}p{8mm}|}}
1362 | \hline
1363 | &&CHead 1&\multicolumn{2}{|c|}{CLevel 1:1}\\\hline
1364 | &&CHead 2&CLevel 2:1&CLevel 2:2\\\hline
1365 | RHead 1&RHead 2&RHead 3&&\\\hline
1366 | RLevel 1:1\%\_&RLevel 2:1&A&6000\%&6156\\\cline{3-3}\cline{4-4}\cline{5-5}
1367 | &&B&2417&2471\\\cline{3-3}\cline{4-4}\cline{5-5}
1368 | &&C&1274&1347\\\cline{2-2}\cline{3-3}\cline{4-4}\cline{5-5}
1369 | &RLevel 2:2&A&10909&11041\\\cline{3-3}\cline{4-4}\cline{5-5}
1370 | &&B&4400&4408\\\cline{3-3}\cline{4-4}\cline{5-5}
1371 | &&C&2309&2319\\\cline{2-2}\cline{3-3}\cline{4-4}\cline{5-5}
1372 | &RLevel 2:3&A&11573&11178\\\cline{3-3}\cline{4-4}\cline{5-5}
1373 | &&B&4461&4976\\\cline{3-3}\cline{4-4}\cline{5-5}
1374 | &&C&2432&2410\\\hline
1375 | RLevel 1:2\%\_&RLevel 2:1&A&6728&6595\\\cline{3-3}\cline{4-4}\cline{5-5}
1376 | &&B&2322&2679\\\cline{3-3}\cline{4-4}\cline{5-5}
1377 | &&C&1300&1474\\\cline{2-2}\cline{3-3}\cline{4-4}\cline{5-5}
1378 | &RLevel 2:2&A&1210&12344\\\cline{3-3}\cline{4-4}\cline{5-5}
1379 | &&B&4845&4367\\\cline{3-3}\cline{4-4}\cline{5-5}
1380 | &&C&2618&2525\\\cline{2-2}\cline{3-3}\cline{4-4}\cline{5-5}
1381 | &RLevel 2:3&A&12553&12117\\\cline{3-3}\cline{4-4}\cline{5-5}
1382 | &&B&4895&4835\\\cline{3-3}\cline{4-4}\cline{5-5}
1383 | &&C&2566&2991\\\hline
1384 |
1385 | \end{tabular}
1386 | \end{normalsize}
1387 | \end{table}
1388 |
1389 |
1390 | The infrared sensor example has the following design characteristics:
1391 |
1392 |
1393 | \begin{center}
1394 |
1395 | \begin{normalsize}
1396 |
1397 | \begin{tabular}{|c|c|c|c|}
1398 | \hline
1399 | Characteristic&Value&Unit&Motivation\\\hline
1400 | Spectral response&3.7--4.9&$\mu$m&detector specification\\\hline
1401 | Pixel size (x and y)&12&$\mu$m&detector specification\\\hline
1402 | Pixel fill factor&0.95&&detector specification\\\hline
1403 | Detector temperature&80&K&detector specification\\\hline
1404 | Detector external quantum efficiency&0.8&&detector specification\\\hline
1405 | Detector internal quantum efficiency&0.75&&detector specification\\\hline
1406 | Number rows&144&-&detector specification\\\hline
1407 | Number columns&256&-&detector specification\\\hline
1408 | Detector PRNU stddev&0.2&&detector specification\\\hline
1409 | Well capacity at 1 V&$3.2\times 10^{6}$&e&detector specification\\\hline
1410 | Sense node voltage&3.0 $\rightarrow$ 1.0&V&detector specification\\\hline
1411 | F-number&3.2&-&detector specification\\\hline
1412 | Band gap 0~K&0.235&eV&material property\\\hline
1413 | Varshni A&0.00068&&material model\\\hline
1414 | Varshni B&500&&material model\\\hline
1415 | Dark FOM&$4\times 10^{-9}$&nA/cm$^2$&material model\\\hline
1416 | Dark cm&1&&material model\\\hline
1417 | Dark FPN stddev&0.4&&material model\\\hline
1418 | Well capacitance at 1.0 V&$5.13\times 10^{-13}$&F&by calculation\\\hline
1419 | k1&$5.13\times 10^{-13}$&CV&by calculation\\\hline
1420 | Gain at 1.0 V&$3.125\times 10^{-7}$&V/e&by calculation\\\hline
1421 | Pixel IFOV (x and y)&$100.0\times 10^{-6}$&rad&design choice\\\hline
1422 | Frame time&0.02&s&design choice\\\hline
1423 | Focal length&0.12&m&design choice\\\hline
1424 | Full field angle&0.84°&focal length and detector\\\hline
1425 |
1426 | \end{tabular}
1427 | \end{normalsize}
1428 | \end{center}
1429 |
1430 | Charge well (sense node) capacitance $C = nq/V$. The charge well is filled to capacity at the minimum sense node voltage $C = \num{3.2e6}\times\num{1.6e-19}/1.0= \num{0.513e-12}$~F. Then $k_1=CV=\num{0.513e-12}\times 1=\num{0.513e-12}$.
1431 |
1432 |
1433 | Sense node gain is given by $V/n = q/C = \num{1.6e-19}/\num{0.513e-12}=\num{3.12e-07}$ V/e.
1434 |
1435 |
1436 |
1437 | A table can be formatted with the metadata, even if the table is not floating with a caption. For example, the following table only uses the following metadata:
1438 |
1439 |
1440 | \begin{verbatim}
1441 | {
1442 | "tableCaption": {
1443 | "format": "{|p{10mm}|p{50mm}|p{100mm}|}",
1444 | "fontsize": "footnotesize"
1445 | }
1446 | }
1447 | \end{verbatim}
1448 |
1449 |
1450 | \begin{center}
1451 |
1452 | \begin{footnotesize}
1453 |
1454 | \begin{tabular}{{|p{10mm}|p{50mm}|p{100mm}|}}
1455 | \hline
1456 | Column Number&Column Description&Example Values\\\hline
1457 | 1&Unique row identifier&MOD15A2.A2000057.h12v03.004.2002357024124.FparExtra\_QC
1458 | MOD15A2.A2000057.h12v03.004.2002357024124.Lai\_1km\\\hline
1459 | 2&MODIS Land Product
1460 | Code&MOD15A2\\\hline
1461 | 3&MODIS Acquisition
1462 | Date [ A (YYYYDDD) ]&A2000057\\\hline
1463 | 4&User selected center
1464 | point coordinates and specified width (Samp) and height (Line) of
1465 | bounding rectangle in pixels. Width x height denotes number of
1466 | Product values starting in Column 7. (e.g., 7 x 7 $=$ 49)&Lat55.879620Lon-98.480810Samp7Line7\\\hline
1467 | 5&MODIS Processing Date
1468 | (YYYYDDDHHMMSS)&2002357024124\\\hline
1469 | 6&Product Scientific
1470 | Data Set (Band): Indicates type of values to follow. Specific values
1471 | vary by Product. Data quality information are interleaved.&MOD15A2: FparExtra\_QC,
1472 | FparLai\_QC, Fpar\_1kmMOD17A2: Gpp\_1km, PsnNet\_1km, Psn\_QC\_1km\\\hline
1473 | 7 to N&Data values of type
1474 | as specified. Number of data columns as given in Column 4.
1475 | Definition of QC component values vary by Scientific Data Set.&QC:
1476 | 00100001, 01100001, 01100001, ...Measurement:
1477 | 2, 2, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, ...to N\\\hline
1478 |
1479 | \end{tabular}
1480 | \end{footnotesize}
1481 | \end{center}
1482 |
1483 |
1484 | Pandas dataframe HTML tables are also rendered.
1485 |
1486 |
1487 |
1488 |
1489 |
1490 | See Listing~\ref{lst:autolistingcell88} for the code.
1491 |
1492 | \begin{center}
1493 |
1494 | \begin{normalsize}
1495 |
1496 | \begin{tabular}{|c|c|c|}
1497 | \hline
1498 | &one&two\\\hline
1499 | a&1.0&1.0\\\hline
1500 | b&2.0&2.0\\\hline
1501 | c&3.0&3.0\\\hline
1502 | d&NaN&4.0\\\hline
1503 |
1504 | \end{tabular}
1505 | \end{normalsize}
1506 | \end{center}
1507 |
1508 |
1509 |
1510 |
1511 | \subsection{Font size in tables}
1512 | \label{sec:Fontsizeintables}
1513 |
1514 | If both \verb+latex/fontsize+ and \verb+tableCaption/fontsize+ are present then the \verb+tableCaption/fontsize+ takes preference, and the table (only) is rendered in the specified fontsize. The floating caption is in the normal document font size.
1515 |
1516 |
1517 | \begin{verbatim}
1518 | {
1519 | "latex": {
1520 | "fontsize": "scriptsize"
1521 | },
1522 | "tableCaption": {
1523 | "caption": "Caption text for Pandas table",
1524 | "label": "tab:lab1",
1525 | "format": "somelabel",
1526 | "fontsize": "tiny"
1527 | }
1528 | }
1529 | \end{verbatim}
1530 |
1531 |
1532 |
1533 |
1534 | \chapter{Embedding LaTeX code in output cells}
1535 | \label{sec:EmbeddingLaTeXcodeinoutputcells}
1536 |
1537 |
1538 | Jupyer uses MathJax for LaTeX rendering in the markdown cells. This is very useful for documentation in general, but sometimes MathJax is not sufficient for special LaTeX constructs. LaTeX constructs can be embedded (but not rendered in Jupyter) in output cells. The LaTeX in the output cell can then be rendered/typeset when the converted LaTeX document is built.
1539 |
1540 |
1541 | Any string you construct in a code cell and then use the \verb+IPython.display.Latex+ function to display will be embedded in the output cell as a data of mime type \verb+text/latex+. The ipynb2tex converter will then process this LaTeX in the output cell as regular LaTeX in the target document. So the following code:
1542 |
1543 |
1544 | \begin{verbatim}
1545 | from IPython.display import Latex
1546 | lstr = 'This is a \LaTeX string.'
1547 | Latex(lstr)
1548 | \end{verbatim}
1549 |
1550 |
1551 | Will make a mime type \verb+text/latex+ data entry with the contents of \verb+lstr+ in the output cell. When rendered in the notebook, it will simply show the text as entered.
1552 |
1553 |
1554 | With this functionality, LaTeX code of any complexity can be constructed by code, for eventual typesetting by the LaTeX compiler after the notebook has been converted to LaTeX.
1555 |
1556 |
1557 |
1558 |
1559 | \section{Pandas DataFrame to LaTeX}
1560 | \label{sec:PandasDataFrametoLaTeX}
1561 |
1562 | The following example shows how to export a Pandas dataframe to a \verb+IPython.core.display.Latex object+ in the string \verb+lstr+. When viewed in the notebook, the table is shown as a LaTeX code, but when the conversion to a LaTeX document takes place, the LaTeX is rendered as regular LaTeX in the output PDF file.
1563 |
1564 |
1565 | The table format specification is provided by the Pandas to\_latex(column\_format)\cite{httppandaspydataorgp00001} argument, as in
1566 |
1567 |
1568 | \verb+'|l|l|p{50mm}|c|r|'+
1569 |
1570 |
1571 |
1572 |
1573 |
1574 | See Listing~\ref{lst:autolistingcell93} for the code to create the dataframe and write the output to LaTeX object at default font size.
1575 |
1576 | {
1577 | \renewcommand{\arraystretch}{1.1}
1578 | \centering
1579 | % to get unbroken vertical lines with booktabs, set separators to zero
1580 | % also set all horizontal lines to same width
1581 | \aboverulesep=0ex
1582 | \belowrulesep=0ex
1583 | \heavyrulewidth=.05em
1584 | \lightrulewidth=.05em
1585 | \cmidrulewidth=.05em
1586 | \belowbottomsep=0pt
1587 | \abovetopsep=0pt
1588 |
1589 | \begin{normalsize}
1590 | \begin{tabular}{|l|l|l|p{50mm}|c|r|}
1591 | \toprule
1592 | {} & A & B & C & D & E \\
1593 | \midrule
1594 | 2013-01-01 & 0.083049 & -0.106439 & 0.381134 & -0.518548 & -1.255566 \\
1595 | 2013-01-02 & -0.570557 & -0.456681 & 1.154854 & -0.250722 & 0.825798 \\
1596 | 2013-01-03 & -1.683748 & 1.430985 & -0.318301 & 0.720622 & 0.543044 \\
1597 | \bottomrule
1598 | \end{tabular}
1599 |
1600 | \end{normalsize}
1601 | \renewcommand{\arraystretch}{1}
1602 | }
1603 |
1604 |
1605 |
1606 |
1607 | See Listing~\ref{lst:autolistingcell94} for the code.
1608 |
1609 | {
1610 | \renewcommand{\arraystretch}{1.1}
1611 | \centering
1612 | % to get unbroken vertical lines with booktabs, set separators to zero
1613 | % also set all horizontal lines to same width
1614 | \aboverulesep=0ex
1615 | \belowrulesep=0ex
1616 | \heavyrulewidth=.05em
1617 | \lightrulewidth=.05em
1618 | \cmidrulewidth=.05em
1619 | \belowbottomsep=0pt
1620 | \abovetopsep=0pt
1621 |
1622 | \begin{normalsize}
1623 | \begin{tabular}{|l|l|p{50mm}|c|r|}
1624 | \toprule
1625 | A & B & C & D & E \\
1626 | \midrule
1627 | 0.083049 & -0.106439 & 0.381134 & -0.518548 & -1.255566 \\
1628 | -0.570557 & -0.456681 & 1.154854 & -0.250722 & 0.825798 \\
1629 | -1.683748 & 1.430985 & -0.318301 & 0.720622 & 0.543044 \\
1630 | \bottomrule
1631 | \end{tabular}
1632 |
1633 | \end{normalsize}
1634 | \renewcommand{\arraystretch}{1}
1635 | }
1636 |
1637 |
1638 | Set the font size for the typesetting by using the \verb+latex/fontsize+ setting in the cell json metadata.
1639 | Use the regular LaTeX font size definitions but without the backslash (Huge, huge, LARGE, Large, large, normalsize, small, footnotesize, scriptsize, tiny):
1640 |
1641 |
1642 | \begin{verbatim}
1643 | {
1644 | "latex": {
1645 | "fontsize": "LARGE"
1646 | }
1647 | }
1648 | \end{verbatim}
1649 |
1650 |
1651 | Of course you may have to use this setting in conjunction with any other json settings.
1652 |
1653 |
1654 |
1655 |
1656 |
1657 | See Listing~\ref{lst:autolistingcell96} for the code to write the table in LARGE.
1658 |
1659 | {
1660 | \renewcommand{\arraystretch}{1.1}
1661 | \centering
1662 | % to get unbroken vertical lines with booktabs, set separators to zero
1663 | % also set all horizontal lines to same width
1664 | \aboverulesep=0ex
1665 | \belowrulesep=0ex
1666 | \heavyrulewidth=.05em
1667 | \lightrulewidth=.05em
1668 | \cmidrulewidth=.05em
1669 | \belowbottomsep=0pt
1670 | \abovetopsep=0pt
1671 |
1672 | \begin{LARGE}
1673 | \begin{tabular}{|l|l|l|p{50mm}|c|r|}
1674 | \toprule
1675 | {} & A & B & C & D & E \\
1676 | \midrule
1677 | 2013-01-01 & 0.083049 & -0.106439 & 0.381134 & -0.518548 & -1.255566 \\
1678 | 2013-01-02 & -0.570557 & -0.456681 & 1.154854 & -0.250722 & 0.825798 \\
1679 | 2013-01-03 & -1.683748 & 1.430985 & -0.318301 & 0.720622 & 0.543044 \\
1680 | \bottomrule
1681 | \end{tabular}
1682 |
1683 | \end{LARGE}
1684 | \renewcommand{\arraystretch}{1}
1685 | }
1686 |
1687 |
1688 | A Pandas dataframe exported with \verb+IPython.core.display.Latex object+ can also be typeset as a floating table by setting the usual table metadata for the floating table. The table format specification is provided by the Pandas \verb+.to\_latex(column\_format)+ argument, so the \verb+tableCaption/format+ specification in the json is ignored.
1689 |
1690 |
1691 | \begin{verbatim}
1692 | {
1693 | "tableCaption": {
1694 | "caption": "Caption text for Pandas table",
1695 | "label": "tab:lab1",
1696 | "format": "IGNORED because this is a pandas dataframe export!!",
1697 | "fontsize": "tiny"
1698 | }
1699 | }
1700 | \end{verbatim}
1701 |
1702 |
1703 |
1704 |
1705 |
1706 | See Listing~\ref{lst:autolistingcell98} for the code to write a floating table in tiny font size.
1707 |
1708 | {
1709 |
1710 | \begin{table}[tb]
1711 | \centering
1712 | \caption{Caption text for the Pandas table\label{tab:labpad1-0}\label{tab:labpad1}}
1713 | % to get unbroken vertical lines with booktabs, set separators to zero
1714 | % also set all horizontal lines to same width
1715 | \aboverulesep=0ex
1716 | \belowrulesep=0ex
1717 | \heavyrulewidth=.05em
1718 | \lightrulewidth=.05em
1719 | \cmidrulewidth=.05em
1720 | \belowbottomsep=0pt
1721 | \abovetopsep=0pt
1722 |
1723 | \begin{tiny}
1724 | \renewcommand{\arraystretch}{1.1}
1725 | \begin{tabular}{|l|l|l|p{50mm}|c|r|}
1726 | \toprule
1727 | {} & A & B & C & D & E \\
1728 | \midrule
1729 | 2013-01-01 & 0.083049 & -0.106439 & 0.381134 & -0.518548 & -1.255566 \\
1730 | 2013-01-02 & -0.570557 & -0.456681 & 1.154854 & -0.250722 & 0.825798 \\
1731 | 2013-01-03 & -1.683748 & 1.430985 & -0.318301 & 0.720622 & 0.543044 \\
1732 | \bottomrule
1733 | \end{tabular}
1734 |
1735 | \renewcommand{\arraystretch}{1}
1736 | \end{tiny}
1737 | \end{table}
1738 |
1739 | }
1740 |
1741 |
1742 |
1743 | \section{Other LaTeX exports}
1744 | \label{sec:OtherLaTeXexports}
1745 |
1746 |
1747 | Write latex strings
1748 |
1749 |
1750 |
1751 | Samples per cluster ID: \\
1752 | 6 7 8 9 5 \\[4ex]
1753 | Samples per visual material: \\
1754 | 4 4 7 2 2 2 4 2 2 5
1755 |
1756 |
1757 |
1758 | See Listing~\ref{lst:autolistingcell102} for the code display a tikz graphic.
1759 |
1760 |
1761 | \begin{tikzpicture}[scale=4.5, line join=bevel]
1762 | % \a and \b are two macros defining characteristic
1763 | % dimensions of the impossible brick.
1764 | \pgfmathsetmacro{\a}{0.18}
1765 | \pgfmathsetmacro{\b}{1.37}
1766 |
1767 | \tikzset{%
1768 | apply style/.code={\tikzset{#1}},
1769 | brick_edges/.style={thick,draw=black},
1770 | face_colourA/.style={fill=gray!50},
1771 | face_colourB/.style={fill=gray!25},
1772 | face_colourC/.style={fill=gray!90},
1773 | }
1774 |
1775 | \foreach \theta/\v/\facestyleone/\facestyletwo in {%
1776 | 0/0/{brick_edges,face_colourA}/{brick_edges,face_colourC},
1777 | 180/-\a/{brick_edges,face_colourB}/{brick_edges,face_colourC}
1778 | }{
1779 | \begin{scope}[rotate=\theta,shift={(\v,0)}]
1780 | \draw[apply style/.expand once=\facestyleone]
1781 | ({-.5*\b},{1.5*\a}) --
1782 | ++(\b,0) --
1783 | ++(-\a,-\a) --
1784 | ++({-\b+2*\a},0) --
1785 | ++(0,-{2*\a}) --
1786 | ++(\b,0) --
1787 | ++(-\a,-\a) --
1788 | ++(-\b,0) --
1789 | cycle;
1790 | \draw[apply style/.expand once=\facestyletwo]
1791 | ({.5*\b},{1.5*\a}) --
1792 | ++(0,{-2*\a}) --
1793 | ++(-\a,0) --
1794 | ++(0,\a) --
1795 | cycle;
1796 | \end{scope}
1797 | }
1798 | \end{tikzpicture}
1799 |
1800 |
1801 |
1802 |
1803 | See Listing~\ref{lst:autolistingcell103} for the code display another tikz graphic, as a floating figure.
1804 |
1805 | {
1806 |
1807 | \begin{figure}[tb]
1808 | \centering
1809 |
1810 | \begin{normalsize}
1811 |
1812 | \begin{tikzpicture}[font = \sansmath]
1813 | \coordinate (O) at (0,0);
1814 |
1815 | % ball background color
1816 | \shade[ball color = blue, opacity = 0.2] (0,0) circle [radius = 2cm];
1817 |
1818 | % cone
1819 | \begin{scope}
1820 | \def\rx{0.71}% horizontal radius of the ellipse
1821 | \def\ry{0.15}% vertical radius of the ellipse
1822 | \def\z{0.725}% distance from center of ellipse to origin
1823 |
1824 | \path [name path = ellipse] (0,\z) ellipse ({\rx} and {\ry});
1825 | \path [name path = horizontal] (-\rx,\z-\ry*\ry/\z)
1826 | -- (\rx,\z-\ry*\ry/\z);
1827 | \path [name intersections = {of = ellipse and horizontal}];
1828 |
1829 | % radius to base of cone in ball
1830 | \draw[fill = gray!50, gray!50] (intersection-1) -- (0,0)
1831 | -- (intersection-2) -- cycle;
1832 | % base of cone in ball
1833 | \draw[fill = gray!30, densely dashed] (0,\z) ellipse ({\rx} and {\ry});
1834 | \end{scope}
1835 |
1836 | % label of cone
1837 | \draw (0.25,0.4) -- (0.9,0.1) node at (1.05,0.0) {$q$};
1838 |
1839 | % ball
1840 | \draw (O) circle [radius=2cm];
1841 | % label of ball center point
1842 | \filldraw (O) circle (1pt) node[below] {$P$};
1843 |
1844 | % radius
1845 | \draw[densely dashed] (O) to [edge label = $r$] (-1.33,1.33);
1846 | \draw[densely dashed] (O) -- (1.33,1.33);
1847 |
1848 | % cut of ball surface
1849 | \draw[red] (-1.35,1.47) arc [start angle = 140, end angle = 40,
1850 | x radius = 17.6mm, y radius = 14.75mm];
1851 | \draw[red, densely dashed] (-1.36,1.46) arc [start angle = 170, end angle = 10,
1852 | x radius = 13.8mm, y radius = 3.6mm];
1853 | \draw[red] (-1.29,1.52) arc [start angle=-200, end angle = 20,
1854 | x radius = 13.75mm, y radius = 3.15mm];
1855 |
1856 | % label of cut of ball surface
1857 | \draw (-1.2,2.2) -- (-0.53,1.83) node at (-1.37,2.37) {$A$};
1858 | \end{tikzpicture}
1859 | \end{normalsize}
1860 | \caption{Caption text for tikz figure\label{fig:tikz-0}\label{fig:tikz}}
1861 | \end{figure}
1862 |
1863 | }
1864 |
1865 |
1866 | The next example creates a LaTeX string and outputs it as a Latex object. The code calculates rules with increasing heights, with this code:
1867 |
1868 |
1869 | \begin{verbatim}
1870 | lstr = '\n\nThis paragraph is embedded as \LaTeX{} in a Jupyter output cell. '\
1871 | + 'One day this could be a complex computed \LaTeX{} string. '\
1872 | + 'This example only has rising rules... \n'
1873 | for height in range(1,20):
1874 | lstr += '\\rule[0pt]{{10pt}}{}{}pt{} '.format('{',height,'}')
1875 | Latex(lstr + '\n')
1876 | \end{verbatim}
1877 |
1878 |
1879 |
1880 |
1881 |
1882 | This paragraph is embedded as \LaTeX{} in a Jupyter output cell. One day this could be a complex computed \LaTeX{} string. This example only has rising rules...
1883 |
1884 | \rule[0pt]{10pt}{1pt} \rule[0pt]{10pt}{2pt} \rule[0pt]{10pt}{3pt} \rule[0pt]{10pt}{4pt} \rule[0pt]{10pt}{5pt} \rule[0pt]{10pt}{6pt} \rule[0pt]{10pt}{7pt} \rule[0pt]{10pt}{8pt} \rule[0pt]{10pt}{9pt} \rule[0pt]{10pt}{10pt} \rule[0pt]{10pt}{11pt} \rule[0pt]{10pt}{12pt} \rule[0pt]{10pt}{13pt} \rule[0pt]{10pt}{14pt} \rule[0pt]{10pt}{15pt} \rule[0pt]{10pt}{16pt} \rule[0pt]{10pt}{17pt} \rule[0pt]{10pt}{18pt} \rule[0pt]{10pt}{19pt}
1885 |
1886 |
1887 | Jelte Fennema wrote pylatex\cite{httpsgithubcomJelteF00002} to create LaTeX text using Python code. He wrote the code to create complete documents, but also to write fragments\cite{httpsjeltefgithubioP00003} --- which we can use here: "Classes can be part of a single document, or can act as pieces on their own. With the \verb+dumps\_as\_content+ method, most classes can return their LaTeX-formatted code, and with the \verb+generate\_tex+ method, this code can be written to a file."
1888 |
1889 |
1890 | I only spent limited time on pylatex and got the following example to work (it requires \verb+pip install pylatex+).
1891 |
1892 |
1893 |
1894 |
1895 |
1896 | See Listing~\ref{lst:autolistingcell107} for the code to format a numy array in \LaTeX{}.
1897 |
1898 | \[%
1899 | arr= \begin{bmatrix}%
1900 | -1.5238753267681426&-0.054106597608410884&0.3133992734699635&-1.914463011081044\\%
1901 | -0.9730171110025135&1.2607379010435467&0.9708551354916619&-1.5426473382692332\\%
1902 | 1.5617776961021184&1.6862635883897612&-1.187051258257019&-0.6077778495302126\\%
1903 | -0.7381209385420484&-0.6953658326619776&-0.3490201919937157&-0.1781985647847829\\%
1904 | 1.5326454450945042&0.6131410607502967&-0.5031807629333506&0.5286306282646915\\%
1905 | -0.8970203037261731&-0.8958130486496836&0.040453221245678746&-0.47384738447189984%
1906 | \end{bmatrix}%
1907 | \]
1908 |
1909 |
1910 | \chapter{Math}
1911 | \label{sec:Math}
1912 |
1913 |
1914 | Inline math delineated with single dollar symbols are rendered inline with paragraph text, as in $\alpha+\beta=\gamma$.
1915 |
1916 |
1917 | Using math mode (anything between two dollar symbols) is interpreted as \LaTeX{} math:
1918 |
1919 |
1920 | \begin{equation}D_{KL}(P||Q) = \sum\limits_{i}ln (\frac{P(i)}{Q(i)}) P(i).\end{equation}
1921 |
1922 |
1923 |
1924 | \begin{equation}\begin{array}{llll}E = \frac{\phi}{A_o} = \int \left[\right.&&&\\&\tau_a(R) \tau_o &&\\&\left[\right.&&\\&&\mkern-82mu \Omega_t k_i\left(\epsilon_t L(T_t)\right)&[1]\\&&\mkern-99mu +\,\,\Omega_t k_i(1-\epsilon_t)\left(\frac{\rho E_\textrm{sun}}{\pi}\right)&[2]\\&&\mkern-98mu +\,\,\Omega_t(1-k_i)(1-\epsilon_t)\left(\frac{\rho E_\textrm{sun}}{\pi}\right)&[3]\\&&\mkern-98mu +\,\, (\Omega_p -\Omega_t) \left(\frac{\rho E_\textrm{sun}}{\pi}\right)&[4]\\&\left.\right]&&\\&+\,\,\tau_o L_\textrm{path}(R) \Omega_p&&[5]\\&\left.\right]d\lambda& &\end{array}\end{equation}
1925 |
1926 |
1927 |
1928 | The probability density function for yaw angle is the wrapped normal distribution\cite{httpsenwikipediaorgw00004}. The first form uses two dollar symbols to show the equation in LaTeX display math:
1929 |
1930 |
1931 | \begin{equation}f_{WN}(\theta;\mu, \sigma) = \frac{1}{\sigma\sqrt{2\pi}}\sum^{\infty}_{k=-\infty} \exp\left[\frac{-(\theta-\mu+2\pi k)^2}{2\sigma^2}\right]\end{equation}
1932 |
1933 |
1934 | The second example uses \verb+begin{equation}+ and \verb+end{equation}+:
1935 |
1936 |
1937 | \begin{equation}f_{WN}(\theta;\mu, \sigma) = \frac{1}{\sigma\sqrt{2\pi}}\sum^{\infty}_{k=-\infty} \exp\left[\frac{-(\theta-\mu+2\pi k)^2}{2\sigma^2}\right]\end{equation}
1938 |
1939 |
1940 |
1941 | \begin{equation}\begin{array}{l}X_{WN}(\theta;\mu, \sigma) = \frac{1}{\sigma\sqrt{2\pi}}\sum^{\infty}_{k=-\infty} \exp\left[\frac{-(\theta-\mu+2\pi k)^2}{2\sigma^2}\right]\end{array}\end{equation}
1942 |
1943 |
1944 |
1945 |
1946 | \chapter{General \LaTeX{} Crib Notes}
1947 | \label{sec:GeneralLaTeXCribNotes}
1948 |
1949 | This chapter contains general notes, not necessarily pertaining to the Jupyter notebook converter.
1950 |
1951 |
1952 |
1953 |
1954 | \section{Quotes}
1955 | \label{sec:Quotes}
1956 |
1957 | Use \verb+\verb+word'+ [+word'] instead of \verb+'word'+ ['word'].\
1958 | Likewise \verb+\verb+word'''+ [+word''] instead of \verb+''word''+ [''word''].
1959 |
1960 |
1961 |
1962 |
1963 | \section{Degree Symbol}
1964 | \label{sec:DegreeSymbol}
1965 |
1966 | The degree symbol in \LaTeX{} should not be done with \verb+\circ+ as shown here: 45$^\circ$.
1967 | Rather use \verb+\usepackage{gensymb}+ and then \verb+45\textdegree{}+ 45\textdegree{}, or \verb+17~\celsius+ 17~\celsius. Better yet, use the siunitx package described below.
1968 |
1969 |
1970 |
1971 |
1972 | \section{Test Sub- and Superscripts}
1973 | \label{sec:TestSubandSuperscripts}
1974 |
1975 | Create superscripts and subscripts in body text with \verb+m\textsuperscript{2}+ and \verb+CO\textsubscript{2}+ to get m\textsuperscript{2} and CO\textsubscript{2}, instead of $m^2$ or CO$_2$.
1976 |
1977 |
1978 |
1979 |
1980 | \section{siunitx}
1981 | \label{sec:siunitx}
1982 |
1983 | Load \verb+siunitx+ package for some really nice features. Load it with \
1984 | \verb+\usepackage[detect-weight,detect-mode]{siunitx}+.
1985 |
1986 |
1987 |
1988 | \newcommand{\tabentry}[1]{\detokenize{#1} & #1}
1989 |
1990 | \begin{tabular}{p{110mm}|l}
1991 | \textbf{\LaTeX{}} & \textbf{Output}\\\hline
1992 | \tabentry{\num{3e-5}}\\
1993 | \tabentry{\si{\metre\per\second\squared}}\\
1994 | \tabentry{\si{\micro\metre}} upright, instead of $\mu m$\\
1995 | \tabentry{\SIlist{0.13;0.67;0.80}{\milli\metre}}\\
1996 | \tabentry{\si{\metre\per\second\squared}}\\
1997 | \tabentry{\si{kg.m.s^{-1}}}\\
1998 | \tabentry{\si{\kilogram\metre\per\second}}\\
1999 | \tabentry{\si[per-mode=symbol]{\kilogram\metre\per\second}}\\
2000 | \tabentry{\si[per-mode=symbol]{\kilogram\metre\per\ampere\per\second}}\\
2001 | \tabentry{\si[per-mode=reciprocal]{\kilogram\metre\per\ampere\per\second}}\\
2002 | \tabentry{\si{\kilogram\metre\per\ampere\per\second}}\\
2003 | \tabentry{\si[per-mode=fraction]{\kilogram\metre\per\ampere\per\second}}\\
2004 | \tabentry{\si[per-mode=symbol]{\watt\per\metre\squared\per \steradian}}\\
2005 | \tabentry{\ang{12.3}}\\
2006 | \tabentry{\ang{1;2;3}}\\
2007 | \tabentry{\si{\farad\squared\lumen\candela}}\\
2008 | \tabentry{\si[inter-unit-product = \ensuremath{{}\cdot{}}]{\farad\squared\lumen\candela}}
2009 | %\tabentry{}\\
2010 | \end{tabular}
2011 |
2012 |
2013 | \section{Math functions}
2014 | \label{sec:Mathfunctions}
2015 |
2016 | Math functions should be entered thus: \verb+\tan()+ to yield $\tan()$ \
2017 | rather than \verb+tan()+ to yield $tan()$.
2018 |
2019 |
2020 |
2021 |
2022 | \section{Use of itemize and enumerate}
2023 | \label{sec:Useofitemizeandenumerate}
2024 |
2025 | Use \verb+itemize+ and \verb+enumerate+ only when there is a sense of counting or a need to have an explicit list where the difference between the entries must be emphasised. Don't use these lists when a simple sentence would suffice.
2026 |
2027 |
2028 | For example, the following would work better in a normal sentence and not as an `itemize':\
2029 | The following types of sensors are commonly used for kinematic recordings:
2030 | \begin{itemize}
2031 | \item accelerometers
2032 | \item gyroscopes
2033 | \item Hall sensors (for static magnetic fields)
2034 | \item induction sensors (for dynamic magnetic fields)
2035 | \end{itemize}
2036 | Instead write:\
2037 | Sensors such as accelerometers, gyroscopes, Hall sensors (for static magnetic fields), and induction sensors (for dynamic magnetic fields) are commonly used for kinematic recordings.
2038 |
2039 |
2040 | Obey the grammar rules for punctuation in these types of lists. If each entry is a separate sentence, start with a capital letter and end with a full stop. If the sentence spreads across the list use commas and capital letters appropriately, as follows:\
2041 | The following types of sensors are commonly used for kinematic recordings:
2042 | \begin{itemize}
2043 | \item accelerometers,
2044 | \item gyroscopes,
2045 | \item Hall sensors (for static magnetic fields), and
2046 | \item induction sensors (for dynamic magnetic fields).
2047 | \end{itemize}
2048 |
2049 |
2050 |
2051 |
2052 | \section{\LaTeX{} fonts in Figures}
2053 | \label{sec:LaTeXfontsinFigures}
2054 |
2055 | If at all possible use \LaTeX{} fonts in figures. For example in the following figure, the fonts on the left side fits better with the equation
2056 | \begin{equation}x(k)=\alpha_1 e(k)+\alpha_0 e(k-1)-\beta_0 x(k-1)\end{equation}
2057 | \begin{center}
2058 | \includegraphics{images/flow2-zzz.png}
2059 | \end{center}
2060 |
2061 |
2062 |
2063 |
2064 | \section{Fonts, Emphasis and Shouting}
2065 | \label{sec:FontsEmphasisandShouting}
2066 |
2067 | Avoid CAPITALISATION OF WORDS. It is like SHOUTING!
2068 |
2069 |
2070 | Avoid \underline{underlined words}, unless there it is really necessary. It is like shouting when normal voice is adequate.
2071 |
2072 |
2073 | Use emphasis to \textit{emphasise words that must stand out}.
2074 | Do not use it too often, perhaps less than three to five times per page.
2075 | Emphasis is like a \textit{waving flag}. If there are \textit{too many flags} waving on a page, it \textit{confuses the reader}.
2076 |
2077 |
2078 | Use \lstinline{verbatim} to highlight software-related words, such as variable names, module/package/library names, command line text, program output, etc.
2079 | The user associates verbatim font with source code listings, so use verbatim with software `words'.
2080 |
2081 |
2082 |
2083 |
2084 | \section{Math Conventions}
2085 | \label{sec:MathConventions}
2086 |
2087 | The IUPAC Green Book, \lstinline{https://en.wikipedia.org/wiki/IUPAC\_book}, conveniently summarises international standards in formatting mathematics text and SI units. See also \lstinline{www.tug.org/TUGboat/Articles/tb18-1/tb54becc.pdf} and \lstinline{https://www.iso.org/standard/31887.html}.
2088 |
2089 |
2090 | The mathematical differential operator must be [ISO 80000-2:2009(E), 2-11.12] upright, not cursive (although pure mathematicians and some house styles prefer cursive).
2091 |
2092 |
2093 | \begin{lstlisting}
2094 | \usepackage{commath}
2095 | \newcommand{\der}{\operatorname{d!}{}}
2096 | $(\der{}x)$ or $(\dif{}x)$ instead of $(dx)$
2097 | \end{lstlisting}
2098 |
2099 |
2100 | \newcommand{\der}{\operatorname{d!}{}}
2101 | $(\der{}x)$ or $(\dif{}x)$ instead of $(dx)$
2102 |
2103 |
2104 | \begin{lstlisting}
2105 | \usepackage{commath}
2106 | \begin{equation*}F(t) = m \od[2]{x(t)}{t}\end{equation*}
2107 | \end{lstlisting}
2108 |
2109 |
2110 | \begin{equation*}F(t) = m \od[2]{x(t)}{t}\end{equation*}
2111 |
2112 |
2113 | Mathematical variables must be cursive ($\alpha\beta$), but constants must be upright ($\mathrm{\pi}$) not cursive ($\pi$). The code
2114 |
2115 |
2116 | \begin{lstlisting}
2117 | \usepackage[utopia]{mathdesign}
2118 | \usepackage[OMLmathrm,OMLmathbf]{isomath}
2119 | \newcommand\ct[1]{\text{\rmfamily\upshape #1}}
2120 | cursive: $\pi$ $\mathbfit{\pi}$ or upright $\mathrm{\pi}$ $\mathbf{\pi}$\
2121 | or\
2122 | cursive: $e^{i\pi}-1=0$ or upright $\ct{e}^{\ct{i}\piup}-1=0$.
2123 | \end{lstlisting}
2124 | yields cursive: $\pi$ $\mathbfit{\pi}$ or upright $\mathrm{\pi}$ $\mathbf{\pi}$\
2125 | or \
2126 | cursive: $e^{i\pi}-1=0$ or upright $\ct{e}^{\ct{i}\piup}-1=0$.
2127 |
2128 |
2129 | Variable subscripts should be typeset in roman if the subscript is a recognisable word:\
2130 | $v_\textrm{aircraft}$ instead of $v_{aircraft}$
2131 |
2132 |
2133 |
2134 |
2135 | \section{Centering in Floats}
2136 | \label{sec:CenteringinFloats}
2137 |
2138 | Use \verb=\centering= in floats instead of \verb|\begin{center}\end{center}|, as in
2139 |
2140 |
2141 | \begin{verbatim}
2142 | \begin{figure}
2143 | \centering
2144 | \includegraphics[width=0.1\textwidth]{./images/keep-calm-and-code-python\_BW.png}
2145 | \caption{Keep calm and code Python\label{fig:keep-calm-and-code-python\_BW}}
2146 | \end{figure}
2147 | \end{verbatim}
2148 |
2149 |
2150 |
2151 |
2152 | \section{Forcing Floats to Show}
2153 | \label{sec:ForcingFloatstoShow}
2154 |
2155 | The floats accumulate up to a point where some or all of these floats are processed an displayed on a page. The floats are displayed in the order given in the input file. The rules as to when the float are processed and displayed are not entirely clear to me. \LaTeX\ appears to have a limit of around 18 unprocessed floats, beyond which an error message is given.
2156 |
2157 |
2158 | You can force all unprocessed floats to output in a number of different ways:
2159 |
2160 |
2161 | \begin{enumerate}
2162 | \item
2163 | Use the \verb+\clearpage+ command. This command immediately stops any further text output and displays all unprocessed floats in the order given. The problem with this command is that no text is output until all floats are output. This means that if the \verb+\clearpage+ command is near the top of a page, the rest of the page could be empty (unless a float fits there).
2164 |
2165 |
2166 | \item
2167 | The \verb+\afterpage{}+ command processes whatever command you have given in, after the text on the current page is processed and output. So by using an \verb+\afterpage{\clearpage}+ command at the point where you want to force float output, further text is processed on the current page, filling and outputting the current page, before the \verb+\clearpage+ command is issued: no more half-empty pages!
2168 |
2169 |
2170 | \item
2171 | The \verb"\FloatBarrier" command causes all unprocessed floats to be processed
2172 | immediately. Unlike \verb"\clearpage", it does not start a new page. The command requires the \texttt{placeins} package.
2173 |
2174 |
2175 | \item
2176 | To keep floats in the sections in which they were included, use
2177 | \verb"\usepackage[section]{placeins}".
2178 |
2179 |
2180 | \item
2181 | If you don't want your floats to float, you can use the [H] float specifier from the \verb"float" package.
2182 |
2183 |
2184 | \item
2185 | If you don't want your figure to float, don't use a floating environment; you can use, for example, a center environment and (if a caption is needed) the \verb"\captionof" command provided by the \texttt{capt-of} (or \texttt{caption}) package.
2186 | \lstinline{http://tex.stackexchange.com/questions/32598/force-latex-image-to-appear-in-the-section-in-which-its-declared}
2187 |
2188 |
2189 | \begin{lstlisting}
2190 | \usepackage{capt-of}
2191 | \centering
2192 | \includegraphics{foo}
2193 | \captionof{figure}{A non floating figure}
2194 | \label{fig:test}
2195 | \end{lstlisting}
2196 |
2197 |
2198 | \end{enumerate}
2199 |
2200 |
2201 | \clearpage
2202 |
2203 |
2204 |
2205 |
2206 | \section{Python and module versions, and dates}
2207 | \label{sec:Pythonandmoduleversionsanddates}
2208 |
2209 |
2210 |
2211 | \begin{lstlisting}[style=outcellstyle]
2212 | The watermark extension is already loaded. To reload it, use:
2213 | %reload_ext watermark
2214 | Python implementation: CPython
2215 | Python version : 3.8.3
2216 | IPython version : 7.19.0
2217 |
2218 | numpy : 1.19.2
2219 | scipy : 1.5.2
2220 | pyradi: 1.1.2
2221 |
2222 | Compiler : MSC v.1916 64 bit (AMD64)
2223 | OS : Windows
2224 | Release : 10
2225 | Machine : AMD64
2226 | Processor : Intel64 Family 6 Model 165 Stepping 2, GenuineIntel
2227 | CPU cores : 16
2228 | Architecture: 64bit
2229 |
2230 | Git hash: 25292a7d413d121bb65a59ebb983e2a32dad9323
2231 |
2232 |
2233 | \end{lstlisting}
2234 |
2235 |
2236 |
2237 |
2238 | \chapter{Listings}
2239 |
2240 |
2241 | \begin{lstlisting}[style=incellstyle,caption={Caption text for first listing}, label=lst:listing1]
2242 | # to prepare the environment
2243 | from IPython.display import display
2244 | from IPython.display import Image
2245 | from IPython.display import HTML
2246 |
2247 | import os.path
2248 | import numpy as np
2249 | %matplotlib inline
2250 |
2251 | import this
2252 | \end{lstlisting}
2253 |
2254 |
2255 | \begin{lstlisting}[style=incellstyle,caption={Caption text for second listing}, label=lst:listingrad]
2256 | #
2257 | print(' ')
2258 | print('Radius = {}'.format(6))
2259 | print('Frontal area = {} m2'.format(7))
2260 | print('This is a very long line of python code, that is supposed to flow over to the next line, in order to test the listing display')
2261 | \end{lstlisting}
2262 |
2263 |
2264 | \begin{lstlisting}[style=incellstyle,caption={Caption text for third listing}, label=lst:listing3]
2265 | # to print the value
2266 | a = ['a','b']
2267 | for v in a:
2268 | print(v)
2269 | \end{lstlisting}
2270 |
2271 |
2272 | \begin{lstlisting}[style=incellstyle,caption={Code Listing in cell 28}, label=lst:autolistingcell28]
2273 | ## this should not appear in the body of the doc if float listings
2274 | a = [0, 1]
2275 | for v in a:
2276 | print(v)
2277 | \end{lstlisting}
2278 |
2279 |
2280 | \begin{lstlisting}[style=incellstyle,caption={Code Listing in cell 30}, label=lst:autolistingcell30]
2281 | print('code with no listing caption')
2282 | \end{lstlisting}
2283 |
2284 |
2285 | \begin{lstlisting}[style=incellstyle,caption={Code Listing in cell 32}, label=lst:autolistingcell32]
2286 | def doprint(i):
2287 | print('function output {}'.format(i))
2288 | return int(i)
2289 | \end{lstlisting}
2290 |
2291 |
2292 | \begin{lstlisting}[style=incellstyle,caption={Code Listing in cell 33}, label=lst:autolistingcell33]
2293 | for i in [1,2,3]:
2294 | si = str(i)
2295 | v = doprint(si)
2296 |
2297 | val = v * 3
2298 | print(val)
2299 | print(v)
2300 | \end{lstlisting}
2301 |
2302 |
2303 | \begin{lstlisting}[style=incellstyle,caption={Listing caption in cell with a figure}, label=lst:figurelisting]
2304 | #this figure is given meta data caption parameters, it will be floated in the latex export
2305 | display(Image(filename='images/keep-calm-and-code-python_BW.png', width=250, height=250))
2306 | print('also force print output')
2307 |
2308 | \end{lstlisting}
2309 |
2310 |
2311 | \begin{lstlisting}[style=incellstyle,caption={Code Listing in cell 46}, label=lst:autolistingcell46]
2312 | #this figure is not given meta data caption parameters, it will be inlined in the latex export
2313 | display(Image(filename='images/random-squares-2.png', width=200, height=200))
2314 | \end{lstlisting}
2315 |
2316 |
2317 | \begin{lstlisting}[style=incellstyle,caption={Code Listing in cell 48}, label=lst:autolistingcell48]
2318 | ##
2319 | %matplotlib inline
2320 |
2321 | import pylab as pl
2322 | import numpy as np
2323 |
2324 | t = np.arange(0.0, 2.0, 0.01)
2325 | s = np.sin(2*np.pi*t)
2326 | pl.plot(t, s)
2327 | pl.xlabel('time (s)')
2328 | pl.ylabel('voltage (mV)')
2329 | pl.title('About as simple as it gets, folks')
2330 | pl.grid(True)
2331 |
2332 | \end{lstlisting}
2333 |
2334 |
2335 | \begin{lstlisting}[style=incellstyle,caption={Code Listing in cell 52}, label=lst:autolistingcell52]
2336 | ##
2337 | %matplotlib inline
2338 |
2339 | import pylab as pl
2340 | import numpy as np
2341 |
2342 | t = np.arange(0.0, 2.0, 0.01)
2343 | s = np.sin(2*np.pi*t)
2344 | pl.plot(t, s)
2345 | pl.xlabel('time (s)')
2346 | pl.ylabel('voltage (mV)')
2347 | pl.title('About as simple as it gets, folks')
2348 | pl.grid(True)
2349 | \end{lstlisting}
2350 |
2351 |
2352 | \begin{lstlisting}[style=incellstyle,caption={Code Listing in cell 54}, label=lst:autolistingcell54]
2353 | import pyradi.ryplot as ryplot
2354 |
2355 | x = np.linspace(0,10,10)
2356 | a = ryplot.Plotter(1,figsize=(3,2))
2357 | b = ryplot.Plotter(2,figsize=(3,2))
2358 | c = ryplot.Plotter(3,figsize=(3,2))
2359 | for i in [1,2]:
2360 | a.plot(1,x,x ** i,'Plotter instance a',label=[str(i)])
2361 | b.plot(1,x,(-x) ** i,'Plotter instance b (non floating)',label=[str(i)])
2362 | c.plot(1,x,(5-x) ** i,'Plotter instance c',label=[str(i)])
2363 | \end{lstlisting}
2364 |
2365 |
2366 | \begin{lstlisting}[style=incellstyle,caption={Code Listing in cell 57}, label=lst:autolistingcell57]
2367 | import pyradi.ryplot as ryplot
2368 |
2369 | x = np.linspace(0,10,10)
2370 | a = ryplot.Plotter(1,figsize=(3,2))
2371 | b = ryplot.Plotter(2,figsize=(3,2))
2372 | for i in [1,2]:
2373 | a.plot(1,x,x ** i,r'Plotter instance with $\alpha$',label=[str(i)])
2374 | b.plot(1,x,(-x) ** i,r'Plotter instance with $\beta$',label=[str(i)])
2375 |
2376 | \end{lstlisting}
2377 |
2378 |
2379 | \begin{lstlisting}[style=incellstyle,caption={Code Listing in cell 60}, label=lst:autolistingcell60]
2380 | plots = []
2381 | for i,name in enumerate(['a','b','c']):
2382 | plots.append(ryplot.Plotter(i,1,1,figsize=(5,5)))
2383 | p = plots[-1]
2384 | p.plot(1, x,x ** (i+3))
2385 |
2386 | \end{lstlisting}
2387 |
2388 |
2389 | \begin{lstlisting}[style=incellstyle,caption={Code Listing in cell 63}, label=lst:autolistingcell63]
2390 | htmlstr = '
'
2391 | HTML(htmlstr)
2392 | \end{lstlisting}
2393 |
2394 |
2395 | \begin{lstlisting}[style=incellstyle,caption={Code Listing in cell 72}, label=lst:autolistingcell72]
2396 | # type(eval("this is a test string")) is not list
2397 | \end{lstlisting}
2398 |
2399 |
2400 | \begin{lstlisting}[style=incellstyle,caption={Code Listing in cell 88}, label=lst:autolistingcell88]
2401 | import pandas as pd
2402 | d = {'one' : pd.Series([1., 2., 3.], index=['a', 'b', 'c']),
2403 | 'two' : pd.Series([1., 2., 3., 4.], index=['a', 'b', 'c', 'd'])}
2404 |
2405 | df = pd.DataFrame(d)
2406 |
2407 | HTML(df.to_html())
2408 | \end{lstlisting}
2409 |
2410 |
2411 | \begin{lstlisting}[style=incellstyle,caption={Code Listing in cell 93}, label=lst:autolistingcell93]
2412 | # to create the dataframe and write the output to LaTeX object at default font size
2413 | import pandas as pd
2414 | import numpy as np
2415 | from IPython.display import Latex
2416 |
2417 | def makeDateRand(nrows=5, ncols=4, cols=list('ABCD')):
2418 | dates = pd.date_range('20130101',periods=nrows)
2419 | df = pd.DataFrame(np.random.randn(nrows,ncols),index=dates,columns=cols)
2420 | return df
2421 |
2422 | df = makeDateRand(nrows=3, ncols=5,cols=list('ABCDE'))
2423 | lstr = df.to_latex(column_format='|l|l|l|p{50mm}|c|r|')
2424 | Latex(lstr)
2425 |
2426 |
2427 | \end{lstlisting}
2428 |
2429 |
2430 | \begin{lstlisting}[style=incellstyle,caption={Code Listing in cell 94}, label=lst:autolistingcell94]
2431 | lstrno = df.to_latex(index=False,column_format='|l|l|p{50mm}|c|r|')
2432 | Latex(lstrno)
2433 | \end{lstlisting}
2434 |
2435 |
2436 | \begin{lstlisting}[style=incellstyle,caption={Code Listing in cell 96}, label=lst:autolistingcell96]
2437 | # to write the table in LARGE
2438 |
2439 | Latex(lstr)
2440 | \end{lstlisting}
2441 |
2442 |
2443 | \begin{lstlisting}[style=incellstyle,caption={Code Listing in cell 98}, label=lst:autolistingcell98]
2444 | # to write a floating table in tiny font size
2445 |
2446 | Latex(lstr)
2447 | \end{lstlisting}
2448 |
2449 |
2450 | \begin{lstlisting}[style=incellstyle,caption={Code Listing in cell 102}, label=lst:autolistingcell102]
2451 | # display a tikz graphic
2452 | lstr = r"""
2453 | \begin{tikzpicture}[scale=4.5, line join=bevel]
2454 | % \a and \b are two macros defining characteristic
2455 | % dimensions of the impossible brick.
2456 | \pgfmathsetmacro{\a}{0.18}
2457 | \pgfmathsetmacro{\b}{1.37}
2458 |
2459 | \tikzset{%
2460 | apply style/.code={\tikzset{#1}},
2461 | brick_edges/.style={thick,draw=black},
2462 | face_colourA/.style={fill=gray!50},
2463 | face_colourB/.style={fill=gray!25},
2464 | face_colourC/.style={fill=gray!90},
2465 | }
2466 |
2467 | \foreach \theta/\v/\facestyleone/\facestyletwo in {%
2468 | 0/0/{brick_edges,face_colourA}/{brick_edges,face_colourC},
2469 | 180/-\a/{brick_edges,face_colourB}/{brick_edges,face_colourC}
2470 | }{
2471 | \begin{scope}[rotate=\theta,shift={(\v,0)}]
2472 | \draw[apply style/.expand once=\facestyleone]
2473 | ({-.5*\b},{1.5*\a}) --
2474 | ++(\b,0) --
2475 | ++(-\a,-\a) --
2476 | ++({-\b+2*\a},0) --
2477 | ++(0,-{2*\a}) --
2478 | ++(\b,0) --
2479 | ++(-\a,-\a) --
2480 | ++(-\b,0) --
2481 | cycle;
2482 | \draw[apply style/.expand once=\facestyletwo]
2483 | ({.5*\b},{1.5*\a}) --
2484 | ++(0,{-2*\a}) --
2485 | ++(-\a,0) --
2486 | ++(0,\a) --
2487 | cycle;
2488 | \end{scope}
2489 | }
2490 | \end{tikzpicture}
2491 | """
2492 |
2493 | Latex(lstr)
2494 | \end{lstlisting}
2495 |
2496 |
2497 | \begin{lstlisting}[style=incellstyle,caption={Code Listing in cell 103}, label=lst:autolistingcell103]
2498 | # display another tikz graphic, as a floating figure
2499 |
2500 | lstr = r"""
2501 | \begin{tikzpicture}[font = \sansmath]
2502 | \coordinate (O) at (0,0);
2503 |
2504 | % ball background color
2505 | \shade[ball color = blue, opacity = 0.2] (0,0) circle [radius = 2cm];
2506 |
2507 | % cone
2508 | \begin{scope}
2509 | \def\rx{0.71}% horizontal radius of the ellipse
2510 | \def\ry{0.15}% vertical radius of the ellipse
2511 | \def\z{0.725}% distance from center of ellipse to origin
2512 |
2513 | \path [name path = ellipse] (0,\z) ellipse ({\rx} and {\ry});
2514 | \path [name path = horizontal] (-\rx,\z-\ry*\ry/\z)
2515 | -- (\rx,\z-\ry*\ry/\z);
2516 | \path [name intersections = {of = ellipse and horizontal}];
2517 |
2518 | % radius to base of cone in ball
2519 | \draw[fill = gray!50, gray!50] (intersection-1) -- (0,0)
2520 | -- (intersection-2) -- cycle;
2521 | % base of cone in ball
2522 | \draw[fill = gray!30, densely dashed] (0,\z) ellipse ({\rx} and {\ry});
2523 | \end{scope}
2524 |
2525 | % label of cone
2526 | \draw (0.25,0.4) -- (0.9,0.1) node at (1.05,0.0) {$q$};
2527 |
2528 | % ball
2529 | \draw (O) circle [radius=2cm];
2530 | % label of ball center point
2531 | \filldraw (O) circle (1pt) node[below] {$P$};
2532 |
2533 | % radius
2534 | \draw[densely dashed] (O) to [edge label = $r$] (-1.33,1.33);
2535 | \draw[densely dashed] (O) -- (1.33,1.33);
2536 |
2537 | % cut of ball surface
2538 | \draw[red] (-1.35,1.47) arc [start angle = 140, end angle = 40,
2539 | x radius = 17.6mm, y radius = 14.75mm];
2540 | \draw[red, densely dashed] (-1.36,1.46) arc [start angle = 170, end angle = 10,
2541 | x radius = 13.8mm, y radius = 3.6mm];
2542 | \draw[red] (-1.29,1.52) arc [start angle=-200, end angle = 20,
2543 | x radius = 13.75mm, y radius = 3.15mm];
2544 |
2545 | % label of cut of ball surface
2546 | \draw (-1.2,2.2) -- (-0.53,1.83) node at (-1.37,2.37) {$A$};
2547 | \end{tikzpicture}
2548 | """
2549 |
2550 | Latex(lstr)
2551 | \end{lstlisting}
2552 |
2553 |
2554 | \begin{lstlisting}[style=incellstyle,caption={Code Listing in cell 105}, label=lst:autolistingcell105]
2555 | ##
2556 | lstr = '\n\nThis paragraph is embedded as \LaTeX{} in a Jupyter output cell. '\
2557 | + 'One day this could be a complex computed \LaTeX{} string. '\
2558 | + 'This example only has rising rules... \n\n'
2559 | for height in range(1,20):
2560 | lstr += '\\rule[0pt]{{10pt}}{}{}pt{} '.format('{',height,'}')
2561 | Latex(lstr + '\n')
2562 | \end{lstlisting}
2563 |
2564 |
2565 | \begin{lstlisting}[style=incellstyle,caption={Code Listing in cell 107}, label=lst:autolistingcell107]
2566 | # to format a numy array in \LaTeX{}
2567 | import numpy as np
2568 | # install with pip install pylatex
2569 | import pylatex as pyl
2570 |
2571 | arr = makeDateRand(nrows=6, ncols=4).values
2572 | matrix = pyl.Matrix(arr, mtype='b')
2573 | math = pyl.Math(data=['arr=', matrix])
2574 | Latex(math.dumps_as_content())
2575 |
2576 | \end{lstlisting}
2577 |
2578 |
2579 | \begin{lstlisting}[style=incellstyle,caption={Code Listing in cell 127}, label=lst:autolistingcell127]
2580 | ##
2581 | # to get software versions
2582 | # https://github.com/rasbt/watermark
2583 | # you only need to do this once
2584 | # pip install watermark
2585 |
2586 | %load_ext watermark
2587 | %watermark -v -m -p numpy,scipy,pyradi -g
2588 | \end{lstlisting}
2589 |
2590 | \atendofdoc
2591 |
2592 | \end{document}
2593 |
2594 |
--------------------------------------------------------------------------------
/workpackage.cls:
--------------------------------------------------------------------------------
1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2 |
3 | \NeedsTeXFormat{LaTeX2e}
4 | \def\fileversion{ver 0.9.0}%
5 | \def\filedate{2012-04-03}%
6 | \ProvidesClass{workpackage}[2012/04/03 v-0.9.0 work package style]
7 | \LoadClass[12pt,a4paper]{report}[1994/12/09]
8 |
9 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10 | \usepackage{ifthen}
11 | \usepackage[titles]{tocloft}
12 | \usepackage{ifpdf} % used to detect PDFLatex or Latex mode
13 |
14 | % the follwing two lines are added to get arial/helvetica as default text style
15 | \usepackage[scaled=0.92]{helvet}
16 | \renewcommand{\familydefault}{\sfdefault}
17 |
18 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
19 | \DeclareOption{twocolumn}{\OptionNotUsed}
20 | \DeclareOption*{\PassOptionsToClass{\CurrentOption}{report}}
21 |
22 | \ProcessOptions
23 |
24 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
25 | % page layout
26 |
27 | \pagenumbering{arabic}
28 | \onecolumn
29 | \raggedbottom
30 |
31 | \setlength{\topmargin}{5.0mm}
32 | \setlength{\headheight}{12mm}
33 | \setlength{\headsep}{10mm}
34 | \setlength{\topskip}{10mm}
35 | \setlength{\footskip}{15mm}
36 |
37 | \setlength{\parindent}{0.0mm}
38 | \setlength{\parskip}{6pt}
39 |
40 | \setlength{\unitlength}{1mm}
41 |
42 | \setcounter{secnumdepth}{4}
43 | \setcounter{tocdepth}{3}
44 |
45 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
46 | % Change the headings in the toc to uppercase
47 | \renewcommand*{\contentsname}{CONTENTS}
48 | \renewcommand*{\listfigurename}{LIST OF FIGURES}
49 | \renewcommand*{\listtablename}{LIST OF TABLES}
50 | \renewcommand*{\bibname}{BIBLIOGRAPHY}
51 | \renewcommand*{\figurename}{FIGURE}
52 | \renewcommand*{\tablename}{TABLE}
53 | \def\listabbreviationname{ABBREVIATIONS}
54 |
55 |
56 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
57 | % Define variables
58 |
59 | \newcommand{\WPproject}[1]{\renewcommand{\WP@project}{#1}}
60 | \newcommand{\WP@project}{}
61 | \@onlypreamble{\WPproject}
62 |
63 | \newcommand{\WPdocnumber}[1]{\renewcommand{\WP@docnumber}{#1}}
64 | \newcommand{\WP@docnumber}{}
65 | \@onlypreamble{\WPdocnumber}
66 |
67 | \newcommand{\WPequipment}[1]{\renewcommand{\WP@equipment}{#1}}
68 | \newcommand{\WP@equipment}{}
69 | \@onlypreamble{\WPequipment}
70 |
71 | \newcommand{\WPsubject}[1]{\renewcommand{\WP@subject}{#1}}
72 | \newcommand{\WP@subject}{}
73 | \@onlypreamble{\WPsubject}
74 |
75 | \newcommand{\WPdistribution}[1]{\renewcommand{\WP@distribution}{#1}}
76 | \newcommand{\WP@distribution}{}
77 | \@onlypreamble{\WPdistribution}
78 |
79 | \newcommand{\WPconclusions}[1]{\renewcommand{\WP@conclusions}{#1}}
80 | \newcommand{\WP@conclusions}{}
81 | \@onlypreamble{\WPconclusions}
82 |
83 | \newcommand{\WPdocauthor}[1]{\renewcommand{\WP@docauthor}{#1}}
84 | \newcommand{\WP@docauthor}{}
85 | \@onlypreamble{\WPdocauthor}
86 |
87 | \newcommand{\WPsigauthor}[1]{\renewcommand{\WP@sigauthor}{#1}}
88 | \newcommand{\WP@sigauthor}{}
89 | \@onlypreamble{\WPsigauthor}
90 |
91 | \newcommand{\WPprevpackdate}[1]{\renewcommand{\WP@prevpackdate}{#1}}
92 | \newcommand{\WP@prevpackdate}{}
93 | \@onlypreamble{\WPprevpackdate}
94 |
95 | \newcommand{\WPprevpacknumber}[1]{\renewcommand{\WP@prevpacknumber}{#1}}
96 | \newcommand{\WP@prevpacknumber}{}
97 | \@onlypreamble{\WPprevpacknumber}
98 |
99 | \newcommand{\WPsuperpackdate}[1]{\renewcommand{\WP@superpackdate}{#1}}
100 | \newcommand{\WP@superpackdate}{}
101 | \@onlypreamble{\WPsuperpackdate}
102 |
103 | \newcommand{\WPsuperpacknumber}[1]{\renewcommand{\WP@superpacknumber}{#1}}
104 | \newcommand{\WP@superpacknumber}{}
105 | \@onlypreamble{\WPsuperpacknumber}
106 |
107 | \newcommand{\WPcurrentpackdate}[1]{\renewcommand{\WP@currentpackdate}{#1}}
108 | \newcommand{\WP@currentpackdate}{}
109 | \@onlypreamble{\WPcurrentpackdate}
110 |
111 | \newcommand{\WPcurrentpacknumber}[1]{\renewcommand{\WP@currentpacknumber}{#1}}
112 | \newcommand{\WP@currentpacknumber}{}
113 | \@onlypreamble{\WPcurrentpacknumber}
114 |
115 |
116 | \newcommand{\WPdocmaxpage}[1]{\renewcommand{\WP@docmaxpage}{#1}}
117 | \newcommand{\WP@docmaxpage}{}
118 | \@onlypreamble{\WPdocmaxpage}
119 |
120 | \newcommand{\WPclassification}[1]{\renewcommand{\WP@classification}{#1}}
121 | \newcommand{\WP@classification}{}
122 | \@onlypreamble{\WPclassification}
123 |
124 | \newcommand{\WPcontractname}[1]{\renewcommand{\WP@contractname}{#1}}
125 | \newcommand{\WP@contractname}{}
126 | \@onlypreamble{\WPcontractname}
127 |
128 | \newcommand{\WPcontractline}[1]{\renewcommand{\WP@contractline}{#1}}
129 | \newcommand{\WP@contractline}{}
130 | \@onlypreamble{\WPcontractline}
131 |
132 | \newcommand{\WPorderno}[1]{\renewcommand{\WP@orderno}{#1}}
133 | \newcommand{\WP@orderno}{}
134 | \@onlypreamble{\WPorderno}
135 |
136 | \newcommand{\WPmilestonenumber}[1]{\renewcommand{\WP@milestonenumber}{#1}}
137 | \newcommand{\WP@milestonenumber}{}
138 | \@onlypreamble{\WPmilestonenumber}
139 |
140 | \newcommand{\WPmilestonetitle}[1]{\renewcommand{\WP@milestonetitle}{#1}}
141 | \newcommand{\WP@milestonetitle}{}
142 | \@onlypreamble{\WPmilestonetitle}
143 |
144 | \newcommand{\WPdocdescript}[1]{\renewcommand{\WP@docdescript}{#1}}
145 | \newcommand{\WP@docdescript}{}
146 | \@onlypreamble{\WPdocdescript}
147 |
148 | \newcommand{\WPdocontractdetails}[1]{\renewcommand{\WP@docontractdetails}{#1}}
149 | \newcommand{\WP@docontractdetails}{}
150 | \@onlypreamble{\WPdocontractdetails}
151 |
152 | \newcommand{\WPdocECPnumber}[1]{\renewcommand{\WP@docECPnumber}{#1}}
153 | \newcommand{\WP@docECPnumber}{}
154 | \@onlypreamble{\WPdocECPnumber}
155 |
156 | \newcommand{\WPdocECPtext}[1]{\renewcommand{\WP@docECPtext}{#1}}
157 | \newcommand{\WP@docECPtext}{ECP}
158 | \@onlypreamble{\WPdocECPtext}
159 |
160 |
161 | \newcommand{\WPdocLogo}[1]{\renewcommand{\WP@docLogo}{#1}}
162 | \newcommand{\WP@docLogo}{}
163 | \@onlypreamble{\WPdocLogo}
164 |
165 |
166 |
167 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
168 | % Packages used in this style
169 |
170 | \ifpdf %This text is produced when in pdfTeX mode.
171 | \usepackage[pdftex]{graphicx}
172 | \usepackage{epstopdf}
173 | \else % This text is produced when in DVI mode,
174 | \usepackage[dvips]{graphics}
175 | \usepackage[dvips]{graphicx}
176 | \fi
177 |
178 |
179 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
180 | % do the chapter page layout
181 | \usepackage{titlesec}
182 | %\titleformat{\chapter}{\normalfont\LARGE\bfseries}{\thechapter.}{1em}{}
183 | \titleformat{\chapter}{\centering\normalfont\Large\bfseries\scshape}{\thechapter}{1em}{}
184 | \titlespacing*{\chapter}{0cm}{-0.2\topskip}{20pt}[0pt]
185 |
186 |
187 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
188 | % Do layout
189 |
190 | \newcommand{\WPlayout}{%
191 | \sloppy%
192 | \begin{picture}(182,240)
193 | \linethickness{1.5mm}
194 | \thicklines
195 |
196 | \ifthenelse{\equal{\WP@docontractdetails}{true}}%
197 | {% true section
198 | \put(2,223){\makebox(0,0)[lc]{{\scriptsize
199 | {\textsc{Contract Title:} \WP@contractname} \ \ \ \
200 | {\textsc{Order Number:} \WP@orderno} \ \ \ \
201 | {\textsc{Line Number:} \WP@contractline} \ \ \ \
202 | {\textsc{\WP@docECPtext number:} \WP@docECPnumber}
203 | }}}
204 | \put(2,219){\makebox(0,0)[lc]{{\scriptsize
205 | {\textsc{Milestone Number:} \WP@milestonenumber} \ \ \ \
206 | {\textsc{Milestone Title:} \WP@milestonetitle} \ \ \ \
207 | }}}
208 | }
209 | {%false section
210 | \vspace{10mm}}
211 |
212 |
213 | \put( 91,230){\makebox(0,0)[cc]{{\huge {\bfseries\sffamily\scshape \WP@project \ Work Package}}}}
214 | \put( 0,203){\framebox(182,14){}}
215 | \put( 2,214){\makebox(0,0)[lc]{{\small \textsc{ Document Number}}}}
216 | \put( 25,208){\makebox(0,0)[cc]{{\WP@docnumber}}}
217 | \put( 50,203){\line(0,1){14}}
218 | \put( 52,214){\makebox(0,0)[lc]{{\small \textsc{ Equipment or Sub-System}}}}
219 | \put(116,208){\makebox(0,0)[cc]{{\WP@equipment}}}
220 | %
221 | \put( 0,190){\makebox(0,0)[lb]{{\large {\sffamily\scshape Subject}}}}
222 | \put( 0,173){\framebox(182,14){}}
223 | \put( 5,180){\parbox[t]{172mm}{{\WP@subject}}}
224 | %
225 | \put( 0,162){\makebox(0,0)[lb]{{\large {\sffamily\scshape Distribution}}}}
226 | \put( 0,140){\framebox(182,19){}}
227 | \put( 5,154){\parbox[t]{172mm}{{\WP@distribution}}}
228 | %
229 | \put( 0,132){\makebox(0,0)[lb]{{\large {\sffamily\scshape
230 | Conclusions/Decisions/Amendments}}}}
231 | \put( 0, 42){\framebox(182,87 ){}}
232 | \put( 5,122){\begin{minipage}[t]{172mm}\WP@conclusions\end{minipage}}
233 | %
234 | \put( 0, 20){\framebox(182,12){}}
235 | \put( 2, 29){\makebox(0,0)[lc]{{\small \textsc{ Author}}}}
236 | \put( 46, 26){\makebox(0,0)[cc]{{\WP@docauthor}}}
237 | \put( 91, 20){\line(0,1){12}}
238 | \put( 93, 29){\makebox(0,0)[lc]{{\small \textsc{ Signature}}}}
239 | \put( 137, 26){\makebox(0,0)[cc]{{\WP@sigauthor}}}
240 | \put( 0, -10){\framebox(54,20){}}
241 | \put( 0, 04){\line(1,0){54}}
242 | \put( 2, 07){\makebox(0,0)[lc]{{\small \textsc{ Date}}}}
243 | \put( 32, 07){\makebox(0,0)[cc]{{\WP@prevpackdate}}}
244 | \put( 2, 01){\makebox(0,0)[lc]{{\small \textsc{ Previous Package No.}}}}
245 | \put( 27, -5){\makebox(0,0)[cc]{{\WP@prevpacknumber}}}
246 | \put( 64, -10){\framebox(54,20){}}
247 | \put( 64, 04){\line(1,0){54}}
248 | \put( 66, 07){\makebox(0,0)[lc]{{\small \textsc{ Date}}}}
249 | \put( 96, 07){\makebox(0,0)[cc]{{\WP@superpackdate}}}
250 | \put( 66, 01){\makebox(0,0)[lc]{{\small \textsc{ Superseding Package No.}}}}
251 | \put( 91, -05){\makebox(0,0)[cc]{{\WP@superpacknumber}}}
252 | \put(128, -10){\framebox(54,20){}}
253 | \put(128, 04){\line(1,0){54}}
254 | \put(130, 07){\makebox(0,0)[lc]{{\small \textsc{ Date}}}}
255 | \put(160, 07){\makebox(0,0)[cc]{{\WP@currentpackdate}}}
256 | \put(130, 01){\makebox(0,0)[lc]{{\small \textsc{ Current Package No.}}}}
257 | \put(155, -05){\makebox(0,0)[cc]{{\WP@currentpacknumber}}}
258 | \end{picture}
259 | \newpage
260 | \fussy
261 |
262 | }
263 |
264 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
265 | % test if logo is empty, else make picture
266 | \newcommand{\doLogo}[1]{
267 | \ifthenelse{\equal{#1}{}}{}{%
268 | \begin{picture}(0,0)
269 | \ifpdf %This text is produced when in pdfTeX mode.
270 | \put(-1,-8){ \includegraphics{logo.png}}
271 | \else % This text is produced when in DVI mode,
272 | \put(-1,-8){ \includegraphics[bb=0 0 2104 171,scale=0.22]{logo.png}}
273 | \fi
274 | \end{picture}
275 | }
276 | }
277 |
278 |
279 |
280 | \newlength{\lengthbuf}
281 |
282 | \newcommand{\ps@WPheadings}{
283 | \renewcommand{\@oddhead}{
284 | \begin{minipage}[t]{\textwidthm}
285 | \doLogo{\WP@docLogo}
286 | \ \newline
287 | \vspace{-4mm}
288 | \settowidth{\lengthbuf}{\scshape\WP@classification}%
289 | \hspace{0.5\textwidth}%
290 | \hspace{-0.5\lengthbuf}%
291 | \makebox{\scshape\small{\WP@classification}}
292 | \hfill
293 | \vspace{8mm}
294 | \hrule
295 | \end{minipage}
296 | \fussy
297 | }
298 | \renewcommand{\@evenhead}{\@oddhead}
299 | \renewcommand{\@oddfoot}{
300 | \begin{minipage}{\textwidthm}
301 | \sloppy \hbadness=10000
302 | \hrule
303 | \small{\vrule height10pt width0pt depth10pt } %
304 | \scshape{\WP@docECPtext \WP@docECPnumber\hfill
305 | \WP@classification \hfill Page \thepage\ of \WP@docmaxpage}
306 | \end{minipage}\fussy
307 | }
308 | \renewcommand{\@evenfoot}{\@oddfoot}
309 | }
310 |
311 | %always use the page format, therefore re-define plain and empty
312 | \renewcommand{\ps@plain}{\ps@WPheadings}
313 | \renewcommand{\ps@empty}{\ps@WPheadings}
314 |
315 | \pagestyle{WPheadings}
316 |
317 |
318 | \def\today{\ifcase\month\or
319 | January\or February\or March\or April\or May\or June\or
320 | July\or August\or September\or October\or November\or December\fi
321 | \space\number\day, \number\year}
322 |
323 | \@addtoreset{equation}{chapter}
324 | \def\theequation{\thechapter.\arabic{equation}}
325 |
326 | %----------------------------------------------------------------------------
327 | %table of contents
328 |
329 | \renewcommand{\@pnumwidth}{2.em}
330 | \renewcommand{\@tocrmarg} {2.55em}
331 | \renewcommand{\@dotsep}{4.5}
332 |
333 | %format of the chapter entry in the toc
334 | \addtocontents{toc}{\protect\renewcommand{\protect\cftchapleader}
335 | {\protect\cftdotfill{\cftsecdotsep}}}
336 | \renewcommand{\cftchapfont}{\mdseries}
337 | \renewcommand{\cftchappagefont}{\mdseries}
338 |
339 | %----------------------------------------------------------------------------
340 |
341 | \WPdocmaxpage{\pageref{LastPage}}
342 |
343 |
--------------------------------------------------------------------------------