23

Consider the following network:

\documentclass[11pt]{article}
\usepackage{tikz}
\usetikzlibrary{arrows,shapes,snakes,automata,backgrounds,petri}
\begin{document}

\begin{tikzpicture}[node distance=1.7cm]
\tikzstyle{place}=[circle,thick,draw=gray!75,fill=gray!20,minimum size=6mm]

\begin{scope}
\node [place] (s1c) [label=above:$c<0$] {$s_1$};
\node [place] (s2c) [below of=s1c] {$s_2$};

\draw[thick,->] (s2c) to [out=135,in=225] (s1c);
\draw[thick,-|] (s1c) to [out=-45,in=45] (s2c);

\draw[thick,->] (s1c) to [out=90,in=180] (s1c);
\draw[thick,-|] (s2c) to [out=-90,in=0] (s2c);
\end{scope}

\end{tikzpicture}

\end{document}

enter image description here

I would like to change four things in it:

  1. Have the arrows going from a node to itself make a nice, quarter-circle-like arc, in a natural-looking way. From this answer, I know that I can make a loop, but I don't know how to control the in/out-angles (as well as the arrow-thickness) and I'm thinking that there must be an easier way.
  2. Have the c<0 be higher above the first node.
  3. Have a small gap between the arrow start/end and the node. The 'shorten' option seem to just cut off the arrow-graphic such that it looses some of its arrowhead. (Not a problem anymore, see edit below.)
  4. Have an arrow point from northeast of the first node down to the first node at a 45 degree angle (such that the arrow is at a 270-45=225 degree angle), preferable without having to define another node.

Thanks.

EARLY EDIT:

From this answer, I found that I could fix problem 3. It also shows how to use the looseness-option to make the arrows from a node to itself look a bit nicer. However, it is still not what I am going for - I would like the curvature to be more evenly spread out throughout the arc of the arrow than the looseness-option seems to allow.

LATE EDIT: This answer gives an excellent solution to the first of the four problems.

3 Answers 3

20
  1. I usually oput a loop argument to the line for the arrow. It is not perfect arc-like, but reasonable.
  2. [above=10mm]
  3. shorten is the way to go. It does not clip the arrow tip. I put it to 1pt on all arriving edges but you can set to whatever you like. On bended lines like yours it looks strange if you take high values (like 1cm).
  4. Draw the line from the node and out.

Code:

\documentclass[11pt]{article}
\usepackage{tikz}
\usetikzlibrary{arrows,shapes,snakes,automata,backgrounds,petri}
\begin{document}

\begin{tikzpicture}[node distance=1.7cm]
\tikzstyle{place}=[circle,thick,draw=gray!75,fill=gray!20,minimum size=6mm]

\begin{scope}
\node [place] (s1c) {$s_1$} node[above=10mm]{$c<0$};
\node [place, below of=s1c] (s2c) {$s_2$};

\draw[thick,->,shorten >=1pt] (s2c) to [out=135,in=225] (s1c);
\draw[thick,-|,shorten >=1pt] (s1c) to [out=-45,in=45] (s2c);

\draw[thick,->,shorten >=1pt] (s1c) to [out=90,in=180,loop,looseness=4.8] (s1c);
\draw[thick,-|,shorten >=1pt] (s2c) to [out=-90,in=0,loop,looseness=4.8] (s2c);

\draw[thick,<-,shorten <=1pt] (s1c) -- +(45:1cm);
\end{scope}

\end{tikzpicture}

\end{document}

enter image description here

EDIT

One (not too elegant) way to get nicer arcs for the self loops is to use an arc. It can probably be better derived, here I used a more iterative (trial-and-error) approach. Replace the arcs with

\draw[red,thick,->] (s1c.90) arc (0:264:4mm);
\draw[red,thick,-|] (s2c.-90) arc (180:180+264:4mm);

to get

enter image description here

Late edit

To formulate a command for a circled arc one can do e.g.

\documentclass[border=5mm]{standalone}
\usepackage{tikz}
\usetikzlibrary{calc,arrows.meta}
%%
\usepackage{xparse}
\NewDocumentCommand\Cycle{O{} m m m O{} m}{%
  % [opt arg cycle]{Node}{Angle}{Node size}[opt arg arch node]{cycle size}
  \draw[#1](#2.{#3+asin(#6/(#4*1.41))}) arc (180+#3-45:180+#3-45-270:#6/2) #5;
}
%%
\begin{document}
\begin{tikzpicture}
  \node[draw,circle,minimum width=20mm,inner sep=0pt,thick](A) at (0,0) {A};
  \Cycle{A}{0}{20mm}{10mm}
  \Cycle[-{Latex[scale=1.2]}]{A}{90}{20mm}{15mm}
  \Cycle[{Latex[scale=0.8]}-]{A}{90}{20mm}{20mm}
  \Cycle[red,dashed,->]{A}{180}{20mm}[{node[anchor=0,pos=0.5,blue]{Test}}]{10mm}
  \foreach \r in {2,4,...,20}{%
    \Cycle[-{Latex[scale=0.5]}]{A}{270}{20mm}{\r mm}
  }
\end{tikzpicture}
\end{document}

enter image description here

0
8

With looseness option and use node names from automata library:

Edit: it seems that I overlooked latter added sub questions. According to them is corrected first example below. The code should be self-explanatory ...

\documentclass[11pt]{article}
\usepackage{tikz}
\usetikzlibrary{arrows, automata, calc, positioning}

\begin{document}
    \begin{tikzpicture}[
shorten >=1pt,>=stealth,
     node distance = 2cm, on grid,
every state/.style = {draw=gray!75, fill=gray!20, thick},
        bend angle = 45
                        ]
\node [state] (s1c) [label={[yshift=6mm] $c<0$}] {$s_1$};
\node [state] (s2c) [below=of s1c] {$s_2$};
%
\draw[thick,->] (s2c) edge [bend right] (s1c)
                (s1c) edge [looseness=5, out= 90, in=180] (s1c)
                ($(s1c)+(45:13mm)$) to (s1c);
\draw[thick,-|] (s1c) edge [bend right] (s2c)
                (s2c) edge [looseness=5, out=270, in=  0] (s2c);

    \end{tikzpicture}
\end{document}

enter image description here

It was not clear, if $c<0$ is condition for the loop at node s_1 or belong to node or image. In the former it should be label of the loop:

 \draw[thick,->] (s1c) to [looseness=5, out= 90, in=180] node[left] {$c<0$} (s1c);

and deleted as label of the first node. In this case you will obtain:

enter image description here

7

This answers question 1 and implicitly questions 2 and 4 (just use the above of (or above right of) syntax used elsewhere in this code). You already know how to take care of 3.

enter image description here

\documentclass[11pt]{article}
\usepackage{tikz}
\usetikzlibrary{arrows,shapes,snakes,automata,backgrounds,petri}
\usetikzlibrary{positioning}

\begin{document}

    \begin{tikzpicture}[node distance=1.7cm]
    \tikzstyle{place}=[circle,thick,draw=gray!75,fill=gray!20,minimum size=6mm]

    \begin{scope}
    \node [place] (s1c) [label=above right:$c<0$] {$s_1$};
    \node [place] (s2c) [below of=s1c] {$s_2$};
    \node[above = 1cm of s1c] (poop){};
    \node[left = 1cm of s1c] (peep){};
    \node[below = 1cm of s2c] (holy){};
    \node[right = 1cm of s2c] (moly){};

    \draw[thick,->] (s2c) to [out=135,in=225] (s1c);
    \draw[thick,-|] (s1c) to [out=-45,in=45] (s2c);

    \draw[thick,->] (s1c.north) ..  controls (poop) and (peep) .. (s1c.west);
    \draw[thick,->] (s2c.south) ..  controls (holy) and (moly) .. (s2c.east);
    \end{scope}

    \end{tikzpicture}

\end{document}
2
  • Thank you for your answer. My edit addresses how I'm not particularly happy with the curvature of the arrows in the node-to-itself-situation. Also, I don't see how this solves problem 2: If I define\node[above = 4cm of s1c] (poop){$c<0$}; the text is inside the node (s1c) no matter the choice of number of cms. Feb 16, 2017 at 15:22
  • That's odd. If I simply add the line ` \node[above = 4cm of s1c] (purp){$c<0$};` to my code then I get c<0 4cm above s1c. As for the first half of your question, just move the poop and peep nodes elsewhere and the curvature changes.
    – JPi
    Feb 16, 2017 at 15:35

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .