3

I want to draw observed and residual variances in a path diagram. I tried the following:

\documentclass{article}
\usepackage{amsmath}
\usepackage{tikz}

% Page style.
\pagestyle{empty}

% `tikz` options.
\usetikzlibrary{positioning}
\usetikzlibrary{arrows.meta}

\begin{document}

% Picture.
\begin{tikzpicture}
    % Define the nodes.
    \node[draw, rectangle, minimum width=1cm, minimum height=1cm] (X) {$X$};
    \node[draw, rectangle, minimum width=1cm, minimum height=1cm, right=2.5cm of X] (Y) {$Y$};
    \node[draw, circle, minimum width=0.8cm, minimum height=0.8cm, right=1cm of Y] (E) {$\varepsilon$};

    % Draw the arrows.
    \draw[very thick, arrows={-Triangle[length=0.25cm, width=0.2cm]}] (X) -- (Y) node[midway, fill=white] {$\beta$};
    \draw[very thick, arrows={-Triangle[length=0.25cm, width=0.2cm]}] (E) -- (Y);

    % Draw variances.
    \draw [
        very thick,
        arrows={[length=0.25cm, width=0.2cm]Triangle-Triangle[length=0.25cm, width=0.2cm]},
        looseness=4,
        bend right=105,
    ] (X.145) to node [midway, fill=white] {$\sigma^{2}$} (X.215);

    \draw [
        very thick,
        arrows={[length=0.25cm, width=0.2cm]Triangle-Triangle[length=0.25cm, width=0.2cm]},
        looseness=4,
        bend left=105,
    ] (E.45) to node [midway, fill=white] {$\theta$} (E.315);
\end{tikzpicture}

\end{document}

Which produces the following output:

enter image description here

I would like the variance arrows (i.e., the double arrowhead arrows) to have a perfectly circular shape, more in line with what I saw elsewhere:

enter image description here

Ideally, I would like:

  • to control the radius of the variance arrow circle without fiddling with looseness and bend
  • regardless of the size of the node (i.e., 1cm for X and 0.8cm for the residual) I would prefer the radius of the variance arrow circle to remain constant

I would greatly appreciate any input and accompanying explanation on how to achieve this.


Edit

I updated the question based on Qrrbrbirlbel's comments below as follows:

% Load additional `tikz` library.
\usetikzlibrary{bending}

% ...

% Adjusted picture environment.
\begin{tikzpicture}
    % Define the nodes.
    \node[draw, rectangle, minimum width=1cm, minimum height=1cm] (X) {$X$};
    \node[draw, rectangle, minimum width=1cm, minimum height=1cm, right=2.5cm of X] (Y) {$Y$};
    \node[draw, circle, minimum width=0.8cm, minimum height=0.8cm, right=1cm of Y] (E) {$\varepsilon$};

    % Draw the arrows.
    \draw[very thick, arrows={-Triangle[length=0.25cm, width=0.2cm]}] (X) -- (Y) node[midway, fill=white] {$\beta$};
    \draw[very thick, arrows={-Triangle[length=0.25cm, width=0.2cm]}] (E) -- (Y);

    % Define angles.
    \def \angleX {145}
    \def \angleE {45}

    % Draw variances.
    \draw [
        very thick,
        arrows={[length=0.25cm, width=0.2cm]Triangle-Triangle[length=0.25cm, width=0.2cm]},
    ] (X.\angleX) arc[start angle=(\angleX-90), end angle=(360-(\angleX-90)), radius=0.45] node[midway, fill=white]{$\theta$};

    \draw [
        very thick,
        arrows={[length=0.25cm, width=0.2cm]Triangle-Triangle[length=0.25cm, width=0.2cm]},
    ] (E.\angleE) arc[start angle=(\angleE), end angle=(360-\angleE), radius=0.5] node[midway, fill=white]{$\theta$};
\end{tikzpicture}

% ...

Which results in:

enter image description here

It is still not clear how to proceed about the theta arrow. Also, I can see that the positioning of the arrows is very much coincidental, in the sense that if I change

arc[start angle=(\angleX-90), end angle=(360-(\angleX-90)), radius=0.45]

to

arc[start angle=(\angleX-110), end angle=(360-(\angleX-110)), radius=0.45]

the alignment with the node X is broken again, i.e.:

enter image description here

4
  • 2
    I also recommend loading the bending library if you want to use arrow tips on curved paths. Otherwise the paths get malformed, depending on the arrow tip and its size. Oct 28, 2023 at 10:46
  • 1
    This helps a lot! I will update my question to include your suggestions and display the result.
    – Mihai
    Oct 28, 2023 at 10:48
  • 1
    As feared, my previous approach was a bit naive (it ignored the node size). I've added an answer with my ext.paths.arcto library. The math is done by PGF then and you only need to specify start/end and radius. Oct 28, 2023 at 21:53
  • 1
    This has gotten four answers but only 1 up-vote (prior to mine). Come on, TeX-SX community, we're meant to be the friendly site! If it's worth answering, it's worth voting up. Oct 28, 2023 at 22:01

4 Answers 4

2

The ext.paths.arcto library of my tikz-ext package allows to specify start and end point as well as radius of an arc to be drawn. The arc to path operation needs two additional information, namely direction and size, to figure out which of the four arcs between two points you need. In this case, these are counter clockwise (because start and end point lie in counter clockwise order) and large (because we want the bigger part of the circle to be drawn).

The circle loop = <direction> can be used with the to or the edge path operation to so that you only need to specify the node name once and every other calculation is done by the style. The values of circle loop radius and circle loop spread are used. The spread defines the angular difference between start and end point on the node's border.

The <direction> parameter specifies where the middle of this circle loop lies. For now, this needs to an actual number. With a bit more effort we could allow circle loop = west or circle loop = east to work. Though, you can always just define cloop right/.style={circle loop = 0} and so on, similarly to the loop keys of TikZ.

Code

\documentclass[tikz]{standalone}
\usepackage{tikz}
\usetikzlibrary{
  chains,          % easy placement of nodes in a row
  arrows.meta,     %
  bending,         % for flex option (for arrow tips on tightly curved paths)
  ext.paths.arcto} % for arcto path operation
\tikzset{
  math nodes/.style={execute at begin node=$, execute at end node=$},
  circle loop radius/.initial=.5cm,
  circle loop spread/.initial=60,
  circle loop/.style={
    to path={
      (\tikztostart.{#1-(\pgfkeysvalueof{/tikz/circle loop spread})/2})
      arc to[counter clockwise, large,
             radius=\pgfkeysvalueof{/tikz/circle loop radius}]
      (\tikztostart.{#1+(\pgfkeysvalueof{/tikz/circle loop spread})/2})
      \tikztonodes }}}
\begin{document}
\begin{tikzpicture}[
  rect/.style={shape=rectangle, draw, minimum size=+1cm},
  circ/.style={shape=circle,    draw, minimum size=+.8cm},
%  Tri/.tip={Triangle[length=+.25cm, width=+.2cm]},
  Tri/.tip={Triangle[angle'=45, scale=1.15]}, % scales with line width
  > = Tri,
  arr/.style={very thick, nodes={fill=white}, shape=circle, inner sep=+.15em},
  math nodes,
]
\begin{scope}[start chain=going right, nodes=on chain]
\node[rect] (X) {X};
\node       (b) {\beta};
\node[rect] (Y) {Y};
\node[circ] (e) {\varepsilon};
\end{scope}
\path[arr] (X) edge (b)
           (b) edge[->] (Y)
           (Y) edge[<-] (e)
           (X) edge[<->, circle loop=180] node {\theta} ()
           (e) edge[<->, circle loop=  0] node {\theta} ()
               edge[<->, gray, thick, % changing the spread
                         circle loop=  0, circle loop spread=90] ()
;
\end{tikzpicture}
\end{document}

Output

enter image description here

2
  • 1
    Of course, the circle loop radius, the circle loop spread and the size of the node have some relationship that won't always work correctly. PGF seems to silently ignore the radius specification if the points are too far away and just draw a semicircle then. If the radius should depend on the node size, we need to adjust the to path further. Oct 28, 2023 at 21:57
  • This helps a lot and seems clear! I am trying it and will report back.
    – Mihai
    Oct 30, 2023 at 2:22
4

No solution yet, just some clean-up, to better see the forrest amongst the trees, i.e. your relevant structures:

%\documentclass{article}
\documentclass[10pt,border=3mm,tikz]{standalone}
\usepackage{amsmath}
%\usepackage{tikz}% already included, see above

% Page style.
%\pagestyle{empty}

% `tikz` options.
\usetikzlibrary{positioning}
\usetikzlibrary{arrows.meta}

\begin{document}

% Picture.
\begin{tikzpicture}[% some clean-up via self defined styles
        nda/.style={draw, rectangle, minimum width=1cm, minimum height=1cm,fill=white},
        ndb/.style={draw, circle, minimum width=0.8cm, minimum height=0.8cm,},
        dra/.style={very thick, arrows={-Triangle[length=0.25cm, width=0.2cm]}},
        drb/.style={very thick, arrows={[length=0.25cm, width=0.2cm]Triangle-Triangle[length=0.25cm, width=0.2cm]}, looseness=4,},
    ]
    % Define the nodes.
    \node[nda]                      (X) {$X$};
    \node[nda, right=2.5cm of X]    (Y) {$Y$};
    \node[ndb, right=1cm of Y]      (E) {$\varepsilon$};

    % Draw the arrows.
    \draw[dra] (X) -- (Y) node[midway, fill=white] {$\beta$};
    \draw[dra] (E) -- (Y);

    % Draw variances.
    \draw [drb, bend right=105] (X.145) to 
            node [midway, fill=white] {$\sigma^{2}$} (X.215);

    \draw [drb, bend left=105]  (E.45 ) to 
            node [midway, fill=white] {$\theta$} (E.315);
\end{tikzpicture}

\end{document}

result

2
  • 2
    This is, indeed, much cleaner and neater!
    – Mihai
    Oct 28, 2023 at 9:36
  • I suggest to lower the inner sep for the theta node if you want the arrow to touch more the theta symbol. But I think it's better like MS-SPO did, visually.
    – SebGlav
    Oct 28, 2023 at 10:04
4

Purely for comparison, here is a version drawn using lualatex and the built-in Metapost language. I've tried to follow a clear approach: define the paths, draw them all, then add the labels. I've used the handy cutbefore and cutafter operators, to make the loops from circles. Follow the link above for tutorials and reference material.

enter image description here

You need to compile this with lualatex.

\documentclass[border=5mm]{standalone}
\usepackage{luamplib}
\begin{document}
\mplibtextextlabel{enable}
\begin{mplibcode}
beginfig(1);
  path x_box, y_box, e_circle, sigma_loop, theta_loop, xy_arrow, ey_arrow;

  y_box = unitsquare shifted -(1/2,1/2) scaled 32;
  x_box = y_box shifted 100 left;
  e_circle = fullcircle scaled 24 shifted 42 right;

  xy_arrow = point 3/2 of x_box -- point 7/2 of y_box;
  ey_arrow = point 4 of e_circle -- point 3/2 of y_box;

  sigma_loop = fullcircle scaled 32
               shifted point 7/2 of x_box 
               shifted 12 left
               cutbefore x_box
               cutafter x_box;

  theta_loop = fullcircle scaled 24 rotated 180
               shifted point 0 of e_circle
               shifted 8 right
               cutbefore e_circle
               cutafter e_circle;

  ahangle := 30;
  drawoptions(withpen pencircle scaled 3/4);
  drawarrow xy_arrow;
  drawarrow ey_arrow;
  drawdblarrow sigma_loop;
  drawdblarrow theta_loop;
  drawoptions();

  draw x_box; label("$X$", center x_box);
  draw y_box; label("$Y$", center y_box);
  draw e_circle; label("$\epsilon$", center e_circle);

  vardef do_filled_label(expr t, z) = 
    save p; picture p; p = thelabel(t, z);  unfill bbox p; draw p;
  enddef;

  do_filled_label("$\sigma^2$", point 4 of sigma_loop shifted 2 right);
  do_filled_label("$\theta$", point 4 of theta_loop);
  do_filled_label("$\beta$", point 1/2 of xy_arrow);

endfig;
\end{mplibcode}
\end{document}
3

Your solution is not so bad, but is not entirely clear what you after. That bendend arows has circled shapes?.

With circle shape arrow to my opinion doesn't look so good ...

\documentclass[margin=3mm]{standalone}
\usepackage{amsmath}
\usepackage{tikz}
\usetikzlibrary{arrows.meta, 
                bending,
                positioning}

\begin{document}
    \begin{tikzpicture}[
alr/.style = {thick, {Triangle[flex']}-{Triangle[flex]}},
arr/.style = {thick, -Triangle},
lbl/.style = {fill=white, inner sep=2pt, midway},
  C/.style = {circle, draw,  minimum width=1cm, inner sep=2pt},
  N/.style = {draw, minimum size =1cm, outer sep=0pt},
                        ]
\node[N] (X) {$X$};
\node[N, right=2.5cm of X] (Y) {$Y$};
\node[C, right=1cm of Y] (E) {$\varepsilon$};
% Draw arrows
\draw[arr] (X) -- node[lbl] {$\beta$} (Y) ;
\draw[arr] (E) -- (Y);
% Draw variances
\draw [alr] (X.west) ++ (0,0.866025/2) arc (60:300:0.5) node [lbl] {$\sigma^2$};% 0.886025=sin(60)
\draw [alr] (E.center) ++ (-60:0.5) arc (-120:120:0.5) node [lbl] {$\theta$};
% test circle, remove in real document
\draw [red, densely dashed, very thin] (X.west) ++ (-0.25,0) circle[radius=0.5];
    \end{tikzpicture}
\end{document}

enter image description here

2
  • Very nice work +1.
    – Sebastiano
    Oct 28, 2023 at 12:19
  • 1
    @Sebastiano, thank you very much!
    – Zarko
    Oct 28, 2023 at 12:24

You must log in to answer this question.

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