我正在尝试使用一些乳胶编码来简化我的工作,目的是根据输入生成两种类型的图表。第一种是线条只向上的图表
第二个是允许线条像这样返回(用 PowerPoint 绘制):
我已经有了第一类图表的工作代码这里其中图表顶部和底部的点从左到右按 1 到 n 进行编号。下面是代码的 MWE。
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{arrows.meta}
\tikzset{pics/planar/.style 2 args = {
code = {
\draw[color=red] (0,0) rectangle (#1*0.3+0.3,0.7);
\foreach \dot in {1,...,#1}{ % draw the dots
\filldraw (0.3*\dot,0) circle [radius=1pt];
\filldraw (0.3*\dot,0.7) circle [radius=1pt];
}
% draw the lines
\foreach \x/\y in #2
\draw[->,>=stealth](0.3*\x,0) .. controls +(0,0.2) and +(0,-0.2) .. (0.3*\y,0.7);
}
}
}
\usepackage{xparse}
\NewDocumentCommand\PlanarDiagram{ O{} D(){3} m }{%
\begin{tikzpicture}[#1]
\foreach \diag [count=\c] in {#3} {
\draw(0,\c*0.7) pic[#1]{planar={#2}{\diag}};
}
\end{tikzpicture}%
}
\begin{document}
\PlanarDiagram(5){{1/2}} \quad
\PlanarDiagram{{1/2,2/2}, {2/3,3/1}} \quad
\PlanarDiagram(4){{1/2, 3/1, 3/3}, {1/1, 2/3, 3/3}}
\PlanarDiagram[scale=0.7, draw=blue](4){{1/2, 3/1, 3/3}, {1/1, 2/3, 3/3}}
\end{document}
我希望如果我将顶部的点从 1 正数编号到 n,将底部的点从 -1 负数编号到 -n,我可以通过命令的输入将两种类型的线分开,因此命令可以是这样的
\NewPlanarDiagram{{-1/-4,-2/-3,1/2,3/4}} % diagram on the left
\NewPlanarDiagram{{-1/3,-2/-3,1/2,4/4}} % diagram on the right
我可以对 for 循环中的宏做类似的事情
\foreach \x/\y in #2
\ifnum \x < 0
\let \signx=-1
\else
\let \signx=1
\fi
\ifnum \y < 0
\let \signy=-1
\else
\let \signy=1
\fi
\let \xysign= \multiply\signx by \signy
\ifnum\xysign<0
\draw(0.3*\x,0.35+\signx*0.35) .. controls +(0,0.2) and +(0,-0.2) .. (0.3*\y,0.35+\signy*0.35);
\else
\draw(0.3*\x,0.35+\signx*0.35) .. controls +(0,0.2) and +(0,-0.2) .. (0.3*\y,0.35+\signy*0.35);
\fi
但出现了许多错误消息。有什么想法吗?
答案1
我只想使用一个pic
,然后以原始用法仍然有效的方式对其进行升级。从技术方面来说,你可以引入一个测试整数
\pgfmathtruncatemacro{\itest}{(\XX<0)+2*(\YY<0)}
\YY
它将根据两个符号都是正数、只有 的符号为正数、只有 的符号为正数或两个符号都是负数分别取值为 0、1、2 或 3。\XX
然后,您可以使用简单的\ifcase
。
\documentclass{article}
\usepackage{tikz}
\newif\ifPlanarDiagamShowLabels
\usetikzlibrary{arrows.meta,bending}
\tikzset{pics/planar diagram/.style={code={
\tikzset{planar diagram/.cd,#1}%
\def\pv##1{\pgfkeysvalueof{/tikz/planar diagram/##1}}%
\draw[/tikz/planar diagram/frame] ({-(\pv{n}+1)*\pv{x}/2},-\pv{y}/2) rectangle
({(\pv{n}+1))*\pv{x}/2},\pv{y}/2);
\ifPlanarDiagamShowLabels
\path foreach \XX in {1,...,\pv{n}}
{({-(\pv{n}+1)*\pv{x}/2+\XX*\pv{x}},-\pv{y}/2)
node[circle,fill,inner sep=1pt,label=below:$\XX$] (-b-\XX){}
({-(\pv{n}+1)*\pv{x}/2+\XX*\pv{x}},\pv{y}/2)
node[circle,fill,inner sep=1pt,label=above:$\XX$] (-t-\XX){}};
\else
\path foreach \XX in {1,...,\pv{n}}
{({-(\pv{n}+1)*\pv{x}/2+\XX*\pv{x}},-\pv{y}/2)
node[circle,fill,inner sep=1pt] (-b-\XX){}
({-(\pv{n}+1)*\pv{x}/2+\XX*\pv{x}},\pv{y}/2)
node[circle,fill,inner sep=1pt] (-t-\XX){}};
\fi
\edef\localconnections{\pv{connections}}
\foreach \XX/\YY in \localconnections{%
\ifnum\XX=\YY
\typeout{Loops are not implemented (yet).}
\else
\pgfmathtruncatemacro{\itest}{(\XX<0)+2*(\YY<0)}
\ifcase\itest % both >0
\draw[planar diagram/arrow] (-t-\XX) to[out=-90,in=-90] (-t-\YY);
\or % \YY >0
\draw[planar diagram/arrow] (-b\XX) to[out=90,in=-90] (-t-\YY);
\or % \XX >0
\draw[planar diagram/arrow] (-t-\XX) to[out=-90,in=90] (-b\YY);
\or % both <0
\draw[planar diagram/arrow] (-b\XX) to[out=90,in=90] (-b\YY);
\fi
\fi
}
}},planar diagram/.cd,n/.initial=5,x/.initial=0.3,y/.initial=0.7,
show labels/.is if=PlanarDiagamShowLabels,frame/.style={},
connections/.initial={1/1},arrow/.style={-{Stealth[bend]}}
}
\begin{document}
\begin{tikzpicture}
\path (0,0) pic[scale=2]{planar diagram={n=4,
arrow/.style={thick,cyan},frame/.style={draw=red},
connections={-1/-4,-2/-3,1/2,3/4}}}
(5,0) pic[scale=2]{planar diagram={n=4,arrow/.style={thick,cyan},
connections={-1/3,-2/-3,1/2,-4/4}}}
(0,-3) pic[scale=2]{planar diagram={n=5,
connections={-1/3,-2/4,-3/1,-4/2,-5/5}}};
\end{tikzpicture}
\end{document}
答案2
建议的循环中的主要问题是\let
不能以这种方式工作:右侧必须是单个标记。您可以使用\def
或\pgfmathsetmacro
。第二个问题:您的两个替代代码路径是相同的。本着与您编写的相同精神,我将在循环中使用类似以下内容:
\foreach \x/\y in #2 {
\pgfmathtruncatemacro{\signx}{\x < 0 ? -1 : 1}
\pgfmathtruncatemacro{\signy}{\y < 0 ? -1 : 1}
\pgfmathsetmacro{\myFactor}
{(1+0.2*(1+\signx*\signy)*abs(abs(\x)-abs(\y)))}
\draw
({0.3*abs(\x)}, 0.35+\signx*0.35)
.. controls +(0, -\myFactor*\signx*0.2) and
+(0, -\myFactor*\signy*0.2) ..
({0.3*abs(\y)}, 0.35+\signy*0.35);
}
我还重写了您的\PlanarDiagram
宏,\NewPlanarDiagram
使用了更多expl3
内容,但最终没有必要(如果您感兴趣,请查看答案的历史记录)。#1
不过,我注释掉了一个,因为您将它同时传递给了tikzpicture
和。此外,您在第二个提议的图表中pic
写了4/4
而不是。在我的示例中,宏的调用方式如下:-4/4
\NewPlanarDiagram
\NewPlanarDiagram(4){{-1/-4,-2/-3,1/2,3/4}, {-1/3,-2/-3,1/2,-4/4}}
完整示例:
\documentclass{article}
\usepackage{xparse}
\usepackage{tikz}
\tikzset{pics/planar/.style 2 args = {
code = {
\draw[color=red] (0,0) rectangle (#1*0.3+0.3,0.7);
\foreach \dot in {1,...,#1} { % draw the dots
\filldraw (0.3*\dot,0) circle [radius=1pt];
\filldraw (0.3*\dot,0.7) circle [radius=1pt];
}
% draw the lines
\foreach \x/\y in #2 {
\pgfmathtruncatemacro{\signx}{\x < 0 ? -1 : 1}
\pgfmathtruncatemacro{\signy}{\y < 0 ? -1 : 1}
\pgfmathsetmacro{\myFactor}
{(1+0.2*(1+\signx*\signy)*abs(abs(\x)-abs(\y)))}
\draw
({0.3*abs(\x)}, 0.35+\signx*0.35)
.. controls +(0, -\myFactor*\signx*0.2) and
+(0, -\myFactor*\signy*0.2) ..
({0.3*abs(\y)}, 0.35+\signy*0.35);
}
}
}
}
\NewDocumentCommand \NewPlanarDiagram { O{} D(){3} m }
{%
\begin{tikzpicture}%[#1] commented out: already passed to the pic...
\foreach \diag [count=\c] in {#3} {
\draw(0, -\c*0.9) pic[#1] {planar={#2}{\diag}};
}
\end{tikzpicture}%
}
\begin{document}
\NewPlanarDiagram(4){{-1/-4,-2/-3,1/2,3/4}, {-1/3,-2/-3,1/2,-4/4}}
\end{document}
答案3
为了保持连续性,这里是我对您之前问题的回答的更新,其中添加了一些“如果/那么”来处理新的情况。
编译lualatex
:
\documentclass{article}
\usepackage{luamplib}
\mplibforcehmode
\begin{document}
\begin{mplibcode}
ux:=1cm; % horizontal scale
uy:=2cm; % vertical scale
ds:=.15*ux; % dot size
def planar(expr pts,levels)(text connections)=
clearxy; save k,l,n;
x=(pts+1)*ux; y=levels*uy; % max x, max y
for i=0 upto levels:
draw (origin--(x,0)) shifted (0,i*uy) withcolor red; % draw horizontal bars
for j=1 upto pts: drawdot (j*ux,i*uy) withpen pencircle scaled ds; endfor; % draw dots
endfor;
draw origin--(0,y) withcolor red; % draw left vertical bar
draw (x,0)--(x,y) withcolor red; % draw right vertical bar
l=length(connections); n=k=0;
for i=0 upto l:
if (substring(i,i+1) of connections="|") or (i=l): % find separators
for p=scantokens(substring(k,i) of connections): % iterate through list up to separator
if (xpart p<0) and (ypart p>0): % between levels
drawarrow (abs(xpart p)*ux,n*uy){up}..{up}((ypart p)*ux,(n+1)*uy)
cutafter fullcircle scaled (ds+1) shifted ((ypart p)*ux,(n+1)*uy);
elseif (xpart p<0) and (ypart p<0): % bottom level
draw (abs(xpart p)*ux,n*uy){up}..{down}(abs(ypart p)*ux,n*uy) ;
elseif (xpart p>0) and (ypart p>0): % top level
draw (abs(xpart p)*ux,(n+1)*uy){down}..{up}(abs(ypart p)*ux,(n+1)*uy);
fi;
endfor;
k:=i+1; % pickup after separator
n:=n+1; % increase level
fi;
endfor;
enddef;
beginfig(0);
planar(3,3)("(-1,-2),(-2,3),(1,2)|(-1,3),(-3,-2)|(-1,-2),(-1,-3),(-1,1)");
endfig;
\end{mplibcode}
\end{document}
答案4
我对薛定谔猫的答案做了一些修改,让圆圈看起来更漂亮,最后还是用了它。我会把它贴在这里,以防有人偶然发现它。
\usepackage{tikz}
\usetikzlibrary{braids,backgrounds,arrows.meta,fit}
\tikzset{pics/planar diagram/.style={code={
\tikzset{planar diagram/.cd,#1}%
\def\pv##1{\pgfkeysvalueof{/tikz/planar diagram/##1}}%
\draw[/tikz/planar diagram/frame] ({-(\pv{n}+1)*\pv{x}/2},-\pv{y}/2) rectangle ({(\pv{n}+1))*\pv{x}/2},\pv{y}/2);
\path foreach \XX in {1,...,\pv{n}}
{({-(\pv{n}+1)*\pv{x}/2+\XX*\pv{x}},-\pv{y}/2)
node[circle,fill,inner sep=0.7pt] (-b-\XX){}
({-(\pv{n}+1)*\pv{x}/2+\XX*\pv{x}},\pv{y}/2)
node[circle,fill,inner sep=0.7pt] (-t-\XX){}};
\edef
\localconnections{\pv{connections}}
\foreach \XX/\YY in \localconnections{%
\ifnum\XX=\YY
\typeout{Loops are not implemented (yet).}
\else
\pgfmathtruncatemacro{\itest}{(\XX<0)+2*(\YY<0)}
\ifcase\itest % both >0
\draw[planar diagram/arrow] (-t-\XX) .. controls +(0,-0.2*\pv{y}+0.025*\XX/\pv{x}-0.025*\YY/\pv{x}) and +(0,-0.2*\pv{y}+0.025*\XX/\pv{x}-0.025*\YY/\pv{x}) .. (-t-\YY);
\or % \YY >0
\draw[planar diagram/arrow] (-b\XX) .. controls +(0,0.2) and +(0,-0.2) .. (-t-\YY);
\or % \XX >0
\draw[planar diagram/arrow] (-t-\XX) .. controls +(0,-0.2) and +(0,0.2) .. (-b\YY);
\or % both <0
\draw[planar diagram/arrow] (-b\XX) .. controls +(0,0.2*\pv{y}+0.025*\XX/\pv{x}-0.025*\YY/\pv{x}) and +(0,0.2*\pv{y}+0.025*\XX/\pv{x}-0.025*\YY/\pv{x}) .. (-b\YY);
\fi
\fi
}
}},
planar diagram/.cd,n/.initial=5,x/.initial=0.3,y/.initial=0.7,frame/.style={draw=red},connections/.initial={1/1},arrow/.style={-{stealth}}
}
\usepackage{xparse}
\NewDocumentCommand\NewPlanarDiagram{ O{} D(){3} m }{%
\begin{tikzpicture}[#1]
\foreach \diag [count=\c] in {#3} {
% \draw(0,\c*0.7) pic[#1]{planar={#2}{\diag}};
\draw (0,\c*0.8) pic[#1]{planar diagram={n=#2,connections={\diag},arrow/.style={black},x=0.3,y=0.8}};
}
\end{tikzpicture}%
}
\NewDocumentCommand\planarDiagram{ O{} D(){3} m }{%
\begin{scope}[#1]
\foreach \diag [count=\c] in {#3} {
\draw (0,\c*0.7) pic[#1]{planar diagram={n=#2,connections={\diag}}};
}
\end{scope}
}
\NewDocumentCommand\PlanarDiagram{ O{} D(){3} m }{%
\begin{tikzpicture}[#1]
\foreach \diag [count=\c] in {#3} {
\draw (0,\c*0.7) pic[#1]{planar diagram={n=#2,connections={\diag}}};
}
\end{tikzpicture}%
}