我想要绘制许多包含子图的 TikZ 图片,例如:
模数样式如下,我可以使用以下代码来做到这一点:
\begin{tikzpicture}
\node[vertex](1) at (1,0){};
\node[vertex](2) at (2,0){};
\draw(1) to[out=60, in=120]node[colour]{$1$}(2);
\end{tikzpicture}
我需要绘制很多这样的图,所以我决定通过定义一张图片来简化它:
\tikzset{
pics/cap/.style = {
code = {
\foreach \x [count=\c from 0, remember=\x as \y] in {#1} {
\node[vertex](\x) at (\x,0){};
\ifnum\c>0
\draw(\y) to [out=60, in=120] node[colour]{$\c$} (\x);
\fi
}
}
},
}
这样我就可以将上面的例子写成:
\begin{tikzpicture}
\pic at (0,0) {cap={1,2}};
\end{tikzpicture}
不幸的是,这不起作用,而是产生:
有人能向我解释为什么我的pics
代码没有给出与“动手”方法相同的输出吗?
完整代码如下:
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\documentclass{article}
\usepackage{tikz}
\tikzset{
colour/.style = {
circle,
draw,
fill=white,
font=\small,
inner sep=0.2pt,
},
pics/cap/.style = {
code = {
\foreach \x [count=\c from 0, remember=\x as \y] in {#1} {
\node[vertex](\x) at (\x,0){};
\ifnum\c>0
\draw(\y) to [out=60, in=120] node[colour]{$\c$} (\x);
\fi
}
}
},
vertex/.style = {
circle,
radius=1mm,
inner sep=-2.0pt,
fill=black
},
}
\begin{document}
\begin{tikzpicture}
\node[vertex](1) at (1,0){};
\node[vertex](2) at (2,0){};
\draw(1) to[out=60, in=120]node[colour]{$1$}(2);
\end{tikzpicture}
\bigskip
\begin{tikzpicture}
\pic at (0,0) {cap={1,2}};
\end{tikzpicture}
\end{document}
答案1
图片是一个节点……当然不是,但 TikZ 使用与解析图片节点规范相同的机制,只需举起一个标志(\iftikz@node@is@pic
),事实上,可以将图片放在路径上,比如说
\draw (0,0) -- pic[sloped] {cap = {3, 5}} (1,2);
midway
(这里,如果 pic 的放置位置明确,不是按照默认值( ) ,我们就会遇到第一个冲突pos = 0.5
。pic 内部的节点是否应该放置在midway
pic 外部范围的默认位置,还是与 pic 本身的放置方式相同?)
node
现在, a (以及 a )做的第一件事pic
就是检查另一个标志:\iftikz@node@is@a@label
。该名称具有误导性,因为它不是关于 TikZ 标签,而是关于是否在路径操作( 、 等)与其目标坐标之间找到了节点(或图片--
)to[…]
。
如果不是,则 的值pos
将被清空,这表明不应应用计时器。(计时器是沿路径段放置节点的算法。)
所有这些确保pos
可以给出默认设置,而无需使用先前设置的计时器,因为位于路径段的目标坐标后面的节点不会使用先前设置的计时器。
我们想区分
\path (c1) -- node {X} (c2);
这会将节点放置在直线上(根据pos
当前设置)并且
\path (c1) -- (c2) node {X};
这会将节点放置c2
在
\path (c1) -- (c2) node[midway] {X};
将节点放置在线段上,即使它是在它之后指定的。(在最后一种情况下,TikZ 缺少一个界面来将节点切换为“标签”,而无需给出明确的pos
设置。)
对于pic
应该适用相同规则的情况,我想,我们希望所有这三种情况都与节点一样工作:
\path (c1) -- pic {X} (c2);
\path (c1) -- (c2) pic {X};
\path (c1) -- (c2) pic[midway] {X};
TikZ 没有为pos
内置的 ition 设定适当的范围,并且所有节点(和图片)始终被视为不位于路径段上。我认为这种情况发生是一个错误,但并不严重。
在哪里你希望节点位于圆弧的中间?那么请midway
明确设置为胡安·卡斯塔尼奥已经显示。你想把它们像图片那样摆放吗?就像图片外面的设置一样?
如果您没有在路径上使用图片和/或使用名称 ( pic (picname) {cap = …}
),那么它只是一个不需要pic
for 的花哨快捷方式。可以采用简单的宏或其他 PGFKeys 方法。
这是一个解决方案。它使用 on path 键make colour chain
并使用chains
库来放置n给定列表的节点n− 1 个“标签”。
第一个节点放置在路径的当前位置,所有其他节点都放置在坐标坐标系向右移动,与手动操作相同。该join
选项用于绘制顶点之间的边,它足够智能,不会尝试将第一个节点与不存在的前任连接起来。
不过,我选择默认colour
使用midway
。用户可以随时更改colour
样式以使用其他pos
选项:
\tikzset{colour/.append style={pos=.12345}}
代码
\documentclass[tikz]{standalone}
\usetikzlibrary{chains}
\tikzset{
colour/.style={% yes, explicitly midway
circle, draw, fill=white, font=\small, inner sep=.2pt, midway},
vertex/.style={
circle, draw, fill, inner sep=2pt},
colour join/.style={bend left=60, edge node={node[colour]{#1}}},
make colour chain/.style={
start chain=colour chain going {at={([shift=(right:1)]\tikzchainprevious.center)}},
insert path={
node foreach \x in {,#1} [vertex, on chain=colour chain, join=by {colour join={\x}}] {}
}
}
}
\begin{document}
\tikz\draw[make colour chain={1, 5, 43}];
\begin{tikzpicture}
\draw[help lines] (0,0) grid (5,3); \draw[help lines, ->] (0,0) -- (30:.8);
\path[rotate=30, ->, blue] (1,0) [make colour chain={5, 4, 11}];
\end{tikzpicture}
\end{document}
输出
答案2
我修改了你的\pic
代码并将选项添加midway
到colour
样式中。
\documentclass[tikz,border=1.618]{standalone}
\tikzset{
colour/.style = {
circle,
draw,
fill=white,
font=\small,
inner sep=0.2pt,
midway% <-- added
},
pics/cap/.style = {
code = {
\node[vertex](0) at (0,0){};
\foreach \x in {#1} {
\pgfmathtruncatemacro\y{\x-1}
\node[vertex](\x) at (\x,0){};
\draw(\y) to [out=60, in=120] node[colour]{$\x$} (\x);
}
}
},
vertex/.style = {
circle,
radius=1mm,
inner sep=-2.0pt,
fill=black
},
}
\begin{document}
\begin{tikzpicture}
\pic at (0, 0) {cap={1,2}};
\pic at (0,-1) {cap={1,...,5}};
\end{tikzpicture}
\end{document}