33

I would like to make the small loop around the circle (loop above) a bit rounder and nicer.

below is a short example of my code:

 \documentclass{scrbook}
 \usepackage{tikz}
 \usetikzlibrary{positioning,automata}
 \begin{document}

 \begin{tikzpicture}[shorten >=1pt,auto]
   \tikzstyle{place}=[circle,thick,draw=blue!75,fill=blue!20,minimum
                      size=6mm]
   \node[place] (foo) [label=above left:Foo] {$1$};
   \path[->] (foo) edge  [loop above] node {1} ();
  \end{tikzpicture}
 \end{document}

example from the previous code

Rmano
  • 40,848
  • 3
  • 64
  • 125
Eagle
  • 2,559
  • Somewhat related http://tex.stackexchange.com/questions/7774/how-can-i-draw-two-loops-above-a-node/7781#7781 – N.N. Nov 19 '11 at 21:45

3 Answers3

39

There are four parameters that you can play with to adjust the loop size and shape. You can set the in and out angles, and also the minimum length for a loop and its looseness. See Section 50.4 of the TikZ documentation for more detail:

\documentclass{scrbook}
\usepackage{tikz}
\usetikzlibrary{positioning,automata}
\begin{document}

\tikzset{every loop/.style={min distance=10mm,in=0,out=60,looseness=10}}
\tikzset{place/.style={circle,thick,draw=blue!75,fill=blue!20,minimum
                      size=6mm}}
\begin{tikzpicture}[shorten >=1pt,auto]   
   \node[place] (foo) [label=above left:Foo] {$1$};
   \path[->] (foo) edge  [loop above] node {1} ();
  \end{tikzpicture}
\end{document}

output of code

I've used \tikzset to set them globally in this example; you can also add the .style specification to an individual tikzpicture or set the parameters for a single loop.

The label distance can be set using the label distance key as part of the node style. To move the label closer to the node, use a negative value. For this example -3pt seems to work nicely. There doesn't seem to be a way to set this key for a single node. So you can

Alan Munn
  • 218,180
16

I tried some time ago to create a loop like a circle (exactly an arc of a circle, a bit rounder and nicer). I didn't find a easy way to do this, but here is the code I wrote to such loops.

First code: I used only TikZ but I used an empirical method to calculate some of the lengths. The macro \tikzAngleOfLine gives me the angle of a line. If \AngleEndis greater than \AngleSart a problem appears. In the second code example I give a solution to this.

\documentclass[a4paper]{article}
\usepackage{tikz}
\usetikzlibrary{arrows,calc} 

\newcommand{\tikzAngleOfLine}{\tikz@AngleOfLine}
\def\tikz@AngleOfLine(#1)(#2)#3{%
\pgfmathanglebetweenpoints{%
\pgfpointanchor{#1}{center}}{%
\pgfpointanchor{#2}{center}}
\pgfmathsetmacro{#3}{\pgfmathresult}%
}

\begin{document} 

\begin{tikzpicture}[scale=1.5,>=stealth']
\node [circle,draw,minimum size=2cm](A) {first node};
\node [circle,minimum size=3cm](B) at ([{shift=(60:1)}]A){};
\coordinate  (C) at (intersection 2 of A and B);
\coordinate  (D) at (intersection 1 of A and B);
 \tikzAngleOfLine(B)(D){\AngleStart}
 \tikzAngleOfLine(B)(C){\AngleEnd}
\draw[red,thick,->]%
   let \p1 = ($ (B) - (D) $), \n2 = {veclen(\x1,\y1)}
   in   
     (B) ++(60:\n2) node[fill=white]{$\alpha$}
     (D) arc (\AngleStart-360:\AngleEnd:\n2); % -360 only if  \AngleStart>\AngleEnd
 \end{tikzpicture}  

\end{document}

The result is output of code

Second code: Here I used some macros from the tkz-euclide package. The idea is to build an orthogonal circle to the first node.

\documentclass{article}
\usepackage{tkz-euclide}
\usetkzobj{all} 
\usetikzlibrary{through}  
\newcommand{\tikzAngleOfLine}{\tikz@AngleOfLine}
\def\tikz@AngleOfLine(#1)(#2)#3{%
\pgfmathanglebetweenpoints{%
\pgfpointanchor{#1}{center}}{%
\pgfpointanchor{#2}{center}}
\pgfmathsetmacro{#3}{\pgfmathresult}%
} 

\def\roundloop[#1]#2#3{%
 \coordinate (rla) at (#2.east); 
 \path   (#2)--++(#1) coordinate (rlb);
 \tkzTgtFromP(#2,rla)(rlb)            
 \node (rlb) at (rlb) [circle through={(tkzFirstPointResult)}] {};
 \coordinate  (rlc) at (intersection 2 of #2 and rlb);
 \coordinate  (rld) at (intersection 1 of #2 and rlb);         
 \tikzAngleOfLine(rlb)(rld){\AngleStart}
 \tikzAngleOfLine(rlb)(rlc){\AngleEnd} 
 \tikzAngleOfLine(#2)(rlb){\AngleLabel}
 \ifdim\AngleStart pt<\AngleEnd pt
 \draw[red,thick,->]%
   let \p1 = ($ (rlb) - (rld) $), \n2 = {veclen(\x1,\y1)}
   in   
     (rlb) ++(\AngleLabel:\n2) node[fill=white]{#3}
     (rld) arc (\AngleStart:\AngleEnd:\n2); 
 \else 
  \draw[red,thick,->]%
   let \p1 = ($ (rlb) - (rld) $), \n2 = {veclen(\x1,\y1)}
   in   
     (rlb) ++(\AngleLabel:\n2) node[fill=white]{#3}
     (rld) arc (\AngleStart-360:\AngleEnd:\n2); 
   \fi 
  }
\begin{document}

\begin{tikzpicture} 
  \node[circle,draw] (O){first node}; 
  \roundloop[180:2]{O}{$\alpha$}
   \roundloop[0:1]{O}{$\beta$}  
     \roundloop[60:3]{O}{$\delta$}
   \roundloop[-120:4]{O}{$\gamma$} 
\end{tikzpicture} 

\end{document}  

output of code

Alan Munn
  • 218,180
Alain Matthes
  • 95,075
  • 1
    very nice solution. In my tikz picture i draw lines from node "A" to node "B". If i would like to use your concept and to place my number (in your example, $\alpha$, $\beta$, etc.) in the middle of the line. How should i change your code? – Eagle Nov 22 '11 at 12:56
  • Wow! Great. A question: why is \makeatletter not required? – Rmano Jul 30 '15 at 12:32
12

You could adjust angles and looseness for example this way:

\path[->,every loop/.style={looseness=10}] (foo)
         edge  [in=120,out=60,loop] node {1} (); 

loop example

Stefan Kottwitz
  • 231,401