1

I'm using the Tufte class for a document with lots of figures, and some of my readers have complained that it is not always easy to locate the caption of figures that are not in the margin. So I'd like to define (and then use) variants the \caption macro display a small triangle in front of the caption, pointing to the figure. For instance \captiondown{my caption} would display "▼ Figure 3: my caption".

It's not clear to me how to write such macros. I thought I could achieve that by redefining \figurename, but looking at the example below it works in the marginfigure environment, not in the figure and figure* environments. Can someone help?

\documentclass[a4paper,nobib]{tufte-handout}
\usepackage{amssymb}
\usepackage{tikz}
\usepackage{showframe}

\renewcommand{\figurename}{\textbf{Figure}}

\begin{document}
\begin{marginfigure}
  \tikz\fill[cyan] rectangle(\marginparwidth,2);
  \renewcommand{\figurename}{$\blacktriangle$~\textbf{Figure}}
  \caption{Some caption for the blue figure.}
\end{marginfigure}
\begin{figure}
  \tikz\fill[yellow]rectangle(\textwidth,4);
  \renewcommand{\figurename}{$\blacktriangleleft$~\textbf{Figure}} %ignored?
  \caption[][3cm]{Some caption for the yellow figure.}
\end{figure}
\begin{figure*}
  \tikz\fill[magenta]rectangle(\textwidth,3);
  \renewcommand{\figurename}{$\blacktriangledown$~\textbf{Figure}} %ignored?
  \caption[][-4.5cm]{Some caption for the magenta figure.}
\end{figure*}
\end{document}

output

Update:

Here is a variant where I redefine \fnum@figure instead. I get the desired output if I redefine that macro before the figure and figure* environment, so I guess I'll make do with that.

I'd still very much prefer to be able to call \captiondown{my caption} inside those environments, but I do not know how to do that.

\documentclass[a4paper,nobib]{tufte-handout}
\usepackage{amssymb}
\usepackage{tikz}
\usepackage{showframe}

\makeatletter
\newcommand{\captionsbelow}{%
  \renewcommand{\fnum@figure}{$\blacktriangle$~\textbf{\figurename}~\thefigure}}
\newcommand{\captionsright}{%
  \renewcommand{\fnum@figure}{$\blacktriangleleft$~\textbf{\figurename}~\thefigure}}
\newcommand{\captionsabove}{%
  \renewcommand{\fnum@figure}{$\blacktriangledown$~\textbf{\figurename}~\thefigure}}
\makeatother

\begin{document}
\captionsbelow
\begin{marginfigure}
  \tikz\fill[cyan] rectangle(\marginparwidth,2);
  \caption{Some caption for the blue figure.}
\end{marginfigure}
\captionsright
\begin{figure}
  \tikz\fill[yellow]rectangle(\textwidth,4);
  \caption[][3cm]{Some caption for the yellow figure.}
\end{figure}
\captionsabove
\begin{figure*}
  \tikz\fill[magenta]rectangle(\textwidth,3);
  \caption[][-4.5cm]{Some caption for the magenta figure.}
\end{figure*}
\end{document}

output

Final update:

Using all the input I got, a managed to patch the Tufte definitions in a way that the orientation is redefined in each float according to the location of the figure. (I'm just not bothering with recto-verso mode, which I don't use, but extending that to support it should not be a problem.)

\documentclass[a4paper,nobib]{tufte-handout}
\usepackage{showframe}
\usepackage{amssymb}
\usepackage{tikz}
\usepackage{etoolbox}

\makeatletter
\renewcommand{\fnum@figure}{\captiontriangle~\textbf{\figurename}~\thefigure}
\newcommand{\captionbelow}{\gdef\captiontriangle{$\blacktriangle$}}
\newcommand{\captionright}{\gdef\captiontriangle{$\blacktriangleleft$}}
\newcommand{\captionabove}{\gdef\captiontriangle{$\blacktriangledown$}}
% Use \captionbelow by default, for margin figures
\AtBeginDocument{\captionbelow}
\AfterEndEnvironment{@tufte@float}{\captionbelow}
% automatically change the triangle for other captions
\AtEndEnvironment{@tufte@float}{%
  \ifthenelse{\boolean{@tufte@float@star}}%
    {\ifthenelse{\equal{\floatalignment}{b}}{\captionabove}{\captionbelow}}%
    {\captionright}}
\makeatother

\setcounter{totalnumber}{4}% for demonstration
\begin{document}
\begin{marginfigure}
  \tikz\fill[cyan] rectangle(\marginparwidth,2);
  \caption{Some caption for the blue figure.}
\end{marginfigure}
\begin{figure}
  \tikz\fill[yellow]rectangle(\textwidth,4);
  \caption[][3cm]{Some caption for the yellow figure.}
\end{figure}
\begin{figure*}
  \tikz\fill[magenta]rectangle(\textwidth,3);
  \setfloatalignment{b} %force caption above
  \caption{Some caption for the magenta figure.}
\end{figure*}
\begin{figure*}
  \tikz\fill[green!30]rectangle(\textwidth,3);
  \caption[][-1.2em]{Some caption for the green figure.}
\end{figure*}
\begin{figure*}[b]
  \tikz\fill[gray!30]rectangle(\textwidth,3);
  \caption{Some caption for the gray figure.}
\end{figure*}
\end{document}

enter image description here

4
  • the intention of the zzzname macros is that they should only have text (to be easily translated) so \renewcommand{\figurename}{\textbf{Figure}} is not really following the guidelines, the styling of the name should be elsewhere, \figurename should just be the text Figure in the current language. Commented Sep 29, 2020 at 8:00
  • @DavidCarlisle I've made some progress and updated the code in a way that do not change \figurename. My problem is not really related to \figurename but to the way the figure environment of tufte captures the caption and displays it afterwards, ignoring any (re)definition local to the environment.
    – adl
    Commented Sep 29, 2020 at 9:47
  • Since figure* could be either above or below the caption, you need the actual relative positions. You could use \tikzmark, or create you own aux file system using \pdfsavepos, \pdflastypos and \pdflastxpos Commented Sep 29, 2020 at 16:07
  • @JohnKormylo With the tufte style, I usually have to shift the captions explicitly so they look nice, so I know beforehand if it is above or below and I'm ok with replacing \caption{...} by \captionabove{...} or \captiondown{...} as appropriate. But I agree getting this figured automatically would be nice. The tufte code seems to use \floatalignment to decide if the caption is above or below, so maybe I can simply check this.
    – adl
    Commented Sep 30, 2020 at 7:39

1 Answer 1

1

A good workaround for what is happening is to define a command which resets the label of a figure. Afterwards, employ \AfterEndEnvironment (from etoolbox) to execute such command after every figure and figure* environment. This way, you might be able to redefine how caption should look like but also still get the original definition of figures caption after the environment ends.

\documentclass[a4paper,nobib]{tufte-handout}
\usepackage{amssymb}
\usepackage{tikz}
\usepackage{showframe}

\usepackage{etoolbox}

\makeatletter
    \renewcommand{\fnum@figure}{\textbf{\figurename}~\thefigure}
    % save older version of \fnum@figure
    \let \fnum@figureold \fnum@figure
    % define a command to reset to the older version
    \newcommand{\resetfnumfigure}{\let \fnum@figure \fnum@figureold}
\makeatother

\AfterEndEnvironment{figure}{\resetfnumfigure}
\AfterEndEnvironment{figure*}{\resetfnumfigure}


\makeatletter
    \newcommand{\captionsbelow}{%
      \renewcommand{\fnum@figure}{$\blacktriangle$~\textbf{\figurename}~\thefigure}}
    \newcommand{\captionsright}{%
      \renewcommand{\fnum@figure}{$\blacktriangleleft$~\textbf{\figurename}~\thefigure}}
    \newcommand{\captionsabove}{%
      \renewcommand{\fnum@figure}{$\blacktriangledown$~\textbf{\figurename}~\thefigure}}
\makeatother

\begin{document}

\begin{marginfigure}
    \captionsbelow
  \tikz\fill[cyan] rectangle(\marginparwidth,2);
  \caption{Some caption for the blue figure.}
\end{marginfigure}
\captionsright
\begin{figure}
  \tikz\fill[yellow]rectangle(\textwidth,4);
  \caption[][3cm]{Some caption for the yellow figure.}
\end{figure}
\captionsabove
\begin{figure*}
  \tikz\fill[magenta]rectangle(\textwidth,3);
  \caption[][-4.5cm]{Some caption for the magenta figure.}
\end{figure*}

\end{document}
2
  • Thanks! AfterEndEnvironment and AtEndEnvironment was exactly the last bit I needed to hook into floating code for the tufte class. I've updated the question with the revised code I'm now using, and I'm going to accept this answer.
    – adl
    Commented Sep 30, 2020 at 8:49
  • @JohnKormylo it would revert if it was changed in the environment. The situation is that in the tufte class, the caption for figure and figure* are not typeset inside those environments: they are saved, and then typeset in the \end par of the environment. So changing \fnum@figure in the environment would have no effect on the caption. That's why calling the \captionsabove or \captionsright macros were still done outside of the environment in this example.
    – adl
    Commented Sep 30, 2020 at 14:40

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .