我想在交換圖中畫出一個指向自身的節點的圓形箭頭。到目前為止我能達成的目標如下:
有什麼方法可以讓循環看起來很像真正的圓嗎?
下面是 MWE。
\documentclass{article}
\usepackage{tikz-cd}
\begin{document}
\begin{tikzcd}[column sep=large]
C & D
\arrow["{F}", bend left = 30, from=1-1, to=1-2]
\arrow["{G}", bend left = 30, from=1-2, to=1-1]
\arrow[""{name=0, anchor=center, inner sep=0}, "{G} \,\circ\, {F}", from=1-1, to=1-1, out=-145, in=145, loop, distance=4em]
\arrow[""{name=1, anchor=center, inner sep=0}, "{F} \,\circ\, {G}", from=1-2, to=1-2, out=35, in=-35, loop, distance=4em]
\arrow["\theta", shorten <=3pt, shorten >=3pt, Rightarrow, from=0, to=1-1]
\arrow["\phi"', shorten <=3pt, shorten >=3pt, Rightarrow, from=1, to=1-2]
\end{tikzcd}
\end{document}
答案1
如手冊第 3.2 節所述tikz-cd
,可以使用它to path
來調整路徑。為了找到合適的圓弧起始角度和終止角度,可以使用calc
函式庫測量節點。雙箭頭也是透過 繪製的to path
。這些路徑的結構是水平的。為了保留邊緣標籤,必須加入\tikztonodes
的參數to path
。
\documentclass{article}
\usepackage{tikz-cd}
\usetikzlibrary{calc}
\begin{document}
\def\myradius{1.5em}
\begin{tikzcd}[column sep=large]
C & D
\arrow["{F}", bend left = 30, from=1-1, to=1-2]
\arrow["{G}", bend left = 30, from=1-2, to=1-1]
\arrow["{G} \,\circ\, {F}","\mathstrut"{name=0, anchor=center, inner sep=0}, from=1-1, to=1-1,to path={%
let \p1=($(\tikztostart.north)-(\tikztostart.south)$),\n1={scalar(asin(0.5*\y1/\myradius))} in
(\tikztostart.south)arc[start angle=-\n1,end angle=-360+\n1,radius=\myradius]\tikztonodes (\tikztotarget)}]
\arrow["{F} \,\circ\, {G}","\mathstrut"{name=1, anchor=center, inner sep=0}, from=1-2, to=1-2,to path={%
let \p1=($(\tikztostart.north)-(\tikztostart.south)$),\n1={scalar(asin(0.5*\y1/\myradius))} in
(\tikztostart.north)arc[start angle=180-\n1,end angle=-180+\n1,radius=\myradius]\tikztonodes (\tikztotarget)}]
\arrow["\theta", shorten <=3pt, shorten >=3pt, Rightarrow, from=0, to=1-1, to path={(\tikztostart|-\tikztotarget) -- (\tikztotarget)\tikztonodes}]
\arrow["\phi"', shorten <=3pt, shorten >=3pt, Rightarrow, from=1, to=1-2, to path={(\tikztostart|-\tikztotarget) -- (\tikztotarget)\tikztonodes}]
\end{tikzcd}
\end{document}
答案2
以下是已接受答案稍作修改的版本。在水平箭頭中,我將箭頭與 的高度對齊,\tikztostart
而不是\tikztotarget
使其更高。然而,為了正確獲得箭頭的終點,我手動向座標添加了 3pt 的水平移動,這在程式碼中看起來相當難看。
\documentclass{article}
\usepackage{tikz-cd}
\usetikzlibrary{calc}
\begin{document}
\begin{tikzcd}[column sep=large]
C & D
\arrow["{F}", bend left = 30, from=1-1, to=1-2]
\arrow["{G}", bend left = 30, from=1-2, to=1-1]
\arrow["{G} \,\circ\, {F}","\mathstrut"{name=0, anchor=center, inner sep=0}, from=1-1, to=1-1,
to path={let \p1=($(\tikztostart.north)-(\tikztostart.south)$),\n1={scalar(asin(0.5*\y1/1.5em))} in
(\tikztostart.south) arc[start angle=-\n1,end angle=-360+\n1,radius=1.5em]\tikztonodes (\tikztotarget)}]
\arrow["{F} \,\circ\, {G}","\mathstrut"{name=1, anchor=center, inner sep=0}, from=1-2, to=1-2,
to path={let \p1=($(\tikztostart.north)-(\tikztostart.south)$),\n1={scalar(asin(0.5*\y1/1.5em))} in
(\tikztostart.north) arc[start angle=180-\n1,end angle=-180+\n1,radius=1.5em]\tikztonodes (\tikztotarget)}]
\arrow["\theta", shorten <=3pt, shorten >=3pt, Rightarrow, from=0, to=1-1, to path={(\tikztostart) -- ($(\tikztotarget|-\tikztostart)+(-3pt,0)$) \tikztonodes }]
\arrow["\phi"', shorten <=3pt, shorten >=3pt, Rightarrow, from=1, to=1-2, to path={(\tikztostart) -- ($(\tikztotarget|-\tikztostart)+(3pt,0)$) \tikztonodes }]
\end{tikzcd}
\end{document}
答案3
TikZ-CD 使用 的 ,asymmetrical rectangle
其中心錨點不在真正的垂直中心,而是axis_height
在基線上方固定距離( ),以便同一行的節點之間的箭頭像數學模式箭頭一樣繪製。 (這也導致它們總是水平的。)
在此程式碼中,繪製圓弧段,使其穿過起點的中心(並且不接觸北錨點或南錨點)。為此,使用spath3
和庫。intersections
對水平/垂直以外的任何方向進行數學計算涉及太多數學,我無法弄清楚。從技術上講,該spath3
函式庫僅用於刪除位於起始節點內部的圓段,可透過了解交點來確定適當的起始角度和結束角度。
我在 TikZ-CD 中添加了兩種使用該circle around rect node
樣式的方法:
circle = <padding>
(<padding>
預設為.5ex
,大約是 TikZ-CD 中節點 inenr seps 的一半)如果填充為零,則以圓恰好接觸目標座標/節點的方式決定半徑。
circle to = <angle>
圍繞起始座標繪製一個圓,該圓「指向」方向<angle>
且直徑為circle to distance
。
程式碼
\documentclass[tikz]{standalone}
\usepackage{tikz-cd}
\usetikzlibrary{calc, intersections, spath3}
\tikzset{
circle around rect node/.style n args={3}{insert path={%
% #1 = node name, #2 = angle, #3 = distance
(#1.center) edge[
path only, spath/save global=carn@circle,
to path={arc[start angle={(180-(#2))}, delta angle=360, radius={(#3)/2}]}](#1)
(#1.south west) edge[
path only, spath/save global=carn@rect,
to path={rectangle(\tikztotarget)}](#1.north east)
[spath/.cd,
split at intersections with={carn@circle}{carn@rect},
remove components={carn@circle}{1,3},
use=carn@circle]}}}
\tikzcdset{
circle to distance/.initial=3em,
circle to/.style={to path={
[circle around rect node/.expanded={\tikztostart}{#1}
{\pgfkeysvalueof{/tikz/commutative diagrams/circle to distance}}]
\tikztonodes}},
circle/.default=.5ex,
circle/.style={
execute at begin to={%
\path[path only](\tikztostart)
--coordinate[at end](tikzcd@circleend)(\tikztotarget);},
to path={
let \p{tikzcd@diff} = ($(tikzcd@circleend)-(\tikztostart)$) in
[circle around rect node/.expanded={\tikztostart}
{atan2(\y{tikzcd@diff},\x{tikzcd@diff})}
{veclen(\p{tikzcd@diff})+(#1)}]
\tikztonodes}}}
\tikzset{
cd/.code=\tikzcdset{#1},
cd node/.style={font=,cd=every cell,name={#1}}}
\begin{document}
\begin{tikzcd}[
column sep=large, bend angle=30,
% /tikz/column 1/.append style={cd={column sep=normal}},
% /tikz/column 3/.append style={cd={column sep=normal}},
]
G \circ F \arrow[r, "\theta", Rightarrow]
& C \arrow[r, "F", bend left]
\arrow[l, circle]
& D \arrow[l, "G", bend left]
\arrow[r, circle]
& F \circ G \arrow[l, "\phi"', Rightarrow]
\end{tikzcd}
\begin{tikzcd}[column sep=large, bend angle=30]
C \arrow[r, "F", bend left]
\arrow[circle to=180, "G \circ F"' cd node=GF]
\arrow[Rightarrow, shorten <=.8ex, from=GF, "\theta"]
& D \arrow[l, "G", bend left]
\arrow[circle to= 0, "F \circ G"' cd node=FG]
\arrow[Rightarrow, shorten <=.8ex, from=FG, "\phi"']
\end{tikzcd}
\begin{tikzpicture}
\node[draw] (A) {A};
\foreach[count=\i] \ang in {0, 45, ..., 359}
\draw[red!\i0!blue, circle around rect node={A}{\ang}{1cm}];
\end{tikzpicture}
\end{document}