diff --git a/README.md b/README.md index 3189fe3..9e4c674 100644 --- a/README.md +++ b/README.md @@ -3,17 +3,17 @@ A more accurate representation of jupyter notebooks when converting to pdfs. This template was designed to make converted jupyter notebooks look (almost) identical to the actual notebook. If something doesn't exist in the original notebook then it doesn't belong in the conversion. ## Improvements -1. \maketitle is removed (If you want a title then add a markdown cell to the top of your notebook) -2. Sections are no longer numbered automatically (notebooks don't number sections so the pdf shouldn't) +1. \maketitle is removed (If you want a title then add a markdown cell to the top of your notebook). +2. Sections are no longer numbered automatically (notebooks don't number sections so the pdf shouldn't). 3. **BOXES!** are drawn around code cells. -4. In/Out will move to the left as the execution count increases instead of pushing code to the right. -5. ~~$\LaTeX$ and $\Tex$ in markdown cells will no longer cause conversion to fail~~ **(This change was merged into nbconvert 5.4.0)** -6. "\LaTeX" and "\TeX" are no longer converted into a logo on conversion to pdf unless they are in math mode. (This and the above point replicate the functionality of these commands in notebook markdown) -7. In/Out text colours updated to match Jupyter -8. Markdown paragraphs are no longer auto-indented in the pdf +4. In/Out counts will move to the left as the execution count increases instead of pushing code to the right (only numbers are displayed by default to save page width). +5. ~~$\LaTeX$ and $\Tex$ in markdown cells will no longer cause conversion to fail.~~ **(This change was merged into nbconvert 5.4.0)** +6. "\LaTeX" and "\TeX" are no longer converted into a logo on conversion to pdf unless they are in math mode. (This and the above point replicate the functionality of these commands in notebook markdown). +7. In/Out prompt colours updated to match Jupyter. +8. Markdown paragraphs are no longer auto-indented in the pdf. 9. Syntax highlighting improvements. (Bonus if using XeLaTeX) 10. Output text wrapping improvements. -11. Code cell text wrapping (requires extra setup) +11. Code cell text wrapping. Quick Comparison: ![comparison](example/comparison.png) @@ -32,18 +32,6 @@ pip install nb_pdf_template python -m nb_pdf_template.install ``` -### Optional Extra Setup -In order to make code cells wrap text, we need to change how nbconvert does syntax highlighting. This feature is experimental. (And known not to work with TeX Live 2015). - -Add the following to your ```jupyter_nbconvert_config.py``` and your ```jupyter_notebook_config.py```: -``` -c.PDFExporter.latex_command = ['xelatex', '-8bit', '-shell-escape','{filename}'] -``` -then run: -``` -python -m nb_pdf_template.install --minted -``` - ## Use From the command line: ``` @@ -63,8 +51,8 @@ This package offers the following templates: Template | Use ---------|------- -classic.tplx | For most accurate recreation of the default Jupyter Notebook Style. -classicm.tplx **(Recommended)**| m for modified. Similar to classic.tplx, but in/out prompts are above cells instead of in the margin. Bonus left margins are smaller so code cells are wider. +classic.tplx **(Recommended)**| For most accurate recreation of the default Jupyter Notebook Style. +classicm.tplx | m for modified. Similar to classic.tplx, but in/out prompts are above cells instead of in the margin. Bonus left margins are smaller so code cells are wider. style_jupyter.tplx | DO NOT use this directly. Inherit from this template if you want to build your own. ## Tips (Good for any template) diff --git a/example/comparison.png b/example/comparison.png index 51fccb3..b596f13 100644 Binary files a/example/comparison.png and b/example/comparison.png differ diff --git a/example/test_classic_template.pdf b/example/test_classic_template.pdf index 3ccc07a..9d05c27 100644 Binary files a/example/test_classic_template.pdf and b/example/test_classic_template.pdf differ diff --git a/example/test_classicm_template.pdf b/example/test_classicm_template.pdf index e5dd92e..fbf4563 100644 Binary files a/example/test_classicm_template.pdf and b/example/test_classicm_template.pdf differ diff --git a/nb_pdf_template/install.py b/nb_pdf_template/install.py index 61a3726..b4da381 100644 --- a/nb_pdf_template/install.py +++ b/nb_pdf_template/install.py @@ -4,12 +4,7 @@ import argparse -parser = argparse.ArgumentParser(description='none') -parser.add_argument('--minted', action='store_true') -args = parser.parse_args() - -TEMPLATES = {"style_jupyter.tplx", "style_jupyter_minted.tplx", - "classic.tplx", "classicm.tplx"} +TEMPLATES = {"style_jupyter.tplx", "classic.tplx", "classicm.tplx"} def install(): @@ -33,11 +28,6 @@ def install(): src = os.path.join(template_path, template) shutil.copy(src, dst) - if args.minted: - src = os.path.join(template_path, 'style_jupyter_minted.tplx') - dst_ = os.path.join(dst, 'style_jupyter.tplx') - shutil.copy(src, dst_) - print("Success") diff --git a/nb_pdf_template/templates/classic.tplx b/nb_pdf_template/templates/classic.tplx index 0afe31a..16b8a35 100644 --- a/nb_pdf_template/templates/classic.tplx +++ b/nb_pdf_template/templates/classic.tplx @@ -35,7 +35,7 @@ ((*- endblock definitions -*)) ((*- block margins -*)) - \geometry{verbose,tmargin=.5in,bmargin=.7in,lmargin=1.1in,rmargin=.5in} + \geometry{verbose,tmargin=.5in,bmargin=.7in,lmargin=.7in,rmargin=.7in} ((*- endblock margins -*)) ((* block maketitle *))((* endblock maketitle *)) diff --git a/nb_pdf_template/templates/classicm.tplx b/nb_pdf_template/templates/classicm.tplx index 52338ac..99b89c4 100644 --- a/nb_pdf_template/templates/classicm.tplx +++ b/nb_pdf_template/templates/classicm.tplx @@ -1,5 +1,10 @@ ((*- extends 'classic.tplx' -*)) +((*- block packages -*)) + \usepackage{needspace} + ((( super() ))) +((*- endblock packages -*)) + ((*- block margins -*)) \geometry{verbose,tmargin=.5in,bmargin=.7in,lmargin=.5in,rmargin=.5in} ((*- endblock margins -*)) @@ -9,6 +14,19 @@ \needspace{1.1cm} \noindent{\color{#2}#1 [#3]:} } - ((* endblock style_prompt *)) +((* endblock style_prompt *)) ((* set charlim = 94 *)) + +((* macro draw_cell(text, cell, prompt, prompt_color) -*)) +((*- if prompt == 'In' -*)) +((*- set style = "breakable, size=fbox, boxrule=1pt, pad at break*=1mm,colback=cellbackground, colframe=cellborder"-*)) +((*- else -*))((*- set style = "breakable, boxrule=.5pt, size=fbox, pad at break*=1mm, opacityfill=0"-*))((*- endif -*)) + +(((- draw_prompt(cell, prompt, prompt_color) ))) +\begin{tcolorbox}[((( style )))] +\begin{Verbatim}[commandchars=\\\{\}] +((( text ))) +\end{Verbatim} +\end{tcolorbox} +((*- endmacro *)) \ No newline at end of file diff --git a/nb_pdf_template/templates/style_jupyter.tplx b/nb_pdf_template/templates/style_jupyter.tplx index 4940b5d..f62084e 100644 --- a/nb_pdf_template/templates/style_jupyter.tplx +++ b/nb_pdf_template/templates/style_jupyter.tplx @@ -4,7 +4,6 @@ ((*- block packages -*)) \usepackage[breakable]{tcolorbox} \tcbset{nobeforeafter} - \usepackage{needspace} ((( super() ))) ((*- endblock packages -*)) @@ -47,7 +46,86 @@ \fi %end magical operator highlighting %End Reconfigured Pygments ((* endblock repygments *)) - + + % For linebreaks inside Verbatim environment from package fancyvrb. + \makeatletter + \newbox\Wrappedcontinuationbox + \newbox\Wrappedvisiblespacebox + % These are user customizable e.g. from latex_elements's preamble key. + % Use of \textvisiblespace for compatibility with XeTeX/LuaTeX/fontspec. + \newcommand*\Wrappedvisiblespace {\textcolor{red}{\textvisiblespace}} + \newcommand*\Wrappedcontinuationsymbol {\textcolor{red}{\llap{\tiny$\m@th\hookrightarrow$}}} + \newcommand*\Wrappedcontinuationindent {3ex } + \newcommand*\Wrappedafterbreak {\kern\Wrappedcontinuationindent\copy\Wrappedcontinuationbox} + % Take advantage of the already applied Pygments mark-up to insert + % potential linebreaks for TeX processing. + % {, <, #, %, $, ' and ": go to next line. + % _, }, ^, &, >, - and ~: stay at end of broken line. + % Use of \textquotesingle for straight quote. + \newcommand*\Wrappedbreaksatspecials {% + \def\PYGZus{\discretionary{\char`\_}{\Wrappedafterbreak}{\char`\_}}% + \def\PYGZob{\discretionary{}{\Wrappedafterbreak\char`\{}{\char`\{}}% + \def\PYGZcb{\discretionary{\char`\}}{\Wrappedafterbreak}{\char`\}}}% + \def\PYGZca{\discretionary{\char`\^}{\Wrappedafterbreak}{\char`\^}}% + \def\PYGZam{\discretionary{\char`\&}{\Wrappedafterbreak}{\char`\&}}% + \def\PYGZlt{\discretionary{}{\Wrappedafterbreak\char`\<}{\char`\<}}% + \def\PYGZgt{\discretionary{\char`\>}{\Wrappedafterbreak}{\char`\>}}% + \def\PYGZsh{\discretionary{}{\Wrappedafterbreak\char`\#}{\char`\#}}% + \def\PYGZpc{\discretionary{}{\Wrappedafterbreak\char`\%}{\char`\%}}% + \def\PYGZdl{\discretionary{}{\Wrappedafterbreak\char`\$}{\char`\$}}% + \def\PYGZhy{\discretionary{\char`\-}{\Wrappedafterbreak}{\char`\-}}% + \def\PYGZsq{\discretionary{}{\Wrappedafterbreak\textquotesingle}{\textquotesingle}}% + \def\PYGZdq{\discretionary{}{\Wrappedafterbreak\char`\"}{\char`\"}}% + \def\PYGZti{\discretionary{\char`\~}{\Wrappedafterbreak}{\char`\~}}% + } + % Some characters . , ; ? ! / are not pygmentized. + % This macro makes them "active" and they will insert potential linebreaks + \newcommand*\Wrappedbreaksatpunct {% + \lccode`\~`\.\lowercase{\def~}{\discretionary{\hbox{\char`\.}}{\Wrappedafterbreak}{\hbox{\char`\.}}}% + \lccode`\~`\,\lowercase{\def~}{\discretionary{\hbox{\char`\,}}{\Wrappedafterbreak}{\hbox{\char`\,}}}% + \lccode`\~`\;\lowercase{\def~}{\discretionary{\hbox{\char`\;}}{\Wrappedafterbreak}{\hbox{\char`\;}}}% + \lccode`\~`\:\lowercase{\def~}{\discretionary{\hbox{\char`\:}}{\Wrappedafterbreak}{\hbox{\char`\:}}}% + \lccode`\~`\?\lowercase{\def~}{\discretionary{\hbox{\char`\?}}{\Wrappedafterbreak}{\hbox{\char`\?}}}% + \lccode`\~`\!\lowercase{\def~}{\discretionary{\hbox{\char`\!}}{\Wrappedafterbreak}{\hbox{\char`\!}}}% + \lccode`\~`\/\lowercase{\def~}{\discretionary{\hbox{\char`\/}}{\Wrappedafterbreak}{\hbox{\char`\/}}}% + \catcode`\.\active + \catcode`\,\active + \catcode`\;\active + \catcode`\:\active + \catcode`\?\active + \catcode`\!\active + \catcode`\/\active + \lccode`\~`\~ + } + \makeatother + + \let\OriginalVerbatim=\Verbatim + \makeatletter + \renewcommand{\Verbatim}[1][1]{% + %\parskip\z@skip + \sbox\Wrappedcontinuationbox {\Wrappedcontinuationsymbol}% + \sbox\Wrappedvisiblespacebox {\FV@SetupFont\Wrappedvisiblespace}% + \def\FancyVerbFormatLine ##1{\hsize\linewidth + \vtop{\raggedright\hyphenpenalty\z@\exhyphenpenalty\z@ + \doublehyphendemerits\z@\finalhyphendemerits\z@ + \strut ##1\strut}% + }% + % If the linebreak is at a space, the latter will be displayed as visible + % space at end of first line, and a continuation symbol starts next line. + % Stretch/shrink are however usually zero for typewriter font. + \def\FV@Space {% + \nobreak\hskip\z@ plus\fontdimen3\font minus\fontdimen4\font + \discretionary{\copy\Wrappedvisiblespacebox}{\Wrappedafterbreak} + {\kern\fontdimen2\font}% + }% + + % Allow breaks at special characters using \PYG... macros. + \Wrappedbreaksatspecials + % Breaks at punctuation characters . , ; ? ! and / need catcode=\active + \OriginalVerbatim[#1,codes*=\Wrappedbreaksatpunct]% + } + \makeatother + % Exact colors from NB ((*- block style_colors *)) \definecolor{incolor}{HTML}{303F9F} @@ -55,40 +133,14 @@ \definecolor{cellborder}{HTML}{CFCFCF} \definecolor{cellbackground}{HTML}{F7F7F7} ((*- endblock style_colors *)) - - % needed definitions - \newlength{\promptlength} % prompt ((*- block style_prompt *)) \newcommand{\prompt}[3]{ - \needspace{1.1cm} - \settowidth{\promptlength}{ #1 [#3] } - \hspace{-\promptlength}\hspace{-5pt} - \noindent{\color{#2}#1 [#3]:} - \vspace{-2.7ex} + \llap{{\color{#2}[#3]: \ }}\vspace{-1.25em} } ((* endblock style_prompt *)) - % environments - ((*- block style_environments *)) - \newenvironment{InVerbatim}{\VerbatimEnvironment% - \begin{tcolorbox}[breakable, size=fbox, boxrule=1pt, pad at break*=1mm, - colback=cellbackground, colframe=cellborder] - \begin{Verbatim} - }{ - \end{Verbatim} - \end{tcolorbox} - } - \newenvironment{OutVerbatim}{\VerbatimEnvironment% - \begin{tcolorbox}[breakable, boxrule=.5pt, size=fbox, pad at break*=1mm, opacityfill=0] - \begin{Verbatim} - }{ - \end{Verbatim} - \end{tcolorbox} - } - ((* endblock style_environments *)) - ((*- endblock definitions -*)) %=============================================================================== @@ -105,7 +157,7 @@ %=============================================================================== ((*- if charlim is not defined -*)) - ((* set charlim = 86 *)) + ((* set charlim = 89 *)) ((*- endif -*)) ((* block execute_result scoped *)) @@ -121,7 +173,7 @@ ((* block stream *)) \begin{Verbatim}[commandchars=\\\{\}] -((( output.text | wrap_text(charlim) | escape_latex | ansi2latex ))) +((( output.text | wrap_text(charlim) | escape_latex | ansi2latex -))) \end{Verbatim} ((* endblock stream *)) @@ -131,12 +183,20 @@ % Name: draw_cell % Purpose: Renders an output/input prompt +((*- if draw_cell is not defined -*)) ((* macro draw_cell(text, cell, prompt, prompt_color) -*)) -((( draw_prompt(cell, prompt, prompt_color) ))) -\begin{((( prompt ~ 'Verbatim')))}[commandchars=\\\{\}] +((*- if prompt == 'In' -*)) +((*- set style = "breakable, size=fbox, boxrule=1pt, pad at break*=1mm,colback=cellbackground, colframe=cellborder"-*)) +((*- else -*))((*- set style = "breakable, boxrule=.5pt, size=fbox, pad at break*=1mm, opacityfill=0"-*))((*- endif -*)) + +\begin{tcolorbox}[((( style )))] +(((- draw_prompt(cell, prompt, prompt_color) ))) +\begin{Verbatim}[commandchars=\\\{\}] ((( text ))) -\end{((( prompt ~ 'Verbatim')))} +\end{Verbatim} +\end{tcolorbox} ((*- endmacro *)) +((*- endif -*)) % Name: draw_prompt % Purpose: Renders an output/input prompt diff --git a/nb_pdf_template/templates/style_jupyter_minted.tplx b/nb_pdf_template/templates/style_jupyter_minted.tplx deleted file mode 100644 index 835d044..0000000 --- a/nb_pdf_template/templates/style_jupyter_minted.tplx +++ /dev/null @@ -1,154 +0,0 @@ -((= IPython input/output style =)) -((*- extends 'base.tplx' -*)) - -((*- block packages -*)) - \usepackage[breakable]{tcolorbox} - \tcbset{nobeforeafter} - \usepackage{needspace} - \usepackage{minted} - \usemintedstyle{jupyter_python} - ((( super() ))) -((*- endblock packages -*)) - -((*- block definitions -*)) - ((( super() ))) -% Pygments definitions - ((* block repygments *)) - \makeatletter - \newcommand*\@iflatexlater{\@ifl@t@r\fmtversion} - \@iflatexlater{2016/03/01}{ - \newcommand{\wordboundary}{4095}}{ - \newcommand{\wordboundary}{255}} - \makeatother - - \newif\ifcode - \codefalse - \definecolor{Grey}{rgb}{0.40,0.40,0.40} - %If using XeLaTeX, use magic to not highlight . operators with purple. - \ifdefined\XeTeXcharclass - \XeTeXinterchartokenstate = 1 - \newXeTeXintercharclass \mycharclassGrey - \XeTeXcharclass `. \mycharclassGrey - \XeTeXinterchartoks 0 \mycharclassGrey = {\bgroup\ifcode\color{Grey}\else\fi} - - \XeTeXinterchartoks \wordboundary \mycharclassGrey = {\bgroup\ifcode\color{Grey}\else\fi} - - \XeTeXinterchartoks \mycharclassGrey 0 = {\egroup} - \XeTeXinterchartoks \mycharclassGrey \wordboundary = {\egroup} - \fi %end magical operator highlighting - %End Reconfigured Pygments - ((* endblock repygments *)) - - % Exact colors from NB - ((*- block style_colors *)) - \definecolor{incolor}{HTML}{303F9F} - \definecolor{outcolor}{HTML}{D84315} - \definecolor{cellborder}{HTML}{CFCFCF} - \definecolor{cellbackground}{HTML}{F7F7F7} - ((*- endblock style_colors *)) - - % needed definitions - \newlength{\promptlength} - - % prompt - ((*- block style_prompt *)) - \newcommand{\prompt}[3]{ - \needspace{1.1cm} - \settowidth{\promptlength}{ #1 [#3] } - \hspace{-\promptlength}\hspace{-5pt} - \noindent{\color{#2}#1 [#3]:} - \vspace{-3.05ex} - } - ((* endblock style_prompt *)) - - % environments - ((*- block style_environments *)) - \newenvironment{OutVerbatim}{\VerbatimEnvironment% - \begin{tcolorbox}[breakable, boxrule=.5pt, size=fbox, pad at break*=1mm, opacityfill=0] - \begin{Verbatim} - }{ - \end{Verbatim} - \end{tcolorbox} - } - ((* endblock style_environments *)) - -((*- endblock definitions -*)) - -%=============================================================================== -% Input -%=============================================================================== - -((* block input scoped *)) - ((( draw_cell_in(cell.source, cell, 'In', 'incolor') ))) -((* endblock input *)) - - -%=============================================================================== -% Output -%=============================================================================== - -((*- if charlim is not defined -*)) - ((* set charlim = 86 *)) -((*- endif -*)) - -((* block execute_result scoped *)) - ((*- for type in output.data | filter_data_type -*)) - ((*- if type in ['text/plain']*)) - ((( draw_cell(output.data['text/plain'] | wrap_text(charlim) | escape_latex, cell, 'Out', 'outcolor') ))) - ((* else -*)) - ((( " " ))) - ((( draw_prompt(cell, 'Out', 'outcolor') )))((( super() ))) - ((*- endif -*)) - ((*- endfor -*)) -((* endblock execute_result *)) - - -((* block stream *)) - \begin{Verbatim}[commandchars=\\\{\}] -((( output.text | wrap_text(charlim) | escape_latex | ansi2latex ))) - \end{Verbatim} -((* endblock stream *)) - -%============================================================================== -% Support Macros -%============================================================================== - -% Name: draw_cell -% Purpose: Renders an output/input prompt -((* macro draw_cell(text, cell, prompt, prompt_color) -*)) -((( draw_prompt(cell, prompt, prompt_color) ))) -\begin{((( prompt ~ 'Verbatim')))}[commandchars=\\\{\}] -((( text ))) -\end{((( prompt ~ 'Verbatim')))} -((*- endmacro *)) - -((*- set nb_language = nb.metadata.kernelspec.get('language', 'python') -*)) -((*- if nb_language == 'python' -*)) - ((*- set nb_language = nb.metadata.language_info.get('pygments_lexer', 'ipython3') -*)) -((*- endif -*)) - -% Name: draw_cell_in -% Purpose: Renders an output/input prompt -((* macro draw_cell_in(text, cell, prompt, prompt_color) -*)) -((( draw_prompt(cell, prompt, prompt_color) ))) -\codetrue -\begin{tcolorbox}[breakable, size=fbox, boxrule=1pt, pad at break*=1mm, colback=cellbackground, colframe=cellborder] -\begin{minted}[breaklines=True]{((( nb_language )))} -((( text ))) -\end{minted} -\end{tcolorbox} -\codefalse -((*- endmacro *)) - -% Name: draw_prompt -% Purpose: Renders an output/input prompt -((* macro draw_prompt(cell, prompt, prompt_color) -*)) - ((*- if cell.execution_count is defined -*)) - ((*- set execution_count = "" ~ (cell.execution_count | replace(None, " ")) -*)) - ((*- else -*))((*- set execution_count = " " -*))((*- endif *)) - - ((*- if (resources.global_content_filter.include_output_prompt and prompt == 'Out') - or (resources.global_content_filter.include_input_prompt and prompt == 'In' ) *)) -\prompt{(((prompt)))}{(((prompt_color)))}{(((execution_count)))} - ((*- endif -*)) -((*- endmacro *)) \ No newline at end of file diff --git a/setup.py b/setup.py index 67738a0..cc9fe3e 100644 --- a/setup.py +++ b/setup.py @@ -4,7 +4,7 @@ long_description = f.read() setup(name='nb_pdf_template', - version='2.1.0.dev0', + version='3.0.0', description='LaTeX templates for jupyter notebook conversion to pdf', long_description=long_description, long_description_content_type='text/markdown',