14

I would like to generate a marginal note showing, for example "Fig. 1" the first time I refer to a figure. I would like this to happen too the first time I refer to a Table or to an equation. I would like this to work in the multicol environment as well.

The package "showlabels" is close to what I need; however, it shows the true label name, not the number assigned to it nor a text such as "Fig." or "Eq.". Additionnally, the option "outer" seems to be not working.

The following (not so minimal) MWE shows where I am:

\documentclass{article}

\usepackage[nolabel,outer]{showlabels}
\usepackage{color}
\renewcommand{\showlabelfont}{\small\slshape\color{red}}
\showlabels{ref}

\usepackage{lipsum}
\usepackage{multicol}


\author{John Doe}
\title{Automatic marginal notes for the first use of a label}

\begin{document}
  \maketitle

  \begin{multicols}{2}

  See Figure~\ref{fig:figure}. \lipsum[1] 

  A new reference to Figure~\ref{fig:figure} is not 
referenced in the marginal note.

  Let's do the same with an equation.
  \begin{equation}
    \label{eq:1}f(x) = x^2
  \end{equation}

  Refering to Equation~\ref{eq:1} for the first time, there should be a marginal note, as is visible here, but it shoudl begin with  ``Eq.'', not ``Fig.''.

  Refering to Table~\ref{tab:1} for the first time. Here, there is no visible marginal note at all...

  \end{multicols}

% lets put a table and a figure
  \begin{table}
    \caption{Table title}
    \label{tab:1}
    \begin{tabular}{cc}
      x & y \\ \hline 
      3 & 3 \\
      4 & 4 \\ \hline
    \end{tabular}
  \end{table}

  \begin{figure}
    \centering\rule{150pt}{10pt}
    \caption{A figure}\label{fig:figure}
  \end{figure}

\end{document}

The result looks like

Result of MWE

We see that the first reference to Fig. 1 is in the wrong margin; the second is also in a marginal note, which is not what I desire (only the first should be in a marginal note). The first reference to the equation shows "{fig:figure}", not "Fig. 1". As of Table, it shows "{tab:1}", not "Tab." in the margin.

Any help appreciated.

  • As you've discovered, the showlabels package won't really help you here, because it's focused on the reference tag, rather than the formatted version. That is in turn because it's intended to be a package used only when drafting, and that in turn is why it makes no strenuous efforts to get labels in the correct margin (your outer problem). In this context it prefers 'lightweight' to 'pretty'. – Norman Gray Nov 6 '15 at 10:41
  • Hello Norman, The package showlabels is a great package very useful for debugging manuscripts. I was well aware that it would not do for my present purpose, but it was easier to illustrate my question with the labels produced from showlabels. I never meant to be disrespectful of your very useful package. – Denis Cousineau Nov 7 '15 at 22:11
  • Ah, sorry: I didn't intend to suggest that you were; I should perhaps have expressed myself better. I was aiming simply to endorse what you'd already concluded, that the showlabels package has quite narrowly focused goals. – Norman Gray Nov 7 '15 at 22:37
12

I am a bit confused about a few of the details in your question, so here is my understanding of the goals of your question:

(1) Show the formatted reference (i.e., Reference type and number) as a note in the appropriate margin corresponding located at the line on which it is referred.

(2) Only do this for the first time a reference is made (i.e., the second \ref{fig:figure} in your MWE should not produce a note in the margin).

(3) Said note should appear in the left margin if the reference is in the first column and in the right margin if the reference is in the second.

Firstly, I'd recommend using the cleveref package and the \cref command, which provides context-aware citation (i.e., it will automatically add the "Figure" to the reference if the passed label corresponds to the figure counter.

With that, I adapted Yiannis Lazarides answer to this question which makes use of the zref package to save the x position of a label which permits the two columns to be distinguished using the multicol package. I have also added the geometry package to test the alignment of the margin notes.

To ensure that the margin note is only used on the first reference of the labelkey, \cref is redefined to check if the command \marginnote@labelkey is defined. If so, then the label has already been made into a margin note. If not, then a margin note is made and the command is defined. This also ensures that the labelkey is unique for finding the associated position with zref (the label marginnote:labelkey is used).

Here is the result:

\usepackage[left=1.5in,right=1in]{geometry}

\usepackage{cleveref}
\crefname{equation}{Equation}{Equations}
\crefname{figure}{Figure}{Figures}
\crefname{table}{Table}{Tables}

\usepackage{zref-savepos}
%Adapted from Yiannis Lazarides' answer at https://tex.stackexchange.com/a/50295/89497
\def\putmarginpar#1#2{%
    \zsavepos{margnote:#1}%
    \ifnum20432158>\number\zposx{margnote:#1}%
        \hbox to 0pt{\hskip\dimexpr-\zposx{margnote:#1}sp \relax\makebox[\dimexpr 1in+\hoffset+\oddsidemargin-\marginparsep]{\hfill #2}}%\hskip\dimexpr-\zposx{#1}sp +0.5cm \relax#2}%
    \else
        \hbox to 0pt{\hskip\dimexpr-\zposx{margnote:#1}sp+1in+\hoffset+\oddsidemargin+\textwidth+\marginparsep\relax\makebox[\dimexpr\paperwidth-\textwidth-1in-\hoffset-\oddsidemargin-\marginparsep]{#2\hfill}}%\hskip4cm #2}%
    \fi%
    }
\makeatletter
%Redefine \cref so that it will make a margin note if the passed label is referenced for the first time.
\let\oldcref=\cref
\def\cref#1{%
    \oldcref{#1}%
    %check if the label has already been referenced.
    \ifcsname marginnote@#1\endcsname
        %already exists...therefore not the first citation
    \else
        \expandafter\gdef\csname marginnote@#1\endcsname{}%first citation
        \putmarginpar{#1}{\mbox{\color{red}\oldcref{#1}}}%add note to margin
    \fi
    }
\makeatother

Which if added to the pramble of your MWE (and changing the \ref calls to \cref and removing showlabels):

\documentclass{article}

%\usepackage[nolabel,right]{showlabels}
\usepackage{color}
%\renewcommand{\showlabelfont}{\small\slshape\color{red}}
%\showlabels{ref}

\usepackage{lipsum}
\usepackage{multicol}

\usepackage[left=1.5in,right=1in]{geometry}

\usepackage{cleveref}
\crefname{equation}{Equation}{Equations}
\crefname{figure}{Figure}{Figures}
\crefname{table}{Table}{Tables}

\usepackage{zref-savepos}
%Adapted from Yiannis Lazarides' answer at https://tex.stackexchange.com/a/50295/89497
\def\putmarginpar#1#2{%
    \zsavepos{margnote:#1}%
    \ifnum20432158>\number\zposx{margnote:#1}%
        \hbox to 0pt{\hskip\dimexpr-\zposx{margnote:#1}sp \relax\makebox[\dimexpr 1in+\hoffset+\oddsidemargin-\marginparsep]{\hfill #2}}%\hskip\dimexpr-\zposx{#1}sp +0.5cm \relax#2}%
    \else
        \hbox to 0pt{\hskip\dimexpr-\zposx{margnote:#1}sp+1in+\hoffset+\oddsidemargin+\textwidth+\marginparsep\relax\makebox[\dimexpr\paperwidth-\textwidth-1in-\hoffset-\oddsidemargin-\marginparsep]{#2\hfill}}%\hskip4cm #2}%
    \fi%
    }
\makeatletter
%Redefine \cref so that it will make a margin note if the passed label is referenced for the first time.
\let\oldcref=\cref
\def\cref#1{%
    \oldcref{#1}%
    %check if the label has already been referenced.
    \ifcsname marginnote@#1\endcsname
        %already exists...therefore not the first citation
    \else
        \expandafter\gdef\csname marginnote@#1\endcsname{}%first citation
        \putmarginpar{#1}{\mbox{\color{red}\oldcref{#1}}}%add note to margin
    \fi
    }
\makeatother

\author{John Doe}
\title{Automatic marginal notes for the first use of a label}

\begin{document}
  \maketitle
  \begin{multicols}{2}

  See \cref{fig:figure}. \lipsum[1] 

  A new reference to \cref{fig:figure} is not 
referenced in the marginal note.

  Let's do the same with an equation.
  \begin{equation}
    \label{eq:1}f(x) = x^2
  \end{equation}

  Refering to \cref{eq:1} for the first time, there should be a marginal note, as is visible here, but it shoudl begin with  ``Eq.'', not ``Fig.''.

  Refering to \cref{tab:1} for the first time. Here, there is no visible marginal note at all...

  \end{multicols}

% lets put a table and a figure
  \begin{table}
    \caption{Table title}
    \label{tab:1}
    \begin{tabular}{cc}
      x & y \\ \hline 
      3 & 3 \\
      4 & 4 \\ \hline
    \end{tabular}
  \end{table}

  \begin{figure}
    \centering\rule{150pt}{10pt}
    \caption{A figure}\label{fig:figure}
  \end{figure}

\end{document}

Yields:

example

Edit: If you want to just use \ref in your document (as you have in your MWE), \ref can be redefined, with \cref used in the note to provide context-aware formatting. This allows for the in-text context to differ from that used in the margin notes (i.e., the abbreviated version you requested). Implemented in your MWE:

\documentclass{article}

%\usepackage[nolabel,right]{showlabels}
\usepackage{color}
%\renewcommand{\showlabelfont}{\small\slshape\color{red}}
%\showlabels{ref}

\usepackage{lipsum}
\usepackage{multicol}

\usepackage[left=1.5in,right=1in]{geometry}

\usepackage{cleveref}
\crefname{equation}{Eq.}{Eqs.}
\crefname{figure}{Fig.}{Figs.}
\crefname{table}{Tab.}{Tabs.}

\usepackage{zref-savepos}
%Adapted from Yiannis Lazarides' answer at https://tex.stackexchange.com/a/50295/89497
\def\putmarginpar#1#2{%
    \zsavepos{margnote:#1}%
    \ifnum20432158>\number\zposx{margnote:#1}%
        \hbox to 0pt{\hskip\dimexpr-\zposx{margnote:#1}sp \relax\makebox[\dimexpr 1in+\hoffset+\oddsidemargin-\marginparsep]{\hfill #2}}%\hskip\dimexpr-\zposx{#1}sp +0.5cm \relax#2}%
    \else
        \hbox to 0pt{\hskip\dimexpr-\zposx{margnote:#1}sp+1in+\hoffset+\oddsidemargin+\textwidth+\marginparsep\relax\makebox[\dimexpr\paperwidth-\textwidth-1in-\hoffset-\oddsidemargin-\marginparsep]{#2\hfill}}%\hskip4cm #2}%
    \fi%
    }
\makeatletter
%Redefine \cref so that it will make a margin note if the passed label is referenced for the first time.
\let\oldref=\ref
\def\ref#1{%
    \oldref{#1}%
    %check if the label has already been referenced.
    \ifcsname marginnote@#1\endcsname
        %already exists...therefore not the first citation
    \else
        \expandafter\gdef\csname marginnote@#1\endcsname{}%first citation
        \putmarginpar{#1}{\mbox{\color{red}\cref{#1}}}%add note to margin
    \fi
    }
\makeatother

\author{John Doe}
\title{Automatic marginal notes for the first use of a label}

\begin{document}
 \maketitle

  \begin{multicols}{2}

  See Figure~\ref{fig:figure}. \lipsum[1] 

  A new reference to Figure~\ref{fig:figure} is not 
referenced in the marginal note.

  Let's do the same with an equation.
  \begin{equation}
    \label{eq:1}f(x) = x^2
  \end{equation}

  Refering to Equation~\ref{eq:1} for the first time, there should be a marginal note, as is visible here, but it shoudl begin with  ``Eq.'', not ``Fig.''.

  Refering to Table~\ref{tab:1} for the first time. Here, there is no visible marginal note at all...

  \end{multicols}

% lets put a table and a figure
  \begin{table}
    \caption{Table title}
    \label{tab:1}
    \begin{tabular}{cc}
      x & y \\ \hline 
      3 & 3 \\
      4 & 4 \\ \hline
    \end{tabular}
  \end{table}

  \begin{figure}
    \centering\rule{150pt}{10pt}
    \caption{A figure}\label{fig:figure}
  \end{figure}

\end{document}

Yields:

second version

  • This is a great answer! – Mico Nov 6 '15 at 6:00
  • Thank you very much for this answer. It is subsequently fairly easy to customize the marginal note formats, for example, \crefname{equation}{\color{red}\footnotesize\it Eq.}{Eqs.} would write "Eq. (1)" in red, italic and footnotesize. Finally, if there are labels that are not meant to be in a marginal note, a new label type can be created, e.g. "notinmargin", and its style can be set to \crefname{notinmargin} {\color{white}}{}. Just create these labels with \label[notinmargin]{label:name}. – Denis Cousineau Nov 7 '15 at 23:06
4

My approach here is to redefine \label and \ref to do what they traditionally did plus an extra thing.

\label is supplemented to write an extra line out to the aux file. The format of the write, let's say for eq:1 is

\expandafter\gdef\csname Zeq:1Z\endcsname{\margnote{eq:1}}

which will be executed on the 2nd pass. This defines a macro that, when invoked, will call on my \margnote definition. But when is it invoked?

It is invoked by the renewed \ref, which now takes an optional argument to define the alignment of the margin note l or r, in addition to the standard argument. This new \ref will call on \margnote, using the \csname Z<label>Z\endcsname mechanism defined in the aux file. It then does what a normal \ref does. And finally it redefines \csname Z<label>Z\endcsname to not call on a margin note again for that label.

The macro \margnote figures out whether you want a left or right margin note, and calls on \decoderef to determine the printed name associated with the label type, followed by the \ref value itself. Thus, one must be consistent in their label types. Here, all figure labels must be fig:xx, all tables must be tab:xx and all equations must be eq:xx. If the colon is accidentally omitted, it uses the label [Unknown]. If the colon is used but the label type name is misspelled (for example Tab:1 instead of tab:1), then no identifying label name appears.

The margin label names for figures, tables, and equations are stored in \figlabel, tablabel, and \eqlabel.

\documentclass{article}
\usepackage{xcolor,lipsum,multicol,tabto}
\let\svlabel\label
\let\svref\ref
\def\myspace{ }
\makeatletter
\def\pwr{\protected@write\@auxout}
\newcommand\Xlabel[1]{\xdef\Addaux{%
    {}{\string\expandafter\string\gdef\string\csname\myspace Z#1Z\string\endcsname%
    {\string\margnote{#1}}}}\expandafter\expandafter\expandafter\pwr\Addaux}
\renewcommand\label[1]{\svlabel{#1}\Xlabel{#1}}
\renewcommand\ref[2][r]{\csname Z#2Z\endcsname{#1}\svref{#2}%
  \expandafter\gdef\csname Z#2Z\endcsname{\@gobble}}
\makeatother
\newcommand\margnote[2]{%
  \if r#2\tabto*{\dimexpr\linewidth+10pt\relax}\else\tabto*{-10pt}\fi%
  \csname #2lap\endcsname{\color{red}\decoderef#1::\relax}\tabto*{\TabPrevPos}}
\def\decoderef#1:#2:#3{%
  \ifx:#3 \csname #1label\endcsname~\svref{#1:#2}\else[Unknown] \svref{#1}\fi}
\def\figlabel{Fig.}
\def\eqlabel{Eq.}
\def\tablabel{Tab.} 

\author{John Doe}
\title{Automatic marginal notes for the first use of a label}
\begin{document}
  \maketitle
  \begin{multicols}{2}

  See Figure~\ref[l]{fig:figure}. \lipsum[1] 

  A new reference to Figure~\ref{fig:figure} is not 
referenced in the marginal note.

  Let's do the same with an equation.
  \begin{equation}
    \label{eq:1}f(x) = x^2
  \end{equation}

  Refering to Equation~\ref{eq:1} for the first time, there should be a marginal note, as is visible here, but it shoudl begin with  ``Eq.'', not ``Fig.''.

  Refering to Table~\ref{tab:1} for the first time. Here, there is no visible marginal note at all...Note table~\ref{tab2} has an improperly formed label, 
even though table~\ref{tab:1} is just fine, but doesn't show the 2nd time.
  \end{multicols}
% lets put a table and a figure
  \begin{table}
  \centering
    \caption{Table title}
    \label{tab:1}
    \begin{tabular}{cc}
      x & y \\ \hline 
      3 & 3 \\
      4 & 4 \\ \hline
    \end{tabular}
  \end{table}
  \begin{table}
  \centering
    \caption{Table title}
    \label{tab2}
    \begin{tabular}{cc}
      x & y \\ \hline 
      3 & 3 \\
      4 & 4 \\ \hline
    \end{tabular}
  \end{table}
  \begin{figure}
    \centering\rule{150pt}{10pt}
    \caption{A figure}\label{fig:figure}
  \end{figure}
\end{document}

enter image description here

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.