![Как сделать перекрестные ссылки на подписи с разными счетчиками?](https://rvso.com/image/476252/%D0%9A%D0%B0%D0%BA%20%D1%81%D0%B4%D0%B5%D0%BB%D0%B0%D1%82%D1%8C%20%D0%BF%D0%B5%D1%80%D0%B5%D0%BA%D1%80%D0%B5%D1%81%D1%82%D0%BD%D1%8B%D0%B5%20%D1%81%D1%81%D1%8B%D0%BB%D0%BA%D0%B8%20%D0%BD%D0%B0%20%D0%BF%D0%BE%D0%B4%D0%BF%D0%B8%D1%81%D0%B8%20%D1%81%20%D1%80%D0%B0%D0%B7%D0%BD%D1%8B%D0%BC%D0%B8%20%D1%81%D1%87%D0%B5%D1%82%D1%87%D0%B8%D0%BA%D0%B0%D0%BC%D0%B8%3F.png)
Я хочу определить гибкий способ включения фрагментов исходного кода и/или рисунков в группу, которая будет действовать как плавающая среда рисунков.
Идея состоит в том, чтобы иметь возможность выбрать счетчик с параметром 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-файл:
Как видно, цифры в подписи и перекрестных ссылках не совпадают.
решение1
Я не предлагаю решения, поскольку вы не уточнили, используете ли вы это в качестве учебного упражнения или для реального применения, поэтому я не знаю, какой ответ дать.
Это ответ на вопрос «почему?», а не на вопрос «как?».
Каждый раз, когда вы используете \caption
внутри figure
среды, figure
счетчик увеличивается. Информация записывается в .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}{}{}{}}
Здесь мы видим информацию, записанную для второго float. Обратите внимание, что значение, записанное в , .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
для третьего float. Опять же, значение figure
не используется при наборе подписей.
\newlabel{text-c}{{1.4a}{3}{}{}{}}
\newlabel{sub@text-c}{{a}{3}{}{}{}}
Опять же, мы figure
увеличиваем счетчик, хотя это и не должно быть так, figure
поскольку это происходит внутри figure
среды.
\@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}