Ocultar dinamicamente o quadro do beamer LaTeX com base em tags

Ocultar dinamicamente o quadro do beamer LaTeX com base em tags

Acho que estou em uma configuração que vai tocar a campainha para muitos: no contexto de um projeto que dura há muitos anos, desenvolvi uma apresentação muito grande no Beamer com muitos slides. Os fontes do LaTeX estão divididos em vários arquivos e como muitas vezes tenho que refazer a apresentação do projeto, incluo (ou não) esses arquivos no documento principal dependendo do horário/público.

Agora gostaria de automatizar de alguma forma a geração da apresentação controlando o quadro que desejo incluir. Parece ser possível estaticamente com os <handout:0|beamer:0>parâmetros na definição do quadro:

\begin{frame}
Hello.
\end{frame}

% this frame won't be included
\begin{frame}<handout:0|beamer:0>
  Hidden
\end{frame}

Eu gostaria de tornar a abordagem mais genérica. Então eu estava pensando na possibilidade de

  • associar uma tag [conjunto de] na definição do quadro
  • decida mais tarde (de alguma forma) sobre o conjunto de tags a serem usadas ao compilar a apresentação, de modo que apenas o quadro que possui essa tag seja considerado (e os outros fiquem, portanto, ocultos).

Alguém sabe uma maneira de fazer isso?

Responder1

Esta é uma pergunta muito legal!

Este é o início de uma solução altamente inspirada emComentário de Wernere com poucas limitações. Isso se deve ao fato da solução estar em cima do Beamer. Por esta razão eu marquei-o como wiki da comunidade e todos podem melhorá-lo (e há muito espaço).

Ele fornece uma interface de usuário simples com o objetivo de

  • criação de tags para a(s) versão(s) diferenciadora(s);
  • decidir qual(is) versão(ões) será(ão) produzida(s).

A primeira tarefa é fornecida pelas chaves

  1. create new version
  2. create multiple versions

e os nomes são bastante claros. Para decidir quais quadros serão gerados, explore:

  1. compile version
  2. compile framespara selecionar um subconjunto de quadros dentro de uma versão
  3. compile generic framespara selecionar quadros de diferentes versões.

Como dito, o mecanismo é praticamente descrito no comentário de Werner: criar uma nova versão significa simplesmente que um novo contador (ou mais) é instanciado e atualizado cada vez que um quadro é marcado dessa forma. A compilação de versões é traduzida nos bastidores com a criação de uma lista que é passada para \includeonlyframes. Até agora tudo bem.

Vejamos agora os limites e pontos semanais da abordagem. Marcar frames da maneira mencionada acima, sem passar por baixo do Beamer, requer alguns truques, ou seja, um novo ambiente. Para o efeito, sebframefoi definido um ambiente que aceita um argumento opcional com a seguinte sintaxe

<tag>-<list of beamer options>

O caractere -é usado para separar a tag de outras opções do Beamer; aliás, isso falha com fragile.

O mwe. É comentado e tomado como prova de conceito: algumas coisas podem ser melhoradas conforme os comentários apontam.

\documentclass{beamer}
\usepackage{lmodern} % https://tex.stackexchange.com/a/58088/13304
\usepackage{mwe} % for dummy image

\newcommand{\enlarge}{\centering\scalebox{13}}% Just for this example

% = = = = = = = = = = = = = = = = = = = = = = = =
% core of the solution

\usepackage{pgffor,pgfkeys,xstring}

\newcommand{\deflistframes}[1]{
\gdef\listframes{}% global list
\foreach \x[count=\xi] in {#1}{\global\let\maxitems\xi}% count the max number of items
\foreach \x[count=\xi] in {#1}{
 \ifnum\xi=\maxitems
   \xdef\listframes{\listframes \vers\x}
 \else
   \xdef\listframes{\listframes \vers\x,}
 \fi
}
}

\newcommand{\defcustomlistframes}[1]{
\gdef\listframes{}% global list
\foreach \x[count=\xi] in {#1}{\global\let\maxitems\xi}% count the max number of items
\foreach \x[count=\xi] in {#1}{
 \ifnum\xi=\maxitems
   \xdef\listframes{\listframes \x}
 \else
   \xdef\listframes{\listframes \x,}
 \fi
}
}

\makeatletter
% https://tex.stackexchange.com/a/74890/13304
\newcommand{\defversion}[1]{\@namedef{vers#1}{}}
\makeatother

% test for multiple versions compilation
\newif\ifmultipleversion
\multipleversionfalse


\pgfkeys{/seb-beamer/.cd,
  create new version/.code={\gdef\vers{#1}\newcounter{#1}},
  create multiple versions/.code={%
    \gdef\listofversions{}
    \foreach \v in {#1}{%
      \defversion{\v}
      \newcounter{\v}
      \xdef\listofversions{\listofversions \v,}
    }%
    \multipleversiontrue
  },
  compile version/.code={% version-based: need to store in .aux a
    % "total frame" counter per version (incremented in custom enviroment)
    % and use it as final value (hard-coded here for simplicity)
    \deflistframes{1,...,1000}
    % list of frames in output
    \expandafter\includeonlyframes\expandafter{\listframes}%
  }, 
  compile frames/.code={% this should be version-based -> second argument (TBA)
    \deflistframes{#1}
    % for the list
    \expandafter\includeonlyframes\expandafter{\listframes}%
  }, 
  compile generic frames/.code={% generic for multi version compilations
   \defcustomlistframes{#1}
   % list of frames in output
   \expandafter\includeonlyframes\expandafter{\listframes}%
  }, 
}

\makeatletter

% see: https://tex.stackexchange.com/a/132411/13304
\newenvironment{sebframe}[1][]{
% cut the string to separate version from other options
\StrCut{#1}{-}\compvers\opt
\edef\seboptions{\opt}
\def\mylabel{}
\ifmultipleversion
  \@ifundefined{c@\compvers}{}{% test if the counter is undefined
    \stepcounter{\compvers}
    % increment here the counter total frames per version
    \edef\mylabel{label=\compvers\the\value{\compvers}}
    }
\else
 \IfStrEq{\vers}{\compvers}{% true
  \stepcounter{\compvers}
  % increment here the counter total frames per version
  \edef\mylabel{label=\compvers\the\value{\compvers}}
 }{% false
  \edef\mylabel{}
 }
\fi
\begingroup\edef\x{\endgroup\noexpand\begin{frame}[\mylabel,\seboptions]}\x}{\end{frame}}

\makeatother

\newcommand{\SebCompileOptions}[1]{%
 \pgfkeys{/seb-beamer/.cd,#1}
}

% = = = = = = = = = = = = = = = = = = = = = = = =
% user interface

%\SebCompileOptions{create new version=A, compile version=A}
%\SebCompileOptions{%
% create multiple versions={A,B}, 
% compile generic frames={A1,A3,B1,B2,C3}
%}
\SebCompileOptions{create new version=C, compile frames={1,3}}


\begin{document}

\begin{sebframe}[A-t,allowframebreaks]
  \frametitle{Version A}
  \enlarge{A1}
\end{sebframe}

\begin{sebframe}[B]
  \frametitle{Version B}
  \enlarge{B1}
\end{sebframe}

\begin{sebframe}[C]
  \frametitle{Version C}
  \enlarge{C1}
\end{sebframe}

\begin{sebframe}[A]
  \frametitle{Version A}
  \enlarge{A2}
\end{sebframe}

\begin{sebframe}[B]
  \frametitle{Version B}
  \enlarge{B2}
\end{sebframe}

\begin{sebframe}[C]
  \frametitle{Version C}
  \enlarge{C2}
\end{sebframe}

\begin{frame}
  \frametitle{Version B or C}
  \enlarge{BC}
\end{frame}

\begin{sebframe}[A-t,b,containsverbatim]% just to point out that passing multiple beamer options works (unless fragile)
  \frametitle{Version A}
  \enlarge{A3}
\end{sebframe}

\begin{sebframe}[C]
  \frametitle{Version C}
  \enlarge{C3}
  \vskip1ex
  \includegraphics<2>[scale=0.5]{example-image}
\end{sebframe}

\begin{sebframe}[A]
  \frametitle{Version A}
  \enlarge{A4}
\end{sebframe}

\begin{frame}[fragile,label=A5]% add manually a label: displayed only in A version though
  \frametitle{Version A \& B \& C}
  \enlarge{ABC}
\end{frame}


\end{document}

Como selecionamos:

\SebCompileOptions{create new version=A, compile version=A}

a saída é:

insira a descrição da imagem aqui

Selecionando

\SebCompileOptions{create new version=C, compile frames={1,3}}

insira a descrição da imagem aqui

Observe que os comandos com reconhecimento de overley ainda funcionam e o quadro C2 não é exibido. Deixa-nos tentar

\SebCompileOptions{%
 create multiple versions={A,B}, 
 compile generic frames={A1,A3,B1,B2,C3}
}

que produz:

insira a descrição da imagem aqui

Como esperado, como a versão C não está definida, o quadro C3 não é exibido. A ordem em que a lista é fornecida não afeta a ordem de aparecimento no PDF: apenas os números das páginas contam para isso.

Responder2

Eu criaria um monte de condicionais, uma para cada tipo de apresentação que você deseja fazer. Vamos chamar esses tipos de “versões”. Então, talvez exista VersionA, VersionBe VersionC.

Para cada versão, crie um uso condicional \newif(eles são definidos como falsos por padrão):

\newif\VersionA
\newif\VersionB
\newif\VersionC

Em seguida, envolva seus slides frameassociados a uma versão específica. Por exemplo, um VersionAslide seria semelhante a

\ifVersionA
\begin{frame}
  ...
\end{frame}
\fi

Se você tiver um slide que deveria estar associado a (digamos) VersionBOR VersionC, então você pode fazer

\makeatletter
\let\ifCombined\ifVersionB
\ifVersionC
  \expandafter\@firstoftwo
\else
  \expandafter\@secondoftwo
\fi
  {\let\ifCombined\iftrue}{}
\makeatother

\ifCombined% Version B or C
\begin{frame}
  ..
\end{frame}
\fi

Os slides visíveis em todas as versões não precisam de nenhum empacotamento condicional. Aqui está um exemplo mínimo da configuração:

insira a descrição da imagem aqui

\documentclass{beamer}% http://ctan.org/pkg/beamer
\let\Tiny=\tiny% http://tex.stackexchange.com/q/58087/5764
\newcommand{\enlarge}{\centering\scalebox{13}}% Just for this example

\newif\ifVersionA
\newif\ifVersionB
\newif\ifVersionC


%\VersionAtrue% Show Version A
\VersionBtrue% Show Version B
%\VersionCtrue% Show Version C

\begin{document}

\ifVersionA
\begin{frame}
  \frametitle{Version A}
  \enlarge{A1}
\end{frame}
\fi

\ifVersionB
\begin{frame}
  \frametitle{Version B}
  \enlarge{B1}
\end{frame}
\fi

\ifVersionC
\begin{frame}
  \frametitle{Version C}
  \enlarge{C1}
\end{frame}
\fi

\ifVersionA
\begin{frame}
  \frametitle{Version A}
  \enlarge{A2}
\end{frame}
\fi

\ifVersionB
\begin{frame}
  \frametitle{Version B}
  \enlarge{B2}
\end{frame}
\fi

\makeatletter
\let\ifCombined\ifVersionB
\ifVersionC
  \expandafter\@firstoftwo
\else
  \expandafter\@secondoftwo
\fi
  {\let\ifCombined\iftrue}{}
\makeatother

\ifCombined% Version B or C
\begin{frame}
  \frametitle{Version B or C}
  \enlarge{BC}
\end{frame}
\fi

\ifVersionA
\begin{frame}
  \frametitle{Version A}
  \enlarge{A3}
\end{frame}
\fi

\ifVersionC
\begin{frame}
  \frametitle{Version C}
  \enlarge{C3}
\end{frame}
\fi

\ifVersionA
\begin{frame}
  \frametitle{Version A}
  \enlarge{A4}
\end{frame}
\fi

\begin{frame}
  \frametitle{Version A \& B \& C}
  \enlarge{ABC}
\end{frame}

\end{document}

Você pode fazer algo semelhante usando ocommentpacote. No entanto, combinar condições não é tão fácil. Uma solução alternativa, é claro, seria duplicar slides contendo informações para múltiplas versões.

Outra opção viável seria criar um labelfor each frameusando

\begin{frame}[label=ConceptX]
  ...
\end{frame}

ou usando o \framecomando. E, em seguida, adicione ConceptXàs versões que você está interessado em incluir usando

\includeonlyframes{...,ConceptX,...}% Version A

No entanto , isso exige que você forneça a cada um frameum rótulo conceitual (exclusivo).

informação relacionada