Думаю, я нахожусь в конфигурации, которая многим покажется знакомой: в контексте проекта, который длился много лет, я разработал очень большую презентацию Beamer с большим количеством слайдов. Исходники LaTeX разделены на множество файлов, и поскольку мне часто приходится переделывать презентацию проекта, я включаю (или не включаю) эти файлы в основной документ в зависимости от времени/аудитории.
Теперь я хотел бы как-то автоматизировать генерацию презентации, управляя кадром, который я хочу включить. Кажется, это возможно статически с параметрами <handout:0|beamer:0>
при определении кадра:
\begin{frame}
Hello.
\end{frame}
% this frame won't be included
\begin{frame}<handout:0|beamer:0>
Hidden
\end{frame}
Я хотел бы сделать подход более общим. Поэтому я думал о возможности
- связать [набор] тегов с определением кадра
- позже (каким-либо образом) решить, какой набор тегов использовать при компиляции презентации, чтобы учитывались только кадры, имеющие этот тег (а остальные, таким образом, были скрыты).
Кто-нибудь знает, как это сделать?
решение1
Это действительно хороший вопрос!
Это начало решения, во многом вдохновленногоКомментарий Вернераи с небольшими ограничениями. Они связаны с тем, что решение находится на вершине Beamer. По этой причине я отмечаю его как сообщество wiki, и каждый может его улучшить (и есть много места).
Он обеспечивает простой пользовательский интерфейс с целью
- создание тегов для различающихся версий;
- принятие решения о том, какую версию(и) выводить.
Первая задача предоставляется ключами
create new version
create multiple versions
и имена вполне понятны. Чтобы решить, какие кадры выводить, используйте:
compile version
compile frames
для выбора подмножества кадров в пределах одной версииcompile generic frames
для выбора кадров из разных версий.
Как уже было сказано, механизм в значительной степени описан в комментарии Вернера: создание новой версии просто означает, что новый счетчик (или несколько) инстанцируется и обновляется каждый раз, когда кадр помечается таким образом. Компиляция версий транслируется за кулисами с созданием списка, который передается в \includeonlyframes
. Пока все хорошо.
Давайте теперь рассмотрим ограничения и слабые стороны подхода. Пометка кадров вышеупомянутым способом без реального погружения в Beamer требует небольшой хитрости, а именно новой среды. Для этой цели sebframe
была определена среда, которая принимает необязательный аргумент со следующим синтаксисом
<tag>-<list of beamer options>
Символ -
используется для отделения тега от других опций Beamer; кстати, это не совпадает с fragile
.
Mwe. Он прокомментирован и воспринимается как доказательство концепции: некоторые вещи можно улучшить, как указано в комментариях.
\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}
Как мы выбрали:
\SebCompileOptions{create new version=A, compile version=A}
выходной сигнал:
Выбрав
\SebCompileOptions{create new version=C, compile frames={1,3}}
Обратите внимание, что команды overleyed-aware все еще работают, а кадр C2 не отображается. Давайте попробуем
\SebCompileOptions{%
create multiple versions={A,B},
compile generic frames={A1,A3,B1,B2,C3}
}
который производит:
Как и ожидалось, поскольку версия C не определена, фрейм C3 не отображается. Порядок, в котором предоставляется список, не влияет на порядок появления в PDF: для этого учитываются только номера страниц.
решение2
Я бы создал кучу условных операторов, по одному для каждого типа презентации, которую вы хотите дать. Давайте назовем эти типы «версиями». Так что, возможно, есть VersionA
, VersionB
и VersionC
.
Для каждой версии создайте условный оператор \newif
(по умолчанию они установлены на false):
\newif\VersionA
\newif\VersionB
\newif\VersionC
Затем оберните ваши слайды, frame
связанные с определенной версией. Например, VersionA
слайд будет напоминать
\ifVersionA
\begin{frame}
...
\end{frame}
\fi
Если у вас есть слайд, который должен быть связан с (например) VersionB
ИЛИ VersionC
, то вы можете сделать
\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
Те слайды, которые видны во всех версиях, не нуждаются ни в каком условном переносе. Вот минимальный пример настройки:
\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}
Вы можете сделать что-то подобное, используяcomment
упаковка. Однако объединить условия не так просто. Обходным путем, конечно, было бы дублирование слайдов, содержащих информацию для нескольких версий.
Другим приемлемым вариантом было бы создание label
для каждого frame
использования
\begin{frame}[label=ConceptX]
...
\end{frame}
или с помощью \frame
команды. А затем добавьте ConceptX
к версиям, которые вас интересуют, включая использование
\includeonlyframes{...,ConceptX,...}% Version A
Однако для этого вам необходимо снабдить каждый из них frame
концептуальной (уникальной) меткой.