这是巧妙的 Beamer 动画?编写脚本来更改 Beamer 中的 tikz 图片?
正如那里所建议的,我将为此提供赏金。
我寻求的是一组宏,也许是用于 beamer/tikz 动画的脚本语言包。
我在这里谨慎行事,因为我不确定一些具体的要求和建议是否可以按原样实现。同时,我不想妨碍任何试图在这里做出回应的人的智慧。我也知道我可能要求了错误的功能集:不是真正需要的东西,缺少真正有用的功能。
当然,我并不期待任何“完整”的解决方案;即使这个“计划”的一小部分能够得以实施,我也会无限感激。
因此,请将以下内容视为初步草案,并可随意更改。
所需的功能集围绕三个要素:角色、动作(或“说”)和脚本。每个图形元素可以承担多个角色,并且可以将每个角色与默认“动作”相关联。
引导我想到这个问题的具体可视化问题与流程图执行的模拟有关。
首先,我定义了“角色”的概念,它可以代替 tikz 定义。因此,如果“角色”是 EBNF 中的非终端符号,我希望能够写“
具体语法为:
role -> 'r' opCode nameSayList
opCode -> '=' //Resets the roles list
'+=' // Add to the roles list
'-=' // Remove items from the role list (not sure it is needed)
nameSayList -> singleSay
'{' singleSay, ... '}'
singleSay -> roleName
roleName '/' keyList
roleName -> Any unique identifier, with whichever syntax
keyList -> singleKey
'{' manyKeys '}'
singleKey -> any pgf key
manyKeys -> any list of pgf keys with their assignments
上述规范的语义:对于每个图形元素(甚至可能是范围),包都会计算一组对。每对的第一个元素是“角色名称”,第二个元素(可选)是 pgf 键分配列表。
现在,可以使用以下内容指定脚本:
script -> \script{ Stages } picture
picture -> \begin{tikzpicture} ... \end{tikzpicture}
stages -> stage, ...
stage -> singleActivation
'{' singleAction, ... '}'
singleActivation -> role
role/says
says -> singleSay
'{' singleSay, .... '}'
singleSay -> key [= value]
该模型不包括图形元素的“淡出”和“引入”,通过该模型,具有角色的元素在其指定阶段之前(或之后)的阶段中通过特定的键设置来激活。
为了演示,请想象一个流程图。
每个节点都属于一个类:决策、IO、流程等。您可以在图表上运行一个脚本,当演讲者谈论不同类型的组件时,该脚本将突出显示某个类的所有节点。
或者,您可以运行模拟,其中边缘和节点在流程图计算过程中突出显示。包含多个角色的阶段可用于突出显示当前输入、当前输出等。
(如果您和我一样不喜欢流程图,请随意使用“图灵机”或“有限状态自动机”。)
'
答案1
似乎这个问题已经存在了一段时间了,所以我正在尝试寻找解决方案,即使唯一的结果是问题本身可能会变得更加清晰。TL;DR:我正在利用样式来/.append style
控制绘图的各个部分。
我不太明白角色中的键的用途(r=role/key
?),所以角色只是让人联想到 CSS 类的标签。它们通过role:
附加到元素的键来实现(可以是节点、边、范围等)。然后我的绘图是一个由规则的附加样式参数化的命令。
我使用 LuaTeX 是因为 TeX 宏扩展让我很郁闷。一个 Lua 函数将角色初始化为空样式,另一个函数生成适当的/.append style
属性。注意:适用于 LuaTeX 0.80,最新版(0.95)已更改newtoken
为token
。
我认为只要我们能够渲染单个帧,投影仪集成就是正交的。所以我举了一个渲染standalone
文档的例子。
\documentclass[border=1mm]{standalone}
\usepackage[dvipsnames]{xcolor}
\usepackage{tikz}
\usetikzlibrary{arrows,positioning}
\directlua{
% Initializes all roles with empty styles
init_roles = function(name, roles)
render_cmd = name
for h in comma_sep(roles) do
tex.sprint("\noexpand\\tikzset{role:" .. h .. "/.style=}")
end
end
% Create an invocation of the form
% \render_cmd{role:role1/.append style=style1, ...}
say = function(actions)
local attrs = {}
for say in comma_sep(actions) do
local role, style = string.match(say, "(.+)/(.+)")
table.insert(attrs, "role:" .. role .. "/.append style=" .. style)
end
tex.sprint("\noexpand\\" .. render_cmd .. "{" .. table.concat(attrs, ",") .. "}")
end
comma_sep = function(s)
return string.gmatch(s, "[^, ][^,]*[^, ]")
end
nxt = newtoken.scan_string
}
\def\initroles{\directlua{init_roles(nxt(), nxt())}}
\def\say{\directlua{say(nxt())}}
\begin{document}
\tikzset{>=latex,
state/.style={draw,circle},
tr/.style=->,
accept/.style=double,
hide/.style={opacity=0},
show/.style={opacity=1}}%
% Roles (could avoid by parsing and extracting from the figure)
\initroles{automaton}{init,s1,s2,s3,fin,s0 on a,s2 on b,s1 on b,s3 on c,check}%
\newcommand\automaton[1]{
\begin{tikzpicture}[#1]
\node[state, role:init](s0) {$s_0$};
\node[state, above right=of s0, role:s1](s1) {$s_1$};
\node[state, below right=of s0, role:s2](s2) {$s_2$};
\node[state, right=of s1, role:s3](s3) {$s_3$};
\node[state, accept, below right=of s3, role:fin](s4) {$s_4$};
\draw (s0) edge[tr,out=60,in=180] node[above left,role:s0 on a] {a} (s1);
\draw (s0) edge[tr,out=-60,in=180] node[below left,role:s0 on a] {a} (s2);
\draw (s2) edge[tr,loop,out=0,in=90,looseness=8] node[above right,role:s2 on b] {b} (s2.north);
\draw (s1) edge[tr] node[above,role:s1 on b] {b} (s3);
\draw (s3) edge[tr,out=0,in=90] node[above,role:s3 on c] {c} (s4);
\node[hide, role:check, below=1mm of s4] {yes!};
\end{tikzpicture}
}
% Animation actions
\tikzset{current/.style={fill=yellow},
enabled/.style={circle,draw=gray,inner sep=1pt,outer sep=2pt},
final accept/.style={fill=green},
final reject/.style={fill=red}}%
\begin{tabular}{ll}
\say{init/current} &
\say{init/current, s0 on a/enabled} \\
\say{s1/current, s2/current} &
\say{s1/current, s2/current, s1 on b/enabled, s2 on b/enabled} \\
\say{s3/current, s2/current} &
\say{s3/current, s2/current, s3 on c/enabled} \\
\say{fin/final accept, check/show}
\end{tabular}
\end{document}
问题:这有点冗长,因为样式总是需要定义 - 所以我必须“声明”所有带有空样式的角色。我认为 OP 想要保留一个框架与另一个框架之间的状态;LuaTeX 可能在这里派上用场,只需添加一种清除样式的方法。
TikZ 样式的另一个问题是您无法扩展“连词”,即“我希望所有标有‘a’的边都变成棕色”,因此您被迫定义此类角色的笛卡尔积(的子集)。