6

I'm trying to draw a diagram and my code is getting too cluttered and difficult to read. For code style purposes, is it possible to define a node in one place and mess with its positioning later?

Suppose I have something simple like this:

\documentclass{standalone}
\usepackage{tikz}

\makeatletter
\tikzstyle{mystyle} = [rectangle,rounded corners,fill=blue!20]
\makeatother

\begin{document}
    \begin{tikzpicture}[font=\sffamily]    
        \node[mystyle](node1) at (0, 0) {A};
        \node[mystyle](node2) [left of=node1] {B};
    \end{tikzpicture}
\end{document}

What I want to be able to do is:

\begin{tikzpicture}[font=\sffamily]    
    \node[mystyle](node1) {A};
    \node[mystyle](node2) {B};

    \somecommand (node1) at (0, 0)
    \somecommand (node2) [left of=node1] 

\end{tikzpicture}

Is that possible?

Or maybe turn something like this:

\begin{tikzpicture}[font=\sffamily]

\matrix  {
    \node[mystyle](node1){A}; & \node[mystyle](node3){D}; \\
    \node[mystyle](node2){B}; & \node[mystyle](node4){C}; \\
};

\end{tikzpicture}

into something like this:

\begin{tikzpicture}[font=\sffamily]

\node[mystyle](node1){A};
\node[mystyle](node2){B};
\node[mystyle](node3){C};
\node[mystyle](node4){D};

\matrix  {
    \something (node1); & \something (node3); \\
    \something (node2); & \something (node4); \\
};

\end{tikzpicture}

Is there any way to do this?

  • Maybe you could use a pic? – cfr Nov 14 '14 at 15:31
  • 1
    Begin by defining coordinates called Coor1 ... then at the end place nodes at this coordinates \node[style] at (Coor1) {stuff}. – Tarass Nov 14 '14 at 15:42
  • Or you may add positioning with a style at=coord so positioning can appear in style definitions (but before use) – Bordaigorl Nov 22 '14 at 16:14
  • All characteristics of a node (position, content, color, etc.) can be store in a style... – Paul Gaborit Nov 22 '14 at 16:25
4

I am not sure what you are really doing so this may be completely unhelpful. If so, just say and I can delete it.

You can use pics to define small pictures which you can reuse later over and over.

Technically, you could create a pic for each node you want and then call the relevant code at the relevant point. However, this is really an abuse of the syntax, I think. If you are creating many similar nodes, however, it would make perfect sense to do this.

Be warned that, although pics are quite node-like, they are not perfectly node-like so this may not work well at all in your actual document.

\documentclass[border=5pt,mult,tikz]{standalone}

\begin{document}

  \tikzset{
    font=\sffamily,
    mystyle/.style = {rectangle, rounded corners, fill=blue!20},
  }

  \begin{tikzpicture}% abuse of pics?
    [
      node1/.pic={
        \node [mystyle, pic actions] (node1) {A};
      },
      node2/.pic={
        \node [mystyle, pic actions] (node2) {B};
      },
    ]
    \pic at (0,0) {node1};
    \pic [left of=node1] {node2};
  \end{tikzpicture}

  \begin{tikzpicture}% more sensible use of pics?
    [
      my node/.pic={
        \node [mystyle] {#1};
      },
    ]

    \matrix  {
      \pic {my node={A}}; & \pic {my node={D}}; \\
      \pic {my node={B}}; & \pic {my node={C}}; \\
    };

  \end{tikzpicture}

\end{document}

If you need to refer to pics in order to draw lines between them, for example, you cannot handle things quite so straightforwardly as if they were nodes because they will not automatically get anchors in the way that nodes do. However, you can use a special syntax to add named coordinates to your pic which you can use later. The way this works is that you add particular named coordinates in the definition e.g. (-my point) (notice the hyphen) and then you pass a name to the pic as you would to a node e.g. (my pic). You can then refer to your named point as e.g. my pic-my point. As I understand it, this is less efficient than using actual nodes but that may not be a huge concern unless your picture is very large when the use of pics could slow compilation time noticeably.

Here's an example which adds some named coordinates to the definition of my node and then uses them to place red circles which correspond to various anchors of the node defined in the pic itself. This is obviously just for purposes of illustration: in practice, you would no doubt not want small red circles everywhere! But the point is you can use these coordinates to e.g. draw lines between the nodes or whatever.

  \begin{tikzpicture}% more sensible use of pics?
    [
      my node/.pic={
        \node (-center) [mystyle] {#1};
      \foreach \i in {north,south,east,west,north west,north east,south west,south east}
        \coordinate (-\i) at (-center.\i);
      },
    ]

    \matrix  {
      \pic (a) {my node={A}}; & \pic (d) {my node={D}}; \\
      \pic (b) {my node={B}}; & \pic (c) {my node={C}}; \\
    };

    \foreach \i in {a,b,c,d}
      \foreach \j in  {north,south,east,west,north west,north east,south west,south east,center}
        \path [fill=red] (\i-\j) circle (.5pt);;

  \end{tikzpicture}

naming pic coordinates

  • Hey there, is there a way to uniquely identify the \pic instances of nodes such that I can draw lines between each of them? I am drawing a network diagram and this code is perfect for drawing data storage devices (need many of them), but I need a way to identify each one uniquely. If that can be done, I will be a happy camper. The code looks so nice and organized. Thanks in advance for your input! – Jonathan Komar Nov 22 '14 at 13:47
  • 1
    @macmadness86 Please see edited answer. Note that the red circles are just to demonstrate the idea - you would e.g. draw arrows between these points rather than giving your nodes measles! – cfr Nov 22 '14 at 16:06
  • 1
    @macmadness86 That's fine. The A is just the content of the node. The a or whatever is the name. So just say \pic (a1) {my node={A}}; and \pic (a2) {my node={A}}; or whatever. You can have unique names for pics whose nodes get the same content. Maybe I just don't understand what you are asking but I'm not seeing the problem. – cfr Nov 22 '14 at 16:41
  • 1
    This might seem stupid, but I couldn't figure out how to type/send a message in the chat room. I still don't know how. – Jonathan Komar Nov 23 '14 at 7:38
  • 1
    @macmadness86 I can't get it to work with a shadow either. I think you should ask this as a new question as it seems distinct from your initial question and will be more likely to get attention that way. (Link to this one so people can see the background if they want.) Your style works fine without the shadow. Agree about the chat interface. – cfr Nov 23 '14 at 12:04
3

You could also just define your own macro that builds the \node content.. On the left is the manually specified examples you provided and on the right are the ones obtained by calling \Node:

enter image description here

Notes:

Code:

\documentclass{article}
\usepackage{tikz}

\tikzset{mystyle/.style={rectangle,rounded corners,fill=blue!20}}

\newcommand{\Node}[2][]{%
    % #1 = node options
    % #2 = node text
    \node[mystyle,#1] (node1) at (0,0) {#2}
}%


\begin{document}
    \begin{tikzpicture}[font=\sffamily]    
        \node[mystyle](node1) at (0, 0) {A};
        \node[mystyle](node2) [left of=node1] {B};
    \end{tikzpicture}    
    \hspace*{2.0cm}
    \begin{tikzpicture}[font=\sffamily]    
        \Node{A};
        \Node[left of=node1]{B};
    \end{tikzpicture}

    \bigskip\par
    \begin{tikzpicture}[font=\sffamily]    
        \matrix  {
            \node[mystyle](node1){A}; & \node[mystyle](node3){D}; \\
            \node[mystyle](node2){B}; & \node[mystyle](node4){C}; \\
        };
    \end{tikzpicture}
    \hspace*{2.0cm}
    \begin{tikzpicture}[font=\sffamily]    
        \matrix  {
            \Node{A}; & \Node{D}; \\
            \Node{B}; & \Node{C}; \\
        };
    \end{tikzpicture}
\end{document}
3

Styles can greatly improve readability.

Here's a proof of concept using only styles.

The idea is to define a <name-of-node>pos style for each named node so that you can specify positioning by defining this style using keys like at or left etc, separately from the point of creation of the nodes.

\documentclass{standalone}
\usepackage{tikz}

\tikzset{
  mynode/.style = {
    rectangle,
    rounded corners,
    fill=blue!20,
    name=#1,
    #1pos/.try
  },
  position of/.style args={#1 is #2}{
    #1pos/.style={#2}
  }
}

\begin{document}

    \begin{tikzpicture}[
      font=\sffamily,
      position of=node1 is {at={(0,0)}},
      position of=node2 is {left of=node1}
    ]
      \node[mynode=node1] {A};
      \node[mynode=node2] {B};
    \end{tikzpicture}

\end{document}

Here the style position of is only used to improve readability over node1pos/.style={...}.

If you prefer to specify coordinates after creation (not necessary) you can wrap your figure in a macro definition:

\documentclass{standalone}
\usepackage{tikz}

\tikzset{
  mynode/.style = {
    rectangle,
    rounded corners,
    fill=blue!20,
    name=#1,
    #1pos/.try
  },
  % Only necessary for option 2
  position of/.style args={#1 is #2}{
    #1pos/.style={#2}
  }
}

\begin{document}

  \newcommand{\makepicture}[1][]{
    \begin{tikzpicture}[font=\sffamily,#1]
        \node[mynode=node1] {A};
        \node[mynode=node2] {B};
    \end{tikzpicture}
  }

  % Option 1
  \makepicture[
    node1pos/.style={at={(0,0)}},
    node2pos/.style={left of=node1}
  ]

  % Option 2
  \makepicture[
    position of=node1 is {at={(0,0)}},
    position of=node2 is {left of=node1}
  ]

\end{document}
  • I believe that the left=of node (with the positioning library) is now preferred to the older syntax. (But I'm not sure what the advantages are.) – cfr Nov 22 '14 at 22:50
  • @cfr yes that's deprecated but I wanted to stick to the OP's example, so the crucial points were more obvious – Bordaigorl Nov 23 '14 at 2:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.