I’m working on a piece of software that outputs IPython Notebooks as tex documents. One of my requirements is to be able to draw code input output blocks that look like the Notebook’s UI.
Disclaimer:
For a long time I was using MDFRAMED to draw the cells. Unfortunately the vertical spacing of the MDFRAMED differs between versions, and I absolutely cannot force users to use a specific version of MDFRAMED. I looked into distributing MDFRAMED along with the software and found that it could not be done without modifications to MDFRAMED
So I bit the bullet and started writing my own custom framing logic in TIKz. My only requirements were to have rounded edges, a small border, support for multiple pages, and support for pygments output (fancyvrb Verbatim).
After a couple hours, I had completely met my goal:
![goodoutput]()
BUT! When I try to use the Sphinx templates to produce my output:
![badoutput]()
The majority of the tikz code is this http://www.texample.net/tikz/examples/framed-tikz/ example modified
EDIT: After David’s suggestion:
![closer]()
EDIT: MWE, with suggested solution(s). Produces same output as above.
% Make sure that the sphinx doc style knows who it inherits from.
defsphinxdocclass{article}
% Declare the document class
documentclass[letterpaper,10pt,english]{/usr/local/lib/python2.7/dist-packages/Sphinx-1.2predev_20130207-py2.7.egg/sphinx/texinputs/sphinxhowto}
usepackage[Bjarne]{/usr/local/lib/python2.7/dist-packages/Sphinx-1.2predev_20130207-py2.7.egg/sphinx/texinputs/fncychap}
usepackage{/usr/local/lib/python2.7/dist-packages/Sphinx-1.2predev_20130207-py2.7.egg/sphinx/texinputs/sphinx}
usepackage{graphicx} % Used to insert images
usepackage{adjustbox} % Used to constrain images to a maximum size
usepackage{color} % Allow colors to be defined
usepackage{enumerate} % Needed for markdown enumerations to work
usepackage{geometry} % Used to adjust the document margins
usepackage{amsmath} % Equations
usepackage{amssymb} % Equations
usepackage[utf8]{inputenc} % Allow utf-8 characters in the tex document
usepackage{ucs} % Extended unicode (utf-8) support
usepackage{fancyvrb} % verbatim replacement that allows latex
usepackage{grffile} % extends the file name processing of package graphics
%to support a larger range
% The hyperref package gives us a pdf with properly built
% internal navigation ('pdf bookmarks' for the table of contents,
% internal cross-reference links, web links for URLs, etc.)
usepackage{hyperref}
usepackage{tikz} % Needed to box output/input
usepackage{scrextend} % Used to indent output
usepackage{needspace} % Make prompts follow contents
usepackage{framed} % Used to draw output that spans multiple pages
definecolor{orange}{cmyk}{0,0.4,0.8,0.2}
definecolor{darkorange}{rgb}{.71,0.21,0.01}
definecolor{darkgreen}{rgb}{.12,.54,.11}
definecolor{myteal}{rgb}{.26, .44, .56}
definecolor{gray}{gray}{0.45}
definecolor{lightgray}{gray}{.95}
definecolor{mediumgray}{gray}{.8}
definecolor{inputbackground}{rgb}{.95, .95, .85}
definecolor{outputbackground}{rgb}{.95, .95, .95}
definecolor{traceback}{rgb}{1, .95, .95}
% new ansi colors
definecolor{brown}{rgb}{0.54,0.27,0.07}
definecolor{purple}{rgb}{0.5,0.0,0.5}
definecolor{darkgray}{gray}{0.25}
definecolor{lightred}{rgb}{1.0,0.39,0.28}
definecolor{lightgreen}{rgb}{0.48,0.99,0.0}
definecolor{lightblue}{rgb}{0.53,0.81,0.92}
definecolor{lightpurple}{rgb}{0.87,0.63,0.87}
definecolor{lightcyan}{rgb}{0.5,1.0,0.83}
% Define a nice break command that doesn't care if a line doesn't already
% exist.
defbr{hspace*{fill} \* }
% Document parameters
title{simpletest}
% Pygments definitions
makeatletter
defPY@reset{letPY@it=relax letPY@bf=relax%
letPY@ul=relax letPY@tc=relax%
letPY@bc=relax letPY@ff=relax}
defPY@tok#1{csname PY@tok@#1endcsname}
defPY@toks#1+{ifxrelax#1emptyelse%
PY@tok{#1}expandafterPY@toksfi}
defPY@do#1{PY@bc{PY@tc{PY@ul{%
PY@it{PY@bf{PY@ff{#1}}}}}}}
defPY#1#2{PY@resetPY@toks#1+relax+PY@do{#2}}
expandafterdefcsname PY@tok@gdendcsname{defPY@tc##1{textcolor[rgb]{0.63,0.00,0.00}{##1}}}
expandafterdefcsname PY@tok@guendcsname{letPY@bf=textbfdefPY@tc##1{textcolor[rgb]{0.50,0.00,0.50}{##1}}}
expandafterdefcsname PY@tok@gtendcsname{defPY@tc##1{textcolor[rgb]{0.00,0.25,0.82}{##1}}}
expandafterdefcsname PY@tok@gsendcsname{letPY@bf=textbf}
expandafterdefcsname PY@tok@grendcsname{defPY@tc##1{textcolor[rgb]{1.00,0.00,0.00}{##1}}}
expandafterdefcsname PY@tok@cmendcsname{letPY@it=textitdefPY@tc##1{textcolor[rgb]{0.25,0.50,0.50}{##1}}}
expandafterdefcsname PY@tok@vgendcsname{defPY@tc##1{textcolor[rgb]{0.10,0.09,0.49}{##1}}}
expandafterdefcsname PY@tok@mendcsname{defPY@tc##1{textcolor[rgb]{0.40,0.40,0.40}{##1}}}
expandafterdefcsname PY@tok@mhendcsname{defPY@tc##1{textcolor[rgb]{0.40,0.40,0.40}{##1}}}
expandafterdefcsname PY@tok@goendcsname{defPY@tc##1{textcolor[rgb]{0.50,0.50,0.50}{##1}}}
expandafterdefcsname PY@tok@geendcsname{letPY@it=textit}
expandafterdefcsname PY@tok@vcendcsname{defPY@tc##1{textcolor[rgb]{0.10,0.09,0.49}{##1}}}
expandafterdefcsname PY@tok@ilendcsname{defPY@tc##1{textcolor[rgb]{0.40,0.40,0.40}{##1}}}
expandafterdefcsname PY@tok@csendcsname{letPY@it=textitdefPY@tc##1{textcolor[rgb]{0.25,0.50,0.50}{##1}}}
expandafterdefcsname PY@tok@cpendcsname{defPY@tc##1{textcolor[rgb]{0.74,0.48,0.00}{##1}}}
expandafterdefcsname PY@tok@giendcsname{defPY@tc##1{textcolor[rgb]{0.00,0.63,0.00}{##1}}}
expandafterdefcsname PY@tok@ghendcsname{letPY@bf=textbfdefPY@tc##1{textcolor[rgb]{0.00,0.00,0.50}{##1}}}
expandafterdefcsname PY@tok@niendcsname{letPY@bf=textbfdefPY@tc##1{textcolor[rgb]{0.60,0.60,0.60}{##1}}}
expandafterdefcsname PY@tok@nlendcsname{defPY@tc##1{textcolor[rgb]{0.63,0.63,0.00}{##1}}}
expandafterdefcsname PY@tok@nnendcsname{letPY@bf=textbfdefPY@tc##1{textcolor[rgb]{0.00,0.00,1.00}{##1}}}
expandafterdefcsname PY@tok@noendcsname{defPY@tc##1{textcolor[rgb]{0.53,0.00,0.00}{##1}}}
expandafterdefcsname PY@tok@naendcsname{defPY@tc##1{textcolor[rgb]{0.49,0.56,0.16}{##1}}}
expandafterdefcsname PY@tok@nbendcsname{defPY@tc##1{textcolor[rgb]{0.00,0.50,0.00}{##1}}}
expandafterdefcsname PY@tok@ncendcsname{letPY@bf=textbfdefPY@tc##1{textcolor[rgb]{0.00,0.00,1.00}{##1}}}
expandafterdefcsname PY@tok@ndendcsname{defPY@tc##1{textcolor[rgb]{0.67,0.13,1.00}{##1}}}
expandafterdefcsname PY@tok@neendcsname{letPY@bf=textbfdefPY@tc##1{textcolor[rgb]{0.82,0.25,0.23}{##1}}}
expandafterdefcsname PY@tok@nfendcsname{defPY@tc##1{textcolor[rgb]{0.00,0.00,1.00}{##1}}}
expandafterdefcsname PY@tok@siendcsname{letPY@bf=textbfdefPY@tc##1{textcolor[rgb]{0.73,0.40,0.53}{##1}}}
expandafterdefcsname PY@tok@s2endcsname{defPY@tc##1{textcolor[rgb]{0.73,0.13,0.13}{##1}}}
expandafterdefcsname PY@tok@viendcsname{defPY@tc##1{textcolor[rgb]{0.10,0.09,0.49}{##1}}}
expandafterdefcsname PY@tok@ntendcsname{letPY@bf=textbfdefPY@tc##1{textcolor[rgb]{0.00,0.50,0.00}{##1}}}
expandafterdefcsname PY@tok@nvendcsname{defPY@tc##1{textcolor[rgb]{0.10,0.09,0.49}{##1}}}
expandafterdefcsname PY@tok@s1endcsname{defPY@tc##1{textcolor[rgb]{0.73,0.13,0.13}{##1}}}
expandafterdefcsname PY@tok@shendcsname{defPY@tc##1{textcolor[rgb]{0.73,0.13,0.13}{##1}}}
expandafterdefcsname PY@tok@scendcsname{defPY@tc##1{textcolor[rgb]{0.73,0.13,0.13}{##1}}}
expandafterdefcsname PY@tok@sxendcsname{defPY@tc##1{textcolor[rgb]{0.00,0.50,0.00}{##1}}}
expandafterdefcsname PY@tok@bpendcsname{defPY@tc##1{textcolor[rgb]{0.00,0.50,0.00}{##1}}}
expandafterdefcsname PY@tok@c1endcsname{letPY@it=textitdefPY@tc##1{textcolor[rgb]{0.25,0.50,0.50}{##1}}}
expandafterdefcsname PY@tok@kcendcsname{letPY@bf=textbfdefPY@tc##1{textcolor[rgb]{0.00,0.50,0.00}{##1}}}
expandafterdefcsname PY@tok@cendcsname{letPY@it=textitdefPY@tc##1{textcolor[rgb]{0.25,0.50,0.50}{##1}}}
expandafterdefcsname PY@tok@mfendcsname{defPY@tc##1{textcolor[rgb]{0.40,0.40,0.40}{##1}}}
expandafterdefcsname PY@tok@errendcsname{defPY@bc##1{setlength{fboxsep}{0pt}fcolorbox[rgb]{1.00,0.00,0.00}{1,1,1}{strut ##1}}}
expandafterdefcsname PY@tok@kdendcsname{letPY@bf=textbfdefPY@tc##1{textcolor[rgb]{0.00,0.50,0.00}{##1}}}
expandafterdefcsname PY@tok@ssendcsname{defPY@tc##1{textcolor[rgb]{0.10,0.09,0.49}{##1}}}
expandafterdefcsname PY@tok@srendcsname{defPY@tc##1{textcolor[rgb]{0.73,0.40,0.53}{##1}}}
expandafterdefcsname PY@tok@moendcsname{defPY@tc##1{textcolor[rgb]{0.40,0.40,0.40}{##1}}}
expandafterdefcsname PY@tok@knendcsname{letPY@bf=textbfdefPY@tc##1{textcolor[rgb]{0.00,0.50,0.00}{##1}}}
expandafterdefcsname PY@tok@miendcsname{defPY@tc##1{textcolor[rgb]{0.40,0.40,0.40}{##1}}}
expandafterdefcsname PY@tok@gpendcsname{letPY@bf=textbfdefPY@tc##1{textcolor[rgb]{0.00,0.00,0.50}{##1}}}
expandafterdefcsname PY@tok@oendcsname{defPY@tc##1{textcolor[rgb]{0.40,0.40,0.40}{##1}}}
expandafterdefcsname PY@tok@krendcsname{letPY@bf=textbfdefPY@tc##1{textcolor[rgb]{0.00,0.50,0.00}{##1}}}
expandafterdefcsname PY@tok@sendcsname{defPY@tc##1{textcolor[rgb]{0.73,0.13,0.13}{##1}}}
expandafterdefcsname PY@tok@kpendcsname{defPY@tc##1{textcolor[rgb]{0.00,0.50,0.00}{##1}}}
expandafterdefcsname PY@tok@wendcsname{defPY@tc##1{textcolor[rgb]{0.73,0.73,0.73}{##1}}}
expandafterdefcsname PY@tok@ktendcsname{defPY@tc##1{textcolor[rgb]{0.69,0.00,0.25}{##1}}}
expandafterdefcsname PY@tok@owendcsname{letPY@bf=textbfdefPY@tc##1{textcolor[rgb]{0.67,0.13,1.00}{##1}}}
expandafterdefcsname PY@tok@sbendcsname{defPY@tc##1{textcolor[rgb]{0.73,0.13,0.13}{##1}}}
expandafterdefcsname PY@tok@kendcsname{letPY@bf=textbfdefPY@tc##1{textcolor[rgb]{0.00,0.50,0.00}{##1}}}
expandafterdefcsname PY@tok@seendcsname{letPY@bf=textbfdefPY@tc##1{textcolor[rgb]{0.73,0.40,0.13}{##1}}}
expandafterdefcsname PY@tok@sdendcsname{letPY@it=textitdefPY@tc##1{textcolor[rgb]{0.73,0.13,0.13}{##1}}}
defPYZbs{char`\}
defPYZus{char`_}
defPYZob{char`{}
defPYZcb{char`}}
defPYZca{char`^}
defPYZam{char`&}
defPYZlt{char`<}
defPYZgt{char`>}
defPYZsh{char`#}
defPYZpc{char`%}
defPYZdl{char`$}
defPYZti{char`~}
% for compatibility with earlier versions
defPYZat{@}
defPYZlb{[}
defPYZrb{]}
makeatother
% NB prompt colors
definecolor{nbframe-border}{rgb}{0.867,0.867,0.867}
definecolor{nbframe-bg}{rgb}{0.969,0.969,0.969}
definecolor{nbframe-in-prompt}{rgb}{0.0,0.0,0.502}
definecolor{nbframe-out-prompt}{rgb}{0.545,0.0,0.0}
% NB prompt lengths
newlength{inputpadding}
setlength{inputpadding}{0.5em}
newlength{cellleftmargin}
setlength{cellleftmargin}{0.15linewidth}
newlength{borderthickness}
setlength{borderthickness}{0.4pt}
newlength{smallerfontscale}
setlength{smallerfontscale}{9.5pt}
% NB prompt font size
defsmaller{fontsize{smallerfontscale}{smallerfontscale}selectfont}
% Define a background layer, in which the nb prompt shape is drawn
pgfdeclarelayer{background}
pgfsetlayers{background,main}
usetikzlibrary{calc}
% define styles for the normal border and the torn border
tikzset{
normal border/.style={draw=nbframe-border, fill=nbframe-bg,
rectangle, rounded corners=2.5pt, line width=borderthickness},
torn border/.style={draw=white, fill=white, line width=borderthickness}}
% Macro to draw the shape behind the text, when it fits completly in the
% page
defnotebookcellframe#1{%
tikz{%
node[inner sep=inputpadding] (A) {#1};% Draw the text of the node
begin{pgfonlayer}{background}% Draw the shape behind
fill[normal border]%
(A.south east) -- ($(A.south west)+(cellleftmargin,0)$) --
($(A.north west)+(cellleftmargin,0)$) -- (A.north east) -- cycle;
end{pgfonlayer}}}%
% Macro to draw the shape, when the text will continue in next page
defnotebookcellframetop#1{%
tikz{%
node[inner sep=inputpadding] (A) {#1}; % Draw the text of the node
begin{pgfonlayer}{background}
fill[normal border] % Draw the ``complete shape'' behind
(A.south east) -- ($(A.south west)+(cellleftmargin,0)$) --
($(A.north west)+(cellleftmargin,0)$) -- (A.north east) -- cycle;
fill[torn border] % Add the torn lower border
($(A.south east)-(0,.1)$) -- ($(A.south west)+(cellleftmargin,-.1)$) --
($(A.south west)+(cellleftmargin,.1)$) -- ($(A.south east)+(0,.1)$) -- cycle;
end{pgfonlayer}}}
% Macro to draw the shape, when the text continues from previous page
defnotebookcellframebottom#1{%
tikz{%
node[inner sep=inputpadding] (A) {#1}; % Draw the text of the node
begin{pgfonlayer}{background}
fill[normal border] % Draw the ``complete shape'' behind
(A.south east) -- ($(A.south west)+(cellleftmargin,0)$) --
($(A.north west)+(cellleftmargin,0)$) -- (A.north east) -- cycle;
fill[torn border] % Add the torn upper border
($(A.north east)-(0,.1)$) -- ($(A.north west)+(cellleftmargin,-.1)$) --
($(A.north west)+(cellleftmargin,.1)$) -- ($(A.north east)+(0,.1)$) -- cycle;
end{pgfonlayer}}}
% Macro to draw the shape, when both the text continues from previous page
% and it will continue in next page
defnotebookcellframemiddle#1{%
tikz{%
node[inner sep=inputpadding] (A) {#1}; % Draw the text of the node
begin{pgfonlayer}{background}
fill[normal border] % Draw the ``complete shape'' behind
(A.south east) -- ($(A.south west)+(cellleftmargin,0)$) --
($(A.north west)+(cellleftmargin,0)$) -- (A.north east) -- cycle;
fill[torn border] % Add the torn lower border
($(A.south east)-(0,.1)$) -- ($(A.south west)+(cellleftmargin,-.1)$) --
($(A.south west)+(cellleftmargin,.1)$) -- ($(A.south east)+(0,.1)$) -- cycle;
fill[torn border] % Add the torn upper border
($(A.north east)-(0,.1)$) -- ($(A.north west)+(cellleftmargin,-.1)$) --
($(A.north west)+(cellleftmargin,.1)$) -- ($(A.north east)+(0,.1)$) -- cycle;
end{pgfonlayer}}}
% Define the environment which puts the frame
% In this case, the environment also accepts an argument with an optional
% title (which defaults to ``Example'', which is typeset in a box overlaid
% on the top border
newenvironment{notebookcell}[1][0]{%
defFrameCommand{notebookcellframe}%
defFirstFrameCommand{notebookcellframetop}%
defLastFrameCommand{notebookcellframebottom}%
defMidFrameCommand{notebookcellframemiddle}%
parvspace{1baselineskip}%
MakeFramed {FrameRestore}%
noindenttikznode[inner sep=0em] at ($(A.north west)-(0,0)$) {%
begin{minipage}{cellleftmargin}%
hfill%
{smaller%
tt%
color{nbframe-in-prompt}%
In [#1]:}%
hspace{inputpadding}%
hspace{2pt}%
hspace{3pt}%
end{minipage}%%
}; par}%
{endMakeFramed}
sloppy % Prevent overflowing lines due to hard-to-break entities
% Setup hyperref package
hypersetup{
breaklinks=true, % so long urls are correctly broken across lines
colorlinks=true,
urlcolor=blue,
linkcolor=darkorange,
citecolor=darkgreen,
}
% Slightly bigger margins than the latex defaults
geometry{verbose,tmargin=1in,bmargin=1in,lmargin=1in,rmargin=1in}
% Override to specify your own logo
newcommand{sphinxlogo}{}
% Make the index page of the document.
makeindex
begin{document}
maketitle
This is a emph{simple} notebook
% Add contents below.
{par%
vspace{-1baselineskip}%
needspace{4baselineskip}}%
begin{notebookcell}[1]%
begin{addmargin}[cellleftmargin]{0em}% left, right
{smaller%
par%
%
vspace{-1smallerfontscale}%
begin{Verbatim}[commandchars=\{}]
PY{k}{print}PY{p}{(}PY{l+s}{"}PY{l+s}{Which has a simple task}PY{l+s+se}{PYZbs{}n}PY{l+s}{Seriously...}PY{l+s}{"}PY{p}{)}
PY{k}{print}PY{p}{(}PY{l+s}{"}PY{l+s}{Cool!}PY{l+s}{"}PY{p}{)}
end{Verbatim}
%
par%
vspace{-1smallerfontscale}}%
end{addmargin}
end{notebookcell}
parvspace{1smallerfontscale}%
% Only render the prompt if the cell is pyout. Note, the outputs prompt
% block isn't used since we need to check each indiviual output and only
% add prompts to the pyout ones.
%
%
begin{addmargin}[cellleftmargin]{0em}% left, right
{smaller%
vspace{-1smallerfontscale}%
begin{Verbatim}[commandchars=\{}]
Which has a simple task
Seriously...
Cool!
end{Verbatim}
}%
end{addmargin}%
% Add contents below.
{par%
vspace{-1baselineskip}%
needspace{4baselineskip}}%
begin{notebookcell}[2]%
begin{addmargin}[cellleftmargin]{0em}% left, right
{smaller%
par%
%
vspace{-1smallerfontscale}%
begin{Verbatim}[commandchars=\{}]
PY{l+s}{"}PY{l+s}{To print hello world}PY{l+s+se}{PYZbs{}n}PY{l+s}{Multiple lines}PY{l+s}{"}
end{Verbatim}
%
par%
vspace{-1smallerfontscale}}%
end{addmargin}
end{notebookcell}
parvspace{1smallerfontscale}%
% Only render the prompt if the cell is pyout. Note, the outputs prompt
% block isn't used since we need to check each indiviual output and only
% add prompts to the pyout ones.
{par%
vspace{-1smallerfontscale}%
noindent%
begin{minipage}{cellleftmargin}%
hfill%
{smaller%
tt%
color{nbframe-out-prompt}%
Out[2]:}%
hspace{inputpadding}%
hspace{0em}%
hspace{3pt}%
end{minipage}%%
}%
%
%
begin{addmargin}[cellleftmargin]{0em}% left, right
{smaller%
vspace{-1smallerfontscale}%
begin{verbatim}
'To print hello worldnMultiple lines'
end{verbatim}
}%
end{addmargin}%
end{document}