how to draw a residual variance self-loop with tikz

842 views
Skip to first unread message

mike allerhand

unread,
Jul 4, 2013, 4:46:03 PM7/4/13
to lav...@googlegroups.com
LaTeX tikz is good for path diagrams, but does anyone know how to draw a self loop at a node with an arrow head at each end, for example to represent residual variance? (Bit of a side-trip, but useful).

mike allerhand

unread,
Jul 5, 2013, 9:06:41 AM7/5/13
to lav...@googlegroups.com
One way is to force a curve through a point outside the node, trying to keep continuity through the point: 

\begin{tikzpicture}
\node (A) at (0,0) [circle, draw] {} ;
\draw[latex-latex] (A.north east) to [bend right=60,out=40,in=90] ([xshift=0.5 cm]A.east) to  [bend right=60,out=90,in=140] (A.south east) ;
\end{tikzpicture}

It looks fair but not perfect. Maybe there's an easier way

yrosseel

unread,
Jul 10, 2013, 5:35:36 AM7/10/13
to lav...@googlegroups.com
On 07/05/2013 03:06 PM, mike allerhand wrote:
> One way is to force a curve through a point outside the node, trying to
> keep continuity through the point:
>
> \begin{tikzpicture}
> \node (A) at (0,0) [circle, draw] {} ;
> \draw[latex-latex] (A.north east) to [bend right=60,out=40,in=90]
> ([xshift=0.5 cm]A.east) to [bend right=60,out=90,in=140] (A.south east) ;
> \end{tikzpicture}

I have not found a better way (yet). Just out of curiosity, I tried to
run semPaths(fit) (from the semPlot package) and pipe the output through
the tikz Device (which is not on CRAN anymore; I had to compile it from
source). The resulting output for a single curve looks like this:

\path[draw=drawColor,line width= 0.4pt,dash pattern=on 4pt off 4pt ,line
join=round,line cap=round] (248.34,432.69) --
(248.16,432.95) --
(247.34,434.17) --
(246.37,435.79) --
(245.74,437.18) --
(245.52,438.35) --
(245.51,438.60) --
(245.62,439.58) --
(245.93,440.63) --
(246.45,441.73) --
(247.14,442.77) --
(247.95,443.68) --
(248.84,444.40) --
(249.24,444.66) --
(250.23,445.12) --
(251.36,445.43) --
(252.60,445.58) --
(253.86,445.53) --
(255.06,445.31) --
(256.12,444.93) --
(256.65,444.66) --
(257.56,444.02) --
(258.41,443.19) --
(259.16,442.19) --
(259.76,441.11) --
(260.16,440.03) --
(260.36,439.01) --
(260.38,438.60) --
(260.23,437.44) --
(259.69,436.12) --
(258.77,434.52) --
(257.86,433.13) --
(257.55,432.69) --
(257.55,432.69);

Not what I was hoping for.

Yves.

mike allerhand

unread,
Jul 24, 2013, 11:25:40 AM7/24/13
to lav...@googlegroups.com
I think translating a lavaan model into a tikz diagram cannot work unless for simple diagrams because its almost impossible to generate nice code that can be modified. Probably better is a library of shapes and painful practice with tikz. Here's another go at the variance self-loop looking a bit better.


\documentclass[border=1cm]{standalone}
\usepackage{tikz}
\usetikzlibrary{shapes.geometric}  % For regular polygon
\usetikzlibrary{calc}

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

% Add a variance self-loop to a node
%   #1 is the node 
%   #2 is the angle of the centre of the arc from the centre of the node  
\newcommand{\variance}[2] {
  \pgfmathsetmacro{\thetaA}{#2} ;  
  \pgfmathsetmacro{\thetaB}{\thetaA+15} ;
  \pgfmathsetmacro{\thetaC}{\thetaA-15} ;
  \coordinate (D) at (#1.\thetaB) ;
  \coordinate (E) at (#1.\thetaC) ;
  \coordinate (F) at ([xshift=6mm,rotate around={\thetaA:(#1.center)}]#1.center) ;    % Centre of arc  (xshift should depend on size of node)   
  \tikzAngleOfLine(F)(D){\AngleStart}
  \tikzAngleOfLine(F)(E){\AngleEnd}    
  \draw[latex-latex] (D) 
    let
      \p1 = ($(D)-(F)$),
      \n1 = {veclen(\x1,\y1)}      % Radius of arc
    in  
      arc [start angle=\AngleStart, end angle=\AngleEnd-360, radius=\n1] ;   % If both angles are in 4th quadrant the arc is short. Then you need to make the start angle be negative, (angle-360).
}

\begin{document}

\begin{tikzpicture}[
    render/.style = {draw=black!80, fill=black!5, inner sep=0, font=\scriptsize\sffamily\bfseries},
    lv/.style = {circle, render, minimum size=8mm},         % Latent variable
    ov/.style = {rectangle, render, minimum size=7mm},      % Observed variable
    lm/.style = {regular polygon, regular polygon sides=3, shape border rotate=0, render, minimum height=1cm} % Latent mean
  ]
 
\node (y1)  at (1,0) [ov] {} ;
\node (f1)  at (3,0) [lv] {} ;
\node (lm1) at (5,0) [lm] {} ;

\variance{y1}{90} ;  
\variance{f1}{135} ;
\variance{lm1}{270} ;
 
 \end{tikzpicture}

\end{document}

yrosseel

unread,
Jul 27, 2013, 3:30:52 AM7/27/13
to lav...@googlegroups.com
On 07/24/2013 05:25 PM, mike allerhand wrote:
> I think translating a lavaan model into a tikz diagram cannot work
> unless for simple diagrams because its almost impossible to generate
> nice code that can be modified. Probably better is a library of shapes
> and painful practice with tikz.

That is in fact a good idea. I you have more shapes, perhaps you can
bundle them somewhere and make them public?

Yves.

Alexander Beaujean

unread,
Aug 7, 2013, 9:52:32 PM8/7/13
to lav...@googlegroups.com
Here is the syntax I use (assuming the error term is at the bottom of the model and named X):

\draw [<->, thick, >=stealth', bend left=270, looseness=2] (X.south west) to node [swap] {a}  (X.south east);

Best,

Alex
Reply all
Reply to author
Forward
0 new messages