├── .gitignore ├── Airbus └── AIRBUS_D&S_Flat_BLACK.jpg ├── Makefile ├── Makefile.include ├── README.md ├── _cleanAllTeX.py ├── codestructure.xlsx ├── header.tex ├── images ├── BW.png ├── Bankedturn.pdf ├── discretestrata01.pdf ├── flow2-zzz.png ├── keep-calm-and-code-python_BW.png ├── random-squares-2.png ├── test2LaTeX_40_0.png ├── test2LaTeX_42_0.png ├── test2LaTeX_44_0.png ├── test2LaTeX_46_0.png ├── test2LaTeX_46_1.png └── test2LaTeX_46_2.png ├── ipnb2tex.py ├── logo.png ├── pic └── .gitkeep ├── test2LaTeX.bib ├── test2LaTeX.ipynb ├── test2LaTeX.pdf ├── test2LaTeX.tex └── workpackage.cls /.gitignore: -------------------------------------------------------------------------------- 1 | /pic 2 | test2LaTeX.aux 3 | test2LaTeX.lof 4 | test2LaTeX.bbl 5 | test2LaTeX.blg 6 | test2LaTeX.log 7 | test2LaTeX.lol 8 | test2LaTeX.lot 9 | test2LaTeX.synctex 10 | test2LaTeX.toc 11 | /.ipynb_checkpoints 12 | /revision.tex 13 | -------------------------------------------------------------------------------- /Airbus/AIRBUS_D&S_Flat_BLACK.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NelisW/ipynb2tex/78598d4bc17a00286af24504b51e392b8e833175/Airbus/AIRBUS_D&S_Flat_BLACK.jpg -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | TARGET=test2LaTeX 2 | PDFVIEWER= 3 | AFTERALL=postprocessing 4 | BEFOREALL=preprocessing 5 | 6 | include Makefile.include 7 | 8 | postprocessing: 9 | # doing post processing 10 | 11 | preprocessing: 12 | # doing preprocessing 13 | @if [ ${NO_BIBTEX_ENV} ]; then \ 14 | cp -p ${BIBTEX_ENV}/*.bib ${LISTFIRSTBIBFILE}/.; \ 15 | cp -p ${BIBTEX_ENV}/abbrev.tex ${LISTFABBREVTEXFILE}/.; \ 16 | else echo no BIBTEX_ENV environment variable found, no *.bib files copied; fi 17 | 18 | 19 | -------------------------------------------------------------------------------- /Makefile.include: -------------------------------------------------------------------------------- 1 | ### 2 | ### generic GNU make Makefile for .tex -> .pdf. 3 | ### ransford at cs.washington.edu 4 | ### http://github.com/ransford/pdflatex-makefile 5 | ### 6 | ### Recommended usage: 7 | ### 1. echo 'include Makefile.include' > Makefile 8 | ### 2. Optional: Edit the Makefile to override $(TARGET) 9 | ### and anything else (e.g., PDFVIEWER, AFTERALL) 10 | ### 3. $ make snapshot 11 | ### # pass around a draft... 12 | ### 4. $ make distill 13 | ### # submit the camera-ready version with embedded fonts 14 | ### 15 | ### Final result: 16 | ### % cat Makefile 17 | ### TARGET=mypaper 18 | ### PDFVIEWER=open -a 'Adobe Acrobat Professional' 19 | ### AFTERALL=mypostprocessingstep 20 | ### include Makefile.include 21 | ### 22 | ### mypostprocessingstep: 23 | ### # do something... 24 | ### 25 | ### this version also buils the main latex file from a Jupyter notebook is present. 26 | 27 | PDFLATEX ?= pdflatex -halt-on-error -file-line-error -shell-escape 28 | BIBTEX ?= bibtex 29 | BIBER ?= biber 30 | MAKEGLOSSARIES ?= makeglossaries 31 | MAKENOMENCL ?= makeindex 32 | MAKEINDEX ?= makeindex 33 | IPNB2TEX ?= python ipnb2tex.py 34 | 35 | ## String to find in log to check whether rerun is necessary 36 | RERUN_PATTERN = Rerun to|rerun LaTeX|run LaTeX again 37 | 38 | ifneq ($(QUIET),) 39 | PDFLATEX += -interaction=batchmode 40 | ERRFILTER := > /dev/null || (egrep ':[[:digit:]]+:' *.log && false) 41 | BIBTEX += -terse 42 | BIBER += --quiet 43 | MAKEGLOSSARIES += -q 44 | MAKENOMENCL += -q 45 | else 46 | PDFLATEX += -interaction=nonstopmode 47 | ERRFILTER= 48 | endif 49 | 50 | ## Action for 'make view' 51 | OS=$(shell uname -s) 52 | ifeq ($(OS),Darwin) 53 | PDFVIEWER ?= open 54 | else 55 | PDFVIEWER ?= xdg-open 56 | endif 57 | 58 | ## Name of the target file, minus .pdf: e.g., TARGET=mypaper causes this 59 | ## Makefile to turn mypaper.tex into mypaper.pdf. 60 | TARGETS += $(TARGET) 61 | TEXTARGETS = $(TARGETS:=.tex) 62 | PDFTARGETS = $(TARGETS:=.pdf) 63 | AUXFILES = $(TARGETS:=.aux) 64 | LOGFILES = $(TARGETS:=.log) 65 | INDEXFILES= $(TARGETS:=.idx) 66 | 67 | ## Inkscape SVG file processing: 68 | ifeq ($(shell which inkscape >/dev/null 2>&1 && echo USING_INKSCAPE),USING_INKSCAPE) 69 | FIG_SVG=$(wildcard $(FIGS)/*.svg) 70 | FIG_PDF=$(FIG_SVG:.svg=.pdf) 71 | else 72 | FIG_PDF= 73 | endif 74 | 75 | LISTALLTEXFILES=$(shell find . -type f -name '*.tex') 76 | 77 | ## If $(TARGET).tex refers to .bib files like \bibliography{foo,bar}, then 78 | ## $(BIBTEXFILES) will contain foo.bib and bar.bib, and both files will be added as 79 | ## dependencies to $(PDFTARGETS). 80 | ## Effect: updating a .bib file will trigger re-typesetting. 81 | BIBTEXFILES += $(patsubst %,%.bib,\ 82 | $(shell grep '^[^%]*\\bibliography{' $(TEXTARGETS) | \ 83 | grep -o '\\bibliography{[^}]\+}' | \ 84 | sed -e 's/^[^%]*\\bibliography{\([^}]*\)}.*/\1/' \ 85 | -e 's/, */ /g')) 86 | 87 | ## If $(TARGET).tex refers to .bib files like \addbibresource{foo.bib}, then 88 | ## $(BIBLATEXFILES) will contain foo.bib and will be added as dependencies to $(PDFTARGETS). 89 | ## Effect: updating a .bib file will trigger re-typesetting. 90 | BIBLATEXFILES += $(shell \ 91 | grep '^[^%]*\\addbibresource{' $(TEXTARGETS) | \ 92 | grep -o '\\addbibresource{[^}]\+}' | \ 93 | sed -e 's/^[^%]*\\addbibresource{\([^}]*\)}.*/\1/' \ 94 | -e 's/, */ /g') 95 | 96 | ## Add \input'ed or \include'd files to $(PDFTARGETS) dependencies; ignore 97 | ## .tex extensions. 98 | ## this version checks for all tex files in cwd, ot just the root files. 99 | INCLUDEDTEX = $(patsubst %,%.tex,\ 100 | $(shell grep '^[^%]*\\\(input\|include\){' $(LISTALLTEXFILES) | \ 101 | grep -o '\\\(input\|include\){[^}]\+}' | \ 102 | sed -e 's/^.*{\([^}]*\)}.*/\1/' \ 103 | -e 's/\.tex$$//')) 104 | 105 | AUXFILES += $(INCLUDEDTEX:.tex=.aux) 106 | 107 | ## $(info $(LISTALLTEXFILES)) 108 | ## $(info $(BIBTEXFILES)) 109 | ## $(info $(BIBLATEXFILES)) 110 | ## $(info $(INCLUDEDTEX)) 111 | ## $(info $(AUXFILES)) 112 | 113 | ## grab a version number from the repository (if any) that stores this. 114 | ## * REVISION is the current revision number (short form, for inclusion in text) 115 | ## * VCSTURD is a file that gets touched after a repo update 116 | SPACE = $(empty) $(empty) 117 | ifeq ($(shell git status >/dev/null 2>&1 && echo USING_GIT),USING_GIT) 118 | ifeq ($(shell git svn info >/dev/null 2>&1 && echo USING_GIT_SVN),USING_GIT_SVN) 119 | # git-svn 120 | ifeq ($(REVISION),) 121 | REVISION := $(shell git svn find-rev git-svn) 122 | endif 123 | VCSTURD := $(subst $(SPACE),\ ,$(shell git rev-parse --git-dir)/refs/remotes/git-svn) 124 | else 125 | # plain git 126 | ifeq ($(REVISION),) 127 | REVISION := $(shell git describe --always HEAD) 128 | endif 129 | GIT_BRANCH := $(shell git symbolic-ref HEAD 2>/dev/null) 130 | VCSTURD := $(subst $(SPACE),\ ,$(shell git rev-parse --git-dir)/$(GIT_BRANCH)) 131 | endif 132 | else ifeq ($(shell hg root >/dev/null 2>&1 && echo USING_HG),USING_HG) 133 | # mercurial 134 | ifeq ($(REVISION),) 135 | REVISION := $(shell hg id -i) 136 | endif 137 | VCSTURD := $(subst $(SPACE),\ ,$(shell hg root)/.hg/dirstate) 138 | else ifeq ($(shell svn info >/dev/null && echo USING_SVN),USING_SVN) 139 | # subversion 140 | ifeq ($(REVISION),) 141 | REVISION := $(subst :,-,$(shell svnversion -n)) 142 | endif 143 | VCSTURD := $(addsuffix /.svn/entries, $(shell svn info | grep 'Root Path' | sed -e 's/\(.*\:\)\(.*\) /\2/')) 144 | endif 145 | 146 | # .PHONY names all targets that aren't filenames 147 | .PHONY: all clean pdf view snapshot distill distclean 148 | 149 | all: $(BEFOREALL) pdf $(AFTERALL) 150 | 151 | ifeq ($(shell which inkscape >/dev/null 2>&1 && echo USING_INKSCAPE),USING_INKSCAPE) 152 | $(FIGS)/%.pdf: $(FIGS)/%.svg ## Figures for the manuscript 153 | inkscape -C -z --file=$< --export-pdf=$@ 2> /dev/null 154 | endif 155 | 156 | pdf: $(FIG_PDF) $(PDFTARGETS) 157 | 158 | 159 | view: $(PDFTARGETS) 160 | $(PDFVIEWER) $(PDFTARGETS) 161 | 162 | # define a \Revision{} command you can include in your document's preamble. 163 | # especially useful with e.g. draftfooter.sty or fancyhdr. 164 | # usage: \input{revision} 165 | # ... \Revision{} 166 | ifneq ($(REVISION),) 167 | REVDEPS += revision.tex 168 | revision.tex: $(VCSTURD) 169 | /bin/echo '\newcommand{\Revision}'"{$(subst _,\_,$(REVISION))}" > $@ 170 | AUXFILES += revision.aux 171 | endif 172 | 173 | # to generate aux, bcf, idx but not pdf from pdflatex, use -draftmode 174 | %.aux %.bcf %.idx: %.tex $(REVDEPS) 175 | $(PDFLATEX) -draftmode $* $(ERRFILTER) 176 | 177 | # specify KEEPAUX=1 if you need to keep auxiliary (.aux) files for some other 178 | # tool (e.g., an autocompleting text editor) 179 | ifneq ($(KEEPAUX),1) 180 | .INTERMEDIATE: $(AUXFILES) 181 | endif 182 | 183 | # introduce BibTeX dependency if we found a \bibliography 184 | ifneq ($(strip $(BIBTEXFILES)),) 185 | BIBDEPS = $(BIBTEXFILES) #%.bbl 186 | %.bbl: %.aux $(BIBTEXFILES) 187 | $(BIBTEX) $* 188 | endif 189 | 190 | # introduce BibLaTeX/Biber dependency if we found a \addbibresource 191 | ifneq ($(strip $(BIBLATEXFILES)),) 192 | BIBDEPS = $(BIBLATEXFILES) #%.bbl 193 | %.bbl: %.aux %.bcf $(BIBLATEXFILES) 194 | $(BIBER) $* 195 | endif 196 | 197 | # introduce makeglossaries dependency if we found \printglossary/ies 198 | HAS_GLOSSARIES = $(shell \ 199 | grep '^[^%]*\\printglossar\(ies\|y\)' $(TEXTARGETS) $(INCLUDEDTEX) && \ 200 | echo HAS_GLOSSARIES) 201 | ifneq ($(HAS_GLOSSARIES),) 202 | GLSDEPS = %.gls 203 | %.gls: %.aux 204 | $(MAKEGLOSSARIES) $(TARGETS) 205 | endif 206 | 207 | # introduce makenomenclature dependency if we found \printnomenclature 208 | HAS_NOMENCL = $(shell \ 209 | grep '^[^%]*\\printnomenclature' $(TEXTARGETS) $(INCLUDEDTEX) && \ 210 | echo HAS_NOMENCL) 211 | ifneq ($(HAS_NOMENCL),) 212 | NLSDEPS = %.nls 213 | %.nls: %.nlo 214 | $(MAKENOMENCL) $(TARGETS).nlo -s nomencl.ist -o $(TARGETS).nls 215 | endif 216 | 217 | ## introduce makeindex dependency if we found \printindex 218 | HAS_INDEX = $(shell \ 219 | grep '^[^%]*\\printindex' $(TEXTARGETS) $(INCLUDEDTEX) && \ 220 | echo HAS_INDEX) 221 | ifneq ($(HAS_INDEX),) 222 | IDXDEPS = %.ind 223 | %.ind: %.idx 224 | $(MAKEINDEX) $(TARGETS) 225 | endif 226 | 227 | ## build the main tex file from notebook 228 | %.tex: %.ipynb 229 | $(IPNB2TEX) $(%.ipynb) 230 | 231 | $(PDFTARGETS): %.pdf: %.tex %.aux $(IDXDEPS) $(GLSDEPS) $(BIBDEPS) $(INCLUDEDTEX) $(REVDEPS) $(NLSDEPS) 232 | $(PDFLATEX) $* $(ERRFILTER) 233 | ifneq ($(strip $(BIBTEXFILES)),) 234 | @if egrep -q "undefined (references|citations)" $*.log; then \ 235 | $(BIBTEX) $* && $(PDFLATEX) $* $(ERRFILTER); fi 236 | endif 237 | ifneq ($(strip $(BIBLATEXFILES)),) 238 | @if egrep -q "Please \(re\)run Biber on the file:" $*.log; then \ 239 | $(BIBER) $*; fi 240 | endif 241 | @while egrep -q "$(RERUN_PATTERN)" $*.log; do \ 242 | $(PDFLATEX) $* $(ERRFILTER); done 243 | 244 | DRAFTS := $(PDFTARGETS:.pdf=-$(REVISION).pdf) 245 | $(DRAFTS): %-$(REVISION).pdf: %.pdf 246 | cp $< $@ 247 | snapshot: $(DRAFTS) 248 | 249 | %.distilled.pdf: %.pdf 250 | gs -q -dSAFER -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -sOutputFile=$@ \ 251 | -dCompatibilityLevel=1.5 -dPDFSETTINGS=/prepress -c .setpdfwrite -f $< 252 | exiftool -overwrite_original -Title="" -Creator="" -CreatorTool="" $@ 253 | 254 | distill: $(PDFTARGETS:.pdf=.distilled.pdf) 255 | 256 | distclean: clean 257 | $(RM) $(PDFTARGETS) $(PDFTARGETS:.pdf=.distilled.pdf) $(EXTRADISTCLEAN) 258 | 259 | clean: 260 | $(RM) $(foreach T,$(TARGETS), \ 261 | $(T).bbl $(T).bcf $(T).bit $(T).blg \ 262 | $(T)-blx.bib $(T).brf $(T).fdb_latexmk \ 263 | $(T).fls $(T).glg $(T).glo $(T).gls \ 264 | $(T).glsdefs $(T).glx $(T).gxg \ 265 | $(T).gxs $(T).idx $(T).ilg $(T).ind \ 266 | $(T).ist $(T).loa $(T).lof $(T).lol \ 267 | $(T).lot $(T).maf $(T).mtc $(T).nav \ 268 | $(T).out $(T).pag $(T).run.xml $(T).snm \ 269 | $(T).svn $(T).tdo $(T).tns $(T).toc \ 270 | $(T).vtc $(T).url $(T).mw $(T).mw.mw $(T).synctex $(T).synctex.gz \ 271 | $(T).tbb $(T).tbc x.pdf $(T).prj.bak \ 272 | $(T).oldaux \ 273 | $(REVDEPS) $(AUXFILES) $(LOGFILES) \ 274 | $(EXTRACLEAN) $(FIG_PDF) \ 275 | ) 276 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ipynb2tex 2 | ========= 3 | 4 | Yet another IPython notebook to LaTeX converter - this one exports clean code in the user-required style, or can easily be absorbed in other reports. 5 | 6 | The LaTeX converters supplied with IPython 2 used Pygments to colour the Python code, as well as several other features which do not fit my requirement. 7 | 8 | ## Features 9 | 10 | - Reads and converts IPython 2.x and 3.x files (nbformats 3 and 4). 11 | - Code is formatted as a LaTeX `lstlistings` environment, which looks neater to my eye. 12 | - Pictures, graphs and tables can be formatted as LaTeX floats, or in line with the text. 13 | - Floating figures and tables can have LaTeX captions. 14 | - Raw NBConvert cells are passed through to LaTeX with no change. 15 | - References and hyperlinks are treated as first-class LaTeX references. 16 | - HTML tables are reformatted as LaTeX tables. 17 | - The header template interface allows the user to add his own style file. 18 | - Supports Pandas `to_latex()` dataframe exports as inline or floating tables 19 | - Supports `IPython.core.display.Latex object` in the output cell. 20 | 21 | ## Known deficiencies 22 | 23 | 1. Some complex cell-merged HTML tables may not render correctly in LaTeX (let me know if you have such a table). 24 | 1. The following HTML elements are not currently processed, these elements are simply ignored: `div`, `img`. 25 | 1. The `iframe` HTML element is tested for embedded PDF files which are then included as an image. 26 | 1. Coloured text in HTML is not exported as coloured text in LaTeX. 27 | 1. 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. 28 | 3. IPython notebook names must not have spaces in the filename. 29 | 4. This notebook is not kept current with the latest Jupyter developments. 30 | 31 | ## Instructions 32 | 33 | The instructions on how to set up the notebook is given in the example notebook `test2LaTeX.ipynb`, please study it carefully. Someday when I have more time, I will write better instructions :-). 34 | 35 | The most important (and most difficult) is to use the cell meta data to control LaTeX output such as: 36 | 37 | - captions for figures, tables and listings. 38 | - LaTeX citations and references. 39 | 40 | See the example notebook for more information. 41 | 42 | -------------------------------------------------------------------------------- /_cleanAllTeX.py: -------------------------------------------------------------------------------- 1 | #clean a precisely defined set of files from a precisely defined directory set. 2 | #the specified files are deleted, after the user has been prompted 3 | 4 | import os.path, fnmatch 5 | import sys 6 | 7 | 8 | ################################################################ 9 | #lists the files in a directory and subdirectories 10 | #this code is adapted from a recipe in the Python Cookbook 11 | def listFiles(root, patterns='*', recurse=1, return_folders=0, useRegex=False): 12 | """Lists the files/directories meeting specific requirement 13 | 14 | Returns a list of file paths to files in a file system, searching a 15 | directory structure along the specified path, looking for files 16 | that matches the glob pattern. If specified, the search will continue 17 | into sub-directories. A list of matching names is returned. The 18 | function supports a local or network reachable filesystem, but not URLs. 19 | 20 | Args: 21 | | root (string): directory root from where the search must take place 22 | | patterns (string): glob/regex pattern for filename matching. Multiple pattens 23 | may be present, each one separated by ; 24 | | recurse (unt): flag to indicate if subdirectories must also be searched (optional) 25 | | return_folders (int): flag to indicate if folder names must also be returned (optional) 26 | | useRegex (bool): flag to indicate if patterns areregular expression strings (optional) 27 | 28 | Returns: 29 | | A list with matching file/directory names 30 | 31 | Raises: 32 | | No exception is raised. 33 | """ 34 | if useRegex: 35 | import re 36 | 37 | # Expand patterns from semicolon-separated string to list 38 | pattern_list = patterns.split(';') 39 | filenames = [] 40 | filertn = [] 41 | 42 | if sys.version_info[0] < 3: 43 | 44 | # Collect input and output arguments into one bunch 45 | class Bunch(object): 46 | def __init__(self, **kwds): self.__dict__.update(kwds) 47 | arg = Bunch(recurse=recurse, pattern_list=pattern_list, 48 | return_folders=return_folders, results=[]) 49 | 50 | def visit(arg, dirname, files): 51 | # Append to arg.results all relevant files (and perhaps folders) 52 | for name in files: 53 | fullname = os.path.normpath(os.path.join(dirname, name)) 54 | if arg.return_folders or os.path.isfile(fullname): 55 | for pattern in arg.pattern_list: 56 | if useRegex: 57 | #search returns None is pattern not found 58 | regex = re.compile(pattern) 59 | if regex.search(name): 60 | arg.results.append(fullname) 61 | break 62 | else: 63 | if fnmatch.fnmatch(name, pattern): 64 | arg.results.append(fullname) 65 | break 66 | # Block recursion if recursion was disallowed 67 | if not arg.recurse: files[:]=[] 68 | os.path.walk(root, visit, arg) 69 | return arg.results 70 | 71 | else: #python 3 72 | for dirpath,dirnames,files in os.walk(root): 73 | if dirpath==root or recurse: 74 | for filen in files: 75 | # filenames.append(os.path.abspath(os.path.join(os.getcwd(),dirpath,filen))) 76 | filenames.append(os.path.relpath(os.path.join(dirpath,filen))) 77 | if return_folders: 78 | for dirn in dirnames: 79 | # filenames.append(os.path.abspath(os.path.join(os.getcwd(),dirpath,dirn))) 80 | filenames.append(os.path.relpath(os.path.join(dirpath,dirn))) 81 | 82 | for name in filenames: 83 | if return_folders or os.path.isfile(name): 84 | for pattern in pattern_list: 85 | if useRegex: 86 | #search returns None is pattern not found 87 | regex = re.compile(pattern) 88 | if regex.search(name): 89 | filertn.append(name) 90 | break 91 | else: 92 | # split only the filename to compare, discard folder path 93 | if fnmatch.fnmatch(os.path.basename(name), pattern): 94 | filertn.append(name) 95 | break 96 | return filertn 97 | 98 | 99 | 100 | 101 | #function to delete files in specified directory 102 | # first parameter defines if the search must be recursively 0=not, 1=recusrive 103 | # second parameter specifies the path 104 | # third parameter specifies the file patterns to erase 105 | #the user is promted before the files are deleted 106 | def QueryDelete(recurse,dir,patn): 107 | thefiles = listFiles(dir, patn,recurse) 108 | if len(thefiles)>0: 109 | for filename in thefiles: 110 | print(filename) 111 | if sys.version_info[0] < 3: 112 | instr=raw_input("Delete these files? (y/n)") 113 | else: 114 | instr=input("Delete these files? (y/n)") 115 | 116 | if instr=='y': 117 | for filename in thefiles: 118 | os.remove(filename) 119 | 120 | 121 | 122 | #we take the conservative approach and do not do blanket erase, 123 | #rather do it by directories, one at a time 124 | #we take the conservative approach and do not do blanket erase, 125 | #rather do it by type, asking the user first 126 | #QueryDelete(1,'.', '*.ps') 127 | QueryDelete(1,'.', '*.bib') 128 | QueryDelete(1,'.', '*.log') 129 | QueryDelete(1,'.', '*.bbl;comment.cut') 130 | QueryDelete(1,'.', '*.bbl;*.sav;*.bak;*.synctex;*.log;*.svn') 131 | QueryDelete(1,'.', '*.blg;*.dfn;*.smb;*.bak;*.aux;*.out;*.lot;*.lof;*.toc;*.tex.bak;*.lol;*.dvi;*.efc;*.abr') 132 | 133 | 134 | 135 | 136 | 137 | -------------------------------------------------------------------------------- /codestructure.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NelisW/ipynb2tex/78598d4bc17a00286af24504b51e392b8e833175/codestructure.xlsx -------------------------------------------------------------------------------- /header.tex: -------------------------------------------------------------------------------- 1 | % the first cell of the notebook must be a RawNBConvert cell with the following contents: 2 | % 3 | %%%\documentclass that you want to use 4 | %%%\input{header.tex} 5 | %%%whatever preamble lines you require 6 | %%%\begin{document} 7 | %%%whatever extra info before the notebook follows 8 | %%%\end{document} % is added by the converter. 9 | % 10 | %The header.tex file provides the functionality required by the converter-created code. 11 | %This content is input using the \LaTeX{} input command. 12 | % 13 | % 14 | % - The exporter extracts the document class line from the first cell of the notebook. 15 | % - Then follows the contents of this file (as preamble) 16 | % - Then follows the rest of the first cell of the notebook (rest of preamble, begin doc, etc) 17 | % - Finally the rest of the notebook is exported. 18 | % 19 | 20 | 21 | \usepackage{ragged2e} 22 | \usepackage{listings} 23 | \usepackage{xcolor} 24 | \usepackage{graphicx} 25 | \usepackage[T1]{fontenc} 26 | \usepackage{textcomp} % additional fonts, required for upquote in listings and \textmu 27 | \usepackage{placeins} % FloatBarrier 28 | \usepackage{url} % for websites 29 | \usepackage[detect-weight,detect-mode]{siunitx} % nice! SI units and print numbers 30 | \usepackage{afterpage} % afterpage{\clearpage} 31 | \usepackage{gensymb} % get the degree symbol as in \celcius 32 | \usepackage{amsmath} 33 | \usepackage{commath} 34 | \usepackage[printonlyused]{acronym} 35 | \usepackage{lastpage} 36 | \usepackage{longtable} 37 | \usepackage[utopia]{mathdesign} 38 | \usepackage[OMLmathrm,OMLmathbf]{isomath} 39 | \usepackage{booktabs} 40 | 41 | % to get upright math symbols. 42 | \newcommand\ct[1]{\text{\rmfamily\upshape #1}} 43 | 44 | %the following is required for carriage return symbol 45 | %ftp://ftp.botik.ru/rented/znamensk/CTAN/fonts/mathabx/texinputs/mathabx.dcl 46 | %https://secure.kitserve.org.uk/content/mathabx-font-symbol-redefinition-clash-latex 47 | \DeclareFontFamily{U}{mathb}{\hyphenchar\font45} 48 | \DeclareFontShape{U}{mathb}{m}{n}{ 49 | <5> <6> <7> <8> <9> <10> gen * mathb 50 | <10.95> mathb10 <12> <14.4> <17.28> <20.74> <24.88> mathb12 51 | }{} 52 | \DeclareSymbolFont{mathb}{U}{mathb}{m}{n} 53 | \DeclareMathSymbol{\dlsh}{3}{mathb}{"EA} 54 | 55 | 56 | %enable smart resizing: large images are resized down but small images are left as they are 57 | \usepackage[Export]{adjustbox} 58 | \adjustboxset{max size={\textwidth}{0.7\textheight}} 59 | 60 | 61 | \definecolor{LightGrey}{rgb}{0.95,0.95,0.95} 62 | \definecolor{LightRed}{rgb}{1.0,0.9,0.9} 63 | \definecolor{mygreen}{rgb}{0,0.6,0} 64 | \definecolor{mygray}{rgb}{0.5,0.5,0.5} 65 | \definecolor{mymauve}{rgb}{0.58,0,0.82} 66 | 67 | % syntax highlight https://www.overleaf.com/latex/examples/syntax-highlighting-in-latex-with-the-listings-package/jxnppmxxvsvk#.WKwPq3pp5_Y 68 | \lstset{ % 69 | backgroundcolor=\color{white}, % choose the background color 70 | commentstyle=\color{mygreen}, % comment style 71 | keywordstyle=\color{blue}, % keyword style 72 | stringstyle=\color{mymauve}, % string literal style 73 | upquote=true, % gives the upquote instead of the curly quote 74 | basicstyle=\ttfamily\footnotesize, % the size of the fonts that are used for the code 75 | numbers=none, % where to put the line-numbers 76 | showspaces=false, % show spaces adding particular underscores 77 | showstringspaces=false, % underline spaces within strings 78 | showtabs=false, % show tabs within strings adding particular underscores 79 | frame=lines, % adds a frame around the code 80 | tabsize=4, % sets default tabsize to 2 spaces 81 | captionpos=b, % sets the caption-position to bottom 82 | framesep=1pt, 83 | xleftmargin=0pt, 84 | xrightmargin=0pt, 85 | captionpos=t, % sets the caption-position to top 86 | %deletekeywords={...}, % if you want to delete keywords from the given language 87 | %escapeinside={\%*}{*)}, % if you want to add LaTeX within your code 88 | %escapeinside={\%}{)}, % if you want to add a comment within your code 89 | breaklines=true, % sets automatic line breaking 90 | breakatwhitespace=false, % sets if automatic breaks should only happen at whitespace 91 | prebreak=\raisebox{0ex}[0ex][0ex]{$\dlsh$} % add linebreak symbol 92 | } 93 | 94 | \lstdefinestyle{incellstyle}{ 95 | backgroundcolor=\color{LightGrey}, % choose the background color, add \usepackage{color} 96 | language=Python, 97 | } 98 | 99 | \lstdefinestyle{outcellstyle}{ 100 | backgroundcolor=\color{LightRed}, % choose the background color; you must add \usepackage{color} or \usepackage{xcolor} 101 | } 102 | 103 | \usepackage[a4paper, margin=0.75in]{geometry} 104 | \newlength{\textwidthm} 105 | \setlength{\textwidthm}{\textwidth} 106 | 107 | 108 | 109 | -------------------------------------------------------------------------------- /images/BW.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NelisW/ipynb2tex/78598d4bc17a00286af24504b51e392b8e833175/images/BW.png -------------------------------------------------------------------------------- /images/Bankedturn.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NelisW/ipynb2tex/78598d4bc17a00286af24504b51e392b8e833175/images/Bankedturn.pdf -------------------------------------------------------------------------------- /images/discretestrata01.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NelisW/ipynb2tex/78598d4bc17a00286af24504b51e392b8e833175/images/discretestrata01.pdf -------------------------------------------------------------------------------- /images/flow2-zzz.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NelisW/ipynb2tex/78598d4bc17a00286af24504b51e392b8e833175/images/flow2-zzz.png -------------------------------------------------------------------------------- /images/keep-calm-and-code-python_BW.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NelisW/ipynb2tex/78598d4bc17a00286af24504b51e392b8e833175/images/keep-calm-and-code-python_BW.png -------------------------------------------------------------------------------- /images/random-squares-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NelisW/ipynb2tex/78598d4bc17a00286af24504b51e392b8e833175/images/random-squares-2.png -------------------------------------------------------------------------------- /images/test2LaTeX_40_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NelisW/ipynb2tex/78598d4bc17a00286af24504b51e392b8e833175/images/test2LaTeX_40_0.png -------------------------------------------------------------------------------- /images/test2LaTeX_42_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NelisW/ipynb2tex/78598d4bc17a00286af24504b51e392b8e833175/images/test2LaTeX_42_0.png -------------------------------------------------------------------------------- /images/test2LaTeX_44_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NelisW/ipynb2tex/78598d4bc17a00286af24504b51e392b8e833175/images/test2LaTeX_44_0.png -------------------------------------------------------------------------------- /images/test2LaTeX_46_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NelisW/ipynb2tex/78598d4bc17a00286af24504b51e392b8e833175/images/test2LaTeX_46_0.png -------------------------------------------------------------------------------- /images/test2LaTeX_46_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NelisW/ipynb2tex/78598d4bc17a00286af24504b51e392b8e833175/images/test2LaTeX_46_1.png -------------------------------------------------------------------------------- /images/test2LaTeX_46_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NelisW/ipynb2tex/78598d4bc17a00286af24504b51e392b8e833175/images/test2LaTeX_46_2.png -------------------------------------------------------------------------------- /ipnb2tex.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python2 2 | """Notebook to LaTeX and PDF 3 | 4 | http://ipython.org/ipython-doc/3/notebook/nbformat.html#nbformat 5 | http://ipython.org/ipython-doc/3/whatsnew/version3.html 6 | """ 7 | 8 | from __future__ import print_function, division 9 | 10 | 11 | import re 12 | import os 13 | import io 14 | import base64 15 | import shutil 16 | import re 17 | import itertools 18 | import operator 19 | import unicodedata 20 | import os.path, fnmatch 21 | # from IPython.nbformat import current as ipnbcurrent 22 | import nbformat 23 | import docopt 24 | import lxml.html 25 | import markdown 26 | from lxml import etree as ET 27 | import numpy as np 28 | import sys 29 | 30 | 31 | from builtins import bytes,chr 32 | from builtins import str 33 | 34 | nbformat 35 | 36 | #list of bibtex entries to be built up in this file 37 | bibtexlist = [] 38 | #dict of bibtex label crossreferences between local and existing bibtex files. 39 | bibxref = {} 40 | bibtexindex = 0 41 | listindentcurrent = 0 42 | listindentprevious = 0 43 | figure_index = 0 44 | table_index = 0 45 | 46 | protectEvnStringStart = 'beginincludegraphics\n' 47 | protectEvnStringEnd = 'endincludegraphics\n' 48 | 49 | 50 | docoptstring = """Usage: ipnb2tex.py [] [] [] [-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 | --------------------------------------------------------------------------------