Quiero definir una manera flexible de incluir piezas de código fuente y/o figuras en un grupo que actúa como un entorno de figuras flotantes.
La idea es poder seleccionar el contador con el parámetro type
del comando \insertCaption
. Si es 'Listado' use un contador, si es 'Figura', use el otro.
El problema al que me enfrento es que no puedo seleccionar correctamente el contador. Se muestra bien en el título, pero cada vez que hago referencia al grupo, no muestra la numeración correcta. Considere el siguiente ejemplo que no funciona:
\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}
Suponiendo que los archivos de texto e imagen estén ahí, obtengo el siguiente pdf:
Como se puede observar, los números del título y las referencias cruzadas no coinciden.
Respuesta1
No estoy ofreciendo una solución porque no has aclarado si estás usando esto como un ejercicio de aprendizaje o para un uso real, así que no sé qué tipo de respuesta dar.
Esta es una respuesta al '¿por qué?' en lugar del '¿cómo?'
Cada vez que se utiliza \caption
dentro de un figure
entorno, el figure
contador se incrementa. La información se escribe en el .aux
archivo para su uso en referencias cruzadas, etc.
Ha modificado la apariencia del formato de la etiqueta de título, pero no ha tocado el contador que se utiliza. Su formato no utiliza el contador utilizado. Es decir, no utiliza figure
. Por lo tanto, no se ve el valor utilizado en el figure
entorno mismo. Solo verás tus contadores personalizados. Pero esos no se utilizan para la referencia cruzada. Entonces, cuando hagas referencia a él más adelante, obtendrás la información escrita en .aux
, que usa figure
. Y el formato que ha especificado no está activo aquí, por lo que esta vez se usa el valor del contador.
Para comprender lo que está sucediendo, mire .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}{}{}{}}
Tenga en cuenta que estos utilizan lo que esperaríamos.
\@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}{}{}{}}
Aquí está nuestra primera figura.
\@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}{}{}{}}
Aquí vemos la información escrita para la segunda carroza. Tenga en cuenta que el valor escrito en el .aux
está utilizando el figure
contador, aunque este no se utiliza en ninguna parte del formato del título.
\@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 }
Así que ahora vamos 3
por la tercera carroza. Nuevamente, el valor de figure
no se utiliza al componer los subtítulos.
\newlabel{text-c}{{1.4a}{3}{}{}{}}
\newlabel{sub@text-c}{{a}{3}{}{}{}}
Nuevamente, incrementamos el figure
contador, aunque esto no pretende ser así figure
porque está sucediendo dentro del figure
entorno.
\@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}
Si prefiere ver lo que sucede en un documento compilado, aquí tiene un código que puede ayudar. Tendrás que compilarlo ya que mis imágenes están tostadas debido a un error de Okular. Tenga cuidado: el resultado real es extremadamente feo.
% 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}