![如何存储和检索固定布局的数据?](https://linux22.com/image/452987/%E5%A6%82%E4%BD%95%E5%AD%98%E5%82%A8%E5%92%8C%E6%A3%80%E7%B4%A2%E5%9B%BA%E5%AE%9A%E5%B8%83%E5%B1%80%E7%9A%84%E6%95%B0%E6%8D%AE%EF%BC%9F.png)
我今天的问题是关于当我想创建固定设计时,存储数据的合适方法。假设我在 TikZ 绘图中有一个给定的布局,我想在其中有动态文本。但是用户不必面对 TikZ 代码,他只需定义内容,然后我将其填充到 TikZ 节点中。所以这是我的示例:
\documentclass[tikz]{standalone}
\begin{document}
\begin{tikzpicture}
\node(center)[fill=cyan,circle,minimum size=3cm] at (135:10cm) {Topic};
\foreach \i in {0,...,7}
{
\node(bubble)[fill=green,text width=2cm,circle,align=center] at (\i*20:\i*3cm) {\textbf{Heading \i}\\Content};
\draw (center) -- (bubble);
}
\end{tikzpicture}
\end{document}
现在我的节点已经设置好了,但是预先提供数据的合适方法是什么呢?当然,我可以为每个节点定义一个宏,如下所示:
\newcommand{\headingone}{Heading 1}
\newcommand{\contentone}{Content 1}
然后使用这些宏来读取数据。但是,难道没有更简单、更数据驱动的方法吗?由于图表不应动态增长,我不想创建一个包含项目的环境,尽管这对我来说似乎是一种可行的方法。但是,难道没有更聪明的方法来做到这一点吗?
答案1
我不太清楚您想要什么,但您可以创建两个clist
并将数据存储在那里。tikzpicture
然后您可以在 中检索循环内的数据\foreach
。
确切的实现取决于您想要存储的数据类型,但对于简单的字符串,它可以像这样工作:
\documentclass[tikz]{standalone}
\ExplSyntaxOn
\clist_new:N \l_mypic_headers_clist
\clist_new:N \l_mypic_contents_clist
\NewDocumentCommand { \getHeadersAtIndex } { m } {
\clist_item:Nn \l_mypic_headers_clist { #1 }
}
\NewDocumentCommand { \getContentsAtIndex } { m } {
\clist_item:Nn \l_mypic_contents_clist { #1 }
}
\NewDocumentCommand { \getMaxIndex } { } {
\clist_count:N \l_mypic_headers_clist
}
\NewDocumentCommand { \addToLists } { m m } {
\clist_put_right:Nn \l_mypic_headers_clist { { #1 } }
\clist_put_right:Nn \l_mypic_contents_clist { { #2 } }
}
\ExplSyntaxOff
\addToLists{Header 1}{Contents 1}
\addToLists{Header 2}{Contents 2}
\addToLists{Header 3}{Contents 3}
\addToLists{Header 4}{Contents 4}
\addToLists{Header 5}{Contents 5}
\addToLists{Header 6}{Contents 6}
\addToLists{Header 7}{Contents 7}
\begin{document}
\begin{tikzpicture}
\node(center)[fill=cyan,circle,minimum size=3cm] at (135:10cm) {Topic};
\foreach \i in {1,...,\getMaxIndex} {
\node(bubble)[fill=green,text width=2cm,circle,align=center] at (\i*20:\i*3cm)
{\textbf{\getHeadersAtIndex{\i}} \\ \getContentsAtIndex{\i}};
\draw (center) -- (bubble);
}
\end{tikzpicture}
\end{document}
如果您需要更强大的设置,您可以使用序列而不是逗号列表进行存储。只需将上述代码中的clist
每个替换为即可。seq
编辑
您可以在块内添加以下函数ExplSyntax
:
\NewDocumentCommand { \addMultipleToLists } { m } {
\clist_map_inline:nn { #1 } {
\clist_put_right:Nn \l_mypic_headers_clist {
\clist_item:nn { ##1 } { 1 }
}
\clist_put_right:Nn \l_mypic_contents_clist {
\clist_item:nn { ##1 } { 2 }
}
}
}
然后,您可以使用一种可能更方便的方式来输入数据(请注意,在这种情况下,如果文本包含逗号,则需要将其括在额外的括号中,并且显然不能简单地在此处切换到序列,因为您首先向宏提供了逗号列表):
\addMultipleToLists{{Header 1,Contents 1},
{Header 2,Contents 2},
{Header 3,Contents 3},
{Header 4,Contents 4},
{Header 5,Contents 5},
{Header 6,Contents 6},
{Header 7,Contents 7}}
答案2
此 PGFkeys 支持的解决方案支持以下形式的列表
{{Header 1, Content 1}, {Header 2, Content 2}, {…}, …}
也
{Header 1, Content 1, Header 2, Content 2, …
后者是默认的list use = all comma
,前者可以与一起使用list use = tuples
。
为了放置绿色节点,我使用chains
图书馆的
on chain = <chain name> placed {at = (<calculation>)}
简单来说(<calculation>)
就是
(\tikzchaincount*20: \tikzchaincount*3cm)
即与您的相同,但\i
替换为\tikzchaincount
。
代码
\documentclass[tikz]{standalone}
\usetikzlibrary{chains}
\makeatletter
\tikzset{
/utils/if not empty/.code 2 args={%
\if\relax\detokenize{#1}\relax\expandafter\pgfutil@gobble
\else\expandafter\pgfutil@firstofone\fi
{\pgfkeysalso{#2}}}}
\makeatother
\tikzset{
% defaults
topic style/.style={shape=circle, minimum size=3cm, fill=cyan},
list style/.style={fill=green, text width=2cm, circle, align=center},
topic/.initial=Topic,
list/.initial={Header 1, Contents 1,
Header 2, Contents 2,
Header 3, Contents 3,
Header 4, Contents 4,
Header 5, Contents 5,
Header 6, Contents 6},
% mantaining the lists/settings
reset list/.style={list=},
add to list/.style={list/.append={,#1}},
list use/.is choice,
list use/all comma/.style={use list/.style={% H1, C1, H2, C2, …
list parser/.expand twice/.expand once={\pgfkeysvalueof{/tikz/list},}}},
list use/tuples/.style={use list/.style={% {H1, C1}, {H2, C2}, …
placer/.list/.expand twice/.expand once=\pgfkeysvalueof{/tikz/list}}},
list use=all comma,% default: all comma
% actual placing
list parser/.style args={#1,#2,#3}{ % parsing H1, C1, H2, C2, …
placer={{#1},{#2}},
/utils/if not empty={#3}{list parser={#3}}},
tuples parser/.style args={#1,#2}{placer={{#1},{#2}}},% parsing {H1, C1}, {H2, C2}, …
placer/.code args={#1,#2}{%
\node [list style, on chain] {\textbf{#1}\\#2} edge (center);}}
\newcommand*\myTikz[1][]{%
\begin{tikzpicture}[#1,
start chain=headers placed {at=(\tikzchaincount*20:\tikzchaincount*3cm)}]
\node (center) [topic style] at (135:10cm) {\pgfkeysvalueof{/tikz/topic}};
\tikzset{use list}
\end{tikzpicture}}
\begin{document}
\myTikz
\myTikz[add to list={Header X, Content X, Header Y, Content Y}]
\myTikz[topic=\TeX, list={TikZ, extends PGF, \LaTeX, extends \TeX}]
\tikzset{
list use=tuples,
list={{Header 1, Contents 1},
{Header 2, Contents 2},
{Header 3, Contents 3},
{Header 4, Contents 4},
{Header 5, Contents 5},
{Header 6, Contents 6}}}
\myTikz
\myTikz[add to list={{Header X, Content X}, {Header Y, Content Y}}]
\myTikz[topic=\TeX, list={{TikZ, extends PGF}, {\LaTeX, extends \TeX}}]
\end{document}