2

I'm drawing a lattice of nodes and I would like to highlight certain paths with different colors. When the paths overlap, I would like the colors to appear adjacent to each other. I've seen solutions on this site for when the nodes appear either only vertically or only horizontally displaced from one another. My situation, for which I haven't found an answer yet, is one where the nodes are offset by some nonzero slope.

I can kind of achieve the effect I want. But, I'm not entirely happy with my solution to this. It requires a bit too much tinkering on my part.

To duplicate what I've done, I'd like something to transform canvas orthogonally to some path. (Or perhaps there's another approach I'm unaware of.)

Here's my attempt at this,

enter image description here

Here's my code for this:

\documentclass[border=3pt]{standalone}

\usepackage{tikz}
\usetikzlibrary{calc}

\def\aev{\dimexpr12pt+0.65cm}
\def\aeh{\dimexpr12pt+1.00cm}
\newcommand\aes[2]{\scalebox{\ifcase#1\or1.00\or0.90\or0.80\or0.70\fi}{#2}}

\begin{document}
\begin{tikzpicture}[
  aec/.style={circle,draw,inner sep=1pt,minimum size=0.80cm},
  ae transform top/.style={transform canvas={yshift= 1.3pt,xshift= 0.3pt}},
  ae transform bot/.style={transform canvas={yshift=-1.3pt,xshift=-0.3pt}},
  ]

%% ------------------------------------------------------------
%% a bit of a work around for several issues                   
%% the primary one here is how "transformed" path connect      
%% at the nodes                                                
%% ------------------------------------------------------------
\coordinate (cA) at (0,0);
\coordinate (cB) at ($(cA.south)+(0,-\aev)$);
\coordinate (cC) at ($(cB.south)+(0,-\aev)$);
\coordinate (cD) at ($(cC.south)+(0,-\aev)$);
\coordinate (cAB) at ($($(cA.south)!0.5!(cB.north)$)+(\aeh,0pt)$);
\coordinate (cBC) at ($($(cB.south)!0.5!(cC.north)$)+(\aeh,0pt)$);
\coordinate (cCD) at ($($(cC.south)!0.5!(cD.north)$)+(\aeh,0pt)$);
\coordinate (cABC) at ($($(cAB.south)!0.5!(cBC.north)$)+(\aeh,0pt)$);
\coordinate (cBCD) at ($($(cBC.south)!0.5!(cCD.north)$)+(\aeh,0pt)$);
\coordinate (cABCD) at ($($(cABC.south)!0.5!(cBCD.north)$)+(\aeh,0pt)$);

\node[aec] (A) at (cA) {A};
\node[aec] (B) at (cB) {B};
\node[aec] (C) at (cC) {C};
\node[aec] (D) at (cD) {D};
\node[aec] (AB) at (cAB) {\aes{2}{AB}};
\node[aec] (BC) at (cBC) {\aes{2}{BC}};
\node[aec] (CD) at (cCD) {\aes{2}{CD}};
\node[aec] (BCD) at (cBCD) {\aes{3}{BCD}};

\draw (AB) -- (A);
\draw (AB) -- (B);
\draw (BC) -- (B);
\draw (BC) -- (C);
\draw (CD) -- (C);
\draw (CD) -- (D);
%\draw (ABC) -- (AB);
%\draw (ABC) -- (BC);
\draw (BCD) -- (BC);
\draw (BCD) -- (CD);
%\draw (ABCD) -- (ABC);
%\draw (ABCD) -- (BCD);

%% ------------------------------------------------------------
%% Using my "coordinate" construct work around to make the     
%% lines connecting nodes look more "beautiful                 
%% ------------------------------------------------------------

\draw[  red,line width=3pt]           (cABC) -- (BC);
\draw[green,line width=3pt]           (cABC) -- (AB) -- (B);

\draw[green,line width=3pt,ae transform top] (cABCD) -- (cABC);
\draw[  red,line width=3pt,ae transform bot] (cABCD) -- (cABC);

%% ------------------------------------------------------------
%% Using a more pure "node" approach to this, but the          
%% transformed colored paths don't connect to the nodes very   
%% beautifully and I'm not happy with that.                    
%% ------------------------------------------------------------

\node[aec,fill=white] (ABC) at (cABC) {\aes{3}{ABC}};
\node[aec,fill=white] (ABCD) at (cABCD) {\aes{4}{ABCD}};

\draw[ blue,line width=3pt] (ABCD) -- (BCD) -- (BC);

\draw[ red,line width=3pt,ae transform top] (BC) -- (B);
\draw[blue,line width=3pt,ae transform bot] (BC) -- (B);

\end{tikzpicture}
\end{document}

So, there are two issues I'd like fixed.

  1. The most important of the two is how to more easily transform canvas or use some other technique to color the same essential path in parallel (with up to three colors potentially used for the same path).

  2. Of secondary interest (since I already have a bit of a work-around) is: once I've got the path colored as I would like (point 1), how can I make the connection with the nodes more beautiful.

Regarding the second point, you can see the appearance created by my work around between nodes ABCD and ABC.

You can see the ugly connect created by not using my work-around between the nodes BC and B.

1 Answer 1

5

You can use the methode in this answer: Draw additional parallel paths in TikZ

-or as it is just lines, you can calculate the shift with calc notation. Line join to circle nodes will never be nice, when the line width is much larger than the node boundary width. I avoid this by drawing the lines in the background. Instead of understanding your code, I started over and I just copied code instead of making relevant styles.

\documentclass[tikz, border=1 cm]{standalone}
\usetikzlibrary{positioning,calc}
\tikzset{aec/.style={circle, draw, inner sep=1pt, minimum size=0.80cm, on grid, fill=white}}
\begin{document}
\pgfdeclarelayer{background}
\pgfsetlayers{background, main}
\begin{tikzpicture}[node distance=0.5 cm and 1.5cm]
\node[aec] (A) {A};
\node[aec, below right=of A] (AB) {\scalebox{0.9}{AB}};
\node[aec, below left=of AB] (B) {B};
\node[aec, below right=of B] (BC) {\scalebox{0.9}{BC}};
\node[aec, below left=of BC] (C) {C};
\node[aec, below right=of C] (CD) {\scalebox{0.9}{CD}};
\node[aec, below left=of CD] (D) {D};
\node[aec, below right=of AB] (ABC) {\scalebox{0.8}{ABC}};
\node[aec, below right=of BC] (BCD) {\scalebox{0.8}{BCD}};
\node[aec, below right=of ABC] (ABCD) {\scalebox{0.7}{ABCD}};
\begin{pgfonlayer}{background}
\draw (A) -- (AB);
\draw (C) -- (BC);
\draw (C) -- (CD);
\draw (D) -- (CD);
\draw[green, line width=3pt] (B.center) -- (AB.center);
\draw[green, line width=3pt] (AB.center) -- (ABC.center);
\draw[red,   line width=3pt] (BC.center) -- (ABC.center);
\draw[blue,  line width=3pt] (BC.center) -- (BCD.center);
\draw[blue,  line width=3pt] (BCD.center) -- (ABCD.center);
\draw[red,   line width=3pt] ($ (B.center)!1.5pt!90:(BC.center) $) -- ($ (BC.center)!1.5pt!-90:(B.center) $);
\draw[blue,  line width=3pt] ($ (B.center)!-1.5pt!90:(BC.center) $) -- ($ (BC.center)!-1.5pt!-90:(B.center) $);
\draw[green, line width=3pt] ($ (ABC.center)!1.5pt!90:(ABCD.center) $) -- ($ (ABCD.center)!1.5pt!-90:(ABC.center) $);
\draw[red,   line width=3pt] ($ (ABC.center)!-1.5pt!90:(ABCD.center) $) -- ($ (ABCD.center)!-1.5pt!-90:(ABC.center) $);
\end{pgfonlayer}
\end{tikzpicture}
\end{document}

Nodes with colored lines

To avoid calc completely, you could also do a shift={(\angle:1.5pt)} where \angle can be calculated with atan2 using the let notation. I would do a coordinate shift rather than a canvas shift.

Edit:

Node placement without positioning:

\documentclass[tikz, border=1 cm]{standalone}
\usetikzlibrary{calc}
\def\aev{\dimexpr12pt+0.65cm}
\def\aeh{\dimexpr12pt+1.00cm}
\begin{document}
\begin{tikzpicture}[
  aec/.style={circle,draw,inner sep=1pt,minimum size=0.80cm},
  ]
\coordinate (A) at (0,0);
\coordinate (B) at ([yshift=-\aev] A);
\coordinate (C) at ([yshift=-\aev] B);
\coordinate (D) at ([yshift=-\aev] C);
\coordinate (AB) at ($(A)!0.5!(B)+(\aeh,0)$);
\coordinate (BC) at ($(B)!0.5!(C)+(\aeh,0)$);
\coordinate (CD) at ($(C)!0.5!(D)+(\aeh,0)$);
\coordinate (ABC) at ($(AB)!0.5!(BC)+(\aeh,0)$);
\coordinate (BCD) at ($(BC)!0.5!(CD)+(\aeh,0)$);
\coordinate (ABCD) at ($(ABC)!0.5!(BCD)+(\aeh,0)$);
\foreach \text/\scale in {A/1, B/1, C/1, D/1, AB/2, BC/2, CD/2, ABC/3, BCD/3, ABCD/4}
\node[aec] at (\text) {\scalebox{\ifcase\scale\or1.00\or0.90\or0.80\or0.70\fi}{\text}};
\end{tikzpicture}
\end{document}

Node placement without positioning and without calc:

\documentclass[tikz, border=1 cm]{standalone}
\def\aev{\dimexpr12pt+0.65cm}
\def\aeh{\dimexpr12pt+1.00cm}
\begin{document}
\begin{tikzpicture}[
  aec/.style={circle,draw,inner sep=1pt,minimum size=0.80cm},
  ]
\coordinate (A) at (0,0);
\coordinate (B) at ([yshift=-\aev] A);
\coordinate (C) at ([yshift=-\aev] B);
\coordinate (D) at ([yshift=-\aev] C);
\path (A) --coordinate[right=\aeh](AB) (B);
\path (B) --coordinate[right=\aeh](BC) (C);
\path (C) --coordinate[right=\aeh](CD) (D);
\path (AB) --coordinate[right=\aeh](ABC) (BC);
\path (BC) --coordinate[right=\aeh](BCD) (CD);
\path (ABC) --coordinate[right=\aeh](ABCD) (BCD);
\foreach \text/\scale in {A/1, B/1, C/1, D/1, AB/2, BC/2, CD/2, ABC/3, BCD/3, ABCD/4}
\node[aec] at (\text) {\scalebox{\ifcase\scale\or1.00\or0.90\or0.80\or0.70\fi}{\text}};
\end{tikzpicture}
\end{document}

If nodes needs to be named, you can use e.g.:

\node[aec] (\text_node) at (\text) {\scalebox{\ifcase\scale\or1.00\or0.90\or0.80\or0.70\fi}{\text}};

for node names (A_node), ....

5
  • Life without calc will be nasty for what I'm actually doing. I had not thought of using the !1.5pt!90: approach since I rarely use it. Great suggestion. Also, great suggestion for the use of pgfonlayer. I had considered using A.center and if this were all I was doing with these points/nodes that would be fine. But, for my document with everything else I'm doing in it, using coordinates really seems more practical. Great ideas. Let me think on this a bit and play with it.
    – A.Ellett
    Oct 18, 2021 at 20:13
  • If you define all coordinates, draw all lines and first then draw all nodes - you will not need layers. Oct 18, 2021 at 20:24
  • Definitely. But, by the way, I didn't mean the comment about A.center as a criticism of your answer. I really like this answer for how you approached it all.
    – A.Ellett
    Oct 18, 2021 at 20:26
  • @A.Ellett: I made some additions - just in case you can use it. Oct 19, 2021 at 19:58
  • I wish I could upvote again. Your edit is beautiful. It's so clean compared to my code. Thank you.
    – A.Ellett
    Oct 20, 2021 at 0:15

You must log in to answer this question.

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