TikZ start from scratch A Petri Net for Hagen

0. Preface

This tutorial is translated from the official TikZ document. Here we learn the drawing of node s

1. Problem statement

To draw such a picture

2. Create environment

\documentclass{article} 
\usepackage{tikz}
\usetikzlibrary{arrows} 
\usetikzlibrary{decorations.pathmorphing} % Used to draw a serpentine line at the center of the diagram
\usetikzlibrary{backgrounds} % Used to draw a gray background
\usetikzlibrary{positioning} % Used to place nodes by relative position
\usetikzlibrary{fit} % The size of the background rectangle can be easily calculated
\usetikzlibrary{petri}
\begin{document}
\begin{tikzpicture}
	\draw (0,0) -- (1,1);
\end{tikzpicture}
\end{document}

3. Node introduction

In principle, in addition to the serpentine line, we can already draw this picture with the knowledge of the previous section. But that method has serious disadvantages, that is, if you want to add positions (places, which refers to the circle in Petri Net), it will be very troublesome, and all coordinates must be recalculated; In addition, the readability of the code will be poor, because it is all some coordinates, so some internal structure information of Petri Net is omitted.

Fortunately, TikZ can use node to improve this situation. We mentioned node in the previous section. Now let's study it in depth. When creating a node, we need to provide location information and shape parameters, and some text can be placed in the node. In addition, node can be named for subsequent reference.

Here, we use node to implement places and transition (referring to the small rectangle in the figure), that is, instead of circle and rectangle learned in the previous section, we use node to draw them.

\path ( 0,2) node [shape=circle,draw] {}
( 0,1) node [shape=circle,draw] {}
( 0,0) node [shape=circle,draw] {}
( 1,1) node [shape=rectangle,draw] {}
(-1,1) node [shape=rectangle,draw] {};

How does this code work\ Path creates a path, first move to (0,2), and then draw a node. The node shape is a circle, and it specifies that draw is to be drawn, {} indicates that no text is added; Then move to (0,1) and draw the node... Note that no operation is performed during move. If you want to draw the connection, on the one hand, add -- after {} to indicate the connection, on the other hand, change the command to \ path[draw] or \ draw. (\ draw and node[draw] are different. The former is the drawing path and the latter is the drawing node).

4. Placing nodes with At statements

The above is a little cumbersome because mobile operation is added. In fact, this process can be simplified by at. At directly specifies the node to be placed, thus avoiding the rule of node positioning that "the node immediately follows which is the reference system" (see the previous section for details).

\path node at ( 0,2) [shape=circle,draw] {}
node at ( 0,1) [shape=circle,draw] {}
node at ( 0,0) [shape=circle,draw] {}
node at ( 1,1) [shape=rectangle,draw] {}
node at (-1,1) [shape=rectangle,draw] {};

In this way, the move operation is omitted, but there is still a path. In fact, it can be more concise and the path is saved:

\node at ( 0,2) [circle,draw] {};
\node at ( 0,1) [circle,draw] {};
\node at ( 0,0) [circle,draw] {};
\node at ( 1,1) [rectangle,draw] {};
\node at (-1,1) [rectangle,draw] {};

Different from the previous code: a semicolon is added after each node drawing operation, the shape parameter name is omitted (for example, the parameter name that will not cause ambiguity such as color shape can be omitted), and the \ path command is saved.

5. Use Styles

Let's color this picture to make it look better.

\node at ( 0,2) [circle,draw=blue!50,fill=blue!20] {};
\node at ( 0,1) [circle,draw=blue!50,fill=blue!20] {};
\node at ( 0,0) [circle,draw=blue!50,fill=blue!20] {};
\node at ( 1,1) [rectangle,draw=black!50,fill=black!20] {};
\node at (-1,1) [rectangle,draw=black!50,fill=black!20] {};


The diagram looks better, but the code segment looks ugly. We want to clearly express the three places and two transitions here. Don't look at the statements specified by so many colors. For this purpose, we can preset styles.

[place/.style={circle,draw=blue!50,fill=blue!20},
transition/.style={rectangle,draw=black!50,fill=black!20}]
\node at ( 0,2) [place] {};
\node at ( 0,1) [place] {};
\node at ( 0,0) [place] {};
\node at ( 1,1) [transition] {};
\node at (-1,1) [transition] {};

6. Node size

If the text is empty, TikZ will automatically set some white space for it. If we want to change the size, we can set the white space larger through the inner sep parameter.

[inner sep=2mm,
place/.style={circle,draw=blue!50,fill=blue!20,thick},
transition/.style={rectangle,draw=black!50,fill=black!20,thick}]
\node at ( 0,2) [place] {};
\node at ( 0,1) [place] {};
\node at ( 0,0) [place] {};
\node at ( 1,1) [transition] {};
\node at (-1,1) [transition] {};


But a better way is to set the minimum size. With the minimum size, if you add some text, the node will automatically become larger. If the text is empty, it will be the minimum size. Through minimum height and minimum width, we can also set the minimum height and minimum width.

[place/.style={circle,draw=blue!50,fill=blue!20,inner sep=0pt,minimum size=6mm},
transition/.style={rectangle,draw=black!50,fill=black!20,inner sep=0pt,minimum size=4mm}]
\node at ( 0,2) [place] {};
\node at ( 0,1) [place] {};
\node at ( 0,0) [place] {};
\node at ( 1,1) [transition] {fffffffff};
\node at (-1,1) [transition] {};


The text is too crowded, which can be solved by increasing the inner sep of transition

[place/.style={circle,draw=blue!50,fill=blue!20,inner sep=0pt,minimum size=6mm},
transition/.style={rectangle,draw=black!50,fill=black!20,inner sep=1pt,minimum size=4mm}]
\node at ( 0,2) [place] {};
\node at ( 0,1) [place] {};
\node at ( 0,0) [place] {};
\node at ( 1,1) [transition] {fffffffff};
\node at (-1,1) [transition] {};

7. Named node

The next step is to add an arrow, but it seems very troublesome, because the arrow must be drawn not from the center of the figure, but from the edge of the circle and rectangle. If you have to calculate the coordinates (for example, which point is the radius when the center of the circle is shifted to the right), it will be troublesome.
Fortunately, PGF can automatically help us do these things, but in that case, we have to name the node first.

There are two ways to name a node. One is to use the name = option, and the other is to put the name in parentheses. Here we introduce the second.

\node[place] (waiting 1) at ( 0,2) {};
\node[place] (critical 1) at ( 0,1) {};
\node[place] (semaphore) at ( 0,0) {};
\node[transition] (leave critical) at ( 1,1) {};
\node[transition] (enter critical) at (-1,1) {};

To make it easier to read, the options are placed immediately after \ node. The name can be arbitrary, including underscores and hyphens, as long as there are no commas, periods, parentheses, colons and other special characters.

8. Placing nodes using relative positions

Before connecting nodes, we have to solve a problem, that is, the placement of nodes. The at statement is very useful, but it can't reflect the correlation of nodes. For example, critical 1 should be under waiting 1. There are many ways to implement it. The better thing is that the below option is implemented through the positioning library.

\node[place] (waiting) {};
\node[place] (critical) [below=of waiting] {};
\node[place] (semaphore) [below=of critical] {};
\node[transition] (leave critical) [right=of critical] {};
\node[transition] (enter critical) [left=of critical] {};

9. Add dimensions next to nodes

Before connecting the nodes, we first add to the semaphore places at the bottom s ≤ 3 s\le 3 capacity of s ≤ 3.
There are two ways.

  • Add a new node to the north of the semaphore node (applicable in any case).
[place/.style={circle,draw=blue!50,fill=blue!20,inner sep=0pt,minimum size=6mm},
transition/.style={rectangle,draw=black!50,fill=black!20,inner sep=1pt,minimum size=4mm}]
\node[place] (waiting) {};
\node[place] (critical) [below=of waiting] {};
\node[place] (semaphore) [below=of critical] {};
\node[transition] (leave critical) [right=of critical] {};
\node[transition] (enter critical) [left=of critical] {};

\node[red,above] at (semaphore.north) {$s\le 3$};

  • Use the dimension option, which is an optional parameter of node.
[place/.style={circle,draw=blue!50,fill=blue!20,inner sep=0pt,minimum size=6mm},
transition/.style={rectangle,draw=black!50,fill=black!20,inner sep=1pt,minimum size=4mm}]
\node[place] (waiting) {};
\node[place] (critical) [below=of waiting] {};
\node[place] (semaphore) [below=of critical,
label=above:\textcolor{red}{$ s\le 3 $}] {};
\node[transition] (leave critical) [right=of critical] {};
\node[transition] (enter critical) [left=of critical] {};

In addition to above, we can also set the position to low left and 60 (representing 60 degrees in polar coordinates).

\node[circle,draw,label=below:$ -90^\circ $,label=60:$ 60^\circ $] {my circle};


To change the annotation color to red, you can use label=above:\textcolor{red}{text}, label={[red]above:text}, or preset the style every label/.style={red}. The following is the complete code of the preset style

[place/.style={circle,draw=blue!50,fill=blue!20,inner sep=0pt,minimum size=6mm},
transition/.style={rectangle,draw=black!50,fill=black!20,inner sep=1pt,minimum size=4mm},
every label/.style={red}]
\node[place] (waiting) {};
\node[place] (critical) [below=of waiting] {};
\node[place] (semaphore) [below=of critical,
label=above:$ s\le 3 $] {};
\node[transition] (leave critical) [right=of critical] {};
\node[transition] (enter critical) [left=of critical] {};

10. Connection node

Finally, it's time to start connecting nodes. Let's start with a simple and connect the lines from enter critical to critical. To do this, we call the anchor of the node through < node's name >. < anchor's name >.

... % define styles
\node[place] (waiting) {};
\node[place] (critical) [below=of waiting] {};
\node[place] (semaphore) [below=of critical,
label=above:$ s\le 3 $] {};
\node[transition] (leave critical) [right=of critical] {};
\node[transition] (enter critical) [left=of critical] {};

\draw[->](enter critical.east)--(critical.west);

Now, let's draw a curve from waiting to enter critical. This is achieved by < a >.. controls < b > and < C >.. < d > drawing arcs.

\node[place] (waiting) {};
\node[place] (critical) [below=of waiting] {};
\node[place] (semaphore) [below=of critical,
label=above:$ s\le 3 $] {};
\node[transition] (leave critical) [right=of critical] {};
\node[transition] (enter critical) [left=of critical] {};

\draw[->] (enter critical.east)--(critical.west);
\draw[->] (waiting.west)..controls +(left:5mm) and +(up:5mm)..(enter critical.north);

Here + (left:5mm) and + (up:5mm) both describe the relative position (so as to locate the tangent line), indicating 5mm to the left of waiting.west and 5mm above enter critical.north.

This code can be optimized because TikZ can intelligently help us determine which side of the node the anchor will be on, so we can omit the anchor.

\node[place] (waiting) {};
\node[place] (critical) [below=of waiting] {};
\node[place] (semaphore) [below=of critical,
label=above:$ s\le 3 $] {};
\node[transition] (leave critical) [right=of critical] {};
\node[transition] (enter critical) [left=of critical] {};

\draw[->](enter critical)--(critical);
\draw[->](waiting)..controls+(left:5mm)and+(up:5mm)..(enter critical);


It seems that the arc is a bit like a straight line. Maybe TikZ is not so intelligent, so I chose to keep the anchor for the arc code and omit the straight line.

\node[place] (waiting) {};
\node[place] (critical) [below=of waiting] {};
\node[place] (semaphore) [below=of critical,
label=above:$ s\le 3 $] {};
\node[transition] (leave critical) [right=of critical] {};
\node[transition] (enter critical) [left=of critical] {};

\draw[->](enter critical)--(critical);
\draw[->](waiting.west)..controls+(left:5mm)and+(up:5mm)..(enter critical.north);


The arc code can be further optimized. We can use the to statement instead of the control and statement, and specify the tangent angle of the node and the tangent angle of the incoming node (both refer to the included angle with the polar axis. You can imagine a unit circle with a positive angle in the counterclockwise direction).

\node[place] (waiting) {};
\node[place] (critical) [below=of waiting] {};
\node[place] (semaphore) [below=of critical,
label=above:$ s\le 3 $] {};
\node[transition] (leave critical) [right=of critical] {};
\node[transition] (enter critical) [left=of critical] {};

\draw[->](enter critical)--(critical);
\draw[->](waiting.west) to[out=180,in=90] (enter critical.north);


This is closer to the 1 / 4 arc drawn by the control and statement. Love.
There is also a bend right and bend left option that can be used, but I think it is more difficult to understand. I think right and left are the opposite. It turns left, but it is bend right. It turns 90 degrees, but it is bend right=45..

Another way to specify an edge is the edge statement, which usually gives the connection to other nodes immediately after the node is defined.
In order to really understand the bend right and bend left parameters, I tried four examples with the edge statement. I found that the arc shape drawn by him had nothing to do with [- >] or [< -]

\node[place] (waiting) {};
\node[place] (critical) [below=of waiting] {};
\node[place] (semaphore) [below=of critical,
label=above:$ s\le 3 $] {};
\node[transition] (leave critical) [right=of critical] {};
\node[transition] (enter critical) [left=of critical] {}
edge [->] (critical)
edge [bend left=45,red] (waiting)
edge [bend right=45,blue] (waiting)
edge [bend left=45,red] (semaphore)
edge [bend right=45,blue](semaphore);


My explanation is that bend right or bend left depends on the connection segment between the defined node and the node to be reached. From the direction of the node, if the line is broken to the left, it is bend left, and vice versa. But I really can't explain the to statement,,,

\node[place] (waiting) {};
\node[place] (critical) [below=of waiting] {};
\node[place] (semaphore) [below=of critical,
label=above:$ s\le 3 $] {};
\node[transition] (leave critical) [right=of critical] {}
edge [<-] (critical)
edge [<-,in=0,out=270] (semaphore)
edge [->,bend right=45] (waiting);
\node[transition] (enter critical) [left=of critical] {}
edge [->] (critical)
edge [<-,bend left=45] (waiting)
edge [->,bend right=45](semaphore);

Note: in the edge statement, [< -] or [- >] does not affect the direction, but only the position of the arrow tip. It is not normal to use the in-out option. I feel that I have to try a few more before I can try it out. I don't quite understand its principle.

We can preset the style of arrow connection. The preset bending angle is 45 degrees. Through pre and post, note that the codes of all styles should be placed in the same square bracket.

[place/.style={circle,draw=blue!50,fill=blue!20,inner sep=0pt,minimum size=6mm},
transition/.style={rectangle,draw=black!50,fill=black!20,inner sep=1pt,minimum size=4mm},every label/.style={red},
bend angle=45,
pre/.style={<-,shorten <=1pt,>={Stealth[round]},semithick},
post/.style={->,shorten >=1pt,>={Stealth[round]},semithick}]
\node[place] (waiting) {};
\node[place] (critical) [below=of waiting] {};
\node[place] (semaphore) [below=of critical,
label=above:$ s\le 3 $] {};
\node[transition] (leave critical) [right=of critical] {}
edge [pre] (critical)
edge [pre,bend left] (semaphore)
edge [post,bend right] (waiting);
\node[transition] (enter critical) [left=of critical] {}
edge [post] (critical)
edge [pre,bend left] (waiting)
edge [post,bend right](semaphore);

11. Add dimensions to lines


In the 9 kinds of nodes, we add labels next to them. Here we learn how to add labels to wires.
Of course, we can add nodes manually, but through the auto parameter, we can automatically add text next to the line instead of on the line; Through swap, we perform the mirroring operation, because it is added on the inner side by default.

\node[place] (waiting) {};
\node[place] (critical) [below=of waiting] {};
\node[place] (semaphore) [below=of critical,
label=above:$ s\le 3 $] {};
\node[transition] (leave critical) [right=of critical] {}
edge [pre] (critical)
edge [pre,bend left] (semaphore)
edge [post,bend right] node[auto,swap]{2} (waiting);
\node[transition] (enter critical) [left=of critical] {}
edge [post] (critical)
edge [pre,bend left] (waiting)
edge [post,bend right](semaphore);

12. Add serpentine and multiline text

To do this, we need to add decorate and decoration=snake in the optional parameters. This requires importing TikZ's improvements.pathmorphing library.
This drawing is not right, because the arrow looks bad. In fact, we can set more parameters.

\draw[->,decorate,decoration={snake,amplitude=.4mm,segment length=10mm,post length=1mm}] (0,0)--(2,0);
\draw[->,decorate,decoration={snake,amplitude=1mm,segment length=4mm,post length=1mm}] (0,-1)--(2,-1);
\draw[->,decorate,decoration={snake,amplitude=1mm,segment length=10mm,post length=1mm}] (0,-2)--(2,-2);
\draw[->,decorate,decoration={snake,amplitude=.4mm,segment length=10mm,post length=5mm}] (3,0)--(5,0);
\draw[->,decorate,decoration={snake,amplitude=1mm,segment length=4mm,post length=5mm}] (3,-1)--(5,-1);
\draw[->,decorate,decoration={snake,amplitude=1mm,segment length=10mm,post length=5mm}] (3,-2)--(5,-2);

Amplitude specifies the amplitude, segment length is similar to the period length, and post length is about the length of the straight line segment at the end of arrow tip

The following is to add multiple lines of text. There are two methods. In both methods, we need to specify align=center first (or left right, but we must specify the alignment, otherwise we can't wrap lines)

  • Then use \ \ to force a line break.
\draw[->,decorate,decoration={snake,amplitude=.4mm,segment length=2mm,post length=1mm}](0,0)--(3,0)node[above,midway,align=center]
{replacement of\\the capacity\\by two places};

Because we have made the position midway, it doesn't matter where the node is placed in the statement.

  • This is achieved by specifying the text width TeX \TeX TE # X auto wrap.
\draw[->,decorate,decoration={snake,amplitude=.4mm,segment length=2mm,post length=1mm}](0,0)--(3,0)node[above,midway,align=center,text width=3cm]
{replacement of the \textcolor{red}{capacity} by \textcolor{red}{two places}};

13. Working with layers: rectangular background

This is a bit tricky. We must draw a rectangle after drawing Petri Net, because we don't know how big the Petri Net we draw is before we draw it. This can be achieved through TikZ's background library. After loading the background library, we can put part of the diagram in the scope with the on background layer option set. When the tikzpicture environment ends, the layers are stacked up in turn, and the background layer is stacked first.

Another tricky question is, what about the size of the background rectangle? Of course, you can manually calculate the abscissa and ordinate, but a better way is to let TikZ calculate a rectangle suitable for all nodes. This is about to import the fit library. It defines the fit option. When a node is given, it will resize the node and move the node so that all nodes are covered by the background.

\node[place] (waiting) {};
\node[place] (critical) [below=of waiting] {};
\node[place] (semaphore) [below=of critical,
label=above:$ s\le 3 $] {};
\node[transition] (leave critical) [right=of critical] {}
edge [pre] (critical)
edge [pre,bend left] (semaphore)
edge [post,bend right] node[auto,swap]{2} (waiting);
\node[transition] (enter critical) [left=of critical] {}
edge [post] (critical)
edge [pre,bend left] (waiting)
edge [post,bend right](semaphore);

\begin{scope}[on background layer]
	\node [fill=black!30,fit=(waiting)(critical)(semaphore)(enter critical)(leave critical)] {};
\end{scope}

Note: the node shape is rectangular by default, so you can not specify a rectangle. Each node of fit is placed in parentheses. There can be no separator except spaces between parentheses. Remember to add {} representing empty text at the end.

14. Complete code

\documentclass{article} 
\usepackage{tikz}
\usetikzlibrary{arrows.meta} 
\usetikzlibrary{decorations.pathmorphing} % Used to draw a serpentine line at the center of the diagram
\usetikzlibrary{backgrounds} % Used to draw a gray background
\usetikzlibrary{positioning} % It is used to determine the node location conveniently
\usetikzlibrary{fit} % Rectangular dimensions can be easily calculated
\usetikzlibrary{petri}
\begin{document}
	\begin{tikzpicture}
		[
		node distance=1.3cm,on grid,>={Stealth[round]},bend angle=45,auto,
		every place/.style={minimum size=6mm,thick,draw=blue!75,fill=blue!20},
		every transition/.style={thick,draw=black!75,fill=black!20},
		red place/.style= {place,draw=red!75,fill=red!20},
		every label/.style={red}
		]
		\node [place,tokens=1] (w1) {};
		\node [place] (c1) [below=of w1] {};
		\node [place] (s) [below=of c1,label=above:$s\le 3$] {};
		\node [place] (c2) [below=of s] {};
		\node [place,tokens=1] (w2) [below=of c2] {};
		\node [transition] (e1) [left=of c1] {}
		edge [pre,bend left] (w1)
		edge [post,bend right] (s)
		edge [post] (c1);
		\node [transition] (e2) [left=of c2] {}
		edge [pre,bend right] (w2)
		edge [post,bend left] (s)
		edge [post] (c2);
		\node [transition] (l1) [right=of c1] {}
		edge [pre] (c1)
		edge [pre,bend left] (s)
		edge [post,bend right] node[swap] {2} (w1);
		\node [transition] (l2) [right=of c2] {}
		edge [pre] (c2)
		edge [pre,bend right] (s)
		edge [post,bend left] node {2} (w2);
		
		\begin{scope}[xshift=6cm]
			\node [place,tokens=1] (w1') {};
			\node [place] (c1') [below=of w1'] {};
			\node [red place] (s1') [below=of c1',xshift=-5mm]
			[label=left:$s$] {};
			\node [red place,tokens=3] (s2') [below=of c1',xshift=5mm]
			[label=right:$\bar s$] {};
			\node [place] (c2') [below=of s1',xshift=5mm] {};
			\node [place,tokens=1] (w2') [below=of c2'] {};
			\node [transition] (e1') [left=of c1'] {}
			edge [pre,bend left] (w1')
			edge [post] (s1')
			edge [pre] (s2')
			edge [post] (c1');
			\node [transition] (e2') [left=of c2'] {}
			edge [pre,bend right] (w2')
			edge [post] (s1')
			edge [pre] (s2')
			edge [post] (c2');
			\node [transition] (l1') [right=of c1'] {}
			edge [pre] (c1')
			edge [pre] (s1')
			edge [post] (s2')
			edge [post,bend right] node[swap] {2} (w1');
			\node [transition] (l2') [right=of c2'] {}
			edge [pre] (c2')
			edge [pre] (s1')
			edge [post] (s2')
			edge [post,bend left] node {2} (w2');
		\end{scope}
		\begin{scope}[on background layer]
			\node (r1) [fill=black!10,rounded corners,fit=(w1)(w2)(e1)(e2)(l1)(l2)] {};
			\node (r2) [fill=black!10,rounded corners,fit=(w1')(w2')(e1')(e2')(l1')(l2')] {};
		\end{scope}
		\draw [->,shorten >=1mm,
		-to, % Used to load the following pre option
		thick,decorate,
		decoration={snake,amplitude=.4mm,segment length=2mm,
			pre=moveto,
			pre length=1mm, %Length of straight line segment at the beginning of arrow
			post length=2mm}]
		(r1) -- (r2) node [above=1mm,midway,text width=3cm,align=center]
		{replacement of the \textcolor{red}{capacity} by \textcolor{red}{two places}};
	\end{tikzpicture}
\end{document}

Tags: Latex

Posted on Sat, 23 Oct 2021 19:57:28 -0400 by puja