# Tikz + Verbatim + Sphinx , output drawn twice with slight offset. Works great Tikz + Verbatim

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:

BUT! When I try to use the Sphinx templates to produce my output:

The majority of the tikz code is this http://www.texample.net/tikz/examples/framed-tikz/ example modified

EDIT: After David's suggestion:

EDIT: MWE, with suggested solution(s). Produces same output as above.

% Make sure that the sphinx doc style knows who it inherits from.
\def\sphinxdocclass{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
\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.
\def\br{\hspace*{\fill} \\* }

% Document parameters
\title{simpletest}

% Pygments definitions

\makeatletter
\def\PY@reset{\let\PY@it=\relax \let\PY@bf=\relax%
\let\PY@ul=\relax \let\PY@tc=\relax%
\let\PY@bc=\relax \let\PY@ff=\relax}
\def\PY@tok#1{\csname PY@tok@#1\endcsname}
\def\PY@toks#1+{\ifx\relax#1\empty\else%
\PY@tok{#1}\expandafter\PY@toks\fi}
\def\PY@do#1{\PY@bc{\PY@tc{\PY@ul{%
\PY@it{\PY@bf{\PY@ff{#1}}}}}}}
\def\PY#1#2{\PY@reset\PY@toks#1+\relax+\PY@do{#2}}

\expandafter\def\csname PY@tok@gd\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.63,0.00,0.00}{##1}}}
\expandafter\def\csname PY@tok@gu\endcsname{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.50,0.00,0.50}{##1}}}
\expandafter\def\csname PY@tok@gt\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.00,0.25,0.82}{##1}}}
\expandafter\def\csname PY@tok@gs\endcsname{\let\PY@bf=\textbf}
\expandafter\def\csname PY@tok@gr\endcsname{\def\PY@tc##1{\textcolor[rgb]{1.00,0.00,0.00}{##1}}}
\expandafter\def\csname PY@tok@cm\endcsname{\let\PY@it=\textit\def\PY@tc##1{\textcolor[rgb]{0.25,0.50,0.50}{##1}}}
\expandafter\def\csname PY@tok@vg\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.10,0.09,0.49}{##1}}}
\expandafter\def\csname PY@tok@m\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.40,0.40,0.40}{##1}}}
\expandafter\def\csname PY@tok@mh\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.40,0.40,0.40}{##1}}}
\expandafter\def\csname PY@tok@go\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.50,0.50,0.50}{##1}}}
\expandafter\def\csname PY@tok@ge\endcsname{\let\PY@it=\textit}
\expandafter\def\csname PY@tok@vc\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.10,0.09,0.49}{##1}}}
\expandafter\def\csname PY@tok@il\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.40,0.40,0.40}{##1}}}
\expandafter\def\csname PY@tok@cs\endcsname{\let\PY@it=\textit\def\PY@tc##1{\textcolor[rgb]{0.25,0.50,0.50}{##1}}}
\expandafter\def\csname PY@tok@cp\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.74,0.48,0.00}{##1}}}
\expandafter\def\csname PY@tok@gi\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.00,0.63,0.00}{##1}}}
\expandafter\def\csname PY@tok@gh\endcsname{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.00,0.00,0.50}{##1}}}
\expandafter\def\csname PY@tok@ni\endcsname{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.60,0.60,0.60}{##1}}}
\expandafter\def\csname PY@tok@nl\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.63,0.63,0.00}{##1}}}
\expandafter\def\csname PY@tok@nn\endcsname{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.00,0.00,1.00}{##1}}}
\expandafter\def\csname PY@tok@no\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.53,0.00,0.00}{##1}}}
\expandafter\def\csname PY@tok@na\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.49,0.56,0.16}{##1}}}
\expandafter\def\csname PY@tok@nb\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.00,0.50,0.00}{##1}}}
\expandafter\def\csname PY@tok@nc\endcsname{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.00,0.00,1.00}{##1}}}
\expandafter\def\csname PY@tok@nd\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.67,0.13,1.00}{##1}}}
\expandafter\def\csname PY@tok@ne\endcsname{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.82,0.25,0.23}{##1}}}
\expandafter\def\csname PY@tok@nf\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.00,0.00,1.00}{##1}}}
\expandafter\def\csname PY@tok@si\endcsname{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.73,0.40,0.53}{##1}}}
\expandafter\def\csname PY@tok@s2\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.73,0.13,0.13}{##1}}}
\expandafter\def\csname PY@tok@vi\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.10,0.09,0.49}{##1}}}
\expandafter\def\csname PY@tok@nt\endcsname{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.00,0.50,0.00}{##1}}}
\expandafter\def\csname PY@tok@nv\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.10,0.09,0.49}{##1}}}
\expandafter\def\csname PY@tok@s1\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.73,0.13,0.13}{##1}}}
\expandafter\def\csname PY@tok@sh\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.73,0.13,0.13}{##1}}}
\expandafter\def\csname PY@tok@sc\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.73,0.13,0.13}{##1}}}
\expandafter\def\csname PY@tok@sx\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.00,0.50,0.00}{##1}}}
\expandafter\def\csname PY@tok@bp\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.00,0.50,0.00}{##1}}}
\expandafter\def\csname PY@tok@c1\endcsname{\let\PY@it=\textit\def\PY@tc##1{\textcolor[rgb]{0.25,0.50,0.50}{##1}}}
\expandafter\def\csname PY@tok@kc\endcsname{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.00,0.50,0.00}{##1}}}
\expandafter\def\csname PY@tok@c\endcsname{\let\PY@it=\textit\def\PY@tc##1{\textcolor[rgb]{0.25,0.50,0.50}{##1}}}
\expandafter\def\csname PY@tok@mf\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.40,0.40,0.40}{##1}}}
\expandafter\def\csname PY@tok@err\endcsname{\def\PY@bc##1{\setlength{\fboxsep}{0pt}\fcolorbox[rgb]{1.00,0.00,0.00}{1,1,1}{\strut ##1}}}
\expandafter\def\csname PY@tok@kd\endcsname{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.00,0.50,0.00}{##1}}}
\expandafter\def\csname PY@tok@ss\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.10,0.09,0.49}{##1}}}
\expandafter\def\csname PY@tok@sr\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.73,0.40,0.53}{##1}}}
\expandafter\def\csname PY@tok@mo\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.40,0.40,0.40}{##1}}}
\expandafter\def\csname PY@tok@kn\endcsname{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.00,0.50,0.00}{##1}}}
\expandafter\def\csname PY@tok@mi\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.40,0.40,0.40}{##1}}}
\expandafter\def\csname PY@tok@gp\endcsname{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.00,0.00,0.50}{##1}}}
\expandafter\def\csname PY@tok@o\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.40,0.40,0.40}{##1}}}
\expandafter\def\csname PY@tok@kr\endcsname{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.00,0.50,0.00}{##1}}}
\expandafter\def\csname PY@tok@s\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.73,0.13,0.13}{##1}}}
\expandafter\def\csname PY@tok@kp\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.00,0.50,0.00}{##1}}}
\expandafter\def\csname PY@tok@w\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.73,0.73,0.73}{##1}}}
\expandafter\def\csname PY@tok@kt\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.69,0.00,0.25}{##1}}}
\expandafter\def\csname PY@tok@ow\endcsname{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.67,0.13,1.00}{##1}}}
\expandafter\def\csname PY@tok@sb\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.73,0.13,0.13}{##1}}}
\expandafter\def\csname PY@tok@k\endcsname{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.00,0.50,0.00}{##1}}}
\expandafter\def\csname PY@tok@se\endcsname{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.73,0.40,0.13}{##1}}}
\expandafter\def\csname PY@tok@sd\endcsname{\let\PY@it=\textit\def\PY@tc##1{\textcolor[rgb]{0.73,0.13,0.13}{##1}}}

\def\PYZbs{\char\\}
\def\PYZus{\char\_}
\def\PYZob{\char\{}
\def\PYZcb{\char\}}
\def\PYZca{\char\^}
\def\PYZam{\char\&}
\def\PYZlt{\char\<}
\def\PYZgt{\char\>}
\def\PYZsh{\char\#}
\def\PYZpc{\char\%}
\def\PYZdl{\char\$} \def\PYZti{\char\~} % for compatibility with earlier versions \def\PYZat{@} \def\PYZlb{[} \def\PYZrb{]} \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.15\linewidth} \newlength{\borderthickness} \setlength{\borderthickness}{0.4pt} \newlength{\smallerfontscale} \setlength{\smallerfontscale}{9.5pt} % NB prompt font size \def\smaller{\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 \def\notebookcellframe#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 \def\notebookcellframetop#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 \def\notebookcellframebottom#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 \def\notebookcellframemiddle#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]{% \def\FrameCommand{\notebookcellframe}% \def\FirstFrameCommand{\notebookcellframetop}% \def\LastFrameCommand{\notebookcellframebottom}% \def\MidFrameCommand{\notebookcellframemiddle}% \par\vspace{1\baselineskip}% \MakeFramed {\FrameRestore}% \noindent\tikz\node[inner sep=0em] at ($(A.north west)-(0,0)\$) {%
\begin{minipage}{\cellleftmargin}%
\hfill%
{\smaller%
\tt%
\color{nbframe-in-prompt}%
In [#1]:}%
\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
urlcolor=blue,
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

{\par%
\vspace{-1\baselineskip}%
\needspace{4\baselineskip}}%
\begin{notebookcell}[1]%
{\smaller%
\par%
%
\vspace{-1\smallerfontscale}%
\begin{Verbatim}[commandchars=\\\{\}]
\PY{k}{print}\PY{p}{(}\PY{l+s}{"}\PY{l+s}{Cool!}\PY{l+s}{"}\PY{p}{)}
\end{Verbatim}
%
\par%
\vspace{-1\smallerfontscale}}%
\end{notebookcell}

\par\vspace{1\smallerfontscale}%
% 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.
%
%
{\smaller%
\vspace{-1\smallerfontscale}%

\begin{Verbatim}[commandchars=\\\{\}]
Seriously...
Cool!
\end{Verbatim}
}%

{\par%
\vspace{-1\baselineskip}%
\needspace{4\baselineskip}}%
\begin{notebookcell}[2]%
{\smaller%
\par%
%
\vspace{-1\smallerfontscale}%
\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{-1\smallerfontscale}}%
\end{notebookcell}

\par\vspace{1\smallerfontscale}%
% 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{-1\smallerfontscale}%
\noindent%
\begin{minipage}{\cellleftmargin}%
\hfill%
{\smaller%
\tt%
\color{nbframe-out-prompt}%
Out[2]:}%
\hspace{0em}%
\hspace{3pt}%
\end{minipage}%%
}%
%
%
{\smaller%
\vspace{-1\smallerfontscale}%

\begin{verbatim}
'To print hello world\nMultiple lines'
\end{verbatim}

}%

\end{document}

• I can't run you code but I'd be suspicious of def\notebookcellframe#1{ and similar definitions missing a % after the { which will typically offset the contents by one word space. – David Carlisle Sep 3 '13 at 1:10
• @DavidCarlisle That helped! It removed the horizontal offset however I still have a vertical offset in my output, I'll upload a new screen capture. – Jonathan Sep 3 '13 at 1:14
• is it not possible to create a reproducible example (that preferably doesn't require running sphinx (I don't know if you can capture the tex it generates?) – David Carlisle Sep 3 '13 at 1:17
• The sphinx latex code itself is very complex. The best I could do is package the sphinx dependencies in a zip and upload that somewhere. I'm almost certain I would hit some sort of character limit trying to upload all of the sphinx code in my post. – Jonathan Sep 3 '13 at 1:23
• sphinx-doc.org – Jonathan Sep 3 '13 at 1:24

Asnoted in comments the code has several missing % from the ends of lines which will be interpreted as word spaces so causing a horizontal offset

so

\def\notebookcellframe#1{


should be

\def\notebookcellframe#1{%


The code around your vertical skip is also very fragile.

\needspace{4\baselineskip}%
\begin{notebookcell}[((( cell.prompt_number )))]
\smaller%
\vspace{-1\baselineskip}%
\vspace{-1\borderthickness}%
((( cell.input | highlight2latex )))%
\vspace{-1\baselineskip}%


I don't see the definition for addmargin but I assume the content starts in vertical mode.

The \needsspace test uses the outer (larger) value of baselineskip.

\smaller is a font change so changes the font size (immediately) and the baselineskip will change immediately, although the effective value that will be used for text depends on whether the paragraph ends in the current scope (ie the definition of \endaddmargin)

\smmaller is

\def\smaller{\fontsize{9.5pt}{9.5pt}\selectfont}


which sets 9.5pt font to a 9.5pt target baseline so normally this is not possible and so \baselineskip in fact will not be used and \lineskip will be used instead, normally the baseline space is around 10-12% larger than the font size.

Assuming addmargin does start in vertical mode then

\vspace{-1\baselineskip}%
\vspace{-1\borderthickness}%


will now add -ve space (using the 9.5pt for \baselineskip)/ If addmargin starts in horizontal mode then these spaces will be held in a \vadjust node and added following the next line of text. You may way to put \par in front of them to make sure you are in vmode.

Then the text is set in the small font then

\vspace{-1\baselineskip}%


is interpreted in horizontal mode so held in a vadjust node until the paragraph ends, presumably in the definition of \enddaddmargin somewhere. Again you may want to put \par before the \vskip.

If you are getting different layout around these spaces the causes are probably one definition of addmargin or notebookcell

• adds a box or write node or special of some kind at the start

or

• redefines things so that addmargin starts in horizontal mode

or

• redefines things so there is an extra group layer and so the group ends before the paragraph of small text, so it is set with the original larger baseline.
• I believe I've implement everything you've suggested. I tried using small font vspace jumps (which is what is pasted above) and normal sized jumps. – Jonathan Sep 3 '13 at 17:37
• I just added a MWE to my original post. It has all of the changes you suggested – Jonathan Sep 3 '13 at 17:38
• @Jonathan OK I'm out, good luck, not more I can suggest without the code (and I choose not to install sphinx just to test this:-) – David Carlisle Sep 3 '13 at 17:55
• thank you so much for the help. Sorry it's a PITA. If no one else can discover why the vertical spacing is behaving differently, I'll mark this as the solution. – Jonathan Sep 3 '13 at 17:57

The main remaining cause of your issue is that Sphinx Verbatim uses itself framed.sty and framed.sty induces vertical spaces which your code did not at all try to control. It is quite complicated if furthermore the framed is started in horizontal mode. I gave a shot to your problem with current Sphinx.

Removing all the various vertical spaces accumulated in each use of the notebookcell environments, plus drawing the In[1]: without entering paragraph mode (and without using TikZ which was confusing there), there only remains a \smallskip which is always inserted by Sphinx on top of frame. Then we use a conditional to tell the verbatim it is already inside a frame environment (it then must be done inside a minipage); this conditional is only in recent versions of Sphinx (there was no reason for it in older times as no Verbatim would end up inside another Verbatim... but more recent Sphinx uses framed for other things).

Result:

The rule is there to show alignment.

Code for notebookcell:

\newenvironment{notebookcell}[1][0]{\sphinxverbatimwithminipagetrue
\def\FrameCommand{\notebookcellframe}%
\def\FirstFrameCommand{\notebookcellframetop}%
\def\LastFrameCommand{\notebookcellframebottom}%
\def\MidFrameCommand{\notebookcellframemiddle}%
\par\MakeFramed {\FrameRestore}%
\vspace{\baselineskip}%
\hbox{{\smash{\makebox[\cellleftmargin][r]{%
\smaller
\tt\color{nbframe-in-prompt}In [#1]:%
}}\hss}%
\vspace{-\baselineskip}%
\vspace{-\smallskipamount}%
}%
{\endMakeFramed}

\def\x{\llap{\rule{2cm}{0.1pt}}\rlap{\rule{3cm}{0.1pt}}}


Code for use of notebookcell (all various vertical skips have been removed):

\begin{notebookcell}[1]%

and similarly for the other one. Apart from that you need to get a recent sphinx.sty` and one obtains the above.