Making a margin figure wider than the margin

I'm using the Tufte class and I want to create a margin figure that is larger than the margin, making the text wrap around it. Any tips of how I might do that? I tried adapting the @tufte@margin@floatbox to get a third argument for the minipage width, but I'm failing miserably. Here's what I got so far:

\newsavebox{\myfloatboxwider}
\newenvironment{myfloatwider}[3][-1.2ex]%
{\FloatBarrier% process all floats before this point so the figure/table numbers stay in order.
\begin{lrbox}{\myfloatboxwider}%
\hspace*{-\marginparwidth}%
\begin{minipage}{#3}%
\@tufte@caption@font%
\def\@captype{#2}%
\hbox{}\vspace*{#1}%
\@tufte@caption@justification%
\@tufte@margin@par%
\noindent%
}
{\end{minipage}%
\end{lrbox}%
\marginpar{\usebox{\myfloatboxwider}}%
}

\newenvironment{marginfigurewider}[2][-1.2ex]%
{\begin{myfloatwider}[#1]{figure}{#2}}
{\end{myfloatwider}}


To use like this

\begin{marginfigurewider}[1.2ex]{2.0\marginparwidth}%
\includegraphics[width=\linewidth]{myimage.jpg}
\caption{Some caption.}
\label{fig:somefig}
\end{marginfigurewider}


However there are two problems left that I cannot solve:

1. The hspace should actually be #3-\marginparwidth, but I can't find a way to make this calculation.
2. The main text does not wrap around it. Do I need something like wrapfig for this?

Update

This achieves more or less what I want:

\setlength\columnsep{\marginparsep}
\begin{wrapfigure}{O}[\dimexpr \marginparwidth+\marginparsep]{2.0\marginparwidth}
\FloatBarrier%
\vspace{-0.7\baselineskip}
\begin{minipage}[b]{2.0\marginparwidth}
\includegraphics[width=\linewidth]{myimage.jpg}
\caption{Some caption.}
\label{fig:somefig}
\end{minipage}
\end{wrapfigure}


There are still two problems:

1. Side notes, like cite, are overlaid over the image, not floated down below it.
2. I can't make it work as a \newenvironment. Nothing shows, and width=\linewidth is flagged as not a number. I can live by using the code manually, but it'd be nicer if it was an environment. Attempt is below:

\newenvironment{marginfigurewide}[1]%
{\FloatBarrier%
\setlength\columnsep{\marginparsep}%
\begin{wrapfigure}{O}[\dimexpr \marginparwidth+\marginparsep]{2.0\marginparwidth}%
\vspace{-0.7\baselineskip}%
\begin{minipage}[b]{2.0\marginparwidth}
}
{\end{minipage}%
\end{wrapfigure}
}

• Wrapfig has an overhang option Use [\dimexpr \marginparsep+\marginparwidth] Sep 8, 2020 at 14:14
• Thanks, this helped, but I still have the other margin items overlaid instead of floated. any other tips? Sep 8, 2020 at 18:08
• So what is the argument of marginfigurewide supposed to be? Sep 8, 2020 at 22:35
• It's the final width of the figure, as you figured out in your answer. Sep 9, 2020 at 16:10
• It seems that tufte-book ALWAYS puts the margin on the right side, even when using [twoside]. Oct 3, 2020 at 17:30

1 Answer

I had the bright idea of reserving blank space in the margin using \marginpar. However, wrapfigure will still overlap any pre-existing margin material. I don't know of any way to delay the start of wrapfigure until the margin is empty (except manually).

Also, I don't know why \wrapfigure works and \begin{wrapfigure} doesn't, but it probably has something to do with local vs. global values.

\documentclass{tufte-book}
\usepackage{graphicx}
\usepackage{wrapfig}
\usepackage{marginfix}

\usepackage{lipsum}
\usepackage{showframe}

\newsavebox{\marginbox}

\makeatletter
\newenvironment{marginfigurewide}[1]% #1 = width
{\begin{lrbox}{\marginbox}%
\def\@captype{figure}%
\begin{minipage}{#1}}%
{\end{minipage}\end{lrbox}%
%\setlength{\intextsep}{0pt}%
\setlength{\columnsep}{\marginparsep}%
\wrapfigure{r}[\dimexpr \marginparwidth+\marginparsep]{\wd\marginbox}
\usebox\marginbox
\endwrapfigure
\marginpar{\rule{0pt}{\dimexpr \ht\marginbox+\dp\marginbox+2\intextsep}}}% reserve space in margin
\makeatother

\begin{document}

\begin{marginfigurewide}{2\marginparwidth}
\includegraphics[width=\linewidth]{example-image}
\caption{Some caption.}
\label{fig:somefig}
\end{marginfigurewide}

test\sidenote{\LipsumPar{2}}

\LipsumPar{1}

\end{document}


The version will overlap the bottom of the page.

\documentclass[twoside]{tufte-book}
\usepackage{graphicx}
\usepackage{wrapfig}
\usepackage{marginfix}

\usepackage{lipsum}
\usepackage{showframe}

\newsavebox{\marginbox}

\makeatletter
\newenvironment{marginfigurewide}[1]% #1 = width
{\begin{lrbox}{\marginbox}%
\def\@captype{figure}%
\begin{minipage}{#1}}%
{\end{minipage}\end{lrbox}%
\setlength{\columnsep}{\marginparsep}%
\dimen0=\dimexpr \pagegoal-\pagetotal-\ht\strutbox\relax% remaining space on page
\dimen1=\dimexpr \ht\marginbox+\dp\marginbox+\intextsep\relax% size of figure
\ifdim\dimen1<\dimen0% fits page
\wrapfigure{r}[\dimexpr \marginparwidth+\marginparsep]{\wd\marginbox}
\usebox\marginbox
\endwrapfigure
\marginpar{\rule{0pt}{\dimexpr \ht\marginbox+\dp\marginbox+2\intextsep}}% reserve space in margin
\else% overlaps bottom
\wrapfigure{r}[\dimexpr \marginparwidth+\marginparsep]{\wd\marginbox}
\raisebox{\dimexpr \dimen0-\intextsep-\ht\marginbox}[\dimexpr \dimen0-2\intextsep][0pt]{\usebox\marginbox}%
\endwrapfigure
\marginpar{\rule{0pt}{\dimen0}}%
\fi}
\makeatother

\begin{document}

\begin{marginfigurewide}{2\marginparwidth}
\includegraphics[width=\linewidth]{example-image}
\caption{Some caption.}
\label{fig:somefig}
\end{marginfigurewide}

Place note here.\sidenote{\LipsumPar{2}}

%\LipsumPar{1}
\lipsum[1-2]

\begin{marginfigurewide}{2\marginparwidth}
\includegraphics[width=\linewidth]{example-image}
\caption{Some caption.}
\label{fig:somefig}
\end{marginfigurewide}

Place note here.\sidenote{\LipsumPar{2}}

\lipsum[3-4]

\end{document}

• Thank you, this works and is an environment, making it simple to use! But this has the same problem of my approach above. Here's what happens with a sidenote: imgur.com/a/8F6NRPS . I still can't find a way to flush the margin or reserve space there. Sep 9, 2020 at 16:09
• If you change the 0pt to \marginparwidth in the \marginpar, you will see that the space SHOULD be occupied. OTOH, marginnotes (for example) overlaps anything, including itself. Sep 9, 2020 at 16:36
• I found another solution meanwhile: just loading \use{marginfix} seems to automatically solve the issues. I suggest you patch your answer with this and I'll accept it. Thanks a lot! Sep 9, 2020 at 17:19
• Your second example does not work as well. The height is smaller than expected, and text goes back to its normal length before it should. Sep 9, 2020 at 17:24
• Both wrapfigure and marginpar have problems with the end of the page. One can use \WFclear between paragraphs to stop wrpafigure from wrapping text. I might be able to do something about marginpar. Oct 3, 2020 at 16:27