Me gustaría dibujar una flecha circular de un nodo que apunte a sí mismo en un diagrama conmutativo. Lo que pude lograr hasta ahora se parece a lo siguiente:
¿Hay alguna manera de hacer que los bucles se parezcan mucho a un círculo real?
A continuación se muestra un 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}
Respuesta1
Como se explica en la sección 3.2 del tikz-cd
manual, se puede utilizar to path
para modificar rutas. Para encontrar el ángulo inicial y final apropiado del arco, se puede medir el nodo con la calc
biblioteca. Las flechas dobles también se dibujan mediante to path
. Estos caminos son horizontales por construcciones. Para preservar las etiquetas de los bordes, hay que agregar \tikztonodes
al argumento de 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}
Respuesta2
A continuación se muestra una versión ligeramente modificada de la respuesta aceptada. En las flechas horizontales, alineé la flecha con la altura de \tikztostart
en lugar de \tikztotarget
hacerla más alta. Sin embargo, para obtener correctamente el punto final de la flecha, agregué manualmente un desplazamiento horizontal de 3 puntos a la coordenada, lo que parece bastante feo en el código.
\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}
Respuesta3
TikZ-CD utiliza el asymmetrical rectangle
cual tiene su ancla central no en el centro vertical real sino a una distancia fija ( axis_height
) por encima de la línea de base para que las flechas entre los nodos de la misma fila se dibujen como flechas en modo matemático. (Esto también lleva a que siempre estén horizontales).
En este código, el segmento circular se dibuja de modo que pase por el centro del inicio (y no toque el ancla norte o sur). Para ello se utilizan spath3
las bibliotecas y . intersections
Hacer esto matemáticamente para cualquier dirección que no sea horizontal/vertical implica demasiadas matemáticas para querer resolverlo. Técnicamente, la spath3
biblioteca solo se usa para eliminar el segmento del círculo que se encuentra dentro del nodo inicial; los ángulos inicial y final apropiados podrían haberse determinado conociendo los puntos de intersección.
Agregué dos formas a TikZ-CD para usar el circle around rect node
estilo:
circle = <padding>
(<padding>
el valor predeterminado es.5ex
aproximadamente la mitad de los segundos internos de los nodos en un TikZ-CD)Si el relleno fuera cero, esto determina el radio de tal manera que el círculo apenas tocaría la coordenada/nodo objetivo.
circle to = <angle>
dibuja un círculo alrededor de la coordenada inicial que “apunta” en la dirección<angle>
y tiene diámetrocircle to distance
.
Código
\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}