# Connecting nodes by lines which represent density of connections

How could the lines be connected to signify density(heat) by the number of lines connecting to parenting nodes. I.e the more lines connect to same parent node, the brighter the heat of the converging line. The lines can be at 90 degree angles, straight or curved, but they should converge somehow. Is there a reasnoable way to represent this data? We can already see the heatmap effect happening on the picture by the density of black connecting lines, however it should be more obvious what node has most connections incoming.

Perhaps making the lines slightly opaque and let stacking create the visual effect of density? Perhaps applying some coloring?

What is density heatmap for the lines? For some inspiration:

Current:

\documentclass[12pt, a4paper]{report}
\usepackage{pgfplots}
\usepackage{subcaption}
\usepackage{pgfplots}
\usepackage{xstring}
\usepackage[ruled,vlined]{algorithm2e}
\usepackage{tikz}
\usepackage{amsmath,caption}
\usepackage{svg}

\usepackage{tikz}
\usetikzlibrary{calc,shapes.geometric, arrows, positioning, arrows.meta, fit, backgrounds, patterns, arrows.meta,bending}

\newcommand\drawNodesSuperTight[2]{
\foreach \neurons [count=\lyrIdx] in #2 {
\StrCount{\neurons}{,}[\lyrLength]
\foreach \n [count=\nIdx] in \neurons {
\pgfmathsetmacro\xpos{(\nIdx-1)*\nodespacingSuperTight-\nodespacingSuperTight*(\lyrLength-1)/2}
\node[neuron2] (#1-\lyrIdx-\nIdx) at (\xpos, \layerdistanceSuperTight*\lyrIdx) {\n};
}
}
}

\newcommand\connectSomeNodesSmallArrow[2]{
\foreach \layer [count=\lyrIdx, evaluate=\lyrIdx as \nextLyr using int(\lyrIdx+1)] in #2
\foreach \neuron [count=\nIdx] in \layer
\foreach \edge in \neuron
\draw[my_arrow2] (#1-\lyrIdx-\nIdx.north) -- (#1-\nextLyr-\edge.south);
}

\newcommand{\nodeFontSuperTight}{\fontsize{4pt}{4pt}\selectfont}
\newcommand{\nodesizeSuperTight}{0.4cm}
\newcommand{\nodespacingSuperTight}{0.1ex}
\newcommand{\layerdistanceSuperTight}{6ex}
\newcommand{\nodesize}{0.5cm}
\newcommand{\nodespacing}{0.3ex}
\newcommand{\nodespacingThight}{0.15ex}
\newcommand{\layerdistance}{8ex}

\tikzset{
my_arrow/.style={-{Stealth[length=3pt]}, line width=0.1mm},
my_arrow2/.style={-{Stealth[length=1.5pt]}, line width=0.1mm},
neuron/.style={circle, draw, font=\tiny, minimum size=\nodesize, inner sep=\nodepadding, thick},
neuron2/.style={circle, draw, font=\nodeFontSuperTight, minimum size=\nodesizeSuperTight, inner sep=\nodepaddingSuperTight, thick},
legend/.style={font=\tiny, fill=white, inner sep=1pt},
odds/.style={legend,fill=white,pos=0.5,inner sep=2pt},
severity/.style={legend,right=1.4ex,align=left,anchor=west},
}

\begin{document}

\begin{tikzpicture}
\drawNodesSuperTight{fcnn}{{{129,549,233,137,586,175,624,176,112,594,242,114,212,21,117,439,184,26,122,28,124,94},{1,2,3,4,5,6},{1,2,4,5,6},{1,2,3,4,5,6,7,8,9,10,11,12,13,14},{1,2,3},{HCS}}}
\connectSomeNodesSmallArrow{fcnn}{{{{1,2,5,6},5,{1,2,3,4,5},5,5,5,6,{1,2,5,6},{1,2,5,6},{1,2,5,6},5,{1,2,5},5,5,{1,5,6},{1,2,3,4,5,6},{5,6},5,5,5,{1,2,5,6},5},{{2,3,4,5},{2,3,5},{3,5},{2,3,5},{1,2,3,4,5},{1,2,3,4,5}},{{1,2,3,4,5,6,7,8,9,10,11,12,13,14},{1,2,3,4,5,6,7,8,9,10,11,12,13,14},{1,2,3,4,5,6,7,8,9,10,11,12,13,14},{3,5,6,7,8,9,10,12,14},{1,2,3,4,5,6,7,8,9,10,11,12,13}},{{1,2,3},{1,2,3},{1,2,3},{1,2,3},{1,2,3},{1,2,3},{1,2,3},{1,2,3},{1,2,3},{1,2,3},{1,2,3},{1,2,3},{1,2,3},{1,2,3}},{1,1,1}}}
\end{tikzpicture}

\end{document}


• Did you try it? Adding opacity seems a reasonable thing to try and is a simple tweak. I take it you're not just asking how to make the lines partially transparent given the code you've come up with already.
– cfr
Commented Mar 12 at 5:04

I don't know exactly what this represents - it reminds me of a neural net - but, on the assumption that it is the nodes which are affected and not (or not just the lines), I'd be tempted to apply the stacking effect to them (or them too).

You could rewrite the code to do that, but you can get part way there with simple tweaks if you apply the stacking just to the nodes' borders, as opposed to their content.

For example,

\documentclass[12pt,border=5pt]{standalone}
\usepackage{xstring}
\usepackage{tikz}

\usepackage{tikz}
\usetikzlibrary{arrows.meta,bending,fit}

\newcommand\drawNodesSuperTight[2]{
\foreach \neurons [count=\lyrIdx] in #2 {
\StrCount{\neurons}{,}[\lyrLength]
\foreach \n [count=\nIdx] in \neurons {
\pgfmathsetmacro\xpos{(\nIdx-1)*\nodespacingSuperTight-\nodespacingSuperTight*(\lyrLength-1)/2}
\node[neuron2,draw=none,line width=0pt,minimum size=0pt] (#1-\lyrIdx-\nIdx) at (\xpos, \layerdistanceSuperTight*\lyrIdx) {\n};
}
}
}

\newcommand\connectSomeNodesSmallArrow[2]{
\foreach \layer [count=\lyrIdx, evaluate=\lyrIdx as \nextLyr using int(\lyrIdx+1)] in #2
\foreach \neuron [count=\nIdx] in \layer
\foreach \edge in \neuron
{
\node [fit=(#1-\lyrIdx-\nIdx),neuron2,inner sep=-0.8pt] (n-#1-\lyrIdx-\nIdx) {};
\node [neuron2,fit=(#1-\nextLyr-\edge),inner sep=-0.8pt] (n-#1-\nextLyr-\edge)  {};
\draw[my_arrow2] (n-#1-\lyrIdx-\nIdx.north) -- (n-#1-\nextLyr-\edge.south);
}
}

\newcommand{\nodeFontSuperTight}{\fontsize{4pt}{4pt}\selectfont}
\newcommand{\nodesizeSuperTight}{0.4cm}
\newcommand{\nodespacingSuperTight}{0.1ex}
\newcommand{\layerdistanceSuperTight}{6ex}
\newcommand{\nodesize}{0.5cm}

\tikzset{
my_arrow2/.style={-{Stealth[length=1.5pt]}, line width=0.1mm},
neuron2/.style={circle, draw, font=\nodeFontSuperTight, minimum size=\nodesizeSuperTight, inner sep=\nodepaddingSuperTight, thick},
}

\begin{document}

\begin{tikzpicture}[draw opacity=.25,every node/.append style={draw opacity=.05}]
\drawNodesSuperTight{fcnn}{{{129,549,233,137,586,175,624,176,112,594,242,114,212,21,117,439,184,26,122,28,124,94},{1,2,3,4,5,6},{1,2,4,5,6},{1,2,3,4,5,6,7,8,9,10,11,12,13,14},{1,2,3},{HCS}}}
\connectSomeNodesSmallArrow{fcnn}{{{{1,2,5,6},5,{1,2,3,4,5},5,5,5,6,{1,2,5,6},{1,2,5,6},{1,2,5,6},5,{1,2,5},5,5,{1,5,6},{1,2,3,4,5,6},{5,6},5,5,5,{1,2,5,6},5},{{2,3,4,5},{2,3,5},{3,5},{2,3,5},{1,2,3,4,5},{1,2,3,4,5}},{{1,2,3,4,5,6,7,8,9,10,11,12,13,14},{1,2,3,4,5,6,7,8,9,10,11,12,13,14},{1,2,3,4,5,6,7,8,9,10,11,12,13,14},{3,5,6,7,8,9,10,12,14},{1,2,3,4,5,6,7,8,9,10,11,12,13}},{{1,2,3},{1,2,3},{1,2,3},{1,2,3},{1,2,3},{1,2,3},{1,2,3},{1,2,3},{1,2,3},{1,2,3},{1,2,3},{1,2,3},{1,2,3},{1,2,3}},{1,1,1}}}
\end{tikzpicture}

\end{document}


It's impossible to determine what looks right without knowing what you're trying to represent, but you probably want distinct values for the edges and node borders. Otherwise you get insufficient variation in one or other.

Note that the crappy image is courtesy of the latest, greatest KDE upgrade which, in time honoured fashion, makes a perfectly functional desktop initially completely unusable. Fixing graphical copy isn't high on my priority list right now, so you'll just have to take my word for it that the original looks nothing like this.

• Thanks for the opacity trick. I see that you have applied the method on nodes (which, in fact, is not a bad idea) - but I was leaning more towards using the connecting lines to show heatmap (density). Sorry for the poor explanation, I don't know exactly where I'm trying to go with this either. But the important part is that I am looking for a way to upgrade visuals which can better represent that some nodes have more incoming connections than others (i.e., perhaps visualize it in a heatmap style). I added a line heatmap example to the original post. Commented Mar 12 at 7:34
• @JoosepParts I applied it to both node borders and the connecting lines. You can use one or other or both (or neither) according to what you want to do. I used a lower opacity for the node borders because otherwise the effect was either not clear for the lines or not clear for the nodes, but you can obviously adjust this, too. The effect on the lines is really not obvious at all in the clipped image. In the PDF, it is a bit more subtle than the effect for the nodes, but much clearer than it looks here.
– cfr
Commented Mar 12 at 20:12

Maybe you can use @cfr's idea and add colors. (I also tried to play with blend modes, but with no success). The colors are horrible, but you get the idea...

Notice that arrows are strange; you should enclose every drawn line in a transparency group (see them commented out in the code), but if I use them, the resulting PDF kills my viewer (okular, and also evince if zoomed in), in the sense that it is not able to render the image.

\documentclass[12pt, a4paper]{report}
\usepackage{xstring}
\usepackage{tikz}
\usepackage{svg}

\usepackage{tikz}
\usetikzlibrary{calc,shapes.geometric, arrows, positioning, arrows.meta, fit, backgrounds, patterns, arrows.meta,bending}

\newcommand\drawNodesSuperTight[2]{
\foreach \neurons [count=\lyrIdx] in #2 {
\StrCount{\neurons}{,}[\lyrLength]
\foreach \n [count=\nIdx] in \neurons {
\pgfmathsetmacro\xpos{(\nIdx-1)*\nodespacingSuperTight-\nodespacingSuperTight*(\lyrLength-1)/2}
\node[neuron2] (#1-\lyrIdx-\nIdx) at (\xpos, \layerdistanceSuperTight*\lyrIdx) {\n};
}
}
}

\newcommand\connectSomeNodesSmallArrow[3][]{
\foreach \layer [count=\lyrIdx, evaluate=\lyrIdx as \nextLyr using int(\lyrIdx+1)] in #3
\foreach \neuron [count=\nIdx] in \layer
\foreach \edge in \neuron {
% this transparency group kills my viewer(s)
%\begin{scope}[transparency group, opacity=0.3]
\draw[my_arrow2, line cap=round, #1] (#2-\lyrIdx-\nIdx.north) -- (#2-\nextLyr-\edge.south);
% \end{scope}
}
}

\newcommand{\nodeFontSuperTight}{\fontsize{4pt}{4pt}\selectfont}
\newcommand{\nodesizeSuperTight}{0.4cm}
\newcommand{\nodespacingSuperTight}{0.1ex}
\newcommand{\layerdistanceSuperTight}{6ex}
\newcommand{\nodesize}{0.5cm}
\newcommand{\nodespacing}{0.3ex}
\newcommand{\nodespacingThight}{0.15ex}
\newcommand{\layerdistance}{8ex}

\tikzset{
my_arrow/.style={-{Stealth[length=3pt]}, line width=0.1mm},
my_arrow2/.style={-{Stealth[length=3.5pt]}, line width=0.4mm},
neuron/.style={circle, draw, font=\tiny, minimum size=\nodesize, inner sep=\nodepadding, thick},
neuron2/.style={circle, draw, font=\nodeFontSuperTight, minimum size=\nodesizeSuperTight, inner sep=\nodepaddingSuperTight, thick},
legend/.style={font=\tiny, fill=white, inner sep=1pt},
odds/.style={legend,fill=white,pos=0.5,inner sep=2pt},
severity/.style={legend,right=1.4ex,align=left,anchor=west},
}

\newcommand{\DoNodes}{%
\drawNodesSuperTight{fcnn}{{{129,549,233,137,586,175,624,176,112,594,242,114,212,21,117,439,184,26,122,28,124,94},{1,2,3,4,5,6},{1,2,4,5,6},{1,2,3,4,5,6,7,8,9,10,11,12,13,14},{1,2,3},{HCS}}}
}
\newcommand{\DoConns}[1]{%
\connectSomeNodesSmallArrow[#1]{fcnn}{{{{1,2,5,6},5,{1,2,3,4,5},5,5,5,6,{1,2,5,6},{1,2,5,6},{1,2,5,6},5,{1,2,5},5,5,{1,5,6},{1,2,3,4,5,6},{5,6},5,5,5,{1,2,5,6},5},{{2,3,4,5},{2,3,5},{3,5},{2,3,5},{1,2,3,4,5},{1,2,3,4,5}},{{1,2,3,4,5,6,7,8,9,10,11,12,13,14},{1,2,3,4,5,6,7,8,9,10,11,12,13,14},{1,2,3,4,5,6,7,8,9,10,11,12,13,14},{3,5,6,7,8,9,10,12,14},{1,2,3,4,5,6,7,8,9,10,11,12,13}},{{1,2,3},{1,2,3},{1,2,3},{1,2,3},{1,2,3},{1,2,3},{1,2,3},{1,2,3},{1,2,3},{1,2,3},{1,2,3},{1,2,3},{1,2,3},{1,2,3}},{1,1,1}}}
}

\begin{document}

\begin{tikzpicture}
\DoNodes
\DoConns{draw opacity=.25, line width=2pt, color=green}
\DoConns{draw opacity=.25, line width=2pt, color=red}
\end{tikzpicture}

\end{document}

• This looks very promising. I would also probably introduce varying opacity. To use min-max normalization for each layer s.t lines which converge the most get opacity = 0.9, lines which converge the least get 0.3 opacity, and eveything else in between. In addition to stacking this varying opacity would probably highlight density even more. Commented Mar 12 at 12:24
• @JoosepParts To be honest, I can't see the arrow heads well at all, but they should be in transparency groups, indeed. Blend modes could potentially work well. Unfortunately, viewer support is very patchy, so there's no knowing how any of them will look in other viewers.
– cfr
Commented Mar 12 at 20:16