다른 카운터를 사용하여 캡션을 상호 참조하는 방법은 무엇입니까?

다른 카운터를 사용하여 캡션을 상호 참조하는 방법은 무엇입니까?

나는 부동 그림 환경 역할을 하는 그룹에 소스 코드 및/또는 그림 조각을 포함하는 유연한 방식을 정의하고 싶습니다.

아이디어는 type명령의 매개변수를 사용하여 카운터를 선택할 수 있다는 것입니다 \insertCaption. 'Listing'인 경우 카운터 하나를 사용하고, 'Figure'인 경우 다른 카운터를 사용합니다.

내가 직면한 문제는 카운터를 올바르게 선택할 수 없다는 것입니다. 캡션에는 잘 표시되지만 그룹을 참조할 때마다 올바른 번호가 표시되지 않습니다. 다음 작동하지 않는 예를 고려하십시오.

\documentclass{book}
\usepackage{geometry}
\geometry{margin=0.2in,papersize={8.5in,11in}}
\usepackage{graphicx}
\usepackage{pgfkeys}
\usepackage{subcaption}
\usepackage{ifthen}
\usepackage{listings}
\usepackage{xcolor}
\definecolor{lightgray}{gray}{0.9}

\makeatletter

\pgfkeys{/fig/entities/.cd,
    file/.initial={},
    width/.initial={},
    caption/.initial={},
    label/.initial={},
}
\def\fig@set@keys#1{\pgfkeys{/fig/entities/.cd,#1}}
\def\fig@get#1{\pgfkeysvalueof{/fig/entities/#1}}
\def\fig@set@defaults{\pgfkeys{/fig/entities/.cd,
    file/.initial={DUMMY},
    width/.initial={0.6},
    caption/.initial={},
    label/.initial={},
}}
\newcommand\insertFigure[1]{%%
    \fig@set@defaults%%
    \fig@set@keys{#1}%%
    \bgroup\begin{subfigure}[b]{\fig@get{width}\textwidth}%%
        \centering%%
        \includegraphics[width=1\textwidth]{\fig@get{file}}%%
        \ifthenelse{\NOT\equal{\fig@get{caption}}{}}{%%
            \ifthenelse{\equal{\fig@get{caption}}{abc}}{%%
                \caption{}%%
            }{%%
                \caption{\fig@get{caption}}%%
            }%%
            \ifthenelse{\NOT\equal{\fig@get{label}}{}}{%%
                \label{\fig@get{label}}%%
            }{}%%
        }{}%%
    \end{subfigure}\egroup%%
}


\pgfkeys{/code/entities/.cd,
    file/.initial={},
    width/.initial={},
    caption/.initial={},
    label/.initial={},
}
\def\code@set@keys#1{\pgfkeys{/code/entities/.cd,#1}}
\def\code@get#1{\pgfkeysvalueof{/code/entities/#1}}
\def\code@set@defaults{\pgfkeys{/code/entities/.cd,
    file/.initial={DUMMY},
    width/.initial={0.6},
    caption/.initial={},
    label/.initial={},
}}
\newcommand\insertCode[1]{%%
    \code@set@defaults%%
    \code@set@keys{#1}%%
    \bgroup\begin{subfigure}[b]{\code@get{width}\textwidth}%%
        \centering%%
        \fcolorbox{lightgray}{lightgray}{%%
            \begin{minipage}[t]{0.98\textwidth}
                \hspace{0pt}\vspace{-1pt}%% hack to align \fbox with \lstinputlisting.
                \lstinputlisting[basicstyle=\ttfamily\scriptsize]%%
                                {\code@get{file}}%%
            \end{minipage}%%
        }%%
        \ifthenelse{\NOT\equal{\code@get{caption}}{}}{%%
            \ifthenelse{\equal{\code@get{caption}}{abc}}{%%
                \caption{}%%
            }{%%
                \caption{\code@get{caption}}%%
            }%%
            \ifthenelse{\NOT\equal{\code@get{label}}{}}{%%
                \label{\code@get{label}}%%
            }{}%%
        }{}%%
    \end{subfigure}\egroup%%
}


\pgfkeys{/capt/entities/.cd,
    type/.initial={},
    caption/.initial={},
    label/.initial={},
}
\def\capt@set@keys#1{\pgfkeys{/capt/entities/.cd,#1}}
\def\capt@get#1{\pgfkeysvalueof{/capt/entities/#1}}
\def\capt@set@defaults{\pgfkeys{/capt/entities/.cd,
    type/.initial={Figure},
    caption/.initial={},
    label/.initial={},
}}
% counter for captions of type 'Figure' and 'Listing'
\newcounter{figurecounter}[chapter]
\newcounter{codecounter}[chapter]
\DeclareCaptionLabelFormat{figurefmt}{Figure~\thechapter.\thefigurecounter}
\DeclareCaptionLabelFormat{codefmt}{Listing~\thechapter.\thecodecounter}

\newcommand\insertCaption[1]{%%
    \capt@set@defaults%%
    \capt@set@keys{#1}%%
    \ifthenelse{\NOT\equal{\capt@get{caption}}{}}{%%
        \ifthenelse{\equal{\capt@get{type}}{Listing}}{%%
            \captionsetup{name=Listing}%%
            \refstepcounter{codecounter}%%
            \captionsetup{labelformat=codefmt}%%
        }{%%
            \captionsetup{name=Figure}%%
            \refstepcounter{figurecounter}%%
            \captionsetup{labelformat=figurefmt}%%
        }%%
        \ifthenelse{\equal{\capt@get{caption}}{abc}}{%%
            \caption{}%%
        }{%%
            \caption{\capt@get{caption}}%%
        }%%
        \ifthenelse{\NOT\equal{\capt@get{label}}{}}{%%
            \label{\capt@get{label}}%%
        }{}%%
    }{}%%
}

\newcommand\FloatingElements[1]{%%
    \begin{figure}[h!]\centering#1\end{figure}%%
}

\begin{document}
\chapter{Chapter One}
\FloatingElements{
  \insertFigure{
    file={figA},
    width=0.2,
    caption={abc},
  }\hfil%%
  \insertCode{
    file={textA.txt},
    width=0.3,
    caption={abc},
    label={the-first-text}
  }%%
  \insertCaption{
    type=Figure,
    caption={This is a figure with some text, use the Figure counter.},
    label={group1},
  }%%
}

\FloatingElements{
  \insertCode{
    file={textB.txt},
    width=0.8,
  }%%
  \insertCaption{
    type=Listing,
    caption={This is just text B, so use the Listing counter.},
    label={group2},
  }%%
}

\FloatingElements{
  \insertFigure{
    file={figB},
    width=0.2,
  }%%
  \insertCaption{
    type=Figure,
    caption={This is just a figure, so use the Figure counter.},
    label={group3},
  }%%
}

\FloatingElements{
  \insertCode{
    file={textC.txt},
    width=0.2,
    caption={abc},
    label={text-c}
  }\hfil%%
  \insertCode{
    file={textD.txt},
    width=0.2,
    caption={abc},
  }%%
  \insertCaption{
    type=Listing,
    caption={These are texts C and D, so use the Listing counter.},
    label={group4},
  }%%
}

\textbf{Cross references:}\\
Figure~\ref{group1} has the figureA and textA. Listing~\ref{the-first-text} is within the same Figure~\ref{group1}.\\
Listing~\ref{group2} only has the textB.\\
Figure~\ref{group3} only has the figureB.\\
Listing~\ref{group4} has the texts C and D. And sub-listing~\ref{text-c} is textC.

\end{document}

텍스트와 이미지 파일이 있다고 가정하면 다음 PDF를 얻습니다.

위 코드에서 얻은 PDF

보시다시피 캡션과 상호 참조의 숫자가 일치하지 않습니다.

답변1

이것을 학습 연습으로 사용하는지 실제 사용으로 사용하는지 명확하지 않기 때문에 솔루션을 제공하는 것이 아니므로 어떤 답변을 주어야 할지 모르겠습니다.

'왜?'에 대한 답변입니다. '어떻게?'보다는

환경 \caption내에서 사용할 때마다 카운터가 증가합니다. 정보는figurefigure.aux 정보는 상호 참조 등에 사용하기 위해 파일

캡션 라벨 형식의 모양을 변경했지만 사용되는 카운터를 건드리지 않았습니다. 귀하의 형식은 사용된 카운터를 사용하지 않습니다. 즉, 사용하지 않습니다 figure. 따라서 환경 자체에 사용된 값이 표시되지 않습니다 figure. 사용자 정의 카운터만 표시됩니다. 그러나 이는 상호 참조에 사용되지 않습니다. 따라서 나중에 참조할 때 에 기록된 정보를 얻게 됩니다 .aux.figure . 그리고 지정한 형식은 여기에서 활성화되지 않으므로 이번에는 카운터 값이 사용됩니다.

무슨 일이 일어나고 있는지 이해하려면 다음을 참조하세요 .aux.

\relax
\@writefile{toc}{\contentsline {chapter}{\numberline {1}Chapter One}{1}{}\protected@file@percent }
\@writefile{lof}{\addvspace {10\p@ }}
\@writefile{lot}{\addvspace {10\p@ }}
\@writefile{lol}{\contentsline {lstlisting}{indentfirst.sty}{1}{}\protected@file@percent }
\providecommand*\caption@xref[2]{\@setref\relax\@undefined{#1}}
\newlabel{the-first-text}{{1.1b}{1}{}{}{}}
\newlabel{sub@the-first-text}{{b}{1}{}{}{}}

이는 우리가 기대하는 것을 사용하고 있다는 점에 유의하세요.

\@writefile{lof}{\contentsline {figure}{\numberline {1.1}{\ignorespaces This is a figure with some text, use the Figure counter.}}{1}{}\protected@file@percent }
\newlabel{group1}{{1.1}{1}{}{}{}}

첫 번째 그림은 다음과 같습니다.

\@writefile{lol}{\contentsline {lstlisting}{indentfirst.sty}{2}{}\protected@file@percent }
\@writefile{lof}{\contentsline {figure}{\numberline {1.2}{\ignorespaces This is just text B, so use the Listing counter.}}{2}{}\protected@file@percent }
\newlabel{group2}{{1.2}{2}{}{}{}}

여기서는 두 번째 플로트에 대해 작성된 정보를 볼 수 있습니다. 캡션 형식의 어느 곳에서도 사용되지 않더라도 에 기록된 값은 카운터를 .aux사용하고 있습니다 .figure

\@writefile{lof}{\contentsline {figure}{\numberline {1.3}{\ignorespaces This is just a figure, so use the Figure counter.}}{2}{}\protected@file@percent }
\newlabel{group3}{{1.3}{2}{}{}{}}
\@writefile{lol}{\contentsline {lstlisting}{indentfirst.sty}{3}{}\protected@file@percent }

이제 우리는 3세 번째 플로트를 얻습니다. 다시 말하지만, figure캡션을 조판하는 데 값은 사용되지 않습니다.

\newlabel{text-c}{{1.4a}{3}{}{}{}}
\newlabel{sub@text-c}{{a}{3}{}{}{}}

다시 말하지만, 환경 내부에서 발생하기 때문에 figure이것이 의도된 것은 아니지만 카운터가 증가합니다 .figurefigure

\@writefile{lol}{\contentsline {lstlisting}{indentfirst.sty}{3}{}\protected@file@percent }
\@writefile{lof}{\contentsline {figure}{\numberline {1.4}{\ignorespaces These are texts C and D, so use the Listing counter.}}{3}{}\protected@file@percent }
\newlabel{group4}{{1.4}{3}{}{}{}}
\gdef \@abspage@last{3}

컴파일된 문서에서 무슨 일이 일어나고 있는지 확인하고 싶다면 도움이 될 수 있는 몇 가지 코드가 있습니다. Okular 버그로 인해 내 이미지가 손상되었으므로 이를 컴파일해야 합니다. 주의하세요: 실제 출력은 매우 보기 흉합니다.

% WHY? NOT HOW?
\documentclass{book}
\usepackage{geometry}
\geometry{margin=0.2in,papersize={8.5in,11in}}
\usepackage[draft]{graphicx}
\usepackage{pgfkeys}
\usepackage{subcaption}
\usepackage{ifthen}
\usepackage{listings}
\usepackage{xcolor}
\definecolor{lightgray}{gray}{0.9}

\makeatletter

\pgfkeys{/fig/entities/.cd,
    file/.initial={},
    width/.initial={},
    caption/.initial={},
    label/.initial={},
}
\def\fig@set@keys#1{\pgfkeys{/fig/entities/.cd,#1}}
\def\fig@get#1{\pgfkeysvalueof{/fig/entities/#1}}
\def\fig@set@defaults{\pgfkeys{/fig/entities/.cd,
    file/.initial={DUMMY},
    width/.initial={0.6},
    caption/.initial={},
    label/.initial={},
}}
\newcommand\insertFigure[1]{%%
  \fig@set@defaults%%
  \fig@set@keys{#1}%%
  \bgroup\begin{subfigure}[b]{\fig@get{width}\textwidth}%%
    \centering%%
    \includegraphics[width=1\textwidth]{\fig@get{file}}%%
    \ifthenelse{\NOT\equal{\fig@get{caption}}{}}{%%
      \ifthenelse{\equal{\fig@get{caption}}{abc}}{%%
        \caption{}%%
      }{%%
        \caption{\fig@get{caption}}%%
      }%%
      \ifthenelse{\NOT\equal{\fig@get{label}}{}}{%%
        \label{\fig@get{label}}%%
      }{}%%
    }{}%%
  \end{subfigure}\egroup%%
}


\pgfkeys{/code/entities/.cd,
    file/.initial={},
    width/.initial={},
    caption/.initial={},
    label/.initial={},
}
\def\code@set@keys#1{\pgfkeys{/code/entities/.cd,#1}}
\def\code@get#1{\pgfkeysvalueof{/code/entities/#1}}
\def\code@set@defaults{\pgfkeys{/code/entities/.cd,
    file/.initial={DUMMY},
    width/.initial={0.6},
    caption/.initial={},
    label/.initial={},
}}
\newcommand\insertCode[1]{%%
  \code@set@defaults%%
  \code@set@keys{#1}%%
  \bgroup\begin{subfigure}[b]{\code@get{width}\textwidth}%%
    \centering%%
    \fcolorbox{lightgray}{lightgray}{%%
      \begin{minipage}[t]{0.98\textwidth}
        \hspace{0pt}\vspace{-1pt}%% hack to align \fbox with \lstinputlisting.
        \lstinputlisting[basicstyle=\ttfamily\scriptsize]%%
        {\code@get{file}}%%
      \end{minipage}%%
    }%%
    \ifthenelse{\NOT\equal{\code@get{caption}}{}}{%%
      \ifthenelse{\equal{\code@get{caption}}{abc}}{%%
        \caption{}%%
      }{%%
        \caption{\code@get{caption}}%%
      }%%
      \ifthenelse{\NOT\equal{\code@get{label}}{}}{%%
        \label{\code@get{label}}%%
      }{}%%
    }{}%%
  \end{subfigure}\egroup%%
}


\pgfkeys{/capt/entities/.cd,
  type/.initial={},
  caption/.initial={},
  label/.initial={},
}
\def\capt@set@keys#1{\pgfkeys{/capt/entities/.cd,#1}}
\def\capt@get#1{\pgfkeysvalueof{/capt/entities/#1}}
\def\capt@set@defaults{\pgfkeys{/capt/ent    type/.initial={Figure},
    caption/.initial={},
    label/.initial={},ities/.cd,
    type/.initial={Figure},
    caption/.initial={},
    label/.initial={},
}}
% counter for captions of type 'Figure' and 'Listing'
\newcounter{figurecounter}[chapter]
\newcounter{codecounter}[chapter]
\DeclareCaptionLabelFormat{figurefmt}{Figure~\thechapter.\thefigurecounter}
\DeclareCaptionLabelFormat{codefmt}{Listing~\thechapter.\thecodecounter}

\newcommand\insertCaption[1]{%%
  \capt@set@defaults%%
  \capt@set@keys{#1}%%
  \ifthenelse{\NOT\equal{\capt@get{caption}}{}}{%%
    \ifthenelse{\equal{\capt@get{type}}{Listing}}{%%
      \captionsetup{name=Listing}%%
      \refstepcounter{codecounter}%%
      \captionsetup{labelformat=codefmt}%%
    }{%%
      \captionsetup{name=Figure}%%
      \refstepcounter{figurecounter}%%
      \captionsetup{labelformat=figurefmt}%%
    }%%
    \ifthenelse{\equal{\capt@get{caption}}{abc}}{%%
      \caption{}%%
    }{%%
      \caption{\capt@get{caption}}%%
    }%%
    \ifthenelse{\NOT\equal{\capt@get{label}}{}}{%%
      \label{\capt@get{label}}%%
    }{}%%
  }{}%%
}

\NewDocumentCommand \displaycounter { O {figure} }
{%
  \texttt{\textbackslash the#1} is \csname the#1\endcsname
}
\newcommand\FloatingElements[1]{%%
  \displaycounter
  \begin{figure}[ht!]
    \displaycounter
    
    \centering#1
    
    \displaycounter
  \end{figure}\par
  \displaycounter
}

\begin{document}
\chapter{Chapter One}
\FloatingElements{
  \insertFigure{
    file={example-image-a},
    width=0.2,
    caption={abc},
  }\hfil
  \insertCode{
    file={indentfirst.sty},
    width=0.3,
    caption={abc},
    label={the-first-text}
  }
  
  \displaycounter
%   \displaycounter[lstlisting]
  \insertCaption{
    type=Figure,
    caption={This is a figure with some text, use the Figure counter.},
    label={group1},
  }
  
  \displaycounter
%   \displaycounter[lstlisting]
}

\FloatingElements{
  \insertCode{
    file={indentfirst.sty},
    width=0.8,
  }%%
  \insertCaption{
    type=Listing,
    caption={This is just text B, so use the Listing counter.},
    label={group2},
  }%%
}

\FloatingElements{
  \insertFigure{
    file={example-image-b},
    width=0.2,
  }%%
  \insertCaption{
    type=Figure,
    caption={This is just a figure, so use the Figure counter.},
    label={group3},
  }%%
}

\FloatingElements{
  \insertCode{
    file={indentfirst.sty},
    width=0.2,
    caption={abc},
    label={text-c}
  }\hfil%%
  \insertCode{
    file={indentfirst.sty},
    width=0.2,
    caption={abc},
  }%%
  \insertCaption{
    type=Listing,
    caption={These are texts C and D, so use the Listing counter.},
    label={group4},
  }%%
}\displaycounter

\textbf{Cross references:}

Figure~\ref{group1} has the figureA and textA. Listing~\ref{the-first-text} is within the same Figure~\ref{group1}.

Listing~\ref{group2} only has the textB.

Figure~\ref{group3} only has the figureB.

Listing~\ref{group4} has the texts C and D. And sub-listing~\ref{text-c} is textC.

\end{document}

관련 정보