8

I would like a shorthand command to include a figure.

  • Description and filename are mandatory
  • Short caption is optional
  • Optional arguments can be passed to \includegraphics

Here's the snippet I am trying to write:

    \newcommand\figH[4][]{
    \begin{figure}[H]
        \begin{center}
            \caption[#4]{\label{#2}#3}
            \includegraphics[#1]{#2}
        \end{center}
    \end{figure}%
    }
    
    \figH[width=\linewidth]{filename}{description}{short-description}
    \figH{filename}{description}{short-description}
    \figH{filename}{description}

I am still confused with the optional arguments in commands.

2
  • 1
    Once upon a time, I had a similar idea and created my own command to insert figures and caption inside the figure environment and I have unfortunately used subfigure package. A few months ago I discovered the subcaption package. It is just better. Now i just use caption and subcaption for new documents. I update my old newcommands syntax and I'm still replacing my usage of subfigure package in "on working" projects.
    – FHZ
    May 15, 2022 at 21:04
  • 1
    You should not wrap the contents of floats inside \begin{center}...\end{center} as that gives inconsistent spacing, that's why egreg's and my answers use \centering instead.
    – Skillmon
    May 16, 2022 at 6:25

3 Answers 3

6

Instead of defining many arguments you could also define a key=value interface that sets the label, short-caption, or place for the float's placement. With expkv-cs you can use the ... handler to get all the unknown key=value pairs (and the keys without values) in a single argument to forward them to \includegraphics (resulting in a single optional key=value argument and two mandatory arguments).

\documentclass{article}

\usepackage{graphicx}
\usepackage{float}
\usepackage{expkv-cs}

\makeatletter
\newcommand\fig[2][]{\fig@kv{short={#2},#1}{#2}}
\ekvcSplitAndForward\fig@kv\fig@out
  {
    % defaults here
     short = {}% will get set for each call to match the caption argument
    ,internal-label = {} % empty, not for direct use (easier that way)
    ,place = tbp
    ,...
  }
\ekvcSecondaryKeys\fig@kv
  {
     nmeta H = place=H % shortcut
    ,meta label = internal-label=\label{#1} % wraps \label around the value
    % add more keys you want to be handled special here
  }
\newcommand\fig@out[6]
  {%
    \begin{figure}[#3]
      \centering
      \caption[{#1}]{#5#2}%
      \includegraphics[{#4}]{#6}%
    \end{figure}%
  }
\makeatother

\usepackage{duckuments}

\begin{document}
\listoffigures
\blindduck
\fig[H]{A lovely duck}{example-image-duck}

\fig[width=3cm, short=Ducky]{A frightening duck!}{example-image-duck-portrait}
\end{document}

enter image description here

5
  • Nice answer. I get an error though. the optional "place" to generates an error "! LaTeX Error: Unknown float option H'." i changed it to "t" and ! LaTeX Error: Unknown float option t'.
    – JeT
    May 16, 2022 at 7:30
  • 1
    @JeT it's hard to read your comment right because of the markup :P For H to work you need to load the float package, place=t works just like place=htbp or any other valid placement specification in standard LaTeX. If it doesn't for you, please show the code you tried (you might reach out to me in chat or per mail if this gets too long for a comment).
    – Skillmon
    May 16, 2022 at 8:05
  • 1
    My bad ! i tried commenting on my phone :/ I use H option (too often btw) and float is loaded. But for a reason I ignore, by copying/pasting your exact code, I get an error, LaTeX Error: Unknown float option H. The pb does not come form float since I also get an error if i change H to htbp. I tried both at home and at the office.
    – JeT
    May 16, 2022 at 15:14
  • 1
    @JeT ok, found the issue. One shouldn't change code in examples without checking. The issue is that float scans for the H placement using \@ifnextchar after it removed the [, which fails if the optional argument is wrapped in a nested {} (which is more stable most of the time, but absolutely unnecessary here). That shouldn't have messed with the standard placement, my guess here is that you didn't use place=htbp but just htbp in the option list. Please note that the code in my answer only sets up a shortcut for H, all other placements have to be given to the place key.
    – Skillmon
    May 16, 2022 at 15:32
  • 1
    (the error would've been a keyval error for an unknown key htbp by the graphicx package, not an unknown float option)
    – Skillmon
    May 16, 2022 at 15:34
7

Don't. You lose in flexibility while not gaining much in input speed, because you always have to remember the order of the arguments.

Also, the option [H] should be avoided, because it leads to several pagination problems, which the standard optional arguments to figure try to overcome. Also center is not the best and the \centering declaration is best.

Let's see how you might do. You need

  1. an optional argument for the float placement
  2. an optional argument for the “short” caption
  3. a mandatory argument for the caption
  4. a mandatory argument for the label
  5. an optional argument for the figure parameters
  6. a mandatory argument for the image file.

Placing two consecutive optional arguments that deal with different aspects is bad; so we could insert the label in the second position. Thus we need

\NewDocumentCommand{\addfigure}{
  O{htp} % the suggested default
  m      % the label
  O{#4}  % the short caption (defaults to the long one)
  m      % the caption
  O{}    % the options to \includegraphics
  m      % the file name
}{%
  \begin{figure}[#1]
  \centering
  \caption[#3]{\label{#2}#4}
  \includegraphics[#5]{#6}
  \end{figure}
}

Let's see possible calls:

\addfigure{fig:A}[short desc]{long caption}[width=\columnwidth]{filename}

\addfigure{fig:B}[short desc]{long caption}{filename}

\addfigure[!htbp]{fig:C}{long caption}[width=6cm]{filename}

Compare the last with

\begin{figure}[!htpb]
\centering

\caption{long caption\label{fig:C}}

\includegraphics[width=6cm]{filename}

\end{figure}

and decide which is clearer.

5

The \figH defined has below, using \NewDocumentCommand, has five arguments, as noted in the comment. Here, \NewDocumentCommand is better than \newcommand in that you can easily have multiple optional arguments.

This can be served as a starting point for you, feel free to edit and expand it for your need.

\documentclass{article}

\usepackage{graphicx,float}
\usepackage{geometry}

\NewDocumentCommand \figH { O{} m O{} m o }
% #1 = options for \includegraphics (optional, initial to be empty)
% #2 = figure name
% #3 = short caption (optional, initial to be empty)
% #4 = caption
% #5 = label (optional, initial to be NoValue)
  {%
    \begin{figure}[H]%
      \begin{center}%
        \caption[#3]{\IfValueT{#5}{\label{#5}}#4}%
        \includegraphics[#1]{#2}%
      \end{center}%
    \end{figure}%
  }

\begin{document}

\figH[width=\linewidth]{example-image-a}{description}[fig:A]
\figH{example-image-b}[short-description]{description}[fig:B]
\figH{example-image-c}{description}

\end{document}

You must log in to answer this question.

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